Digital Office Automation System Backend
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

stencil-controller.js 62KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435
  1. /*
  2. * Activiti Modeler component part of the Activiti project
  3. * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
  4. *
  5. * This library is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU Lesser General Public
  7. * License as published by the Free Software Foundation; either
  8. * version 2.1 of the License, or (at your option) any later version.
  9. *
  10. * This library is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. * Lesser General Public License for more details.
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with this library; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. */
  18. 'use strict';
  19. angular.module('activitiModeler')
  20. .controller('StencilController', ['$rootScope', '$scope', '$http', '$modal', '$timeout', function ($rootScope, $scope, $http, $modal, $timeout) {
  21. // Property window toggle state
  22. $scope.propertyWindowState = {'collapsed': false};
  23. // Add reference to global header-config
  24. $scope.headerConfig = KISBPM.HEADER_CONFIG;
  25. $scope.propertyWindowState.toggle = function () {
  26. $scope.propertyWindowState.collapsed = !$scope.propertyWindowState.collapsed;
  27. $timeout(function () {
  28. jQuery(window).trigger('resize');
  29. });
  30. };
  31. // Code that is dependent on an initialised Editor is wrapped in a promise for the editor
  32. $scope.editorFactory.promise.then(function () {
  33. /* Build stencil item list */
  34. // Build simple json representation of stencil set
  35. var stencilItemGroups = [];
  36. // Helper method: find a group in an array
  37. var findGroup = function (name, groupArray) {
  38. for (var index = 0; index < groupArray.length; index++) {
  39. if (groupArray[index].name === name) {
  40. return groupArray[index];
  41. }
  42. }
  43. return null;
  44. };
  45. // Helper method: add a new group to an array of groups
  46. var addGroup = function (groupName, groupArray) {
  47. var group = { name: groupName, items: [], paletteItems: [], groups: [], visible: true };
  48. groupArray.push(group);
  49. return group;
  50. };
  51. /*
  52. StencilSet items
  53. */
  54. $http({method: 'GET', url: KISBPM.URL.getStencilSet()}).success(function (data, status, headers, config) {
  55. var quickMenuDefinition = ['UserTask', 'EndNoneEvent', 'ExclusiveGateway',
  56. 'CatchTimerEvent', 'ThrowNoneEvent', 'TextAnnotation',
  57. 'SequenceFlow', 'Association'];
  58. var ignoreForPaletteDefinition = ['SequenceFlow', 'MessageFlow', 'Association', 'DataAssociation', 'DataStore', 'SendTask'];
  59. var quickMenuItems = [];
  60. var morphRoles = [];
  61. for (var i = 0; i < data.rules.morphingRules.length; i++)
  62. {
  63. var role = data.rules.morphingRules[i].role;
  64. var roleItem = {'role': role, 'morphOptions': []};
  65. morphRoles.push(roleItem);
  66. }
  67. // Check all received items
  68. for (var stencilIndex = 0; stencilIndex < data.stencils.length; stencilIndex++)
  69. {
  70. // Check if the root group is the 'diagram' group. If so, this item should not be shown.
  71. var currentGroupName = data.stencils[stencilIndex].groups[0];
  72. if (currentGroupName === 'Diagram' || currentGroupName === 'Form') {
  73. continue; // go to next item
  74. }
  75. var removed = false;
  76. if (data.stencils[stencilIndex].removed) {
  77. removed = true;
  78. }
  79. var currentGroup = undefined;
  80. if (!removed) {
  81. // Check if this group already exists. If not, we create a new one
  82. if (currentGroupName !== null && currentGroupName !== undefined && currentGroupName.length > 0) {
  83. currentGroup = findGroup(currentGroupName, stencilItemGroups); // Find group in root groups array
  84. if (currentGroup === null) {
  85. currentGroup = addGroup(currentGroupName, stencilItemGroups);
  86. }
  87. // Add all child groups (if any)
  88. for (var groupIndex = 1; groupIndex < data.stencils[stencilIndex].groups.length; groupIndex++) {
  89. var childGroupName = data.stencils[stencilIndex].groups[groupIndex];
  90. var childGroup = findGroup(childGroupName, currentGroup.groups);
  91. if (childGroup === null) {
  92. childGroup = addGroup(childGroupName, currentGroup.groups);
  93. }
  94. // The current group variable holds the parent of the next group (if any),
  95. // and is basically the last element in the array of groups defined in the stencil item
  96. currentGroup = childGroup;
  97. }
  98. }
  99. }
  100. // Construct the stencil item
  101. var stencilItem = {'id': data.stencils[stencilIndex].id,
  102. 'name': data.stencils[stencilIndex].title,
  103. 'description': data.stencils[stencilIndex].description,
  104. 'icon': data.stencils[stencilIndex].icon,
  105. 'type': data.stencils[stencilIndex].type,
  106. 'roles': data.stencils[stencilIndex].roles,
  107. 'removed': removed,
  108. 'customIcon': false,
  109. 'canConnect': false,
  110. 'canConnectTo': false,
  111. 'canConnectAssociation': false};
  112. if (data.stencils[stencilIndex].customIconId && data.stencils[stencilIndex].customIconId > 0) {
  113. stencilItem.customIcon = true;
  114. stencilItem.icon = data.stencils[stencilIndex].customIconId;
  115. }
  116. if (!removed) {
  117. if (quickMenuDefinition.indexOf(stencilItem.id) >= 0) {
  118. quickMenuItems[quickMenuDefinition.indexOf(stencilItem.id)] = stencilItem;
  119. }
  120. }
  121. if (stencilItem.id === 'TextAnnotation' || stencilItem.id === 'BoundaryCompensationEvent') {
  122. stencilItem.canConnectAssociation = true;
  123. }
  124. for (var i = 0; i < data.stencils[stencilIndex].roles.length; i++) {
  125. var stencilRole = data.stencils[stencilIndex].roles[i];
  126. if (stencilRole === 'sequence_start') {
  127. stencilItem.canConnect = true;
  128. } else if (stencilRole === 'sequence_end') {
  129. stencilItem.canConnectTo = true;
  130. }
  131. for (var j = 0; j < morphRoles.length; j++) {
  132. if (stencilRole === morphRoles[j].role) {
  133. if (!removed) {
  134. morphRoles[j].morphOptions.push(stencilItem);
  135. }
  136. stencilItem.morphRole = morphRoles[j].role;
  137. break;
  138. }
  139. }
  140. }
  141. if (currentGroup) {
  142. // Add the stencil item to the correct group
  143. currentGroup.items.push(stencilItem);
  144. if (ignoreForPaletteDefinition.indexOf(stencilItem.id) < 0) {
  145. currentGroup.paletteItems.push(stencilItem);
  146. }
  147. } else {
  148. // It's a root stencil element
  149. if (!removed) {
  150. stencilItemGroups.push(stencilItem);
  151. }
  152. }
  153. }
  154. for (var i = 0; i < stencilItemGroups.length; i++)
  155. {
  156. if (stencilItemGroups[i].paletteItems && stencilItemGroups[i].paletteItems.length == 0)
  157. {
  158. stencilItemGroups[i].visible = false;
  159. }
  160. }
  161. $scope.stencilItemGroups = stencilItemGroups;
  162. var containmentRules = [];
  163. for (var i = 0; i < data.rules.containmentRules.length; i++)
  164. {
  165. var rule = data.rules.containmentRules[i];
  166. containmentRules.push(rule);
  167. }
  168. $scope.containmentRules = containmentRules;
  169. // remove quick menu items which are not available anymore due to custom pallette
  170. var availableQuickMenuItems = [];
  171. for (var i = 0; i < quickMenuItems.length; i++)
  172. {
  173. if (quickMenuItems[i]) {
  174. availableQuickMenuItems[availableQuickMenuItems.length] = quickMenuItems[i];
  175. }
  176. }
  177. $scope.quickMenuItems = availableQuickMenuItems;
  178. $scope.morphRoles = morphRoles;
  179. }).
  180. error(function (data, status, headers, config) {
  181. console.log('Something went wrong when fetching stencil items:' + JSON.stringify(data));
  182. });
  183. /*
  184. * Listen to selection change events: show properties
  185. */
  186. $scope.editor.registerOnEvent(ORYX.CONFIG.EVENT_SELECTION_CHANGED, function (event) {
  187. var shapes = event.elements;
  188. var canvasSelected = false;
  189. if (shapes && shapes.length == 0) {
  190. shapes = [$scope.editor.getCanvas()];
  191. canvasSelected = true;
  192. }
  193. if (shapes && shapes.length > 0) {
  194. var selectedShape = shapes.first();
  195. var stencil = selectedShape.getStencil();
  196. if ($rootScope.selectedElementBeforeScrolling && stencil.id().indexOf('BPMNDiagram') !== -1)
  197. {
  198. // ignore canvas event because of empty selection when scrolling stops
  199. return;
  200. }
  201. if ($rootScope.selectedElementBeforeScrolling && $rootScope.selectedElementBeforeScrolling.getId() === selectedShape.getId())
  202. {
  203. $rootScope.selectedElementBeforeScrolling = null;
  204. return;
  205. }
  206. // Store previous selection
  207. $scope.previousSelectedShape = $scope.selectedShape;
  208. // Only do something if another element is selected (Oryx fires this event multiple times)
  209. if ($scope.selectedShape !== undefined && $scope.selectedShape.getId() === selectedShape.getId()) {
  210. if ($rootScope.forceSelectionRefresh) {
  211. // Switch the flag again, this run will force refresh
  212. $rootScope.forceSelectionRefresh = false;
  213. } else {
  214. // Selected the same element again, no need to update anything
  215. return;
  216. }
  217. }
  218. var selectedItem = {'title': '', 'properties': []};
  219. if (canvasSelected) {
  220. selectedItem.auditData = {
  221. 'author': $scope.modelData.createdByUser,
  222. 'createDate': $scope.modelData.createDate
  223. };
  224. }
  225. // Gather properties of selected item
  226. var properties = stencil.properties();
  227. for (var i = 0; i < properties.length; i++) {
  228. var property = properties[i];
  229. if (property.popular() == false) continue;
  230. var key = property.prefix() + "-" + property.id();
  231. if (key === 'oryx-name') {
  232. selectedItem.title = selectedShape.properties[key];
  233. }
  234. // First we check if there is a config for 'key-type' and then for 'type' alone
  235. var propertyConfig = KISBPM.PROPERTY_CONFIG[key + '-' + property.type()];
  236. if (propertyConfig === undefined || propertyConfig === null) {
  237. propertyConfig = KISBPM.PROPERTY_CONFIG[property.type()];
  238. }
  239. if (propertyConfig === undefined || propertyConfig === null) {
  240. console.log('WARNING: no property configuration defined for ' + key + ' of type ' + property.type());
  241. } else {
  242. if (selectedShape.properties[key] === 'true') {
  243. selectedShape.properties[key] = true;
  244. }
  245. if (KISBPM.CONFIG.showRemovedProperties == false && property.isHidden())
  246. {
  247. continue;
  248. }
  249. var currentProperty = {
  250. 'key': key,
  251. 'title': property.title(),
  252. 'type': property.type(),
  253. 'mode': 'read',
  254. 'hidden': property.isHidden(),
  255. 'value': selectedShape.properties[key]
  256. };
  257. if ((currentProperty.type === 'complex' || currentProperty.type === 'multiplecomplex') && currentProperty.value && currentProperty.value.length > 0) {
  258. try {
  259. currentProperty.value = JSON.parse(currentProperty.value);
  260. } catch (err) {
  261. // ignore
  262. }
  263. }
  264. if (propertyConfig.readModeTemplateUrl !== undefined && propertyConfig.readModeTemplateUrl !== null) {
  265. currentProperty.readModeTemplateUrl = propertyConfig.readModeTemplateUrl + '?version=' + $rootScope.staticIncludeVersion;
  266. }
  267. if (propertyConfig.writeModeTemplateUrl !== null && propertyConfig.writeModeTemplateUrl !== null) {
  268. currentProperty.writeModeTemplateUrl = propertyConfig.writeModeTemplateUrl + '?version=' + $rootScope.staticIncludeVersion;
  269. }
  270. if (propertyConfig.templateUrl !== undefined && propertyConfig.templateUrl !== null) {
  271. currentProperty.templateUrl = propertyConfig.templateUrl + '?version=' + $rootScope.staticIncludeVersion;
  272. currentProperty.hasReadWriteMode = false;
  273. }
  274. else {
  275. currentProperty.hasReadWriteMode = true;
  276. }
  277. if (currentProperty.value === undefined
  278. || currentProperty.value === null
  279. || currentProperty.value.length == 0) {
  280. currentProperty.noValue = true;
  281. }
  282. selectedItem.properties.push(currentProperty);
  283. }
  284. }
  285. // Need to wrap this in an $apply block, see http://jimhoskins.com/2012/12/17/angularjs-and-apply.html
  286. $scope.safeApply(function () {
  287. $scope.selectedItem = selectedItem;
  288. $scope.selectedShape = selectedShape;
  289. });
  290. } else {
  291. $scope.safeApply(function () {
  292. $scope.selectedItem = {};
  293. $scope.selectedShape = null;
  294. });
  295. }
  296. });
  297. $scope.editor.registerOnEvent(ORYX.CONFIG.EVENT_SELECTION_CHANGED, function (event) {
  298. KISBPM.eventBus.dispatch(KISBPM.eventBus.EVENT_TYPE_HIDE_SHAPE_BUTTONS);
  299. var shapes = event.elements;
  300. if (shapes && shapes.length == 1) {
  301. var selectedShape = shapes.first();
  302. var a = $scope.editor.getCanvas().node.getScreenCTM();
  303. var absoluteXY = selectedShape.absoluteXY();
  304. absoluteXY.x *= a.a;
  305. absoluteXY.y *= a.d;
  306. var additionalIEZoom = 1;
  307. if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) {
  308. var ua = navigator.userAgent;
  309. if (ua.indexOf('MSIE') >= 0) {
  310. //IE 10 and below
  311. var zoom = Math.round((screen.deviceXDPI / screen.logicalXDPI) * 100);
  312. if (zoom !== 100) {
  313. additionalIEZoom = zoom / 100
  314. }
  315. }
  316. }
  317. if (additionalIEZoom === 1) {
  318. absoluteXY.y = absoluteXY.y - jQuery("#canvasSection").offset().top + 5;
  319. absoluteXY.x = absoluteXY.x - jQuery("#canvasSection").offset().left;
  320. } else {
  321. var canvasOffsetLeft = jQuery("#canvasSection").offset().left;
  322. var canvasScrollLeft = jQuery("#canvasSection").scrollLeft();
  323. var canvasScrollTop = jQuery("#canvasSection").scrollTop();
  324. var offset = a.e - (canvasOffsetLeft * additionalIEZoom);
  325. var additionaloffset = 0;
  326. if (offset > 10) {
  327. additionaloffset = (offset / additionalIEZoom) - offset;
  328. }
  329. absoluteXY.y = absoluteXY.y - (jQuery("#canvasSection").offset().top * additionalIEZoom) + 5 + ((canvasScrollTop * additionalIEZoom) - canvasScrollTop);
  330. absoluteXY.x = absoluteXY.x - (canvasOffsetLeft * additionalIEZoom) + additionaloffset + ((canvasScrollLeft * additionalIEZoom) - canvasScrollLeft);
  331. }
  332. var bounds = new ORYX.Core.Bounds(a.e + absoluteXY.x, a.f + absoluteXY.y, a.e + absoluteXY.x + a.a*selectedShape.bounds.width(), a.f + absoluteXY.y + a.d*selectedShape.bounds.height());
  333. var shapeXY = bounds.upperLeft();
  334. var stencilItem = $scope.getStencilItemById(selectedShape.getStencil().idWithoutNs());
  335. var morphShapes = [];
  336. if (stencilItem && stencilItem.morphRole)
  337. {
  338. for (var i = 0; i < $scope.morphRoles.length; i++)
  339. {
  340. if ($scope.morphRoles[i].role === stencilItem.morphRole)
  341. {
  342. morphShapes = $scope.morphRoles[i].morphOptions;
  343. }
  344. }
  345. }
  346. var x = shapeXY.x;
  347. if (bounds.width() < 48) {
  348. x -= 24;
  349. }
  350. if (morphShapes && morphShapes.length > 0) {
  351. // In case the element is not wide enough, start the 2 bottom-buttons more to the left
  352. // to prevent overflow in the right-menu
  353. var morphButton = document.getElementById('morph-button');
  354. morphButton.style.display = "block";
  355. morphButton.style.left = x + 24 +'px';
  356. morphButton.style.top = (shapeXY.y+bounds.height() + 2) + 'px';
  357. }
  358. var deleteButton = document.getElementById('delete-button');
  359. deleteButton.style.display = "block";
  360. deleteButton.style.left = x + 'px';
  361. deleteButton.style.top = (shapeXY.y+bounds.height() + 2) + 'px';
  362. if (stencilItem && (stencilItem.canConnect || stencilItem.canConnectAssociation)) {
  363. var quickButtonCounter = 0;
  364. var quickButtonX = shapeXY.x+bounds.width() + 5;
  365. var quickButtonY = shapeXY.y;
  366. jQuery('.Oryx_button').each(function(i, obj) {
  367. if (obj.id !== 'morph-button' && obj.id != 'delete-button') {
  368. quickButtonCounter++;
  369. if (quickButtonCounter > 3) {
  370. quickButtonX = shapeXY.x+bounds.width() + 5;
  371. quickButtonY += 24;
  372. quickButtonCounter = 1;
  373. } else if (quickButtonCounter > 1) {
  374. quickButtonX += 24;
  375. }
  376. obj.style.display = "block";
  377. obj.style.left = quickButtonX + 'px';
  378. obj.style.top = quickButtonY + 'px';
  379. }
  380. });
  381. }
  382. }
  383. });
  384. if (!$rootScope.stencilInitialized) {
  385. KISBPM.eventBus.addListener(KISBPM.eventBus.EVENT_TYPE_HIDE_SHAPE_BUTTONS, function (event) {
  386. jQuery('.Oryx_button').each(function(i, obj) {
  387. obj.style.display = "none";
  388. });
  389. });
  390. /*
  391. * Listen to property updates and act upon them
  392. */
  393. KISBPM.eventBus.addListener(KISBPM.eventBus.EVENT_TYPE_PROPERTY_VALUE_CHANGED, function (event) {
  394. if (event.property && event.property.key) {
  395. // If the name property is been updated, we also need to change the title of the currently selected item
  396. if (event.property.key === 'oryx-name' && $scope.selectedItem !== undefined && $scope.selectedItem !== null) {
  397. $scope.selectedItem.title = event.newValue;
  398. }
  399. // Update "no value" flag
  400. event.property.noValue = (event.property.value === undefined
  401. || event.property.value === null
  402. || event.property.value.length == 0);
  403. }
  404. });
  405. $rootScope.stencilInitialized = true;
  406. }
  407. $scope.morphShape = function() {
  408. $scope.safeApply(function () {
  409. var shapes = $rootScope.editor.getSelection();
  410. if (shapes && shapes.length == 1)
  411. {
  412. $rootScope.currentSelectedShape = shapes.first();
  413. var stencilItem = $scope.getStencilItemById($rootScope.currentSelectedShape.getStencil().idWithoutNs());
  414. var morphShapes = [];
  415. for (var i = 0; i < $scope.morphRoles.length; i++)
  416. {
  417. if ($scope.morphRoles[i].role === stencilItem.morphRole)
  418. {
  419. morphShapes = $scope.morphRoles[i].morphOptions.slice();
  420. }
  421. }
  422. // Method to open shape select dialog (used later on)
  423. var showSelectShapeDialog = function()
  424. {
  425. $rootScope.morphShapes = morphShapes;
  426. $modal({
  427. backdrop: false,
  428. keyboard: true,
  429. template: 'editor-app/popups/select-shape.html?version=' + Date.now()
  430. });
  431. };
  432. showSelectShapeDialog();
  433. }
  434. });
  435. };
  436. $scope.deleteShape = function() {
  437. KISBPM.TOOLBAR.ACTIONS.deleteItem({'$scope': $scope});
  438. };
  439. $scope.quickAddItem = function(newItemId) {
  440. $scope.safeApply(function () {
  441. var shapes = $rootScope.editor.getSelection();
  442. if (shapes && shapes.length == 1)
  443. {
  444. $rootScope.currentSelectedShape = shapes.first();
  445. var containedStencil = undefined;
  446. var stencilSets = $scope.editor.getStencilSets().values();
  447. for (var i = 0; i < stencilSets.length; i++)
  448. {
  449. var stencilSet = stencilSets[i];
  450. var nodes = stencilSet.nodes();
  451. for (var j = 0; j < nodes.length; j++)
  452. {
  453. if (nodes[j].idWithoutNs() === newItemId)
  454. {
  455. containedStencil = nodes[j];
  456. break;
  457. }
  458. }
  459. }
  460. if (!containedStencil) return;
  461. var option = {type: $scope.currentSelectedShape.getStencil().namespace() + newItemId, namespace: $scope.currentSelectedShape.getStencil().namespace()};
  462. option['connectedShape'] = $rootScope.currentSelectedShape;
  463. option['parent'] = $rootScope.currentSelectedShape.parent;
  464. option['containedStencil'] = containedStencil;
  465. var args = { sourceShape: $rootScope.currentSelectedShape, targetStencil: containedStencil };
  466. var targetStencil = $scope.editor.getRules().connectMorph(args);
  467. if (!targetStencil){ return; }// Check if there can be a target shape
  468. option['connectingType'] = targetStencil.id();
  469. var command = new KISBPM.CreateCommand(option, undefined, undefined, $scope.editor);
  470. $scope.editor.executeCommands([command]);
  471. }
  472. });
  473. };
  474. }); // end of $scope.editorFactory.promise block
  475. /* Click handler for clicking a property */
  476. $scope.propertyClicked = function (index) {
  477. if (!$scope.selectedItem.properties[index].hidden) {
  478. $scope.selectedItem.properties[index].mode = "write";
  479. }
  480. };
  481. /* Helper method to retrieve the template url for a property */
  482. $scope.getPropertyTemplateUrl = function (index) {
  483. return $scope.selectedItem.properties[index].templateUrl;
  484. };
  485. $scope.getPropertyReadModeTemplateUrl = function (index) {
  486. return $scope.selectedItem.properties[index].readModeTemplateUrl;
  487. };
  488. $scope.getPropertyWriteModeTemplateUrl = function (index) {
  489. return $scope.selectedItem.properties[index].writeModeTemplateUrl;
  490. };
  491. /* Method available to all sub controllers (for property controllers) to update the internal Oryx model */
  492. $scope.updatePropertyInModel = function (property, shapeId) {
  493. var shape = $scope.selectedShape;
  494. // Some updates may happen when selected shape is already changed, so when an additional
  495. // shapeId is supplied, we need to make sure the correct shape is updated (current or previous)
  496. if (shapeId) {
  497. if (shape.id != shapeId && $scope.previousSelectedShape && $scope.previousSelectedShape.id == shapeId) {
  498. shape = $scope.previousSelectedShape;
  499. } else {
  500. shape = null;
  501. }
  502. }
  503. if (!shape) {
  504. // When no shape is selected, or no shape is found for the alternative
  505. // shape ID, do nothing
  506. return;
  507. }
  508. var key = property.key;
  509. var newValue = property.value;
  510. var oldValue = shape.properties[key];
  511. if (newValue != oldValue) {
  512. var commandClass = ORYX.Core.Command.extend({
  513. construct: function () {
  514. this.key = key;
  515. this.oldValue = oldValue;
  516. this.newValue = newValue;
  517. this.shape = shape;
  518. this.facade = $scope.editor;
  519. },
  520. execute: function () {
  521. this.shape.setProperty(this.key, this.newValue);
  522. this.facade.getCanvas().update();
  523. this.facade.updateSelection();
  524. },
  525. rollback: function () {
  526. this.shape.setProperty(this.key, this.oldValue);
  527. this.facade.getCanvas().update();
  528. this.facade.updateSelection();
  529. }
  530. });
  531. // Instantiate the class
  532. var command = new commandClass();
  533. // Execute the command
  534. $scope.editor.executeCommands([command]);
  535. $scope.editor.handleEvents({
  536. type: ORYX.CONFIG.EVENT_PROPWINDOW_PROP_CHANGED,
  537. elements: [shape],
  538. key: key
  539. });
  540. // Switch the property back to read mode, now the update is done
  541. property.mode = 'read';
  542. // Fire event to all who is interested
  543. // Fire event to all who want to know about this
  544. var event = {
  545. type: KISBPM.eventBus.EVENT_TYPE_PROPERTY_VALUE_CHANGED,
  546. property: property,
  547. oldValue: oldValue,
  548. newValue: newValue
  549. };
  550. KISBPM.eventBus.dispatch(event.type, event);
  551. } else {
  552. // Switch the property back to read mode, no update was needed
  553. property.mode = 'read';
  554. }
  555. };
  556. /**
  557. * Helper method that searches a group for an item with the given id.
  558. * If not found, will return undefined.
  559. */
  560. $scope.findStencilItemInGroup = function (stencilItemId, group) {
  561. var item;
  562. // Check all items directly in this group
  563. for (var j = 0; j < group.items.length; j++) {
  564. item = group.items[j];
  565. if (item.id === stencilItemId) {
  566. return item;
  567. }
  568. }
  569. // Check the child groups
  570. if (group.groups && group.groups.length > 0) {
  571. for (var k = 0; k < group.groups.length; k++) {
  572. item = $scope.findStencilItemInGroup(stencilItemId, group.groups[k]);
  573. if (item) {
  574. return item;
  575. }
  576. }
  577. }
  578. return undefined;
  579. };
  580. /**
  581. * Helper method to find a stencil item.
  582. */
  583. $scope.getStencilItemById = function (stencilItemId) {
  584. for (var i = 0; i < $scope.stencilItemGroups.length; i++) {
  585. var element = $scope.stencilItemGroups[i];
  586. // Real group
  587. if (element.items !== null && element.items !== undefined) {
  588. var item = $scope.findStencilItemInGroup(stencilItemId, element);
  589. if (item) {
  590. return item;
  591. }
  592. } else { // Root stencil item
  593. if (element.id === stencilItemId) {
  594. return element;
  595. }
  596. }
  597. }
  598. return undefined;
  599. };
  600. /*
  601. * DRAG AND DROP FUNCTIONALITY
  602. */
  603. $scope.dropCallback = function (event, ui) {
  604. $scope.editor.handleEvents({
  605. type: ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE,
  606. highlightId: "shapeRepo.attached"
  607. });
  608. $scope.editor.handleEvents({
  609. type: ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE,
  610. highlightId: "shapeRepo.added"
  611. });
  612. $scope.editor.handleEvents({
  613. type: ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE,
  614. highlightId: "shapeMenu"
  615. });
  616. KISBPM.eventBus.dispatch(KISBPM.eventBus.EVENT_TYPE_HIDE_SHAPE_BUTTONS);
  617. if ($scope.dragCanContain) {
  618. var item = $scope.getStencilItemById(ui.draggable[0].id);
  619. var pos = {x: event.pageX, y: event.pageY};
  620. var additionalIEZoom = 1;
  621. if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) {
  622. var ua = navigator.userAgent;
  623. if (ua.indexOf('MSIE') >= 0) {
  624. //IE 10 and below
  625. var zoom = Math.round((screen.deviceXDPI / screen.logicalXDPI) * 100);
  626. if (zoom !== 100) {
  627. additionalIEZoom = zoom / 100;
  628. }
  629. }
  630. }
  631. var screenCTM = $scope.editor.getCanvas().node.getScreenCTM();
  632. // Correcting the UpperLeft-Offset
  633. pos.x -= (screenCTM.e / additionalIEZoom);
  634. pos.y -= (screenCTM.f / additionalIEZoom);
  635. // Correcting the Zoom-Factor
  636. pos.x /= screenCTM.a;
  637. pos.y /= screenCTM.d;
  638. // Correcting the ScrollOffset
  639. pos.x -= document.documentElement.scrollLeft;
  640. pos.y -= document.documentElement.scrollTop;
  641. var parentAbs = $scope.dragCurrentParent.absoluteXY();
  642. pos.x -= parentAbs.x;
  643. pos.y -= parentAbs.y;
  644. var containedStencil = undefined;
  645. var stencilSets = $scope.editor.getStencilSets().values();
  646. for (var i = 0; i < stencilSets.length; i++)
  647. {
  648. var stencilSet = stencilSets[i];
  649. var nodes = stencilSet.nodes();
  650. for (var j = 0; j < nodes.length; j++)
  651. {
  652. if (nodes[j].idWithoutNs() === ui.draggable[0].id)
  653. {
  654. containedStencil = nodes[j];
  655. break;
  656. }
  657. }
  658. if (!containedStencil)
  659. {
  660. var edges = stencilSet.edges();
  661. for (var j = 0; j < edges.length; j++)
  662. {
  663. if (edges[j].idWithoutNs() === ui.draggable[0].id)
  664. {
  665. containedStencil = edges[j];
  666. break;
  667. }
  668. }
  669. }
  670. }
  671. if (!containedStencil) return;
  672. if ($scope.quickMenu)
  673. {
  674. var shapes = $scope.editor.getSelection();
  675. if (shapes && shapes.length == 1)
  676. {
  677. var currentSelectedShape = shapes.first();
  678. var option = {};
  679. option.type = currentSelectedShape.getStencil().namespace() + ui.draggable[0].id;
  680. option.namespace = currentSelectedShape.getStencil().namespace();
  681. option.connectedShape = currentSelectedShape;
  682. option.parent = $scope.dragCurrentParent;
  683. option.containedStencil = containedStencil;
  684. // If the ctrl key is not pressed,
  685. // snapp the new shape to the center
  686. // if it is near to the center of the other shape
  687. if (!event.ctrlKey){
  688. // Get the center of the shape
  689. var cShape = currentSelectedShape.bounds.center();
  690. // Snapp +-20 Pixel horizontal to the center
  691. if (20 > Math.abs(cShape.x - pos.x)){
  692. pos.x = cShape.x;
  693. }
  694. // Snapp +-20 Pixel vertical to the center
  695. if (20 > Math.abs(cShape.y - pos.y)){
  696. pos.y = cShape.y;
  697. }
  698. }
  699. option.position = pos;
  700. if (containedStencil.idWithoutNs() !== 'SequenceFlow' && containedStencil.idWithoutNs() !== 'Association' &&
  701. containedStencil.idWithoutNs() !== 'MessageFlow' && containedStencil.idWithoutNs() !== 'DataAssociation')
  702. {
  703. var args = { sourceShape: currentSelectedShape, targetStencil: containedStencil };
  704. var targetStencil = $scope.editor.getRules().connectMorph(args);
  705. if (!targetStencil){ return; }// Check if there can be a target shape
  706. option.connectingType = targetStencil.id();
  707. }
  708. var command = new KISBPM.CreateCommand(option, $scope.dropTargetElement, pos, $scope.editor);
  709. $scope.editor.executeCommands([command]);
  710. }
  711. }
  712. else
  713. {
  714. var canAttach = false;
  715. if (containedStencil.idWithoutNs() === 'BoundaryErrorEvent' || containedStencil.idWithoutNs() === 'BoundaryTimerEvent' ||
  716. containedStencil.idWithoutNs() === 'BoundarySignalEvent' || containedStencil.idWithoutNs() === 'BoundaryMessageEvent' ||
  717. containedStencil.idWithoutNs() === 'BoundaryCancelEvent' || containedStencil.idWithoutNs() === 'BoundaryCompensationEvent') {
  718. // Modify position, otherwise boundary event will get position related to left corner of the canvas instead of the container
  719. pos = $scope.editor.eventCoordinates( event );
  720. canAttach = true;
  721. }
  722. var option = {};
  723. option['type'] = $scope.modelData.model.stencilset.namespace + item.id;
  724. option['namespace'] = $scope.modelData.model.stencilset.namespace;
  725. option['position'] = pos;
  726. option['parent'] = $scope.dragCurrentParent;
  727. var commandClass = ORYX.Core.Command.extend({
  728. construct: function(option, dockedShape, canAttach, position, facade){
  729. this.option = option;
  730. this.docker = null;
  731. this.dockedShape = dockedShape;
  732. this.dockedShapeParent = dockedShape.parent || facade.getCanvas();
  733. this.position = position;
  734. this.facade = facade;
  735. this.selection = this.facade.getSelection();
  736. this.shape = null;
  737. this.parent = null;
  738. this.canAttach = canAttach;
  739. },
  740. execute: function(){
  741. if (!this.shape) {
  742. this.shape = this.facade.createShape(option);
  743. this.parent = this.shape.parent;
  744. } else if (this.parent) {
  745. this.parent.add(this.shape);
  746. }
  747. if (this.canAttach && this.shape.dockers && this.shape.dockers.length) {
  748. this.docker = this.shape.dockers[0];
  749. this.dockedShapeParent.add(this.docker.parent);
  750. // Set the Docker to the new Shape
  751. this.docker.setDockedShape(undefined);
  752. this.docker.bounds.centerMoveTo(this.position);
  753. if (this.dockedShape !== this.facade.getCanvas()) {
  754. this.docker.setDockedShape(this.dockedShape);
  755. }
  756. this.facade.setSelection( [this.docker.parent] );
  757. }
  758. this.facade.getCanvas().update();
  759. this.facade.updateSelection();
  760. },
  761. rollback: function(){
  762. if (this.shape) {
  763. this.facade.setSelection(this.selection.without(this.shape));
  764. this.facade.deleteShape(this.shape);
  765. }
  766. if (this.canAttach && this.docker) {
  767. this.docker.setDockedShape(undefined);
  768. }
  769. this.facade.getCanvas().update();
  770. this.facade.updateSelection();
  771. }
  772. });
  773. // Update canvas
  774. var command = new commandClass(option, $scope.dragCurrentParent, canAttach, pos, $scope.editor);
  775. $scope.editor.executeCommands([command]);
  776. // Fire event to all who want to know about this
  777. var dropEvent = {
  778. type: KISBPM.eventBus.EVENT_TYPE_ITEM_DROPPED,
  779. droppedItem: item,
  780. position: pos
  781. };
  782. KISBPM.eventBus.dispatch(dropEvent.type, dropEvent);
  783. }
  784. }
  785. $scope.dragCurrentParent = undefined;
  786. $scope.dragCurrentParentId = undefined;
  787. $scope.dragCurrentParentStencil = undefined;
  788. $scope.dragCanContain = undefined;
  789. $scope.quickMenu = undefined;
  790. $scope.dropTargetElement = undefined;
  791. };
  792. $scope.overCallback = function (event, ui) {
  793. $scope.dragModeOver = true;
  794. };
  795. $scope.outCallback = function (event, ui) {
  796. $scope.dragModeOver = false;
  797. };
  798. $scope.startDragCallback = function (event, ui) {
  799. $scope.dragModeOver = false;
  800. $scope.quickMenu = false;
  801. if (!ui.helper.hasClass('stencil-item-dragged')) {
  802. ui.helper.addClass('stencil-item-dragged');
  803. }
  804. };
  805. $scope.startDragCallbackQuickMenu = function (event, ui) {
  806. $scope.dragModeOver = false;
  807. $scope.quickMenu = true;
  808. };
  809. $scope.dragCallback = function (event, ui) {
  810. if ($scope.dragModeOver != false) {
  811. var coord = $scope.editor.eventCoordinatesXY(event.pageX, event.pageY);
  812. var additionalIEZoom = 1;
  813. if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) {
  814. var ua = navigator.userAgent;
  815. if (ua.indexOf('MSIE') >= 0) {
  816. //IE 10 and below
  817. var zoom = Math.round((screen.deviceXDPI / screen.logicalXDPI) * 100);
  818. if (zoom !== 100) {
  819. additionalIEZoom = zoom / 100
  820. }
  821. }
  822. }
  823. if (additionalIEZoom !== 1) {
  824. coord.x = coord.x / additionalIEZoom;
  825. coord.y = coord.y / additionalIEZoom;
  826. }
  827. var aShapes = $scope.editor.getCanvas().getAbstractShapesAtPosition(coord);
  828. if (aShapes.length <= 0) {
  829. if (event.helper) {
  830. $scope.dragCanContain = false;
  831. return false;
  832. }
  833. }
  834. if (aShapes[0] instanceof ORYX.Core.Canvas) {
  835. $scope.editor.getCanvas().setHightlightStateBasedOnX(coord.x);
  836. }
  837. if (aShapes.length == 1 && aShapes[0] instanceof ORYX.Core.Canvas)
  838. {
  839. var parentCandidate = aShapes[0];
  840. $scope.dragCanContain = true;
  841. $scope.dragCurrentParent = parentCandidate;
  842. $scope.dragCurrentParentId = parentCandidate.id;
  843. $scope.editor.handleEvents({
  844. type: ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE,
  845. highlightId: "shapeRepo.attached"
  846. });
  847. $scope.editor.handleEvents({
  848. type: ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE,
  849. highlightId: "shapeRepo.added"
  850. });
  851. return false;
  852. }
  853. else
  854. {
  855. var item = $scope.getStencilItemById(event.target.id);
  856. var parentCandidate = aShapes.reverse().find(function (candidate) {
  857. return (candidate instanceof ORYX.Core.Canvas
  858. || candidate instanceof ORYX.Core.Node
  859. || candidate instanceof ORYX.Core.Edge);
  860. });
  861. if (!parentCandidate) {
  862. $scope.dragCanContain = false;
  863. return false;
  864. }
  865. if (item.type === "node") {
  866. // check if the draggable is a boundary event and the parent an Activity
  867. var _canContain = false;
  868. var parentStencilId = parentCandidate.getStencil().id();
  869. if ($scope.dragCurrentParentId && $scope.dragCurrentParentId === parentCandidate.id) {
  870. return false;
  871. }
  872. var parentItem = $scope.getStencilItemById(parentCandidate.getStencil().idWithoutNs());
  873. if (parentItem.roles.indexOf("Activity") > -1) {
  874. if (item.roles.indexOf("IntermediateEventOnActivityBoundary") > -1) {
  875. _canContain = true;
  876. }
  877. }
  878. else if (parentCandidate.getStencil().idWithoutNs() === 'Pool')
  879. {
  880. if (item.id === 'Lane')
  881. {
  882. _canContain = true;
  883. }
  884. }
  885. if (_canContain)
  886. {
  887. $scope.editor.handleEvents({
  888. type: ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW,
  889. highlightId: "shapeRepo.attached",
  890. elements: [parentCandidate],
  891. style: ORYX.CONFIG.SELECTION_HIGHLIGHT_STYLE_RECTANGLE,
  892. color: ORYX.CONFIG.SELECTION_VALID_COLOR
  893. });
  894. $scope.editor.handleEvents({
  895. type: ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE,
  896. highlightId: "shapeRepo.added"
  897. });
  898. }
  899. else
  900. {
  901. for (var i = 0; i < $scope.containmentRules.length; i++) {
  902. var rule = $scope.containmentRules[i];
  903. if (rule.role === parentItem.id) {
  904. for (var j = 0; j < rule.contains.length; j++) {
  905. if (item.roles.indexOf(rule.contains[j]) > -1) {
  906. _canContain = true;
  907. break;
  908. }
  909. }
  910. if (_canContain) {
  911. break;
  912. }
  913. }
  914. }
  915. // Show Highlight
  916. $scope.editor.handleEvents({
  917. type: ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW,
  918. highlightId: 'shapeRepo.added',
  919. elements: [parentCandidate],
  920. color: _canContain ? ORYX.CONFIG.SELECTION_VALID_COLOR : ORYX.CONFIG.SELECTION_INVALID_COLOR
  921. });
  922. $scope.editor.handleEvents({
  923. type: ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE,
  924. highlightId: "shapeRepo.attached"
  925. });
  926. }
  927. $scope.dragCurrentParent = parentCandidate;
  928. $scope.dragCurrentParentId = parentCandidate.id;
  929. $scope.dragCurrentParentStencil = parentStencilId;
  930. $scope.dragCanContain = _canContain;
  931. } else {
  932. var canvasCandidate = $scope.editor.getCanvas();
  933. var canConnect = false;
  934. var targetStencil = $scope.getStencilItemById(parentCandidate.getStencil().idWithoutNs());
  935. if (targetStencil) {
  936. var associationConnect = false;
  937. if (stencil.idWithoutNs() === 'Association' && (curCan.getStencil().idWithoutNs() === 'TextAnnotation' || curCan.getStencil().idWithoutNs() === 'BoundaryCompensationEvent')) {
  938. associationConnect = true;
  939. } else if (stencil.idWithoutNs() === 'DataAssociation' && curCan.getStencil().idWithoutNs() === 'DataStore') {
  940. associationConnect = true;
  941. }
  942. if (targetStencil.canConnectTo || associationConnect) {
  943. canConnect = true;
  944. }
  945. }
  946. //Edge
  947. $scope.dragCurrentParent = canvasCandidate;
  948. $scope.dragCurrentParentId = canvasCandidate.id;
  949. $scope.dragCurrentParentStencil = canvasCandidate.getStencil().id();
  950. $scope.dragCanContain = canConnect;
  951. // Show Highlight
  952. $scope.editor.handleEvents({
  953. type: ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW,
  954. highlightId: 'shapeRepo.added',
  955. elements: [canvasCandidate],
  956. color: ORYX.CONFIG.SELECTION_VALID_COLOR
  957. });
  958. $scope.editor.handleEvents({
  959. type: ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE,
  960. highlightId: "shapeRepo.attached"
  961. });
  962. }
  963. }
  964. }
  965. };
  966. $scope.dragCallbackQuickMenu = function (event, ui) {
  967. if ($scope.dragModeOver != false) {
  968. var coord = $scope.editor.eventCoordinatesXY(event.pageX, event.pageY);
  969. var additionalIEZoom = 1;
  970. if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) {
  971. var ua = navigator.userAgent;
  972. if (ua.indexOf('MSIE') >= 0) {
  973. //IE 10 and below
  974. var zoom = Math.round((screen.deviceXDPI / screen.logicalXDPI) * 100);
  975. if (zoom !== 100) {
  976. additionalIEZoom = zoom / 100
  977. }
  978. }
  979. }
  980. if (additionalIEZoom !== 1) {
  981. coord.x = coord.x / additionalIEZoom;
  982. coord.y = coord.y / additionalIEZoom;
  983. }
  984. var aShapes = $scope.editor.getCanvas().getAbstractShapesAtPosition(coord);
  985. if (aShapes.length <= 0) {
  986. if (event.helper) {
  987. $scope.dragCanContain = false;
  988. return false;
  989. }
  990. }
  991. if (aShapes[0] instanceof ORYX.Core.Canvas) {
  992. $scope.editor.getCanvas().setHightlightStateBasedOnX(coord.x);
  993. }
  994. var stencil = undefined;
  995. var stencilSets = $scope.editor.getStencilSets().values();
  996. for (var i = 0; i < stencilSets.length; i++)
  997. {
  998. var stencilSet = stencilSets[i];
  999. var nodes = stencilSet.nodes();
  1000. for (var j = 0; j < nodes.length; j++)
  1001. {
  1002. if (nodes[j].idWithoutNs() === event.target.id)
  1003. {
  1004. stencil = nodes[j];
  1005. break;
  1006. }
  1007. }
  1008. if (!stencil)
  1009. {
  1010. var edges = stencilSet.edges();
  1011. for (var j = 0; j < edges.length; j++)
  1012. {
  1013. if (edges[j].idWithoutNs() === event.target.id)
  1014. {
  1015. stencil = edges[j];
  1016. break;
  1017. }
  1018. }
  1019. }
  1020. }
  1021. var candidate = aShapes.last();
  1022. var isValid = false;
  1023. if (stencil.type() === "node")
  1024. {
  1025. //check containment rules
  1026. var canContain = $scope.editor.getRules().canContain({containingShape:candidate, containedStencil:stencil});
  1027. var parentCandidate = aShapes.reverse().find(function (candidate) {
  1028. return (candidate instanceof ORYX.Core.Canvas
  1029. || candidate instanceof ORYX.Core.Node
  1030. || candidate instanceof ORYX.Core.Edge);
  1031. });
  1032. if (!parentCandidate) {
  1033. $scope.dragCanContain = false;
  1034. return false;
  1035. }
  1036. $scope.dragCurrentParent = parentCandidate;
  1037. $scope.dragCurrentParentId = parentCandidate.id;
  1038. $scope.dragCurrentParentStencil = parentCandidate.getStencil().id();
  1039. $scope.dragCanContain = canContain;
  1040. $scope.dropTargetElement = parentCandidate;
  1041. isValid = canContain;
  1042. } else { //Edge
  1043. var shapes = $scope.editor.getSelection();
  1044. if (shapes && shapes.length == 1)
  1045. {
  1046. var currentSelectedShape = shapes.first();
  1047. var curCan = candidate;
  1048. var canConnect = false;
  1049. var targetStencil = $scope.getStencilItemById(curCan.getStencil().idWithoutNs());
  1050. if (targetStencil)
  1051. {
  1052. var associationConnect = false;
  1053. if (stencil.idWithoutNs() === 'Association' && (curCan.getStencil().idWithoutNs() === 'TextAnnotation' || curCan.getStencil().idWithoutNs() === 'BoundaryCompensationEvent'))
  1054. {
  1055. associationConnect = true;
  1056. }
  1057. else if (stencil.idWithoutNs() === 'DataAssociation' && curCan.getStencil().idWithoutNs() === 'DataStore')
  1058. {
  1059. associationConnect = true;
  1060. }
  1061. if (targetStencil.canConnectTo || associationConnect)
  1062. {
  1063. while (!canConnect && curCan && !(curCan instanceof ORYX.Core.Canvas))
  1064. {
  1065. candidate = curCan;
  1066. //check connection rules
  1067. canConnect = $scope.editor.getRules().canConnect({
  1068. sourceShape: currentSelectedShape,
  1069. edgeStencil: stencil,
  1070. targetShape: curCan
  1071. });
  1072. curCan = curCan.parent;
  1073. }
  1074. }
  1075. }
  1076. var parentCandidate = $scope.editor.getCanvas();
  1077. isValid = canConnect;
  1078. $scope.dragCurrentParent = parentCandidate;
  1079. $scope.dragCurrentParentId = parentCandidate.id;
  1080. $scope.dragCurrentParentStencil = parentCandidate.getStencil().id();
  1081. $scope.dragCanContain = canConnect;
  1082. $scope.dropTargetElement = candidate;
  1083. }
  1084. }
  1085. $scope.editor.handleEvents({
  1086. type: ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW,
  1087. highlightId:'shapeMenu',
  1088. elements: [candidate],
  1089. color: isValid ? ORYX.CONFIG.SELECTION_VALID_COLOR : ORYX.CONFIG.SELECTION_INVALID_COLOR
  1090. });
  1091. }
  1092. };
  1093. }]);
  1094. var KISBPM = KISBPM || {};
  1095. //create command for undo/redo
  1096. KISBPM.CreateCommand = ORYX.Core.Command.extend({
  1097. construct: function(option, currentReference, position, facade){
  1098. this.option = option;
  1099. this.currentReference = currentReference;
  1100. this.position = position;
  1101. this.facade = facade;
  1102. this.shape;
  1103. this.edge;
  1104. this.targetRefPos;
  1105. this.sourceRefPos;
  1106. /*
  1107. * clone options parameters
  1108. */
  1109. this.connectedShape = option.connectedShape;
  1110. this.connectingType = option.connectingType;
  1111. this.namespace = option.namespace;
  1112. this.type = option.type;
  1113. this.containedStencil = option.containedStencil;
  1114. this.parent = option.parent;
  1115. this.currentReference = currentReference;
  1116. this.shapeOptions = option.shapeOptions;
  1117. },
  1118. execute: function(){
  1119. if (this.shape) {
  1120. if (this.shape instanceof ORYX.Core.Node) {
  1121. this.parent.add(this.shape);
  1122. if (this.edge) {
  1123. this.facade.getCanvas().add(this.edge);
  1124. this.edge.dockers.first().setDockedShape(this.connectedShape);
  1125. this.edge.dockers.first().setReferencePoint(this.sourceRefPos);
  1126. this.edge.dockers.last().setDockedShape(this.shape);
  1127. this.edge.dockers.last().setReferencePoint(this.targetRefPos);
  1128. }
  1129. this.facade.setSelection([this.shape]);
  1130. } else if (this.shape instanceof ORYX.Core.Edge) {
  1131. this.facade.getCanvas().add(this.shape);
  1132. this.shape.dockers.first().setDockedShape(this.connectedShape);
  1133. this.shape.dockers.first().setReferencePoint(this.sourceRefPos);
  1134. }
  1135. }
  1136. else {
  1137. this.shape = this.facade.createShape(this.option);
  1138. this.edge = (!(this.shape instanceof ORYX.Core.Edge)) ? this.shape.getIncomingShapes().first() : undefined;
  1139. }
  1140. if (this.currentReference && this.position) {
  1141. if (this.shape instanceof ORYX.Core.Edge) {
  1142. if (!(this.currentReference instanceof ORYX.Core.Canvas)) {
  1143. this.shape.dockers.last().setDockedShape(this.currentReference);
  1144. if (this.currentReference.getStencil().idWithoutNs() === 'TextAnnotation')
  1145. {
  1146. var midpoint = {};
  1147. midpoint.x = 0;
  1148. midpoint.y = this.currentReference.bounds.height() / 2;
  1149. this.shape.dockers.last().setReferencePoint(midpoint);
  1150. }
  1151. else
  1152. {
  1153. this.shape.dockers.last().setReferencePoint(this.currentReference.bounds.midPoint());
  1154. }
  1155. }
  1156. else {
  1157. this.shape.dockers.last().bounds.centerMoveTo(this.position);
  1158. }
  1159. this.sourceRefPos = this.shape.dockers.first().referencePoint;
  1160. this.targetRefPos = this.shape.dockers.last().referencePoint;
  1161. } else if (this.edge){
  1162. this.sourceRefPos = this.edge.dockers.first().referencePoint;
  1163. this.targetRefPos = this.edge.dockers.last().referencePoint;
  1164. }
  1165. } else {
  1166. var containedStencil = this.containedStencil;
  1167. var connectedShape = this.connectedShape;
  1168. var bc = connectedShape.bounds;
  1169. var bs = this.shape.bounds;
  1170. var pos = bc.center();
  1171. if(containedStencil.defaultAlign()==="north") {
  1172. pos.y -= (bc.height() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET + (bs.height()/2);
  1173. } else if(containedStencil.defaultAlign()==="northeast") {
  1174. pos.x += (bc.width() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.width()/2);
  1175. pos.y -= (bc.height() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.height()/2);
  1176. } else if(containedStencil.defaultAlign()==="southeast") {
  1177. pos.x += (bc.width() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.width()/2);
  1178. pos.y += (bc.height() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.height()/2);
  1179. } else if(containedStencil.defaultAlign()==="south") {
  1180. pos.y += (bc.height() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET + (bs.height()/2);
  1181. } else if(containedStencil.defaultAlign()==="southwest") {
  1182. pos.x -= (bc.width() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.width()/2);
  1183. pos.y += (bc.height() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.height()/2);
  1184. } else if(containedStencil.defaultAlign()==="west") {
  1185. pos.x -= (bc.width() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET + (bs.width()/2);
  1186. } else if(containedStencil.defaultAlign()==="northwest") {
  1187. pos.x -= (bc.width() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.width()/2);
  1188. pos.y -= (bc.height() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.height()/2);
  1189. } else {
  1190. pos.x += (bc.width() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET + (bs.width()/2);
  1191. }
  1192. // Move shape to the new position
  1193. this.shape.bounds.centerMoveTo(pos);
  1194. // Move all dockers of a node to the position
  1195. if (this.shape instanceof ORYX.Core.Node){
  1196. (this.shape.dockers||[]).each(function(docker){
  1197. docker.bounds.centerMoveTo(pos);
  1198. });
  1199. }
  1200. //this.shape.update();
  1201. this.position = pos;
  1202. if (this.edge){
  1203. this.sourceRefPos = this.edge.dockers.first().referencePoint;
  1204. this.targetRefPos = this.edge.dockers.last().referencePoint;
  1205. }
  1206. }
  1207. this.facade.getCanvas().update();
  1208. this.facade.updateSelection();
  1209. },
  1210. rollback: function(){
  1211. this.facade.deleteShape(this.shape);
  1212. if(this.edge) {
  1213. this.facade.deleteShape(this.edge);
  1214. }
  1215. //this.currentParent.update();
  1216. this.facade.setSelection(this.facade.getSelection().without(this.shape, this.edge));
  1217. }
  1218. });