mxGraphModel.js 62 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707
  1. /**
  2. * Copyright (c) 2006-2018, JGraph Ltd
  3. * Copyright (c) 2006-2018, Gaudenz Alder
  4. */
  5. /**
  6. * Class: mxGraphModel
  7. *
  8. * Extends <mxEventSource> to implement a graph model. The graph model acts as
  9. * a wrapper around the cells which are in charge of storing the actual graph
  10. * datastructure. The model acts as a transactional wrapper with event
  11. * notification for all changes, whereas the cells contain the atomic
  12. * operations for updating the actual datastructure.
  13. *
  14. * Layers:
  15. *
  16. * The cell hierarchy in the model must have a top-level root cell which
  17. * contains the layers (typically one default layer), which in turn contain the
  18. * top-level cells of the layers. This means each cell is contained in a layer.
  19. * If no layers are required, then all new cells should be added to the default
  20. * layer.
  21. *
  22. * Layers are useful for hiding and showing groups of cells, or for placing
  23. * groups of cells on top of other cells in the display. To identify a layer,
  24. * the <isLayer> function is used. It returns true if the parent of the given
  25. * cell is the root of the model.
  26. *
  27. * Events:
  28. *
  29. * See events section for more details. There is a new set of events for
  30. * tracking transactional changes as they happen. The events are called
  31. * startEdit for the initial beginUpdate, executed for each executed change
  32. * and endEdit for the terminal endUpdate. The executed event contains a
  33. * property called change which represents the change after execution.
  34. *
  35. * Encoding the model:
  36. *
  37. * To encode a graph model, use the following code:
  38. *
  39. * (code)
  40. * var enc = new mxCodec();
  41. * var node = enc.encode(graph.getModel());
  42. * (end)
  43. *
  44. * This will create an XML node that contains all the model information.
  45. *
  46. * Encoding and decoding changes:
  47. *
  48. * For the encoding of changes, a graph model listener is required that encodes
  49. * each change from the given array of changes.
  50. *
  51. * (code)
  52. * model.addListener(mxEvent.CHANGE, function(sender, evt)
  53. * {
  54. * var changes = evt.getProperty('edit').changes;
  55. * var nodes = [];
  56. * var codec = new mxCodec();
  57. *
  58. * for (var i = 0; i < changes.length; i++)
  59. * {
  60. * nodes.push(codec.encode(changes[i]));
  61. * }
  62. * // do something with the nodes
  63. * });
  64. * (end)
  65. *
  66. * For the decoding and execution of changes, the codec needs a lookup function
  67. * that allows it to resolve cell IDs as follows:
  68. *
  69. * (code)
  70. * var codec = new mxCodec();
  71. * codec.lookup = function(id)
  72. * {
  73. * return model.getCell(id);
  74. * }
  75. * (end)
  76. *
  77. * For each encoded change (represented by a node), the following code can be
  78. * used to carry out the decoding and create a change object.
  79. *
  80. * (code)
  81. * var changes = [];
  82. * var change = codec.decode(node);
  83. * change.model = model;
  84. * change.execute();
  85. * changes.push(change);
  86. * (end)
  87. *
  88. * The changes can then be dispatched using the model as follows.
  89. *
  90. * (code)
  91. * var edit = new mxUndoableEdit(model, false);
  92. * edit.changes = changes;
  93. *
  94. * edit.notify = function()
  95. * {
  96. * edit.source.fireEvent(new mxEventObject(mxEvent.CHANGE,
  97. * 'edit', edit, 'changes', edit.changes));
  98. * edit.source.fireEvent(new mxEventObject(mxEvent.NOTIFY,
  99. * 'edit', edit, 'changes', edit.changes));
  100. * }
  101. *
  102. * model.fireEvent(new mxEventObject(mxEvent.UNDO, 'edit', edit));
  103. * model.fireEvent(new mxEventObject(mxEvent.CHANGE,
  104. * 'edit', edit, 'changes', changes));
  105. * (end)
  106. *
  107. * Event: mxEvent.CHANGE
  108. *
  109. * Fires when an undoable edit is dispatched. The <code>edit</code> property
  110. * contains the <mxUndoableEdit>. The <code>changes</code> property contains
  111. * the array of atomic changes inside the undoable edit. The changes property
  112. * is <strong>deprecated</strong>, please use edit.changes instead.
  113. *
  114. * Example:
  115. *
  116. * For finding newly inserted cells, the following code can be used:
  117. *
  118. * (code)
  119. * graph.model.addListener(mxEvent.CHANGE, function(sender, evt)
  120. * {
  121. * var changes = evt.getProperty('edit').changes;
  122. *
  123. * for (var i = 0; i < changes.length; i++)
  124. * {
  125. * var change = changes[i];
  126. *
  127. * if (change instanceof mxChildChange &&
  128. * change.change.previous == null)
  129. * {
  130. * graph.startEditingAtCell(change.child);
  131. * break;
  132. * }
  133. * }
  134. * });
  135. * (end)
  136. *
  137. *
  138. * Event: mxEvent.NOTIFY
  139. *
  140. * Same as <mxEvent.CHANGE>, this event can be used for classes that need to
  141. * implement a sync mechanism between this model and, say, a remote model. In
  142. * such a setup, only local changes should trigger a notify event and all
  143. * changes should trigger a change event.
  144. *
  145. * Event: mxEvent.EXECUTE
  146. *
  147. * Fires between begin- and endUpdate and after an atomic change was executed
  148. * in the model. The <code>change</code> property contains the atomic change
  149. * that was executed.
  150. *
  151. * Event: mxEvent.EXECUTED
  152. *
  153. * Fires between START_EDIT and END_EDIT after an atomic change was executed.
  154. * The <code>change</code> property contains the change that was executed.
  155. *
  156. * Event: mxEvent.BEGIN_UPDATE
  157. *
  158. * Fires after the <updateLevel> was incremented in <beginUpdate>. This event
  159. * contains no properties.
  160. *
  161. * Event: mxEvent.START_EDIT
  162. *
  163. * Fires after the <updateLevel> was changed from 0 to 1. This event
  164. * contains no properties.
  165. *
  166. * Event: mxEvent.END_UPDATE
  167. *
  168. * Fires after the <updateLevel> was decreased in <endUpdate> but before any
  169. * notification or change dispatching. The <code>edit</code> property contains
  170. * the <currentEdit>.
  171. *
  172. * Event: mxEvent.END_EDIT
  173. *
  174. * Fires after the <updateLevel> was changed from 1 to 0. This event
  175. * contains no properties.
  176. *
  177. * Event: mxEvent.BEFORE_UNDO
  178. *
  179. * Fires before the change is dispatched after the update level has reached 0
  180. * in <endUpdate>. The <code>edit</code> property contains the <curreneEdit>.
  181. *
  182. * Event: mxEvent.UNDO
  183. *
  184. * Fires after the change was dispatched in <endUpdate>. The <code>edit</code>
  185. * property contains the <currentEdit>.
  186. *
  187. * Constructor: mxGraphModel
  188. *
  189. * Constructs a new graph model. If no root is specified then a new root
  190. * <mxCell> with a default layer is created.
  191. *
  192. * Parameters:
  193. *
  194. * root - <mxCell> that represents the root cell.
  195. */
  196. function mxGraphModel(root)
  197. {
  198. this.currentEdit = this.createUndoableEdit();
  199. if (root != null)
  200. {
  201. this.setRoot(root);
  202. }
  203. else
  204. {
  205. this.clear();
  206. }
  207. };
  208. /**
  209. * Extends mxEventSource.
  210. */
  211. mxGraphModel.prototype = new mxEventSource();
  212. mxGraphModel.prototype.constructor = mxGraphModel;
  213. /**
  214. * Variable: root
  215. *
  216. * Holds the root cell, which in turn contains the cells that represent the
  217. * layers of the diagram as child cells. That is, the actual elements of the
  218. * diagram are supposed to live in the third generation of cells and below.
  219. */
  220. mxGraphModel.prototype.root = null;
  221. /**
  222. * Variable: cells
  223. *
  224. * Maps from Ids to cells.
  225. */
  226. mxGraphModel.prototype.cells = null;
  227. /**
  228. * Variable: maintainEdgeParent
  229. *
  230. * Specifies if edges should automatically be moved into the nearest common
  231. * ancestor of their terminals. Default is true.
  232. */
  233. mxGraphModel.prototype.maintainEdgeParent = true;
  234. /**
  235. * Variable: ignoreRelativeEdgeParent
  236. *
  237. * Specifies if relative edge parents should be ignored for finding the nearest
  238. * common ancestors of an edge's terminals. Default is true.
  239. */
  240. mxGraphModel.prototype.ignoreRelativeEdgeParent = true;
  241. /**
  242. * Variable: createIds
  243. *
  244. * Specifies if the model should automatically create Ids for new cells.
  245. * Default is true.
  246. */
  247. mxGraphModel.prototype.createIds = true;
  248. /**
  249. * Variable: prefix
  250. *
  251. * Defines the prefix of new Ids. Default is an empty string.
  252. */
  253. mxGraphModel.prototype.prefix = '';
  254. /**
  255. * Variable: postfix
  256. *
  257. * Defines the postfix of new Ids. Default is an empty string.
  258. */
  259. mxGraphModel.prototype.postfix = '';
  260. /**
  261. * Variable: nextId
  262. *
  263. * Specifies the next Id to be created. Initial value is 0.
  264. */
  265. mxGraphModel.prototype.nextId = 0;
  266. /**
  267. * Variable: currentEdit
  268. *
  269. * Holds the changes for the current transaction. If the transaction is
  270. * closed then a new object is created for this variable using
  271. * <createUndoableEdit>.
  272. */
  273. mxGraphModel.prototype.currentEdit = null;
  274. /**
  275. * Variable: updateLevel
  276. *
  277. * Counter for the depth of nested transactions. Each call to <beginUpdate>
  278. * will increment this number and each call to <endUpdate> will decrement
  279. * it. When the counter reaches 0, the transaction is closed and the
  280. * respective events are fired. Initial value is 0.
  281. */
  282. mxGraphModel.prototype.updateLevel = 0;
  283. /**
  284. * Variable: endingUpdate
  285. *
  286. * True if the program flow is currently inside endUpdate.
  287. */
  288. mxGraphModel.prototype.endingUpdate = false;
  289. /**
  290. * Function: clear
  291. *
  292. * Sets a new root using <createRoot>.
  293. */
  294. mxGraphModel.prototype.clear = function()
  295. {
  296. this.setRoot(this.createRoot());
  297. };
  298. /**
  299. * Function: isCreateIds
  300. *
  301. * Returns <createIds>.
  302. */
  303. mxGraphModel.prototype.isCreateIds = function()
  304. {
  305. return this.createIds;
  306. };
  307. /**
  308. * Function: setCreateIds
  309. *
  310. * Sets <createIds>.
  311. */
  312. mxGraphModel.prototype.setCreateIds = function(value)
  313. {
  314. this.createIds = value;
  315. };
  316. /**
  317. * Function: createRoot
  318. *
  319. * Creates a new root cell with a default layer (child 0).
  320. */
  321. mxGraphModel.prototype.createRoot = function()
  322. {
  323. var cell = new mxCell();
  324. cell.insert(new mxCell());
  325. return cell;
  326. };
  327. /**
  328. * Function: getCell
  329. *
  330. * Returns the <mxCell> for the specified Id or null if no cell can be
  331. * found for the given Id.
  332. *
  333. * Parameters:
  334. *
  335. * id - A string representing the Id of the cell.
  336. */
  337. mxGraphModel.prototype.getCell = function(id)
  338. {
  339. return (this.cells != null) ? this.cells[id] : null;
  340. };
  341. /**
  342. * Function: filterCells
  343. *
  344. * Returns the cells from the given array where the given filter function
  345. * returns true.
  346. */
  347. mxGraphModel.prototype.filterCells = function(cells, filter)
  348. {
  349. var result = null;
  350. if (cells != null)
  351. {
  352. result = [];
  353. for (var i = 0; i < cells.length; i++)
  354. {
  355. if (filter(cells[i]))
  356. {
  357. result.push(cells[i]);
  358. }
  359. }
  360. }
  361. return result;
  362. };
  363. /**
  364. * Function: getDescendants
  365. *
  366. * Returns all descendants of the given cell and the cell itself in an array.
  367. *
  368. * Parameters:
  369. *
  370. * parent - <mxCell> whose descendants should be returned.
  371. */
  372. mxGraphModel.prototype.getDescendants = function(parent)
  373. {
  374. return this.filterDescendants(null, parent);
  375. };
  376. /**
  377. * Function: filterDescendants
  378. *
  379. * Visits all cells recursively and applies the specified filter function
  380. * to each cell. If the function returns true then the cell is added
  381. * to the resulting array. The parent and result paramters are optional.
  382. * If parent is not specified then the recursion starts at <root>.
  383. *
  384. * Example:
  385. * The following example extracts all vertices from a given model:
  386. * (code)
  387. * var filter = function(cell)
  388. * {
  389. * return model.isVertex(cell);
  390. * }
  391. * var vertices = model.filterDescendants(filter);
  392. * (end)
  393. *
  394. * Parameters:
  395. *
  396. * filter - JavaScript function that takes an <mxCell> as an argument
  397. * and returns a boolean.
  398. * parent - Optional <mxCell> that is used as the root of the recursion.
  399. */
  400. mxGraphModel.prototype.filterDescendants = function(filter, parent)
  401. {
  402. // Creates a new array for storing the result
  403. var result = [];
  404. // Recursion starts at the root of the model
  405. parent = parent || this.getRoot();
  406. // Checks if the filter returns true for the cell
  407. // and adds it to the result array
  408. if (filter == null || filter(parent))
  409. {
  410. result.push(parent);
  411. }
  412. // Visits the children of the cell
  413. var childCount = this.getChildCount(parent);
  414. for (var i = 0; i < childCount; i++)
  415. {
  416. var child = this.getChildAt(parent, i);
  417. result = result.concat(this.filterDescendants(filter, child));
  418. }
  419. return result;
  420. };
  421. /**
  422. * Function: getRoot
  423. *
  424. * Returns the root of the model or the topmost parent of the given cell.
  425. *
  426. * Parameters:
  427. *
  428. * cell - Optional <mxCell> that specifies the child.
  429. */
  430. mxGraphModel.prototype.getRoot = function(cell)
  431. {
  432. var root = cell || this.root;
  433. if (cell != null)
  434. {
  435. while (cell != null)
  436. {
  437. root = cell;
  438. cell = this.getParent(cell);
  439. }
  440. }
  441. return root;
  442. };
  443. /**
  444. * Function: setRoot
  445. *
  446. * Sets the <root> of the model using <mxRootChange> and adds the change to
  447. * the current transaction. This resets all datastructures in the model and
  448. * is the preferred way of clearing an existing model. Returns the new
  449. * root.
  450. *
  451. * Example:
  452. *
  453. * (code)
  454. * var root = new mxCell();
  455. * root.insert(new mxCell());
  456. * model.setRoot(root);
  457. * (end)
  458. *
  459. * Parameters:
  460. *
  461. * root - <mxCell> that specifies the new root.
  462. */
  463. mxGraphModel.prototype.setRoot = function(root)
  464. {
  465. this.execute(new mxRootChange(this, root));
  466. return root;
  467. };
  468. /**
  469. * Function: rootChanged
  470. *
  471. * Inner callback to change the root of the model and update the internal
  472. * datastructures, such as <cells> and <nextId>. Returns the previous root.
  473. *
  474. * Parameters:
  475. *
  476. * root - <mxCell> that specifies the new root.
  477. */
  478. mxGraphModel.prototype.rootChanged = function(root)
  479. {
  480. var oldRoot = this.root;
  481. this.root = root;
  482. // Resets counters and datastructures
  483. this.nextId = 0;
  484. this.cells = null;
  485. this.cellAdded(root);
  486. return oldRoot;
  487. };
  488. /**
  489. * Function: isRoot
  490. *
  491. * Returns true if the given cell is the root of the model and a non-null
  492. * value.
  493. *
  494. * Parameters:
  495. *
  496. * cell - <mxCell> that represents the possible root.
  497. */
  498. mxGraphModel.prototype.isRoot = function(cell)
  499. {
  500. return cell != null && this.root == cell;
  501. };
  502. /**
  503. * Function: isLayer
  504. *
  505. * Returns true if <isRoot> returns true for the parent of the given cell.
  506. *
  507. * Parameters:
  508. *
  509. * cell - <mxCell> that represents the possible layer.
  510. */
  511. mxGraphModel.prototype.isLayer = function(cell)
  512. {
  513. return this.isRoot(this.getParent(cell));
  514. };
  515. /**
  516. * Function: isAncestor
  517. *
  518. * Returns true if the given parent is an ancestor of the given child. Note
  519. * returns true if child == parent.
  520. *
  521. * Parameters:
  522. *
  523. * parent - <mxCell> that specifies the parent.
  524. * child - <mxCell> that specifies the child.
  525. */
  526. mxGraphModel.prototype.isAncestor = function(parent, child)
  527. {
  528. while (child != null && child != parent)
  529. {
  530. child = this.getParent(child);
  531. }
  532. return child == parent;
  533. };
  534. /**
  535. * Function: contains
  536. *
  537. * Returns true if the model contains the given <mxCell>.
  538. *
  539. * Parameters:
  540. *
  541. * cell - <mxCell> that specifies the cell.
  542. */
  543. mxGraphModel.prototype.contains = function(cell)
  544. {
  545. return this.isAncestor(this.root, cell);
  546. };
  547. /**
  548. * Function: getParent
  549. *
  550. * Returns the parent of the given cell.
  551. *
  552. * Parameters:
  553. *
  554. * cell - <mxCell> whose parent should be returned.
  555. */
  556. mxGraphModel.prototype.getParent = function(cell)
  557. {
  558. return (cell != null) ? cell.getParent() : null;
  559. };
  560. /**
  561. * Function: add
  562. *
  563. * Adds the specified child to the parent at the given index using
  564. * <mxChildChange> and adds the change to the current transaction. If no
  565. * index is specified then the child is appended to the parent's array of
  566. * children. Returns the inserted child.
  567. *
  568. * Parameters:
  569. *
  570. * parent - <mxCell> that specifies the parent to contain the child.
  571. * child - <mxCell> that specifies the child to be inserted.
  572. * index - Optional integer that specifies the index of the child.
  573. */
  574. mxGraphModel.prototype.add = function(parent, child, index)
  575. {
  576. if (child != parent && parent != null && child != null)
  577. {
  578. // Appends the child if no index was specified
  579. if (index == null)
  580. {
  581. index = this.getChildCount(parent);
  582. }
  583. var parentChanged = parent != this.getParent(child);
  584. this.execute(new mxChildChange(this, parent, child, index));
  585. // Maintains the edges parents by moving the edges
  586. // into the nearest common ancestor of its terminals
  587. if (this.maintainEdgeParent && parentChanged)
  588. {
  589. this.updateEdgeParents(child);
  590. }
  591. }
  592. return child;
  593. };
  594. /**
  595. * Function: cellAdded
  596. *
  597. * Inner callback to update <cells> when a cell has been added. This
  598. * implementation resolves collisions by creating new Ids. To change the
  599. * ID of a cell after it was inserted into the model, use the following
  600. * code:
  601. *
  602. * (code
  603. * delete model.cells[cell.getId()];
  604. * cell.setId(newId);
  605. * model.cells[cell.getId()] = cell;
  606. * (end)
  607. *
  608. * If the change of the ID should be part of the command history, then the
  609. * cell should be removed from the model and a clone with the new ID should
  610. * be reinserted into the model instead.
  611. *
  612. * Parameters:
  613. *
  614. * cell - <mxCell> that specifies the cell that has been added.
  615. */
  616. mxGraphModel.prototype.cellAdded = function(cell)
  617. {
  618. if (cell != null)
  619. {
  620. // Creates an Id for the cell if not Id exists
  621. if (cell.getId() == null && this.createIds)
  622. {
  623. cell.setId(this.createId(cell));
  624. }
  625. if (cell.getId() != null)
  626. {
  627. var collision = this.getCell(cell.getId());
  628. if (collision != cell)
  629. {
  630. // Creates new Id for the cell
  631. // as long as there is a collision
  632. while (collision != null)
  633. {
  634. cell.setId(this.createId(cell));
  635. collision = this.getCell(cell.getId());
  636. }
  637. // Lazily creates the cells dictionary
  638. if (this.cells == null)
  639. {
  640. this.cells = new Object();
  641. }
  642. this.cells[cell.getId()] = cell;
  643. }
  644. }
  645. // Makes sure IDs of deleted cells are not reused
  646. if (mxUtils.isNumeric(cell.getId()))
  647. {
  648. this.nextId = Math.max(this.nextId, cell.getId());
  649. }
  650. // Recursively processes child cells
  651. var childCount = this.getChildCount(cell);
  652. for (var i=0; i<childCount; i++)
  653. {
  654. this.cellAdded(this.getChildAt(cell, i));
  655. }
  656. }
  657. };
  658. /**
  659. * Function: createId
  660. *
  661. * Hook method to create an Id for the specified cell. This implementation
  662. * concatenates <prefix>, id and <postfix> to create the Id and increments
  663. * <nextId>. The cell is ignored by this implementation, but can be used in
  664. * overridden methods to prefix the Ids with eg. the cell type.
  665. *
  666. * Parameters:
  667. *
  668. * cell - <mxCell> to create the Id for.
  669. */
  670. mxGraphModel.prototype.createId = function(cell)
  671. {
  672. var id = this.nextId;
  673. this.nextId++;
  674. return this.prefix + id + this.postfix;
  675. };
  676. /**
  677. * Function: updateEdgeParents
  678. *
  679. * Updates the parent for all edges that are connected to cell or one of
  680. * its descendants using <updateEdgeParent>.
  681. */
  682. mxGraphModel.prototype.updateEdgeParents = function(cell, root)
  683. {
  684. // Gets the topmost node of the hierarchy
  685. root = root || this.getRoot(cell);
  686. // Updates edges on children first
  687. var childCount = this.getChildCount(cell);
  688. for (var i = 0; i < childCount; i++)
  689. {
  690. var child = this.getChildAt(cell, i);
  691. this.updateEdgeParents(child, root);
  692. }
  693. // Updates the parents of all connected edges
  694. var edgeCount = this.getEdgeCount(cell);
  695. var edges = [];
  696. for (var i = 0; i < edgeCount; i++)
  697. {
  698. edges.push(this.getEdgeAt(cell, i));
  699. }
  700. for (var i = 0; i < edges.length; i++)
  701. {
  702. var edge = edges[i];
  703. // Updates edge parent if edge and child have
  704. // a common root node (does not need to be the
  705. // model root node)
  706. if (this.isAncestor(root, edge))
  707. {
  708. this.updateEdgeParent(edge, root);
  709. }
  710. }
  711. };
  712. /**
  713. * Function: updateEdgeParent
  714. *
  715. * Inner callback to update the parent of the specified <mxCell> to the
  716. * nearest-common-ancestor of its two terminals.
  717. *
  718. * Parameters:
  719. *
  720. * edge - <mxCell> that specifies the edge.
  721. * root - <mxCell> that represents the current root of the model.
  722. */
  723. mxGraphModel.prototype.updateEdgeParent = function(edge, root)
  724. {
  725. var source = this.getTerminal(edge, true);
  726. var target = this.getTerminal(edge, false);
  727. var cell = null;
  728. // Uses the first non-relative descendants of the source terminal
  729. while (source != null && !this.isEdge(source) &&
  730. source.geometry != null && source.geometry.relative)
  731. {
  732. source = this.getParent(source);
  733. }
  734. // Uses the first non-relative descendants of the target terminal
  735. while (target != null && this.ignoreRelativeEdgeParent &&
  736. !this.isEdge(target) && target.geometry != null &&
  737. target.geometry.relative)
  738. {
  739. target = this.getParent(target);
  740. }
  741. if (this.isAncestor(root, source) && this.isAncestor(root, target))
  742. {
  743. if (source == target)
  744. {
  745. cell = this.getParent(source);
  746. }
  747. else
  748. {
  749. cell = this.getNearestCommonAncestor(source, target);
  750. }
  751. if (cell != null && (this.getParent(cell) != this.root ||
  752. this.isAncestor(cell, edge)) && this.getParent(edge) != cell)
  753. {
  754. var geo = this.getGeometry(edge);
  755. if (geo != null)
  756. {
  757. var origin1 = this.getOrigin(this.getParent(edge));
  758. var origin2 = this.getOrigin(cell);
  759. var dx = origin2.x - origin1.x;
  760. var dy = origin2.y - origin1.y;
  761. geo = geo.clone();
  762. geo.translate(-dx, -dy);
  763. this.setGeometry(edge, geo);
  764. }
  765. this.add(cell, edge, this.getChildCount(cell));
  766. }
  767. }
  768. };
  769. /**
  770. * Function: getOrigin
  771. *
  772. * Returns the absolute, accumulated origin for the children inside the
  773. * given parent as an <mxPoint>.
  774. */
  775. mxGraphModel.prototype.getOrigin = function(cell)
  776. {
  777. var result = null;
  778. if (cell != null)
  779. {
  780. result = this.getOrigin(this.getParent(cell));
  781. if (!this.isEdge(cell))
  782. {
  783. var geo = this.getGeometry(cell);
  784. if (geo != null)
  785. {
  786. result.x += geo.x;
  787. result.y += geo.y;
  788. }
  789. }
  790. }
  791. else
  792. {
  793. result = new mxPoint();
  794. }
  795. return result;
  796. };
  797. /**
  798. * Function: getNearestCommonAncestor
  799. *
  800. * Returns the nearest common ancestor for the specified cells.
  801. *
  802. * Parameters:
  803. *
  804. * cell1 - <mxCell> that specifies the first cell in the tree.
  805. * cell2 - <mxCell> that specifies the second cell in the tree.
  806. */
  807. mxGraphModel.prototype.getNearestCommonAncestor = function(cell1, cell2)
  808. {
  809. if (cell1 != null && cell2 != null)
  810. {
  811. // Creates the cell path for the second cell
  812. var path = mxCellPath.create(cell2);
  813. if (path != null && path.length > 0)
  814. {
  815. // Bubbles through the ancestors of the first
  816. // cell to find the nearest common ancestor.
  817. var cell = cell1;
  818. var current = mxCellPath.create(cell);
  819. // Inverts arguments
  820. if (path.length < current.length)
  821. {
  822. cell = cell2;
  823. var tmp = current;
  824. current = path;
  825. path = tmp;
  826. }
  827. while (cell != null)
  828. {
  829. var parent = this.getParent(cell);
  830. // Checks if the cell path is equal to the beginning of the given cell path
  831. if (path.indexOf(current + mxCellPath.PATH_SEPARATOR) == 0 && parent != null)
  832. {
  833. return cell;
  834. }
  835. current = mxCellPath.getParentPath(current);
  836. cell = parent;
  837. }
  838. }
  839. }
  840. return null;
  841. };
  842. /**
  843. * Function: remove
  844. *
  845. * Removes the specified cell from the model using <mxChildChange> and adds
  846. * the change to the current transaction. This operation will remove the
  847. * cell and all of its children from the model. Returns the removed cell.
  848. *
  849. * Parameters:
  850. *
  851. * cell - <mxCell> that should be removed.
  852. */
  853. mxGraphModel.prototype.remove = function(cell)
  854. {
  855. if (cell == this.root)
  856. {
  857. this.setRoot(null);
  858. }
  859. else if (this.getParent(cell) != null)
  860. {
  861. this.execute(new mxChildChange(this, null, cell));
  862. }
  863. return cell;
  864. };
  865. /**
  866. * Function: cellRemoved
  867. *
  868. * Inner callback to update <cells> when a cell has been removed.
  869. *
  870. * Parameters:
  871. *
  872. * cell - <mxCell> that specifies the cell that has been removed.
  873. */
  874. mxGraphModel.prototype.cellRemoved = function(cell)
  875. {
  876. if (cell != null && this.cells != null)
  877. {
  878. // Recursively processes child cells
  879. var childCount = this.getChildCount(cell);
  880. for (var i = childCount - 1; i >= 0; i--)
  881. {
  882. this.cellRemoved(this.getChildAt(cell, i));
  883. }
  884. // Removes the dictionary entry for the cell
  885. if (this.cells != null && cell.getId() != null)
  886. {
  887. delete this.cells[cell.getId()];
  888. }
  889. }
  890. };
  891. /**
  892. * Function: parentForCellChanged
  893. *
  894. * Inner callback to update the parent of a cell using <mxCell.insert>
  895. * on the parent and return the previous parent.
  896. *
  897. * Parameters:
  898. *
  899. * cell - <mxCell> to update the parent for.
  900. * parent - <mxCell> that specifies the new parent of the cell.
  901. * index - Optional integer that defines the index of the child
  902. * in the parent's child array.
  903. */
  904. mxGraphModel.prototype.parentForCellChanged = function(cell, parent, index)
  905. {
  906. var previous = this.getParent(cell);
  907. if (parent != null)
  908. {
  909. if (parent != previous || previous.getIndex(cell) != index)
  910. {
  911. parent.insert(cell, index);
  912. }
  913. }
  914. else if (previous != null)
  915. {
  916. var oldIndex = previous.getIndex(cell);
  917. previous.remove(oldIndex);
  918. }
  919. // Adds or removes the cell from the model
  920. var par = this.contains(parent);
  921. var pre = this.contains(previous);
  922. if (par && !pre)
  923. {
  924. this.cellAdded(cell);
  925. }
  926. else if (pre && !par)
  927. {
  928. this.cellRemoved(cell);
  929. }
  930. return previous;
  931. };
  932. /**
  933. * Function: getChildCount
  934. *
  935. * Returns the number of children in the given cell.
  936. *
  937. * Parameters:
  938. *
  939. * cell - <mxCell> whose number of children should be returned.
  940. */
  941. mxGraphModel.prototype.getChildCount = function(cell)
  942. {
  943. return (cell != null) ? cell.getChildCount() : 0;
  944. };
  945. /**
  946. * Function: getChildAt
  947. *
  948. * Returns the child of the given <mxCell> at the given index.
  949. *
  950. * Parameters:
  951. *
  952. * cell - <mxCell> that represents the parent.
  953. * index - Integer that specifies the index of the child to be returned.
  954. */
  955. mxGraphModel.prototype.getChildAt = function(cell, index)
  956. {
  957. return (cell != null) ? cell.getChildAt(index) : null;
  958. };
  959. /**
  960. * Function: getChildren
  961. *
  962. * Returns all children of the given <mxCell> as an array of <mxCells>. The
  963. * return value should be only be read.
  964. *
  965. * Parameters:
  966. *
  967. * cell - <mxCell> the represents the parent.
  968. */
  969. mxGraphModel.prototype.getChildren = function(cell)
  970. {
  971. return (cell != null) ? cell.children : null;
  972. };
  973. /**
  974. * Function: getChildVertices
  975. *
  976. * Returns the child vertices of the given parent.
  977. *
  978. * Parameters:
  979. *
  980. * cell - <mxCell> whose child vertices should be returned.
  981. */
  982. mxGraphModel.prototype.getChildVertices = function(parent)
  983. {
  984. return this.getChildCells(parent, true, false);
  985. };
  986. /**
  987. * Function: getChildEdges
  988. *
  989. * Returns the child edges of the given parent.
  990. *
  991. * Parameters:
  992. *
  993. * cell - <mxCell> whose child edges should be returned.
  994. */
  995. mxGraphModel.prototype.getChildEdges = function(parent)
  996. {
  997. return this.getChildCells(parent, false, true);
  998. };
  999. /**
  1000. * Function: getChildCells
  1001. *
  1002. * Returns the children of the given cell that are vertices and/or edges
  1003. * depending on the arguments.
  1004. *
  1005. * Parameters:
  1006. *
  1007. * cell - <mxCell> the represents the parent.
  1008. * vertices - Boolean indicating if child vertices should be returned.
  1009. * Default is false.
  1010. * edges - Boolean indicating if child edges should be returned.
  1011. * Default is false.
  1012. */
  1013. mxGraphModel.prototype.getChildCells = function(parent, vertices, edges)
  1014. {
  1015. vertices = (vertices != null) ? vertices : false;
  1016. edges = (edges != null) ? edges : false;
  1017. var childCount = this.getChildCount(parent);
  1018. var result = [];
  1019. for (var i = 0; i < childCount; i++)
  1020. {
  1021. var child = this.getChildAt(parent, i);
  1022. if ((!edges && !vertices) || (edges && this.isEdge(child)) ||
  1023. (vertices && this.isVertex(child)))
  1024. {
  1025. result.push(child);
  1026. }
  1027. }
  1028. return result;
  1029. };
  1030. /**
  1031. * Function: getTerminal
  1032. *
  1033. * Returns the source or target <mxCell> of the given edge depending on the
  1034. * value of the boolean parameter.
  1035. *
  1036. * Parameters:
  1037. *
  1038. * edge - <mxCell> that specifies the edge.
  1039. * isSource - Boolean indicating which end of the edge should be returned.
  1040. */
  1041. mxGraphModel.prototype.getTerminal = function(edge, isSource)
  1042. {
  1043. return (edge != null) ? edge.getTerminal(isSource) : null;
  1044. };
  1045. /**
  1046. * Function: setTerminal
  1047. *
  1048. * Sets the source or target terminal of the given <mxCell> using
  1049. * <mxTerminalChange> and adds the change to the current transaction.
  1050. * This implementation updates the parent of the edge using <updateEdgeParent>
  1051. * if required.
  1052. *
  1053. * Parameters:
  1054. *
  1055. * edge - <mxCell> that specifies the edge.
  1056. * terminal - <mxCell> that specifies the new terminal.
  1057. * isSource - Boolean indicating if the terminal is the new source or
  1058. * target terminal of the edge.
  1059. */
  1060. mxGraphModel.prototype.setTerminal = function(edge, terminal, isSource)
  1061. {
  1062. var terminalChanged = terminal != this.getTerminal(edge, isSource);
  1063. this.execute(new mxTerminalChange(this, edge, terminal, isSource));
  1064. if (this.maintainEdgeParent && terminalChanged)
  1065. {
  1066. this.updateEdgeParent(edge, this.getRoot());
  1067. }
  1068. return terminal;
  1069. };
  1070. /**
  1071. * Function: setTerminals
  1072. *
  1073. * Sets the source and target <mxCell> of the given <mxCell> in a single
  1074. * transaction using <setTerminal> for each end of the edge.
  1075. *
  1076. * Parameters:
  1077. *
  1078. * edge - <mxCell> that specifies the edge.
  1079. * source - <mxCell> that specifies the new source terminal.
  1080. * target - <mxCell> that specifies the new target terminal.
  1081. */
  1082. mxGraphModel.prototype.setTerminals = function(edge, source, target)
  1083. {
  1084. this.beginUpdate();
  1085. try
  1086. {
  1087. this.setTerminal(edge, source, true);
  1088. this.setTerminal(edge, target, false);
  1089. }
  1090. finally
  1091. {
  1092. this.endUpdate();
  1093. }
  1094. };
  1095. /**
  1096. * Function: terminalForCellChanged
  1097. *
  1098. * Inner helper function to update the terminal of the edge using
  1099. * <mxCell.insertEdge> and return the previous terminal.
  1100. *
  1101. * Parameters:
  1102. *
  1103. * edge - <mxCell> that specifies the edge to be updated.
  1104. * terminal - <mxCell> that specifies the new terminal.
  1105. * isSource - Boolean indicating if the terminal is the new source or
  1106. * target terminal of the edge.
  1107. */
  1108. mxGraphModel.prototype.terminalForCellChanged = function(edge, terminal, isSource)
  1109. {
  1110. var previous = this.getTerminal(edge, isSource);
  1111. if (terminal != null)
  1112. {
  1113. terminal.insertEdge(edge, isSource);
  1114. }
  1115. else if (previous != null)
  1116. {
  1117. previous.removeEdge(edge, isSource);
  1118. }
  1119. return previous;
  1120. };
  1121. /**
  1122. * Function: getEdgeCount
  1123. *
  1124. * Returns the number of distinct edges connected to the given cell.
  1125. *
  1126. * Parameters:
  1127. *
  1128. * cell - <mxCell> that represents the vertex.
  1129. */
  1130. mxGraphModel.prototype.getEdgeCount = function(cell)
  1131. {
  1132. return (cell != null) ? cell.getEdgeCount() : 0;
  1133. };
  1134. /**
  1135. * Function: getEdgeAt
  1136. *
  1137. * Returns the edge of cell at the given index.
  1138. *
  1139. * Parameters:
  1140. *
  1141. * cell - <mxCell> that specifies the vertex.
  1142. * index - Integer that specifies the index of the edge
  1143. * to return.
  1144. */
  1145. mxGraphModel.prototype.getEdgeAt = function(cell, index)
  1146. {
  1147. return (cell != null) ? cell.getEdgeAt(index) : null;
  1148. };
  1149. /**
  1150. * Function: getDirectedEdgeCount
  1151. *
  1152. * Returns the number of incoming or outgoing edges, ignoring the given
  1153. * edge.
  1154. *
  1155. * Parameters:
  1156. *
  1157. * cell - <mxCell> whose edge count should be returned.
  1158. * outgoing - Boolean that specifies if the number of outgoing or
  1159. * incoming edges should be returned.
  1160. * ignoredEdge - <mxCell> that represents an edge to be ignored.
  1161. */
  1162. mxGraphModel.prototype.getDirectedEdgeCount = function(cell, outgoing, ignoredEdge)
  1163. {
  1164. var count = 0;
  1165. var edgeCount = this.getEdgeCount(cell);
  1166. for (var i = 0; i < edgeCount; i++)
  1167. {
  1168. var edge = this.getEdgeAt(cell, i);
  1169. if (edge != ignoredEdge && this.getTerminal(edge, outgoing) == cell)
  1170. {
  1171. count++;
  1172. }
  1173. }
  1174. return count;
  1175. };
  1176. /**
  1177. * Function: getConnections
  1178. *
  1179. * Returns all edges of the given cell without loops.
  1180. *
  1181. * Parameters:
  1182. *
  1183. * cell - <mxCell> whose edges should be returned.
  1184. *
  1185. */
  1186. mxGraphModel.prototype.getConnections = function(cell)
  1187. {
  1188. return this.getEdges(cell, true, true, false);
  1189. };
  1190. /**
  1191. * Function: getIncomingEdges
  1192. *
  1193. * Returns the incoming edges of the given cell without loops.
  1194. *
  1195. * Parameters:
  1196. *
  1197. * cell - <mxCell> whose incoming edges should be returned.
  1198. *
  1199. */
  1200. mxGraphModel.prototype.getIncomingEdges = function(cell)
  1201. {
  1202. return this.getEdges(cell, true, false, false);
  1203. };
  1204. /**
  1205. * Function: getOutgoingEdges
  1206. *
  1207. * Returns the outgoing edges of the given cell without loops.
  1208. *
  1209. * Parameters:
  1210. *
  1211. * cell - <mxCell> whose outgoing edges should be returned.
  1212. *
  1213. */
  1214. mxGraphModel.prototype.getOutgoingEdges = function(cell)
  1215. {
  1216. return this.getEdges(cell, false, true, false);
  1217. };
  1218. /**
  1219. * Function: getEdges
  1220. *
  1221. * Returns all distinct edges connected to this cell as a new array of
  1222. * <mxCells>. If at least one of incoming or outgoing is true, then loops
  1223. * are ignored, otherwise if both are false, then all edges connected to
  1224. * the given cell are returned including loops.
  1225. *
  1226. * Parameters:
  1227. *
  1228. * cell - <mxCell> that specifies the cell.
  1229. * incoming - Optional boolean that specifies if incoming edges should be
  1230. * returned. Default is true.
  1231. * outgoing - Optional boolean that specifies if outgoing edges should be
  1232. * returned. Default is true.
  1233. * includeLoops - Optional boolean that specifies if loops should be returned.
  1234. * Default is true.
  1235. */
  1236. mxGraphModel.prototype.getEdges = function(cell, incoming, outgoing, includeLoops)
  1237. {
  1238. incoming = (incoming != null) ? incoming : true;
  1239. outgoing = (outgoing != null) ? outgoing : true;
  1240. includeLoops = (includeLoops != null) ? includeLoops : true;
  1241. var edgeCount = this.getEdgeCount(cell);
  1242. var result = [];
  1243. for (var i = 0; i < edgeCount; i++)
  1244. {
  1245. var edge = this.getEdgeAt(cell, i);
  1246. var source = this.getTerminal(edge, true);
  1247. var target = this.getTerminal(edge, false);
  1248. if ((includeLoops && source == target) || ((source != target) && ((incoming && target == cell) ||
  1249. (outgoing && source == cell))))
  1250. {
  1251. result.push(edge);
  1252. }
  1253. }
  1254. return result;
  1255. };
  1256. /**
  1257. * Function: getEdgesBetween
  1258. *
  1259. * Returns all edges between the given source and target pair. If directed
  1260. * is true, then only edges from the source to the target are returned,
  1261. * otherwise, all edges between the two cells are returned.
  1262. *
  1263. * Parameters:
  1264. *
  1265. * source - <mxCell> that defines the source terminal of the edge to be
  1266. * returned.
  1267. * target - <mxCell> that defines the target terminal of the edge to be
  1268. * returned.
  1269. * directed - Optional boolean that specifies if the direction of the
  1270. * edge should be taken into account. Default is false.
  1271. */
  1272. mxGraphModel.prototype.getEdgesBetween = function(source, target, directed)
  1273. {
  1274. directed = (directed != null) ? directed : false;
  1275. var tmp1 = this.getEdgeCount(source);
  1276. var tmp2 = this.getEdgeCount(target);
  1277. // Assumes the source has less connected edges
  1278. var terminal = source;
  1279. var edgeCount = tmp1;
  1280. // Uses the smaller array of connected edges
  1281. // for searching the edge
  1282. if (tmp2 < tmp1)
  1283. {
  1284. edgeCount = tmp2;
  1285. terminal = target;
  1286. }
  1287. var result = [];
  1288. // Checks if the edge is connected to the correct
  1289. // cell and returns the first match
  1290. for (var i = 0; i < edgeCount; i++)
  1291. {
  1292. var edge = this.getEdgeAt(terminal, i);
  1293. var src = this.getTerminal(edge, true);
  1294. var trg = this.getTerminal(edge, false);
  1295. var directedMatch = (src == source) && (trg == target);
  1296. var oppositeMatch = (trg == source) && (src == target);
  1297. if (directedMatch || (!directed && oppositeMatch))
  1298. {
  1299. result.push(edge);
  1300. }
  1301. }
  1302. return result;
  1303. };
  1304. /**
  1305. * Function: getOpposites
  1306. *
  1307. * Returns all opposite vertices wrt terminal for the given edges, only
  1308. * returning sources and/or targets as specified. The result is returned
  1309. * as an array of <mxCells>.
  1310. *
  1311. * Parameters:
  1312. *
  1313. * edges - Array of <mxCells> that contain the edges to be examined.
  1314. * terminal - <mxCell> that specifies the known end of the edges.
  1315. * sources - Boolean that specifies if source terminals should be contained
  1316. * in the result. Default is true.
  1317. * targets - Boolean that specifies if target terminals should be contained
  1318. * in the result. Default is true.
  1319. */
  1320. mxGraphModel.prototype.getOpposites = function(edges, terminal, sources, targets)
  1321. {
  1322. sources = (sources != null) ? sources : true;
  1323. targets = (targets != null) ? targets : true;
  1324. var terminals = [];
  1325. if (edges != null)
  1326. {
  1327. for (var i = 0; i < edges.length; i++)
  1328. {
  1329. var source = this.getTerminal(edges[i], true);
  1330. var target = this.getTerminal(edges[i], false);
  1331. // Checks if the terminal is the source of
  1332. // the edge and if the target should be
  1333. // stored in the result
  1334. if (source == terminal && target != null && target != terminal && targets)
  1335. {
  1336. terminals.push(target);
  1337. }
  1338. // Checks if the terminal is the taget of
  1339. // the edge and if the source should be
  1340. // stored in the result
  1341. else if (target == terminal && source != null && source != terminal && sources)
  1342. {
  1343. terminals.push(source);
  1344. }
  1345. }
  1346. }
  1347. return terminals;
  1348. };
  1349. /**
  1350. * Function: getTopmostCells
  1351. *
  1352. * Returns the topmost cells of the hierarchy in an array that contains no
  1353. * descendants for each <mxCell> that it contains. Duplicates should be
  1354. * removed in the cells array to improve performance.
  1355. *
  1356. * Parameters:
  1357. *
  1358. * cells - Array of <mxCells> whose topmost ancestors should be returned.
  1359. */
  1360. mxGraphModel.prototype.getTopmostCells = function(cells)
  1361. {
  1362. var dict = new mxDictionary();
  1363. var tmp = [];
  1364. for (var i = 0; i < cells.length; i++)
  1365. {
  1366. dict.put(cells[i], true);
  1367. }
  1368. for (var i = 0; i < cells.length; i++)
  1369. {
  1370. var cell = cells[i];
  1371. var topmost = true;
  1372. var parent = this.getParent(cell);
  1373. while (parent != null)
  1374. {
  1375. if (dict.get(parent))
  1376. {
  1377. topmost = false;
  1378. break;
  1379. }
  1380. parent = this.getParent(parent);
  1381. }
  1382. if (topmost)
  1383. {
  1384. tmp.push(cell);
  1385. }
  1386. }
  1387. return tmp;
  1388. };
  1389. /**
  1390. * Function: isVertex
  1391. *
  1392. * Returns true if the given cell is a vertex.
  1393. *
  1394. * Parameters:
  1395. *
  1396. * cell - <mxCell> that represents the possible vertex.
  1397. */
  1398. mxGraphModel.prototype.isVertex = function(cell)
  1399. {
  1400. return (cell != null) ? cell.isVertex() : false;
  1401. };
  1402. /**
  1403. * Function: isEdge
  1404. *
  1405. * Returns true if the given cell is an edge.
  1406. *
  1407. * Parameters:
  1408. *
  1409. * cell - <mxCell> that represents the possible edge.
  1410. */
  1411. mxGraphModel.prototype.isEdge = function(cell)
  1412. {
  1413. return (cell != null) ? cell.isEdge() : false;
  1414. };
  1415. /**
  1416. * Function: isConnectable
  1417. *
  1418. * Returns true if the given <mxCell> is connectable. If <edgesConnectable>
  1419. * is false, then this function returns false for all edges else it returns
  1420. * the return value of <mxCell.isConnectable>.
  1421. *
  1422. * Parameters:
  1423. *
  1424. * cell - <mxCell> whose connectable state should be returned.
  1425. */
  1426. mxGraphModel.prototype.isConnectable = function(cell)
  1427. {
  1428. return (cell != null) ? cell.isConnectable() : false;
  1429. };
  1430. /**
  1431. * Function: getValue
  1432. *
  1433. * Returns the user object of the given <mxCell> using <mxCell.getValue>.
  1434. *
  1435. * Parameters:
  1436. *
  1437. * cell - <mxCell> whose user object should be returned.
  1438. */
  1439. mxGraphModel.prototype.getValue = function(cell)
  1440. {
  1441. return (cell != null) ? cell.getValue() : null;
  1442. };
  1443. /**
  1444. * Function: setValue
  1445. *
  1446. * Sets the user object of then given <mxCell> using <mxValueChange>
  1447. * and adds the change to the current transaction.
  1448. *
  1449. * Parameters:
  1450. *
  1451. * cell - <mxCell> whose user object should be changed.
  1452. * value - Object that defines the new user object.
  1453. */
  1454. mxGraphModel.prototype.setValue = function(cell, value)
  1455. {
  1456. this.execute(new mxValueChange(this, cell, value));
  1457. return value;
  1458. };
  1459. /**
  1460. * Function: valueForCellChanged
  1461. *
  1462. * Inner callback to update the user object of the given <mxCell>
  1463. * using <mxCell.valueChanged> and return the previous value,
  1464. * that is, the return value of <mxCell.valueChanged>.
  1465. *
  1466. * To change a specific attribute in an XML node, the following code can be
  1467. * used.
  1468. *
  1469. * (code)
  1470. * graph.getModel().valueForCellChanged = function(cell, value)
  1471. * {
  1472. * var previous = cell.value.getAttribute('label');
  1473. * cell.value.setAttribute('label', value);
  1474. *
  1475. * return previous;
  1476. * };
  1477. * (end)
  1478. */
  1479. mxGraphModel.prototype.valueForCellChanged = function(cell, value)
  1480. {
  1481. return cell.valueChanged(value);
  1482. };
  1483. /**
  1484. * Function: getGeometry
  1485. *
  1486. * Returns the <mxGeometry> of the given <mxCell>.
  1487. *
  1488. * Parameters:
  1489. *
  1490. * cell - <mxCell> whose geometry should be returned.
  1491. */
  1492. mxGraphModel.prototype.getGeometry = function(cell)
  1493. {
  1494. return (cell != null) ? cell.getGeometry() : null;
  1495. };
  1496. /**
  1497. * Function: setGeometry
  1498. *
  1499. * Sets the <mxGeometry> of the given <mxCell>. The actual update
  1500. * of the cell is carried out in <geometryForCellChanged>. The
  1501. * <mxGeometryChange> action is used to encapsulate the change.
  1502. *
  1503. * Parameters:
  1504. *
  1505. * cell - <mxCell> whose geometry should be changed.
  1506. * geometry - <mxGeometry> that defines the new geometry.
  1507. */
  1508. mxGraphModel.prototype.setGeometry = function(cell, geometry)
  1509. {
  1510. if (geometry != this.getGeometry(cell))
  1511. {
  1512. this.execute(new mxGeometryChange(this, cell, geometry));
  1513. }
  1514. return geometry;
  1515. };
  1516. /**
  1517. * Function: geometryForCellChanged
  1518. *
  1519. * Inner callback to update the <mxGeometry> of the given <mxCell> using
  1520. * <mxCell.setGeometry> and return the previous <mxGeometry>.
  1521. */
  1522. mxGraphModel.prototype.geometryForCellChanged = function(cell, geometry)
  1523. {
  1524. var previous = this.getGeometry(cell);
  1525. cell.setGeometry(geometry);
  1526. return previous;
  1527. };
  1528. /**
  1529. * Function: getStyle
  1530. *
  1531. * Returns the style of the given <mxCell>.
  1532. *
  1533. * Parameters:
  1534. *
  1535. * cell - <mxCell> whose style should be returned.
  1536. */
  1537. mxGraphModel.prototype.getStyle = function(cell)
  1538. {
  1539. return (cell != null) ? cell.getStyle() : null;
  1540. };
  1541. /**
  1542. * Function: setStyle
  1543. *
  1544. * Sets the style of the given <mxCell> using <mxStyleChange> and
  1545. * adds the change to the current transaction.
  1546. *
  1547. * Parameters:
  1548. *
  1549. * cell - <mxCell> whose style should be changed.
  1550. * style - String of the form [stylename;|key=value;] to specify
  1551. * the new cell style.
  1552. */
  1553. mxGraphModel.prototype.setStyle = function(cell, style)
  1554. {
  1555. if (style != this.getStyle(cell))
  1556. {
  1557. this.execute(new mxStyleChange(this, cell, style));
  1558. }
  1559. return style;
  1560. };
  1561. /**
  1562. * Function: styleForCellChanged
  1563. *
  1564. * Inner callback to update the style of the given <mxCell>
  1565. * using <mxCell.setStyle> and return the previous style.
  1566. *
  1567. * Parameters:
  1568. *
  1569. * cell - <mxCell> that specifies the cell to be updated.
  1570. * style - String of the form [stylename;|key=value;] to specify
  1571. * the new cell style.
  1572. */
  1573. mxGraphModel.prototype.styleForCellChanged = function(cell, style)
  1574. {
  1575. var previous = this.getStyle(cell);
  1576. cell.setStyle(style);
  1577. return previous;
  1578. };
  1579. /**
  1580. * Function: isCollapsed
  1581. *
  1582. * Returns true if the given <mxCell> is collapsed.
  1583. *
  1584. * Parameters:
  1585. *
  1586. * cell - <mxCell> whose collapsed state should be returned.
  1587. */
  1588. mxGraphModel.prototype.isCollapsed = function(cell)
  1589. {
  1590. return (cell != null) ? cell.isCollapsed() : false;
  1591. };
  1592. /**
  1593. * Function: setCollapsed
  1594. *
  1595. * Sets the collapsed state of the given <mxCell> using <mxCollapseChange>
  1596. * and adds the change to the current transaction.
  1597. *
  1598. * Parameters:
  1599. *
  1600. * cell - <mxCell> whose collapsed state should be changed.
  1601. * collapsed - Boolean that specifies the new collpased state.
  1602. */
  1603. mxGraphModel.prototype.setCollapsed = function(cell, collapsed)
  1604. {
  1605. if (collapsed != this.isCollapsed(cell))
  1606. {
  1607. this.execute(new mxCollapseChange(this, cell, collapsed));
  1608. }
  1609. return collapsed;
  1610. };
  1611. /**
  1612. * Function: collapsedStateForCellChanged
  1613. *
  1614. * Inner callback to update the collapsed state of the
  1615. * given <mxCell> using <mxCell.setCollapsed> and return
  1616. * the previous collapsed state.
  1617. *
  1618. * Parameters:
  1619. *
  1620. * cell - <mxCell> that specifies the cell to be updated.
  1621. * collapsed - Boolean that specifies the new collpased state.
  1622. */
  1623. mxGraphModel.prototype.collapsedStateForCellChanged = function(cell, collapsed)
  1624. {
  1625. var previous = this.isCollapsed(cell);
  1626. cell.setCollapsed(collapsed);
  1627. return previous;
  1628. };
  1629. /**
  1630. * Function: isVisible
  1631. *
  1632. * Returns true if the given <mxCell> is visible.
  1633. *
  1634. * Parameters:
  1635. *
  1636. * cell - <mxCell> whose visible state should be returned.
  1637. */
  1638. mxGraphModel.prototype.isVisible = function(cell)
  1639. {
  1640. return (cell != null) ? cell.isVisible() : false;
  1641. };
  1642. /**
  1643. * Function: setVisible
  1644. *
  1645. * Sets the visible state of the given <mxCell> using <mxVisibleChange> and
  1646. * adds the change to the current transaction.
  1647. *
  1648. * Parameters:
  1649. *
  1650. * cell - <mxCell> whose visible state should be changed.
  1651. * visible - Boolean that specifies the new visible state.
  1652. */
  1653. mxGraphModel.prototype.setVisible = function(cell, visible)
  1654. {
  1655. if (visible != this.isVisible(cell))
  1656. {
  1657. this.execute(new mxVisibleChange(this, cell, visible));
  1658. }
  1659. return visible;
  1660. };
  1661. /**
  1662. * Function: visibleStateForCellChanged
  1663. *
  1664. * Inner callback to update the visible state of the
  1665. * given <mxCell> using <mxCell.setCollapsed> and return
  1666. * the previous visible state.
  1667. *
  1668. * Parameters:
  1669. *
  1670. * cell - <mxCell> that specifies the cell to be updated.
  1671. * visible - Boolean that specifies the new visible state.
  1672. */
  1673. mxGraphModel.prototype.visibleStateForCellChanged = function(cell, visible)
  1674. {
  1675. var previous = this.isVisible(cell);
  1676. cell.setVisible(visible);
  1677. return previous;
  1678. };
  1679. /**
  1680. * Function: execute
  1681. *
  1682. * Executes the given edit and fires events if required. The edit object
  1683. * requires an execute function which is invoked. The edit is added to the
  1684. * <currentEdit> between <beginUpdate> and <endUpdate> calls, so that
  1685. * events will be fired if this execute is an individual transaction, that
  1686. * is, if no previous <beginUpdate> calls have been made without calling
  1687. * <endUpdate>. This implementation fires an <execute> event before
  1688. * executing the given change.
  1689. *
  1690. * Parameters:
  1691. *
  1692. * change - Object that described the change.
  1693. */
  1694. mxGraphModel.prototype.execute = function(change)
  1695. {
  1696. change.execute();
  1697. this.beginUpdate();
  1698. this.currentEdit.add(change);
  1699. this.fireEvent(new mxEventObject(mxEvent.EXECUTE, 'change', change));
  1700. // New global executed event
  1701. this.fireEvent(new mxEventObject(mxEvent.EXECUTED, 'change', change));
  1702. this.endUpdate();
  1703. };
  1704. /**
  1705. * Function: beginUpdate
  1706. *
  1707. * Increments the <updateLevel> by one. The event notification
  1708. * is queued until <updateLevel> reaches 0 by use of
  1709. * <endUpdate>.
  1710. *
  1711. * All changes on <mxGraphModel> are transactional,
  1712. * that is, they are executed in a single undoable change
  1713. * on the model (without transaction isolation).
  1714. * Therefore, if you want to combine any
  1715. * number of changes into a single undoable change,
  1716. * you should group any two or more API calls that
  1717. * modify the graph model between <beginUpdate>
  1718. * and <endUpdate> calls as shown here:
  1719. *
  1720. * (code)
  1721. * var model = graph.getModel();
  1722. * var parent = graph.getDefaultParent();
  1723. * var index = model.getChildCount(parent);
  1724. * model.beginUpdate();
  1725. * try
  1726. * {
  1727. * model.add(parent, v1, index);
  1728. * model.add(parent, v2, index+1);
  1729. * }
  1730. * finally
  1731. * {
  1732. * model.endUpdate();
  1733. * }
  1734. * (end)
  1735. *
  1736. * Of course there is a shortcut for appending a
  1737. * sequence of cells into the default parent:
  1738. *
  1739. * (code)
  1740. * graph.addCells([v1, v2]).
  1741. * (end)
  1742. */
  1743. mxGraphModel.prototype.beginUpdate = function()
  1744. {
  1745. this.updateLevel++;
  1746. this.fireEvent(new mxEventObject(mxEvent.BEGIN_UPDATE));
  1747. if (this.updateLevel == 1)
  1748. {
  1749. this.fireEvent(new mxEventObject(mxEvent.START_EDIT));
  1750. }
  1751. };
  1752. /**
  1753. * Function: endUpdate
  1754. *
  1755. * Decrements the <updateLevel> by one and fires an <undo>
  1756. * event if the <updateLevel> reaches 0. This function
  1757. * indirectly fires a <change> event by invoking the notify
  1758. * function on the <currentEdit> und then creates a new
  1759. * <currentEdit> using <createUndoableEdit>.
  1760. *
  1761. * The <undo> event is fired only once per edit, whereas
  1762. * the <change> event is fired whenever the notify
  1763. * function is invoked, that is, on undo and redo of
  1764. * the edit.
  1765. */
  1766. mxGraphModel.prototype.endUpdate = function()
  1767. {
  1768. this.updateLevel--;
  1769. if (this.updateLevel == 0)
  1770. {
  1771. this.fireEvent(new mxEventObject(mxEvent.END_EDIT));
  1772. }
  1773. if (!this.endingUpdate)
  1774. {
  1775. this.endingUpdate = this.updateLevel == 0;
  1776. this.fireEvent(new mxEventObject(mxEvent.END_UPDATE, 'edit', this.currentEdit));
  1777. try
  1778. {
  1779. if (this.endingUpdate && !this.currentEdit.isEmpty())
  1780. {
  1781. this.fireEvent(new mxEventObject(mxEvent.BEFORE_UNDO, 'edit', this.currentEdit));
  1782. var tmp = this.currentEdit;
  1783. this.currentEdit = this.createUndoableEdit();
  1784. tmp.notify();
  1785. this.fireEvent(new mxEventObject(mxEvent.UNDO, 'edit', tmp));
  1786. }
  1787. }
  1788. finally
  1789. {
  1790. this.endingUpdate = false;
  1791. }
  1792. }
  1793. };
  1794. /**
  1795. * Function: createUndoableEdit
  1796. *
  1797. * Creates a new <mxUndoableEdit> that implements the
  1798. * notify function to fire a <change> and <notify> event
  1799. * through the <mxUndoableEdit>'s source.
  1800. *
  1801. * Parameters:
  1802. *
  1803. * significant - Optional boolean that specifies if the edit to be created is
  1804. * significant. Default is true.
  1805. */
  1806. mxGraphModel.prototype.createUndoableEdit = function(significant)
  1807. {
  1808. var edit = new mxUndoableEdit(this, (significant != null) ? significant : true);
  1809. edit.notify = function()
  1810. {
  1811. // LATER: Remove changes property (deprecated)
  1812. edit.source.fireEvent(new mxEventObject(mxEvent.CHANGE,
  1813. 'edit', edit, 'changes', edit.changes));
  1814. edit.source.fireEvent(new mxEventObject(mxEvent.NOTIFY,
  1815. 'edit', edit, 'changes', edit.changes));
  1816. };
  1817. return edit;
  1818. };
  1819. /**
  1820. * Function: mergeChildren
  1821. *
  1822. * Merges the children of the given cell into the given target cell inside
  1823. * this model. All cells are cloned unless there is a corresponding cell in
  1824. * the model with the same id, in which case the source cell is ignored and
  1825. * all edges are connected to the corresponding cell in this model. Edges
  1826. * are considered to have no identity and are always cloned unless the
  1827. * cloneAllEdges flag is set to false, in which case edges with the same
  1828. * id in the target model are reconnected to reflect the terminals of the
  1829. * source edges.
  1830. */
  1831. mxGraphModel.prototype.mergeChildren = function(from, to, cloneAllEdges)
  1832. {
  1833. cloneAllEdges = (cloneAllEdges != null) ? cloneAllEdges : true;
  1834. this.beginUpdate();
  1835. try
  1836. {
  1837. var mapping = new Object();
  1838. this.mergeChildrenImpl(from, to, cloneAllEdges, mapping);
  1839. // Post-processes all edges in the mapping and
  1840. // reconnects the terminals to the corresponding
  1841. // cells in the target model
  1842. for (var key in mapping)
  1843. {
  1844. var cell = mapping[key];
  1845. var terminal = this.getTerminal(cell, true);
  1846. if (terminal != null)
  1847. {
  1848. terminal = mapping[mxCellPath.create(terminal)];
  1849. this.setTerminal(cell, terminal, true);
  1850. }
  1851. terminal = this.getTerminal(cell, false);
  1852. if (terminal != null)
  1853. {
  1854. terminal = mapping[mxCellPath.create(terminal)];
  1855. this.setTerminal(cell, terminal, false);
  1856. }
  1857. }
  1858. }
  1859. finally
  1860. {
  1861. this.endUpdate();
  1862. }
  1863. };
  1864. /**
  1865. * Function: mergeChildren
  1866. *
  1867. * Clones the children of the source cell into the given target cell in
  1868. * this model and adds an entry to the mapping that maps from the source
  1869. * cell to the target cell with the same id or the clone of the source cell
  1870. * that was inserted into this model.
  1871. */
  1872. mxGraphModel.prototype.mergeChildrenImpl = function(from, to, cloneAllEdges, mapping)
  1873. {
  1874. this.beginUpdate();
  1875. try
  1876. {
  1877. var childCount = from.getChildCount();
  1878. for (var i = 0; i < childCount; i++)
  1879. {
  1880. var cell = from.getChildAt(i);
  1881. if (typeof(cell.getId) == 'function')
  1882. {
  1883. var id = cell.getId();
  1884. var target = (id != null && (!this.isEdge(cell) || !cloneAllEdges)) ?
  1885. this.getCell(id) : null;
  1886. // Clones and adds the child if no cell exists for the id
  1887. if (target == null)
  1888. {
  1889. var clone = cell.clone();
  1890. clone.setId(id);
  1891. // Sets the terminals from the original cell to the clone
  1892. // because the lookup uses strings not cells in JS
  1893. clone.setTerminal(cell.getTerminal(true), true);
  1894. clone.setTerminal(cell.getTerminal(false), false);
  1895. // Do *NOT* use model.add as this will move the edge away
  1896. // from the parent in updateEdgeParent if maintainEdgeParent
  1897. // is enabled in the target model
  1898. target = to.insert(clone);
  1899. this.cellAdded(target);
  1900. }
  1901. // Stores the mapping for later reconnecting edges
  1902. mapping[mxCellPath.create(cell)] = target;
  1903. // Recurses
  1904. this.mergeChildrenImpl(cell, target, cloneAllEdges, mapping);
  1905. }
  1906. }
  1907. }
  1908. finally
  1909. {
  1910. this.endUpdate();
  1911. }
  1912. };
  1913. /**
  1914. * Function: getParents
  1915. *
  1916. * Returns an array that represents the set (no duplicates) of all parents
  1917. * for the given array of cells.
  1918. *
  1919. * Parameters:
  1920. *
  1921. * cells - Array of cells whose parents should be returned.
  1922. */
  1923. mxGraphModel.prototype.getParents = function(cells)
  1924. {
  1925. var parents = [];
  1926. if (cells != null)
  1927. {
  1928. var dict = new mxDictionary();
  1929. for (var i = 0; i < cells.length; i++)
  1930. {
  1931. var parent = this.getParent(cells[i]);
  1932. if (parent != null && !dict.get(parent))
  1933. {
  1934. dict.put(parent, true);
  1935. parents.push(parent);
  1936. }
  1937. }
  1938. }
  1939. return parents;
  1940. };
  1941. //
  1942. // Cell Cloning
  1943. //
  1944. /**
  1945. * Function: cloneCell
  1946. *
  1947. * Returns a deep clone of the given <mxCell> (including
  1948. * the children) which is created using <cloneCells>.
  1949. *
  1950. * Parameters:
  1951. *
  1952. * cell - <mxCell> to be cloned.
  1953. * includeChildren - Optional boolean indicating if the cells should be cloned
  1954. * with all descendants. Default is true.
  1955. */
  1956. mxGraphModel.prototype.cloneCell = function(cell, includeChildren)
  1957. {
  1958. if (cell != null)
  1959. {
  1960. return this.cloneCells([cell], includeChildren)[0];
  1961. }
  1962. return null;
  1963. };
  1964. /**
  1965. * Function: cloneCells
  1966. *
  1967. * Returns an array of clones for the given array of <mxCells>.
  1968. * Depending on the value of includeChildren, a deep clone is created for
  1969. * each cell. Connections are restored based if the corresponding
  1970. * cell is contained in the passed in array.
  1971. *
  1972. * Parameters:
  1973. *
  1974. * cells - Array of <mxCell> to be cloned.
  1975. * includeChildren - Optional boolean indicating if the cells should be cloned
  1976. * with all descendants. Default is true.
  1977. * mapping - Optional mapping for existing clones.
  1978. */
  1979. mxGraphModel.prototype.cloneCells = function(cells, includeChildren, mapping)
  1980. {
  1981. includeChildren = (includeChildren != null) ? includeChildren : true;
  1982. mapping = (mapping != null) ? mapping : new Object();
  1983. var clones = [];
  1984. for (var i = 0; i < cells.length; i++)
  1985. {
  1986. if (cells[i] != null)
  1987. {
  1988. clones.push(this.cloneCellImpl(cells[i], mapping, includeChildren));
  1989. }
  1990. else
  1991. {
  1992. clones.push(null);
  1993. }
  1994. }
  1995. for (var i = 0; i < clones.length; i++)
  1996. {
  1997. if (clones[i] != null)
  1998. {
  1999. this.restoreClone(clones[i], cells[i], mapping);
  2000. }
  2001. }
  2002. return clones;
  2003. };
  2004. /**
  2005. * Function: cloneCellImpl
  2006. *
  2007. * Inner helper method for cloning cells recursively.
  2008. */
  2009. mxGraphModel.prototype.cloneCellImpl = function(cell, mapping, includeChildren)
  2010. {
  2011. var ident = mxObjectIdentity.get(cell);
  2012. var clone = mapping[ident];
  2013. if (clone == null)
  2014. {
  2015. clone = this.cellCloned(cell);
  2016. mapping[ident] = clone;
  2017. if (includeChildren)
  2018. {
  2019. var childCount = this.getChildCount(cell);
  2020. for (var i = 0; i < childCount; i++)
  2021. {
  2022. var cloneChild = this.cloneCellImpl(
  2023. this.getChildAt(cell, i), mapping, true);
  2024. clone.insert(cloneChild);
  2025. }
  2026. }
  2027. }
  2028. return clone;
  2029. };
  2030. /**
  2031. * Function: cellCloned
  2032. *
  2033. * Hook for cloning the cell. This returns cell.clone() or
  2034. * any possible exceptions.
  2035. */
  2036. mxGraphModel.prototype.cellCloned = function(cell)
  2037. {
  2038. return cell.clone();
  2039. };
  2040. /**
  2041. * Function: restoreClone
  2042. *
  2043. * Inner helper method for restoring the connections in
  2044. * a network of cloned cells.
  2045. */
  2046. mxGraphModel.prototype.restoreClone = function(clone, cell, mapping)
  2047. {
  2048. var source = this.getTerminal(cell, true);
  2049. if (source != null)
  2050. {
  2051. var tmp = mapping[mxObjectIdentity.get(source)];
  2052. if (tmp != null)
  2053. {
  2054. tmp.insertEdge(clone, true);
  2055. }
  2056. }
  2057. var target = this.getTerminal(cell, false);
  2058. if (target != null)
  2059. {
  2060. var tmp = mapping[mxObjectIdentity.get(target)];
  2061. if (tmp != null)
  2062. {
  2063. tmp.insertEdge(clone, false);
  2064. }
  2065. }
  2066. var childCount = this.getChildCount(clone);
  2067. for (var i = 0; i < childCount; i++)
  2068. {
  2069. this.restoreClone(this.getChildAt(clone, i),
  2070. this.getChildAt(cell, i), mapping);
  2071. }
  2072. };
  2073. //
  2074. // Atomic changes
  2075. //
  2076. /**
  2077. * Class: mxRootChange
  2078. *
  2079. * Action to change the root in a model.
  2080. *
  2081. * Constructor: mxRootChange
  2082. *
  2083. * Constructs a change of the root in the
  2084. * specified model.
  2085. */
  2086. function mxRootChange(model, root)
  2087. {
  2088. this.model = model;
  2089. this.root = root;
  2090. this.previous = root;
  2091. };
  2092. /**
  2093. * Function: execute
  2094. *
  2095. * Carries out a change of the root using
  2096. * <mxGraphModel.rootChanged>.
  2097. */
  2098. mxRootChange.prototype.execute = function()
  2099. {
  2100. this.root = this.previous;
  2101. this.previous = this.model.rootChanged(this.previous);
  2102. };
  2103. /**
  2104. * Class: mxChildChange
  2105. *
  2106. * Action to add or remove a child in a model.
  2107. *
  2108. * Constructor: mxChildChange
  2109. *
  2110. * Constructs a change of a child in the
  2111. * specified model.
  2112. */
  2113. function mxChildChange(model, parent, child, index)
  2114. {
  2115. this.model = model;
  2116. this.parent = parent;
  2117. this.previous = parent;
  2118. this.child = child;
  2119. this.index = index;
  2120. this.previousIndex = index;
  2121. };
  2122. /**
  2123. * Function: execute
  2124. *
  2125. * Changes the parent of <child> using
  2126. * <mxGraphModel.parentForCellChanged> and
  2127. * removes or restores the cell's
  2128. * connections.
  2129. */
  2130. mxChildChange.prototype.execute = function()
  2131. {
  2132. if (this.child != null)
  2133. {
  2134. var tmp = this.model.getParent(this.child);
  2135. var tmp2 = (tmp != null) ? tmp.getIndex(this.child) : 0;
  2136. if (this.previous == null)
  2137. {
  2138. this.connect(this.child, false);
  2139. }
  2140. tmp = this.model.parentForCellChanged(
  2141. this.child, this.previous, this.previousIndex);
  2142. if (this.previous != null)
  2143. {
  2144. this.connect(this.child, true);
  2145. }
  2146. this.parent = this.previous;
  2147. this.previous = tmp;
  2148. this.index = this.previousIndex;
  2149. this.previousIndex = tmp2;
  2150. }
  2151. };
  2152. /**
  2153. * Function: disconnect
  2154. *
  2155. * Disconnects the given cell recursively from its
  2156. * terminals and stores the previous terminal in the
  2157. * cell's terminals.
  2158. */
  2159. mxChildChange.prototype.connect = function(cell, isConnect)
  2160. {
  2161. isConnect = (isConnect != null) ? isConnect : true;
  2162. var source = cell.getTerminal(true);
  2163. var target = cell.getTerminal(false);
  2164. if (source != null)
  2165. {
  2166. if (isConnect)
  2167. {
  2168. this.model.terminalForCellChanged(cell, source, true);
  2169. }
  2170. else
  2171. {
  2172. this.model.terminalForCellChanged(cell, null, true);
  2173. }
  2174. }
  2175. if (target != null)
  2176. {
  2177. if (isConnect)
  2178. {
  2179. this.model.terminalForCellChanged(cell, target, false);
  2180. }
  2181. else
  2182. {
  2183. this.model.terminalForCellChanged(cell, null, false);
  2184. }
  2185. }
  2186. cell.setTerminal(source, true);
  2187. cell.setTerminal(target, false);
  2188. var childCount = this.model.getChildCount(cell);
  2189. for (var i=0; i<childCount; i++)
  2190. {
  2191. this.connect(this.model.getChildAt(cell, i), isConnect);
  2192. }
  2193. };
  2194. /**
  2195. * Class: mxTerminalChange
  2196. *
  2197. * Action to change a terminal in a model.
  2198. *
  2199. * Constructor: mxTerminalChange
  2200. *
  2201. * Constructs a change of a terminal in the
  2202. * specified model.
  2203. */
  2204. function mxTerminalChange(model, cell, terminal, source)
  2205. {
  2206. this.model = model;
  2207. this.cell = cell;
  2208. this.terminal = terminal;
  2209. this.previous = terminal;
  2210. this.source = source;
  2211. };
  2212. /**
  2213. * Function: execute
  2214. *
  2215. * Changes the terminal of <cell> to <previous> using
  2216. * <mxGraphModel.terminalForCellChanged>.
  2217. */
  2218. mxTerminalChange.prototype.execute = function()
  2219. {
  2220. if (this.cell != null)
  2221. {
  2222. this.terminal = this.previous;
  2223. this.previous = this.model.terminalForCellChanged(
  2224. this.cell, this.previous, this.source);
  2225. }
  2226. };
  2227. /**
  2228. * Class: mxValueChange
  2229. *
  2230. * Action to change a user object in a model.
  2231. *
  2232. * Constructor: mxValueChange
  2233. *
  2234. * Constructs a change of a user object in the
  2235. * specified model.
  2236. */
  2237. function mxValueChange(model, cell, value)
  2238. {
  2239. this.model = model;
  2240. this.cell = cell;
  2241. this.value = value;
  2242. this.previous = value;
  2243. };
  2244. /**
  2245. * Function: execute
  2246. *
  2247. * Changes the value of <cell> to <previous> using
  2248. * <mxGraphModel.valueForCellChanged>.
  2249. */
  2250. mxValueChange.prototype.execute = function()
  2251. {
  2252. if (this.cell != null)
  2253. {
  2254. this.value = this.previous;
  2255. this.previous = this.model.valueForCellChanged(
  2256. this.cell, this.previous);
  2257. }
  2258. };
  2259. /**
  2260. * Class: mxStyleChange
  2261. *
  2262. * Action to change a cell's style in a model.
  2263. *
  2264. * Constructor: mxStyleChange
  2265. *
  2266. * Constructs a change of a style in the
  2267. * specified model.
  2268. */
  2269. function mxStyleChange(model, cell, style)
  2270. {
  2271. this.model = model;
  2272. this.cell = cell;
  2273. this.style = style;
  2274. this.previous = style;
  2275. };
  2276. /**
  2277. * Function: execute
  2278. *
  2279. * Changes the style of <cell> to <previous> using
  2280. * <mxGraphModel.styleForCellChanged>.
  2281. */
  2282. mxStyleChange.prototype.execute = function()
  2283. {
  2284. if (this.cell != null)
  2285. {
  2286. this.style = this.previous;
  2287. this.previous = this.model.styleForCellChanged(
  2288. this.cell, this.previous);
  2289. }
  2290. };
  2291. /**
  2292. * Class: mxGeometryChange
  2293. *
  2294. * Action to change a cell's geometry in a model.
  2295. *
  2296. * Constructor: mxGeometryChange
  2297. *
  2298. * Constructs a change of a geometry in the
  2299. * specified model.
  2300. */
  2301. function mxGeometryChange(model, cell, geometry)
  2302. {
  2303. this.model = model;
  2304. this.cell = cell;
  2305. this.geometry = geometry;
  2306. this.previous = geometry;
  2307. };
  2308. /**
  2309. * Function: execute
  2310. *
  2311. * Changes the geometry of <cell> ro <previous> using
  2312. * <mxGraphModel.geometryForCellChanged>.
  2313. */
  2314. mxGeometryChange.prototype.execute = function()
  2315. {
  2316. if (this.cell != null)
  2317. {
  2318. this.geometry = this.previous;
  2319. this.previous = this.model.geometryForCellChanged(
  2320. this.cell, this.previous);
  2321. }
  2322. };
  2323. /**
  2324. * Class: mxCollapseChange
  2325. *
  2326. * Action to change a cell's collapsed state in a model.
  2327. *
  2328. * Constructor: mxCollapseChange
  2329. *
  2330. * Constructs a change of a collapsed state in the
  2331. * specified model.
  2332. */
  2333. function mxCollapseChange(model, cell, collapsed)
  2334. {
  2335. this.model = model;
  2336. this.cell = cell;
  2337. this.collapsed = collapsed;
  2338. this.previous = collapsed;
  2339. };
  2340. /**
  2341. * Function: execute
  2342. *
  2343. * Changes the collapsed state of <cell> to <previous> using
  2344. * <mxGraphModel.collapsedStateForCellChanged>.
  2345. */
  2346. mxCollapseChange.prototype.execute = function()
  2347. {
  2348. if (this.cell != null)
  2349. {
  2350. this.collapsed = this.previous;
  2351. this.previous = this.model.collapsedStateForCellChanged(
  2352. this.cell, this.previous);
  2353. }
  2354. };
  2355. /**
  2356. * Class: mxVisibleChange
  2357. *
  2358. * Action to change a cell's visible state in a model.
  2359. *
  2360. * Constructor: mxVisibleChange
  2361. *
  2362. * Constructs a change of a visible state in the
  2363. * specified model.
  2364. */
  2365. function mxVisibleChange(model, cell, visible)
  2366. {
  2367. this.model = model;
  2368. this.cell = cell;
  2369. this.visible = visible;
  2370. this.previous = visible;
  2371. };
  2372. /**
  2373. * Function: execute
  2374. *
  2375. * Changes the visible state of <cell> to <previous> using
  2376. * <mxGraphModel.visibleStateForCellChanged>.
  2377. */
  2378. mxVisibleChange.prototype.execute = function()
  2379. {
  2380. if (this.cell != null)
  2381. {
  2382. this.visible = this.previous;
  2383. this.previous = this.model.visibleStateForCellChanged(
  2384. this.cell, this.previous);
  2385. }
  2386. };
  2387. /**
  2388. * Class: mxCellAttributeChange
  2389. *
  2390. * Action to change the attribute of a cell's user object.
  2391. * There is no method on the graph model that uses this
  2392. * action. To use the action, you can use the code shown
  2393. * in the example below.
  2394. *
  2395. * Example:
  2396. *
  2397. * To change the attributeName in the cell's user object
  2398. * to attributeValue, use the following code:
  2399. *
  2400. * (code)
  2401. * model.beginUpdate();
  2402. * try
  2403. * {
  2404. * var edit = new mxCellAttributeChange(
  2405. * cell, attributeName, attributeValue);
  2406. * model.execute(edit);
  2407. * }
  2408. * finally
  2409. * {
  2410. * model.endUpdate();
  2411. * }
  2412. * (end)
  2413. *
  2414. * Constructor: mxCellAttributeChange
  2415. *
  2416. * Constructs a change of a attribute of the DOM node
  2417. * stored as the value of the given <mxCell>.
  2418. */
  2419. function mxCellAttributeChange(cell, attribute, value)
  2420. {
  2421. this.cell = cell;
  2422. this.attribute = attribute;
  2423. this.value = value;
  2424. this.previous = value;
  2425. };
  2426. /**
  2427. * Function: execute
  2428. *
  2429. * Changes the attribute of the cell's user object by
  2430. * using <mxCell.setAttribute>.
  2431. */
  2432. mxCellAttributeChange.prototype.execute = function()
  2433. {
  2434. if (this.cell != null)
  2435. {
  2436. var tmp = this.cell.getAttribute(this.attribute);
  2437. if (this.previous == null)
  2438. {
  2439. this.cell.value.removeAttribute(this.attribute);
  2440. }
  2441. else
  2442. {
  2443. this.cell.setAttribute(this.attribute, this.previous);
  2444. }
  2445. this.previous = tmp;
  2446. }
  2447. };
  2448. __mxOutput.mxGraphModel = typeof mxGraphModel !== 'undefined' ? mxGraphModel : undefined;