1/**
2 * Copyright (c) 2006-2017, JGraph Ltd
3 * Copyright (c) 2006-2017, Gaudenz Alder
4 */
5(function()
6{
7	/**
8	 * Defines resources.
9	 */
10	EditorUi.prototype.altShiftActions[68] = 'selectDescendants'; // Alt+Shift+D
11
12	/**
13	 * Overrides folding based on treeFolding style.
14	 */
15	var graphFoldCells = Graph.prototype.foldCells;
16
17	Graph.prototype.foldCells = function(collapse, recurse, cells, checkFoldable, evt)
18	{
19		recurse = (recurse != null) ? recurse : false;
20
21		if (cells == null)
22		{
23			cells = this.getFoldableCells(this.getSelectionCells(), collapse);
24		}
25
26		this.stopEditing();
27
28		this.model.beginUpdate();
29		try
30		{
31			var newCells = cells.slice();
32			var tmp = [];
33
34			for (var i = 0; i < cells.length; i++)
35			{
36				if (mxUtils.getValue(this.getCurrentCellStyle(cells[i]),
37					'treeFolding', '0') == '1')
38				{
39					this.foldTreeCell(collapse, cells[i]);
40				}
41			}
42
43			cells = newCells;
44			cells = graphFoldCells.apply(this, arguments);
45		}
46		finally
47		{
48			this.model.endUpdate();
49		}
50
51		return cells;
52	};
53
54	/**
55	 * Implements folding a tree cell.
56	 */
57	Graph.prototype.foldTreeCell = function(collapse, cell)
58	{
59		this.model.beginUpdate();
60		try
61		{
62			var tmp = [];
63
64			this.traverse(cell, true, mxUtils.bind(this, function(vertex, edge)
65			{
66				var treeEdge = edge != null && this.isTreeEdge(edge);
67
68				if (treeEdge)
69				{
70					tmp.push(edge);
71				}
72
73				if (vertex != cell && (edge == null || treeEdge))
74				{
75					tmp.push(vertex);
76				}
77
78				// Stops traversal on collapsed vertices
79				return (edge == null || treeEdge) &&
80					(vertex == cell || !this.model.isCollapsed(vertex));
81			}));
82
83			this.model.setCollapsed(cell, collapse);
84
85			for (var i = 0; i < tmp.length; i++)
86			{
87				this.model.setVisible(tmp[i], !collapse);
88			}
89		}
90		finally
91		{
92			this.model.endUpdate();
93		}
94	};
95
96	/**
97	 * Implements folding a tree cell.
98	 */
99	Graph.prototype.isTreeEdge = function(cell)
100	{
101		return !this.isEdgeIgnored(cell);
102	};
103
104	/**
105	 * Returns all tree edges for the given cell.
106	 */
107	Graph.prototype.getTreeEdges = function(cell, parent, incoming, outgoing, includeLoops, recurse)
108	{
109		return this.model.filterCells(this.getEdges(cell, parent, incoming, outgoing, includeLoops, recurse), mxUtils.bind(this, function(cell)
110		{
111			return this.isTreeEdge(cell);
112		}));
113	};
114
115	/**
116	 * Returns all incoming tree edges for the given cell.
117	 */
118	Graph.prototype.getIncomingTreeEdges = function(cell, parent)
119	{
120		return this.getTreeEdges(cell, parent, true, false, false);
121	};
122
123	/**
124	 * Returns all outgoing tree edges for the given cell.
125	 */
126	Graph.prototype.getOutgoingTreeEdges = function(cell, parent)
127	{
128		return this.getTreeEdges(cell, parent, false, true, false);
129	};
130
131	/**
132	 * Overrides functionality in editor.
133	 */
134	var editorUiInit = EditorUi.prototype.init;
135
136	EditorUi.prototype.init = function()
137	{
138		editorUiInit.apply(this, arguments);
139
140		if (!this.editor.isChromelessView() || this.editor.editable)
141		{
142			this.addTrees();
143		}
144	};
145
146	EditorUi.prototype.addTrees = function()
147	{
148		var ui = this;
149		var graph = ui.editor.graph;
150		var model = graph.getModel();
151		var spacing = 10;
152		var level = 40;
153
154		function isTreeVertex(cell)
155		{
156			return model.isVertex(cell) && hasTreeParent(cell);
157		};
158
159		function isTreeMoving(cell)
160		{
161			var result = false;
162
163			if (cell != null)
164			{
165				var style = graph.getCurrentCellStyle(cell);
166
167				result = style['treeMoving'] == '1';
168			}
169
170			return result;
171		};
172
173		function hasTreeParent(cell)
174		{
175			var result = false;
176
177			if (cell != null)
178			{
179				var parent = model.getParent(cell);
180				var pstate = graph.view.getState(parent);
181				var style = (pstate != null) ? pstate.style : graph.getCellStyle(parent);
182
183				result = style['containerType'] == 'tree';
184			}
185
186			return result;
187		};
188
189		function hasLayoutParent(cell)
190		{
191			var result = false;
192
193			if (cell != null)
194			{
195				var parent = model.getParent(cell);
196				var pstate = graph.view.getState(parent);
197
198				var state = graph.view.getState(parent);
199				var style = (pstate != null) ? pstate.style : graph.getCellStyle(parent);
200
201				result = style['childLayout'] != null;
202			}
203
204			return result;
205		};
206
207		var uiCreatePopupMenu = ui.menus.createPopupMenu;
208		ui.menus.createPopupMenu = function(menu, cell, evt)
209		{
210			uiCreatePopupMenu.apply(this, arguments);
211
212			if (graph.getSelectionCount() == 1)
213			{
214				var cell = graph.getSelectionCell();
215				var sib = graph.getOutgoingTreeEdges(cell);
216				menu.addSeparator();
217
218				if (sib.length > 0)
219				{
220					if (isTreeVertex(graph.getSelectionCell()))
221					{
222						this.addMenuItems(menu, ['selectChildren'], null, evt);
223					}
224
225					this.addMenuItems(menu, ['selectDescendants'], null, evt);
226				}
227
228				if (isTreeVertex(graph.getSelectionCell()))
229				{
230					menu.addSeparator();
231
232					if (graph.getIncomingTreeEdges(cell).length > 0)
233					{
234						this.addMenuItems(menu, ['selectSiblings', 'selectParent'], null, evt);
235					}
236				}
237				else if (graph.model.getEdgeCount(cell) > 0)
238				{
239					this.addMenuItems(menu, ['selectConnections'], null, evt);
240				}
241			}
242		};
243
244		// Adds actions
245		ui.actions.addAction('selectChildren', function()
246		{
247			if (graph.isEnabled() && graph.getSelectionCount() == 1)
248			{
249				var cell = graph.getSelectionCell();
250				var sib = graph.getOutgoingTreeEdges(cell);
251
252				if (sib != null)
253				{
254					var tmp = [];
255
256					for (var i = 0; i < sib.length; i++)
257					{
258						tmp.push(graph.model.getTerminal(sib[i], false));
259					}
260
261					graph.setSelectionCells(tmp);
262				}
263			}
264		}, null, null, 'Alt+Shift+X');
265
266		// Adds actions
267		ui.actions.addAction('selectSiblings', function()
268		{
269			if (graph.isEnabled() && graph.getSelectionCount() == 1)
270			{
271				var cell = graph.getSelectionCell();
272				var edges = graph.getIncomingTreeEdges(cell);
273
274				if (edges != null && edges.length > 0)
275				{
276					var sib = graph.getOutgoingTreeEdges(graph.model.getTerminal(edges[0], true));
277
278					if (sib != null)
279					{
280						var tmp = [];
281
282						for (var i = 0; i < sib.length; i++)
283						{
284							tmp.push(graph.model.getTerminal(sib[i], false));
285						}
286
287						graph.setSelectionCells(tmp);
288					}
289				}
290			}
291		}, null, null, 'Alt+Shift+S');
292
293		// Adds actions
294		ui.actions.addAction('selectParent', function()
295		{
296			if (graph.isEnabled() && graph.getSelectionCount() == 1)
297			{
298				var cell = graph.getSelectionCell();
299				var edges = graph.getIncomingTreeEdges(cell);
300
301				if (edges != null && edges.length > 0)
302				{
303					graph.setSelectionCell(graph.model.getTerminal(edges[0], true));
304				}
305			}
306		}, null, null, 'Alt+Shift+P');
307
308		ui.actions.addAction('selectDescendants', function(trigger, evt)
309		{
310			var cell = graph.getSelectionCell();
311
312			if (graph.isEnabled() && graph.model.isVertex(cell))
313			{
314				if (evt != null && mxEvent.isAltDown(evt))
315				{
316					graph.setSelectionCells(graph.model.getTreeEdges(cell,
317						evt == null || !mxEvent.isShiftDown(evt),
318						evt == null || !mxEvent.isControlDown(evt)));
319				}
320				else
321				{
322					var subtree = [];
323
324					graph.traverse(cell, true, function(vertex, edge)
325					{
326						var treeEdge = edge != null && graph.isTreeEdge(edge);
327
328						if (treeEdge)
329						{
330							subtree.push(edge);
331						}
332
333						if ((edge == null || treeEdge) &&
334							(evt == null || !mxEvent.isShiftDown(evt)))
335						{
336							subtree.push(vertex);
337						}
338
339						return edge == null || treeEdge;
340					});
341				}
342
343				graph.setSelectionCells(subtree);
344			}
345		}, null, null, 'Alt+Shift+D');
346
347		/**
348		 * Overriddes
349		 */
350		var graphRemoveCells = graph.removeCells;
351
352		graph.removeCells = function(cells, includeEdges)
353		{
354			includeEdges = (includeEdges != null) ? includeEdges : true;
355
356			if (cells == null)
357			{
358				cells = this.getDeletableCells(this.getSelectionCells());
359			}
360
361			// Adds all edges to the cells
362			if (includeEdges)
363			{
364				// FIXME: Remove duplicate cells in result or do not add if
365				// in cells or descendant of cells
366				cells = this.getDeletableCells(this.addAllEdges(cells));
367			}
368
369			var tmp = [];
370
371			for (var i = 0; i < cells.length; i++)
372			{
373				var target = cells[i];
374
375				if (model.isEdge(target) && hasTreeParent(target))
376				{
377					tmp.push(target);
378					target = model.getTerminal(target, false);
379				}
380
381				if (isTreeVertex(target))
382				{
383					var subtree = [];
384
385					graph.traverse(target, true, function(vertex, edge)
386					{
387						var treeEdge = edge != null && graph.isTreeEdge(edge);
388
389						if (treeEdge)
390						{
391							subtree.push(edge);
392						}
393
394						if (edge == null || treeEdge)
395						{
396							subtree.push(vertex);
397						}
398
399						return edge == null || treeEdge;
400					});
401
402					if (subtree.length > 0)
403					{
404						tmp = tmp.concat(subtree);
405						var edges = graph.getIncomingTreeEdges(cells[i]);
406						cells = cells.concat(edges);
407					}
408				}
409				else if (target != null)
410				{
411					tmp.push(cells[i]);
412				}
413			}
414
415			cells = tmp;
416
417			return graphRemoveCells.apply(this, arguments);
418		};
419
420		ui.hoverIcons.getStateAt = function(state, x, y)
421		{
422			return (isTreeVertex(state.cell)) ? null : this.graph.view.getState(this.graph.getCellAt(x, y));
423		};
424
425		var graphDuplicateCells = graph.duplicateCells;
426
427		graph.duplicateCells = function(cells, append)
428		{
429			cells = (cells != null) ? cells : this.getSelectionCells();
430			var temp = cells.slice(0);
431
432			for (var i = 0; i < temp.length; i++)
433			{
434				var cell = temp[i];
435				var state = graph.view.getState(cell);
436
437				if (state != null && isTreeVertex(state.cell))
438				{
439					// Avoids disconnecting subtree by removing all incoming edges
440					var edges = graph.getIncomingTreeEdges(state.cell);
441
442					for (var j = 0; j < edges.length; j++)
443					{
444						mxUtils.remove(edges[j], cells);
445					}
446				}
447			}
448
449			this.model.beginUpdate();
450			try
451			{
452				var result = graphDuplicateCells.call(this, cells, append);
453
454				if (result.length == cells.length)
455				{
456					for (var i = 0; i < cells.length; i++)
457					{
458						if (isTreeVertex(cells[i]))
459						{
460							var newEdges = graph.getIncomingTreeEdges(result[i]);
461							var edges = graph.getIncomingTreeEdges(cells[i]);
462
463							if (newEdges.length == 0 && edges.length > 0)
464							{
465								var clone = this.cloneCell(edges[0]);
466								this.addEdge(clone, graph.getDefaultParent(),
467									this.model.getTerminal(edges[0], true), result[i]);
468							}
469						}
470					}
471				}
472			}
473			finally
474			{
475				this.model.endUpdate();
476			}
477
478			return result;
479		};
480
481		var graphMoveCells = graph.moveCells;
482
483		graph.moveCells = function(cells, dx, dy, clone, target, evt, mapping)
484		{
485			var result = null;
486
487			this.model.beginUpdate();
488			try
489			{
490				var newSource = target;
491				var style = this.getCurrentCellStyle(target);
492
493				if (cells != null && isTreeVertex(target) && mxUtils.getValue(style, 'treeFolding', '0') == '1')
494				{
495					// Handles only drag from tree or from sidebar with dangling edges
496					for (var i = 0; i < cells.length; i++)
497					{
498						if (isTreeVertex(cells[i]) || (graph.model.isEdge(cells[i]) &&
499							graph.model.getTerminal(cells[i], true) == null))
500						{
501							target = graph.model.getParent(cells[i]);
502							break;
503						}
504					}
505
506					// Applies distance between previous and current parent for non-sidebar drags
507					if (newSource != null && target != newSource && this.view.getState(cells[0]) != null)
508					{
509						var edges = graph.getIncomingTreeEdges(cells[0]);
510
511						if (edges.length > 0)
512						{
513							var state1 = graph.view.getState(graph.model.getTerminal(edges[0], true));
514
515							if (state1 != null)
516							{
517								var state2 = graph.view.getState(newSource);
518
519								if (state2 != null)
520								{
521									dx = (state2.getCenterX() - state1.getCenterX()) / graph.view.scale;
522									dy = (state2.getCenterY() - state1.getCenterY()) / graph.view.scale;
523								}
524							}
525						}
526					}
527				}
528
529				result = graphMoveCells.apply(this, arguments);
530
531				if (result != null && cells != null && result.length == cells.length)
532				{
533					for (var i = 0; i < result.length; i++)
534					{
535						// Connects all dangling edges from the sidebar
536						// when dropped into drop target (not hover icon)
537						if (this.model.isEdge(result[i]))
538						{
539							if (isTreeVertex(newSource) && mxUtils.indexOf(result,
540								this.model.getTerminal(result[i], true)) < 0)
541							{
542								this.model.setTerminal(result[i], newSource, true);
543							}
544						}
545						else if (isTreeVertex(cells[i]))
546						{
547							var edges = graph.getIncomingTreeEdges(cells[i]);
548
549							if (edges.length > 0)
550							{
551								if (!clone)
552								{
553									if (isTreeVertex(newSource) && mxUtils.indexOf(cells,
554										this.model.getTerminal(edges[0], true)) < 0)
555									{
556										this.model.setTerminal(edges[0], newSource, true);
557									}
558								}
559								else
560								{
561									var newEdges = graph.getIncomingTreeEdges(result[i]);
562
563									if (newEdges.length == 0)
564									{
565										var temp = newSource;
566
567										if (temp == null || temp == graph.model.getParent(cells[i]))
568										{
569											temp = graph.model.getTerminal(edges[0], true);
570										}
571
572										var clone = this.cloneCell(edges[0]);
573										this.addEdge(clone, graph.getDefaultParent(), temp, result[i]);
574									}
575								}
576							}
577						}
578					}
579				}
580			}
581			finally
582			{
583				this.model.endUpdate();
584			}
585
586			return result;
587		};
588
589		// Connects all dangling edges from the sidebar (by
590		// default only first dangling edge gets connected)
591		if (ui.sidebar != null)
592		{
593			var sidebarDropAndConnect = ui.sidebar.dropAndConnect;
594
595			ui.sidebar.dropAndConnect = function(source, targets, direction, dropCellIndex)
596			{
597				var model = graph.model;
598				var result = null;
599
600				model.beginUpdate();
601				try
602				{
603					result = sidebarDropAndConnect.apply(this, arguments);
604
605					if (isTreeVertex(source))
606					{
607						for (var i = 0; i < result.length; i++)
608						{
609							if (model.isEdge(result[i]) && model.getTerminal(result[i], true) == null)
610							{
611								model.setTerminal(result[i], source, true);
612								var geo = graph.getCellGeometry(result[i]);
613								geo.points = null;
614
615								if (geo.getTerminalPoint(true) != null)
616								{
617									geo.setTerminalPoint(null, true);
618								}
619							}
620						}
621					}
622				}
623				finally
624				{
625					model.endUpdate();
626				}
627
628				return result;
629			};
630		}
631
632		/**
633		 * Checks source point of incoming edge relative to target terminal.
634		 */
635		function getTreeDirection(cell)
636		{
637			var state = graph.view.getState(cell);
638
639			if (state != null)
640			{
641				var edges = graph.getIncomingTreeEdges(state.cell);
642
643				if (edges.length > 0)
644				{
645					var edgeState = graph.view.getState(edges[0]);
646
647					if (edgeState != null)
648					{
649						var abs = edgeState.absolutePoints;
650
651						if (abs != null && abs.length > 0)
652						{
653							var pt = abs[abs.length - 1];
654
655							if (pt != null)
656							{
657								if (pt.y == state.y && Math.abs(pt.x - state.getCenterX()) < state.width / 2)
658								{
659									return mxConstants.DIRECTION_SOUTH;
660								}
661								else if (pt.y == state.y + state.height && Math.abs(pt.x - state.getCenterX()) < state.width / 2)
662								{
663									return mxConstants.DIRECTION_NORTH;
664								}
665								else if (pt.x > state.getCenterX())
666								{
667									return mxConstants.DIRECTION_WEST;
668								}
669							}
670						}
671					}
672				}
673			}
674
675			return mxConstants.DIRECTION_EAST;
676		};
677
678		function addSibling(cell, after)
679		{
680			after = (after != null) ? after : true;
681
682			graph.model.beginUpdate();
683			try
684			{
685				var parent = graph.model.getParent(cell);
686				var edges = graph.getIncomingTreeEdges(cell);
687				var clones = graph.cloneCells([edges[0], cell]);
688				graph.model.setTerminal(clones[0], graph.model.getTerminal(edges[0], true), true);
689				var dir = getTreeDirection(cell);
690				var pgeo = parent.geometry;
691
692				if (dir == mxConstants.DIRECTION_SOUTH || dir == mxConstants.DIRECTION_NORTH)
693				{
694					clones[1].geometry.x += (after) ? cell.geometry.width + spacing :
695						-clones[1].geometry.width - spacing;
696				}
697				else
698				{
699					clones[1].geometry.y += (after) ? cell.geometry.height + spacing :
700						-clones[1].geometry.height - spacing;
701				}
702
703				if (graph.view.currentRoot != parent)
704				{
705					clones[1].geometry.x -= pgeo.x;
706					clones[1].geometry.y -= pgeo.y;
707				}
708
709				// Moves existing siblings
710				var state = graph.view.getState(cell);
711				var s = graph.view.scale;
712
713				if (state != null)
714				{
715					var bbox = mxRectangle.fromRectangle(state);
716
717					if (dir == mxConstants.DIRECTION_SOUTH ||
718						dir == mxConstants.DIRECTION_NORTH)
719					{
720						bbox.x += ((after) ? cell.geometry.width + spacing :
721							-clones[1].geometry.width - spacing) * s;
722					}
723					else
724					{
725						bbox.y += ((after) ? cell.geometry.height + spacing :
726							-clones[1].geometry.height - spacing) * s;
727					}
728
729					var sib = graph.getOutgoingTreeEdges(graph.model.getTerminal(edges[0], true));
730
731					if (sib != null)
732					{
733						var hor = (dir == mxConstants.DIRECTION_SOUTH || dir == mxConstants.DIRECTION_NORTH);
734						var dx = 0;
735						var dy = 0;
736
737						for (var i = 0; i < sib.length; i++)
738						{
739							var temp = graph.model.getTerminal(sib[i], false);
740
741							if (dir == getTreeDirection(temp))
742							{
743								var sibling = graph.view.getState(temp);
744
745								if (temp != cell && sibling != null)
746								{
747									if ((hor && after != sibling.getCenterX() < state.getCenterX()) ||
748										(!hor && after != sibling.getCenterY() < state.getCenterY()))
749									{
750										if (mxUtils.intersects(bbox, sibling))
751										{
752											dx = spacing + Math.max(dx, (Math.min(bbox.x + bbox.width,
753												sibling.x + sibling.width) - Math.max(bbox.x, sibling.x)) / s);
754											dy = spacing + Math.max(dy, (Math.min(bbox.y + bbox.height,
755												sibling.y + sibling.height) - Math.max(bbox.y, sibling.y)) / s);
756										}
757									}
758								}
759							}
760						}
761
762						if (hor)
763						{
764							dy = 0;
765						}
766						else
767						{
768							dx = 0;
769						}
770
771						for (var i = 0; i < sib.length; i++)
772						{
773							var temp = graph.model.getTerminal(sib[i], false);
774
775							if (dir == getTreeDirection(temp))
776							{
777								var sibling = graph.view.getState(temp);
778
779								if (temp != cell && sibling != null)
780								{
781									if ((hor && after != sibling.getCenterX() < state.getCenterX()) ||
782										(!hor && after != sibling.getCenterY() < state.getCenterY()))
783									{
784										var subtree = [];
785
786										graph.traverse(sibling.cell, true, function(vertex, edge)
787										{
788											var treeEdge = edge != null && graph.isTreeEdge(edge);
789
790											if (treeEdge)
791											{
792												subtree.push(edge);
793											}
794
795											if (edge == null || treeEdge)
796											{
797												subtree.push(vertex);
798											}
799
800											return edge == null || treeEdge;
801										});
802
803										graph.moveCells(subtree, ((after) ? 1 : -1) * dx, ((after) ? 1 : -1) * dy);
804									}
805								}
806							}
807						}
808					}
809				}
810
811				return graph.addCells(clones, parent);
812			}
813			finally
814			{
815				graph.model.endUpdate();
816			}
817		};
818
819		function addParent(cell)
820		{
821			graph.model.beginUpdate();
822			try
823			{
824				var dir = getTreeDirection(cell);
825				var edges = graph.getIncomingTreeEdges(cell);
826				var clones = graph.cloneCells([edges[0], cell]);
827				graph.model.setTerminal(edges[0], clones[1], false);
828				graph.model.setTerminal(clones[0], clones[1], true);
829				graph.model.setTerminal(clones[0], cell, false);
830
831				// Makes space for new parent
832				var parent = graph.model.getParent(cell);
833				var pgeo = parent.geometry;
834				var subtree = [];
835
836				if (graph.view.currentRoot != parent)
837				{
838					clones[1].geometry.x -= pgeo.x;
839					clones[1].geometry.y -= pgeo.y;
840				}
841
842				graph.traverse(cell, true, function(vertex, edge)
843				{
844					var treeEdge = edge != null && graph.isTreeEdge(edge);
845
846					if (treeEdge)
847					{
848						subtree.push(edge);
849					}
850
851					if (edge == null || treeEdge)
852					{
853						subtree.push(vertex);
854					}
855
856					return edge == null || treeEdge;
857				});
858
859				var dx = cell.geometry.width + level;
860				var dy = cell.geometry.height + level;
861
862				if (dir == mxConstants.DIRECTION_SOUTH)
863				{
864					dx = 0;
865				}
866				else if (dir == mxConstants.DIRECTION_NORTH)
867				{
868					dx = 0;
869					dy = -dy;
870				}
871				else if (dir == mxConstants.DIRECTION_WEST)
872				{
873					dx = -dx;
874					dy = 0;
875				}
876				else if (dir == mxConstants.DIRECTION_EAST)
877				{
878					dy = 0;
879				}
880
881				graph.moveCells(subtree, dx, dy);
882
883				return graph.addCells(clones, parent);
884			}
885			finally
886			{
887				graph.model.endUpdate();
888			}
889		};
890
891		function addChild(cell, direction)
892		{
893			graph.model.beginUpdate();
894			try
895			{
896				var parent = graph.model.getParent(cell);
897				var edges = graph.getIncomingTreeEdges(cell);
898				var dir = getTreeDirection(cell);
899
900				// Handles special case for click on tree root
901				if (edges.length == 0)
902				{
903					edges = [graph.createEdge(parent, null, '', null, null,
904						graph.createCurrentEdgeStyle())];
905					dir = direction;
906				}
907
908				var clones = graph.cloneCells([edges[0], cell]);
909				graph.model.setTerminal(clones[0], cell, true);
910
911				if (graph.model.getTerminal(clones[0], false) == null)
912				{
913					graph.model.setTerminal(clones[0], clones[1], false);
914
915					var style = graph.getCellStyle(clones[1]);
916					var temp = style['newEdgeStyle'];
917
918					if (temp != null)
919					{
920						try
921						{
922							var styles = JSON.parse(temp);
923
924							for (var key in styles)
925							{
926								graph.setCellStyles(key, styles[key], [clones[0]]);
927
928								// Sets elbow direction
929								if (key == 'edgeStyle' && styles[key] == 'elbowEdgeStyle')
930								{
931									graph.setCellStyles('elbow', (dir == mxConstants.DIRECTION_SOUTH ||
932										dir == mxConstants.DIRECTION_NOTH) ? 'vertical' : 'horizontal',
933										[clones[0]]);
934								}
935							}
936						}
937						catch (e)
938						{
939							// ignore
940						}
941					}
942				}
943
944				// Finds free space
945				var edges = graph.getOutgoingTreeEdges(cell);
946				var pgeo = parent.geometry;
947				var targets = [];
948
949				// Not offset if inside group
950				if (graph.view.currentRoot == parent)
951				{
952					pgeo = new mxRectangle();
953				}
954
955				for (var i = 0; i < edges.length; i++)
956				{
957					var target = graph.model.getTerminal(edges[i], false);
958
959					if (target != null)
960					{
961						targets.push(target);
962					}
963				}
964
965				var bbox = graph.view.getBounds(targets);
966				var tr = graph.view.translate;
967				var s = graph.view.scale;
968
969				if (dir == mxConstants.DIRECTION_SOUTH)
970				{
971					clones[1].geometry.x = (bbox == null) ? cell.geometry.x + (cell.geometry.width -
972						clones[1].geometry.width) / 2 : (bbox.x + bbox.width) / s - tr.x -
973						pgeo.x + spacing;
974					clones[1].geometry.y += clones[1].geometry.height - pgeo.y + level;
975				}
976				else if (dir == mxConstants.DIRECTION_NORTH)
977				{
978					clones[1].geometry.x = (bbox == null) ? cell.geometry.x + (cell.geometry.width -
979						clones[1].geometry.width) / 2 : (bbox.x + bbox.width) / s - tr.x + -
980						pgeo.x + spacing;
981					clones[1].geometry.y -= clones[1].geometry.height + pgeo.y + level;
982				}
983				else if (dir == mxConstants.DIRECTION_WEST)
984				{
985					clones[1].geometry.x -= clones[1].geometry.width + pgeo.x + level;
986					clones[1].geometry.y = (bbox == null) ? cell.geometry.y + (cell.geometry.height -
987						clones[1].geometry.height) / 2 : (bbox.y + bbox.height) / s - tr.y + -
988						pgeo.y + spacing;
989				}
990				else
991				{
992					clones[1].geometry.x += clones[1].geometry.width - pgeo.x + level;
993					clones[1].geometry.y = (bbox == null) ? cell.geometry.y + (cell.geometry.height -
994						clones[1].geometry.height) / 2 : (bbox.y + bbox.height) / s - tr.y + -
995						pgeo.y + spacing;
996				}
997
998				return graph.addCells(clones, parent);
999			}
1000			finally
1001			{
1002				graph.model.endUpdate();
1003			}
1004		};
1005
1006		function getOrderedTargets(cell, horizontal, ref)
1007		{
1008			var sib = graph.getOutgoingTreeEdges(cell);
1009			var state = graph.view.getState(ref);
1010			var targets = [];
1011
1012			if (state != null && sib != null)
1013			{
1014				for (var i = 0; i < sib.length; i++)
1015				{
1016					var temp = graph.view.getState(graph.model.getTerminal(sib[i], false));
1017
1018					if (temp != null && ((!horizontal && (Math.min(temp.x + temp.width,
1019						state.x + state.width) >= Math.max(temp.x, state.x))) ||
1020						(horizontal && (Math.min(temp.y + temp.height, state.y + state.height) >=
1021						Math.max(temp.y, state.y)))))
1022					{
1023						targets.push(temp);
1024					}
1025				}
1026
1027				targets.sort(function(a, b)
1028				{
1029					return (horizontal) ? a.x + a.width - b.x - b.width : a.y + a.height - b.y - b.height;
1030				});
1031			}
1032
1033			return targets;
1034		};
1035
1036		function selectCell(cell, direction)
1037		{
1038			var dir = getTreeDirection(cell);
1039			var h1 = dir == mxConstants.DIRECTION_EAST || dir == mxConstants.DIRECTION_WEST;
1040			var h2 = direction == mxConstants.DIRECTION_EAST || direction == mxConstants.DIRECTION_WEST;
1041
1042			if (h1 == h2 && dir != direction)
1043			{
1044				ui.actions.get('selectParent').funct();
1045			}
1046			else if (dir == direction)
1047			{
1048				var sib = graph.getOutgoingTreeEdges(cell);
1049
1050				if (sib != null && sib.length > 0)
1051				{
1052					graph.setSelectionCell(graph.model.getTerminal(sib[0], false));
1053				}
1054			}
1055			else
1056			{
1057				var edges = graph.getIncomingTreeEdges(cell);
1058
1059				if (edges != null && edges.length > 0)
1060				{
1061					var targets = getOrderedTargets(graph.model.getTerminal(edges[0], true), h2, cell);
1062					var state = graph.view.getState(cell);
1063
1064					if (state != null)
1065					{
1066						var idx = mxUtils.indexOf(targets, state);
1067
1068						if (idx >= 0)
1069						{
1070							idx += (direction == mxConstants.DIRECTION_NORTH || direction == mxConstants.DIRECTION_WEST) ? -1 : 1;
1071
1072							if (idx >= 0 && idx <= targets.length - 1)
1073							{
1074								graph.setSelectionCell(targets[idx].cell);
1075							}
1076						}
1077					}
1078				}
1079			}
1080		};
1081
1082		// Overrides keyboard shortcuts inside tree containers
1083		var altShiftActions = {88: ui.actions.get('selectChildren'), // Alt+Shift+X
1084				84: ui.actions.get('selectSubtree'), // Alt+Shift+T
1085				80: ui.actions.get('selectParent'), // Alt+Shift+P
1086				83: ui.actions.get('selectSiblings')} // Alt+Shift+S
1087
1088		var editorUiOnKeyDown = ui.onKeyDown;
1089
1090		ui.onKeyDown = function(evt)
1091		{
1092			try
1093			{
1094				if (graph.isEnabled() && !graph.isEditing() &&
1095					isTreeVertex(graph.getSelectionCell()) &&
1096					graph.getSelectionCount() == 1)
1097				{
1098					var cells = null;
1099
1100					if (graph.getIncomingTreeEdges(graph.getSelectionCell()).length > 0)
1101					{
1102						if (evt.which == 9) // Tab adds child
1103						{
1104							cells = (mxEvent.isShiftDown(evt)) ?
1105								addParent(graph.getSelectionCell()) :
1106								addChild(graph.getSelectionCell());
1107						}
1108						else if (evt.which == 13) // Enter adds sibling
1109						{
1110							cells = addSibling(graph.getSelectionCell(), !mxEvent.isShiftDown(evt));
1111						}
1112					}
1113
1114					if (cells != null && cells.length > 0)
1115					{
1116						if (cells.length == 1 && graph.model.isEdge(cells[0]))
1117						{
1118							graph.setSelectionCell(graph.model.getTerminal(cells[0], false));
1119						}
1120						else
1121						{
1122							graph.setSelectionCell(cells[cells.length - 1]);
1123						}
1124
1125						if (ui.hoverIcons != null)
1126						{
1127							ui.hoverIcons.update(graph.view.getState(graph.getSelectionCell()));
1128						}
1129
1130						graph.startEditingAtCell(graph.getSelectionCell());
1131						mxEvent.consume(evt);
1132					}
1133					else
1134					{
1135						if (mxEvent.isAltDown(evt) && mxEvent.isShiftDown(evt))
1136						{
1137							var action = altShiftActions[evt.keyCode];
1138
1139							if (action != null)
1140							{
1141								action.funct(evt);
1142								mxEvent.consume(evt);
1143							}
1144						}
1145						else
1146						{
1147							if (evt.keyCode == 37) // left
1148							{
1149								selectCell(graph.getSelectionCell(), mxConstants.DIRECTION_WEST);
1150								mxEvent.consume(evt);
1151							}
1152							else if (evt.keyCode == 38) // up
1153							{
1154								selectCell(graph.getSelectionCell(), mxConstants.DIRECTION_NORTH);
1155								mxEvent.consume(evt);
1156							}
1157							else if (evt.keyCode == 39) // right
1158							{
1159								selectCell(graph.getSelectionCell(), mxConstants.DIRECTION_EAST);
1160								mxEvent.consume(evt);
1161							}
1162							else if (evt.keyCode == 40) // down
1163							{
1164								selectCell(graph.getSelectionCell(), mxConstants.DIRECTION_SOUTH);
1165								mxEvent.consume(evt);
1166							}
1167						}
1168					}
1169				}
1170			}
1171			catch (e)
1172			{
1173				ui.handleError(e);
1174			}
1175
1176			if (!mxEvent.isConsumed(evt))
1177			{
1178				editorUiOnKeyDown.apply(this, arguments);
1179			}
1180		};
1181
1182		var graphConnectVertex = graph.connectVertex;
1183
1184		graph.connectVertex = function(source, direction, length, evt, forceClone, ignoreCellAt, targetCell)
1185		{
1186			var edges = graph.getIncomingTreeEdges(source);
1187
1188			if (isTreeVertex(source))
1189			{
1190				var dir = getTreeDirection(source);
1191				var h1 = dir == mxConstants.DIRECTION_EAST || dir == mxConstants.DIRECTION_WEST;
1192				var h2 = direction == mxConstants.DIRECTION_EAST || direction == mxConstants.DIRECTION_WEST;
1193
1194				if (dir == direction || edges.length == 0)
1195				{
1196					return addChild(source, direction);
1197				}
1198				else if (h1 == h2)
1199				{
1200					return addParent(source);
1201				}
1202				else
1203				{
1204					return addSibling(source, direction != mxConstants.DIRECTION_NORTH &&
1205						direction != mxConstants.DIRECTION_WEST);
1206				}
1207			}
1208			else
1209			{
1210				return graphConnectVertex.apply(this, arguments);
1211			}
1212		};
1213
1214		graph.getSubtree = function(initialCell)
1215		{
1216			var cells = [initialCell];
1217
1218			if ((isTreeMoving(initialCell) || isTreeVertex(initialCell)) &&
1219				!hasLayoutParent(initialCell))
1220			{
1221				// Gets the subtree from cell downwards
1222				graph.traverse(initialCell, true, function(vertex, edge)
1223				{
1224					var treeEdge = edge != null && graph.isTreeEdge(edge);
1225
1226					// LATER: Use dictionary to avoid duplicates
1227					if (treeEdge && mxUtils.indexOf(cells, edge) < 0)
1228					{
1229						cells.push(edge);
1230					}
1231
1232					if ((edge == null || treeEdge) &&
1233						mxUtils.indexOf(cells, vertex) < 0)
1234					{
1235						cells.push(vertex);
1236					}
1237
1238					return edge == null || treeEdge;
1239				});
1240			}
1241
1242			return cells;
1243		};
1244
1245		var vertexHandlerInit = mxVertexHandler.prototype.init;
1246
1247		mxVertexHandler.prototype.init = function()
1248		{
1249			vertexHandlerInit.apply(this, arguments);
1250
1251			if (((isTreeMoving(this.state.cell) || isTreeVertex(this.state.cell)) &&
1252				!hasLayoutParent(this.state.cell)) && this.graph.getOutgoingTreeEdges(
1253				this.state.cell).length > 0)
1254			{
1255				this.moveHandle = mxUtils.createImage(Editor.moveImage);
1256				this.moveHandle.setAttribute('title', 'Move Subtree');
1257				this.moveHandle.style.position = 'absolute';
1258				this.moveHandle.style.cursor = 'pointer';
1259				this.moveHandle.style.width = '24px';
1260				this.moveHandle.style.height = '24px';
1261				this.graph.container.appendChild(this.moveHandle);
1262
1263				mxEvent.addGestureListeners(this.moveHandle, mxUtils.bind(this, function(evt)
1264				{
1265					this.graph.graphHandler.start(this.state.cell,
1266						mxEvent.getClientX(evt), mxEvent.getClientY(evt),
1267						this.graph.getSubtree(this.state.cell));
1268					this.graph.graphHandler.cellWasClicked = true;
1269					this.graph.isMouseTrigger = mxEvent.isMouseEvent(evt);
1270					this.graph.isMouseDown = true;
1271					ui.hoverIcons.reset();
1272					mxEvent.consume(evt);
1273				}));
1274			}
1275		};
1276
1277		var vertexHandlerRedrawHandles = mxVertexHandler.prototype.redrawHandles;
1278
1279		mxVertexHandler.prototype.redrawHandles = function()
1280		{
1281			vertexHandlerRedrawHandles.apply(this, arguments);
1282
1283			if (this.moveHandle != null)
1284			{
1285				this.moveHandle.style.left = this.state.x + this.state.width +
1286					((this.state.width < 40) ? 10 : 0) + 2 + 'px';
1287				this.moveHandle.style.top = this.state.y + this.state.height +
1288					((this.state.height < 40) ? 10 : 0) + 2 + 'px';
1289			}
1290		};
1291
1292		var vertexHandlerSetHandlesVisible = mxVertexHandler.prototype.setHandlesVisible;
1293
1294		mxVertexHandler.prototype.setHandlesVisible = function(visible)
1295		{
1296			vertexHandlerSetHandlesVisible.apply(this, arguments);
1297
1298			if (this.moveHandle != null)
1299			{
1300				this.moveHandle.style.display = (visible) ? '' : 'none';
1301			}
1302		};
1303
1304		var vertexHandlerDestroy = mxVertexHandler.prototype.destroy;
1305
1306		mxVertexHandler.prototype.destroy = function(sender, me)
1307		{
1308			vertexHandlerDestroy.apply(this, arguments);
1309
1310			if (this.moveHandle != null)
1311			{
1312				this.moveHandle.parentNode.removeChild(this.moveHandle);
1313				this.moveHandle = null;
1314			}
1315		};
1316	};
1317
1318	/**
1319	 * Adds shapes to sidebar in edit mode.
1320	 */
1321	if (typeof Sidebar !== 'undefined')
1322	{
1323		var sidebarCreateAdvancedShapes = Sidebar.prototype.createAdvancedShapes;
1324		Sidebar.prototype.createAdvancedShapes = function()
1325		{
1326			var result = sidebarCreateAdvancedShapes.apply(this, arguments);
1327			var graph = this.graph;
1328
1329			// Style that defines the key, value pairs to be used for creating styles of new connections if no incoming edge exists
1330			var mmEdgeStyle = 'newEdgeStyle={"edgeStyle":"entityRelationEdgeStyle","startArrow":"none","endArrow":"none","segment":10,"curved":1};';
1331			var treeEdgeStyle = 'newEdgeStyle={"edgeStyle":"elbowEdgeStyle","startArrow":"none","endArrow":"none"};';
1332
1333			return result.concat([
1334				this.addEntry('tree container', function()
1335				{
1336					var cell = new mxCell('Tree Container', new mxGeometry(0, 0, 400, 320),
1337						'swimlane;startSize=20;horizontal=1;containerType=tree;');
1338					cell.vertex = true;
1339
1340			    	var cell2 = new mxCell('Parent', new mxGeometry(140, 60, 120, 40),
1341			    		'whiteSpace=wrap;html=1;treeFolding=1;treeMoving=1;' + treeEdgeStyle);
1342			    	cell2.vertex = true;
1343
1344			    	var cell3 = new mxCell('Child', new mxGeometry(140, 140, 120, 40),
1345			    		'whiteSpace=wrap;html=1;treeFolding=1;treeMoving=1;' + treeEdgeStyle);
1346			    	cell3.vertex = true;
1347
1348			    	var edge = new mxCell('', new mxGeometry(0, 0, 0, 0),
1349			    		'edgeStyle=elbowEdgeStyle;elbow=vertical;' +
1350						'startArrow=none;endArrow=none;rounded=0;');
1351					edge.geometry.relative = true;
1352					edge.edge = true;
1353
1354					cell2.insertEdge(edge, true);
1355					cell3.insertEdge(edge, false);
1356
1357			    	cell.insert(edge);
1358			    	cell.insert(cell2);
1359			    	cell.insert(cell3);
1360
1361			    	return sb.createVertexTemplateFromCells([cell], cell.geometry.width,
1362				    	cell.geometry.height, cell.value);
1363				}),
1364				this.addEntry('tree mindmap mindmaps central idea branch topic', function()
1365				{
1366					var mindmap = new mxCell('Mindmap', new mxGeometry(0, 0, 420, 126),
1367						'swimlane;startSize=20;horizontal=1;containerType=tree;');
1368					mindmap.vertex = true;
1369
1370					var cell = new mxCell('Central Idea', new mxGeometry(160, 60, 100, 40),
1371				    	'ellipse;whiteSpace=wrap;html=1;align=center;' +
1372				    	'treeFolding=1;treeMoving=1;' + mmEdgeStyle);
1373			    	cell.vertex = true;
1374
1375			    	var cell2 = new mxCell('Topic', new mxGeometry(320, 40, 80, 20),
1376				    	'whiteSpace=wrap;html=1;rounded=1;arcSize=50;align=center;verticalAlign=middle;' +
1377		    			'strokeWidth=1;autosize=1;spacing=4;treeFolding=1;treeMoving=1;' + mmEdgeStyle);
1378			    	cell2.vertex = true;
1379
1380			    	var edge = new mxCell('', new mxGeometry(0, 0, 0, 0), 'edgeStyle=entityRelationEdgeStyle;' +
1381						'startArrow=none;endArrow=none;segment=10;curved=1;');
1382					edge.geometry.relative = true;
1383					edge.edge = true;
1384
1385					cell.insertEdge(edge, true);
1386					cell2.insertEdge(edge, false);
1387
1388			    	var cell3 = new mxCell('Branch', new mxGeometry(320, 80, 72, 26),
1389			    		'whiteSpace=wrap;html=1;shape=partialRectangle;top=0;left=0;bottom=1;right=0;points=[[0,1],[1,1]];' +
1390			    		'fillColor=none;align=center;verticalAlign=bottom;routingCenterY=0.5;' +
1391			    		'snapToPoint=1;autosize=1;treeFolding=1;treeMoving=1;' + mmEdgeStyle);
1392			    	cell3.vertex = true;
1393
1394			    	var edge2 = new mxCell('', new mxGeometry(0, 0, 0, 0), 'edgeStyle=entityRelationEdgeStyle;' +
1395						'startArrow=none;endArrow=none;segment=10;curved=1;');
1396					edge2.geometry.relative = true;
1397					edge2.edge = true;
1398
1399					cell.insertEdge(edge2, true);
1400					cell3.insertEdge(edge2, false);
1401
1402			    	var cell4 = new mxCell('Topic', new mxGeometry(20, 40, 80, 20),
1403				    	'whiteSpace=wrap;html=1;rounded=1;arcSize=50;align=center;verticalAlign=middle;' +
1404		    			'strokeWidth=1;autosize=1;spacing=4;treeFolding=1;treeMoving=1;' + mmEdgeStyle);
1405			    	cell4.vertex = true;
1406
1407			    	var edge3 = new mxCell('', new mxGeometry(0, 0, 0, 0), 'edgeStyle=entityRelationEdgeStyle;' +
1408						'startArrow=none;endArrow=none;segment=10;curved=1;');
1409					edge3.geometry.relative = true;
1410					edge3.edge = true;
1411
1412					cell.insertEdge(edge3, true);
1413					cell4.insertEdge(edge3, false);
1414
1415			    	var cell5 = new mxCell('Branch', new mxGeometry(20, 80, 72, 26),
1416			    		'whiteSpace=wrap;html=1;shape=partialRectangle;top=0;left=0;bottom=1;right=0;points=[[0,1],[1,1]];' +
1417			    		'fillColor=none;align=center;verticalAlign=bottom;routingCenterY=0.5;' +
1418			    		'snapToPoint=1;autosize=1;treeFolding=1;treeMoving=1;' + mmEdgeStyle);
1419			    	cell5.vertex = true;
1420
1421			    	var edge4 = new mxCell('', new mxGeometry(0, 0, 0, 0), 'edgeStyle=entityRelationEdgeStyle;' +
1422						'startArrow=none;endArrow=none;segment=10;curved=1;');
1423					edge4.geometry.relative = true;
1424					edge4.edge = true;
1425
1426					cell.insertEdge(edge4, true);
1427					cell5.insertEdge(edge4, false);
1428
1429					mindmap.insert(edge);
1430					mindmap.insert(edge2);
1431					mindmap.insert(edge3);
1432					mindmap.insert(edge4);
1433					mindmap.insert(cell);
1434					mindmap.insert(cell2);
1435					mindmap.insert(cell3);
1436					mindmap.insert(cell4);
1437					mindmap.insert(cell5);
1438
1439					return sb.createVertexTemplateFromCells([mindmap], mindmap.geometry.width,
1440						mindmap.geometry.height, mindmap.value);
1441				}),
1442				this.addEntry('tree mindmap mindmaps central idea', function()
1443				{
1444					var cell = new mxCell('Central Idea', new mxGeometry(0, 0, 100, 40),
1445				    	'ellipse;whiteSpace=wrap;html=1;align=center;' + mmEdgeStyle +
1446				    	'treeFolding=1;treeMoving=1;');
1447			    	cell.vertex = true;
1448
1449			    	return sb.createVertexTemplateFromCells([cell], cell.geometry.width,
1450			    		cell.geometry.height, cell.value);
1451				}),
1452				this.addEntry('tree mindmap mindmaps branch', function()
1453				{
1454			    	var cell = new mxCell('Branch', new mxGeometry(0, 0, 80, 20),
1455			    		'whiteSpace=wrap;html=1;shape=partialRectangle;top=0;left=0;bottom=1;right=0;points=[[0,1],[1,1]];' +
1456			    		'fillColor=none;align=center;verticalAlign=bottom;routingCenterY=0.5;' +
1457			    		'snapToPoint=1;recursiveResize=0;autosize=1;treeFolding=1;treeMoving=1;' + mmEdgeStyle);
1458			    	cell.vertex = true;
1459
1460			    	var edge = new mxCell('', new mxGeometry(0, 0, 0, 0), 'edgeStyle=entityRelationEdgeStyle;' +
1461						'startArrow=none;endArrow=none;segment=10;curved=1;');
1462					edge.geometry.setTerminalPoint(new mxPoint(-40, 40), true);
1463					edge.geometry.relative = true;
1464					edge.edge = true;
1465
1466					cell.insertEdge(edge, false);
1467
1468					return sb.createVertexTemplateFromCells([cell, edge], cell.geometry.width,
1469						cell.geometry.height, cell.value);
1470				}),
1471				this.addEntry('tree mindmap mindmaps sub topic', function()
1472				{
1473			   		var cell = new mxCell('Sub Topic', new mxGeometry(0, 0, 72, 26),
1474			    		'whiteSpace=wrap;html=1;rounded=1;arcSize=50;align=center;verticalAlign=middle;' +
1475			    		'strokeWidth=1;autosize=1;spacing=4;treeFolding=1;treeMoving=1;' + mmEdgeStyle);
1476			    	cell.vertex = true;
1477
1478			    	var edge = new mxCell('', new mxGeometry(0, 0, 0, 0), 'edgeStyle=entityRelationEdgeStyle;' +
1479			    		'startArrow=none;endArrow=none;segment=10;curved=1;');
1480					edge.geometry.setTerminalPoint(new mxPoint(-40, 40), true);
1481					edge.geometry.relative = true;
1482					edge.edge = true;
1483
1484					cell.insertEdge(edge, false);
1485
1486					return sb.createVertexTemplateFromCells([cell, edge], cell.geometry.width,
1487						cell.geometry.height, cell.value);
1488				}),
1489				this.addEntry('tree orgchart organization division', function()
1490				{
1491					var orgchart = new mxCell('Orgchart', new mxGeometry(0, 0, 280, 220),
1492						'swimlane;startSize=20;horizontal=1;containerType=tree;' + treeEdgeStyle);
1493					orgchart.vertex = true;
1494
1495			    	var cell = new mxCell('Organization', new mxGeometry(80, 40, 120, 60),
1496			    		'whiteSpace=wrap;html=1;align=center;treeFolding=1;treeMoving=1;' + treeEdgeStyle);
1497				    graph.setAttributeForCell(cell, 'treeRoot', '1');
1498			    	cell.vertex = true;
1499
1500			    	var cell2 = new mxCell('Division', new mxGeometry(20, 140, 100, 60),
1501			    		'whiteSpace=wrap;html=1;align=center;verticalAlign=middle;treeFolding=1;treeMoving=1;' + treeEdgeStyle);
1502			    	cell2.vertex = true;
1503
1504			    	var edge = new mxCell('', new mxGeometry(0, 0, 0, 0),
1505			    		'edgeStyle=elbowEdgeStyle;elbow=vertical;' +
1506						'startArrow=none;endArrow=none;rounded=0;');
1507					edge.geometry.relative = true;
1508					edge.edge = true;
1509
1510					cell.insertEdge(edge, true);
1511					cell2.insertEdge(edge, false);
1512
1513			    	var cell3 = new mxCell('Division', new mxGeometry(160, 140, 100, 60),
1514			    		'whiteSpace=wrap;html=1;align=center;verticalAlign=middle;treeFolding=1;treeMoving=1;' + treeEdgeStyle);
1515			    	cell3.vertex = true;
1516
1517			    	var edge2 = new mxCell('', new mxGeometry(0, 0, 0, 0),
1518			    		'edgeStyle=elbowEdgeStyle;elbow=vertical;' +
1519						'startArrow=none;endArrow=none;rounded=0;');
1520					edge2.geometry.relative = true;
1521					edge2.edge = true;
1522
1523					cell.insertEdge(edge2, true);
1524					cell3.insertEdge(edge2, false);
1525
1526					orgchart.insert(edge);
1527					orgchart.insert(edge2);
1528					orgchart.insert(cell);
1529					orgchart.insert(cell2);
1530					orgchart.insert(cell3);
1531
1532					return sb.createVertexTemplateFromCells([orgchart], orgchart.geometry.width,
1533							orgchart.geometry.height, orgchart.value);
1534				}),
1535				this.addEntry('tree root', function()
1536				{
1537			    	var cell = new mxCell('Organization', new mxGeometry(0, 0, 120, 60),
1538			    		'whiteSpace=wrap;html=1;align=center;treeFolding=1;treeMoving=1;' + treeEdgeStyle);
1539				    graph.setAttributeForCell(cell, 'treeRoot', '1');
1540			    	cell.vertex = true;
1541
1542			    	return sb.createVertexTemplateFromCells([cell], cell.geometry.width,
1543				    		cell.geometry.height, cell.value);
1544				}),
1545				this.addEntry('tree division', function()
1546				{
1547		    		var cell = new mxCell('Division', new mxGeometry(20, 40, 100, 60),
1548			    		'whiteSpace=wrap;html=1;align=center;verticalAlign=middle;treeFolding=1;treeMoving=1;' + treeEdgeStyle);
1549			    	cell.vertex = true;
1550
1551			    	var edge = new mxCell('', new mxGeometry(0, 0, 0, 0),
1552			    		'edgeStyle=elbowEdgeStyle;elbow=vertical;' +
1553						'startArrow=none;endArrow=none;rounded=0;');
1554			    	edge.geometry.setTerminalPoint(new mxPoint(0, 0), true);
1555					edge.geometry.relative = true;
1556					edge.edge = true;
1557
1558					cell.insertEdge(edge, false);
1559
1560					return sb.createVertexTemplateFromCells([cell, edge], cell.geometry.width,
1561						cell.geometry.height, cell.value);
1562				}),
1563				this.addEntry('tree sub sections', function()
1564				{
1565			    	var cell = new mxCell('Sub Section', new mxGeometry(0, 0, 100, 60),
1566			    		'whiteSpace=wrap;html=1;align=center;verticalAlign=middle;treeFolding=1;treeMoving=1;');
1567			    	cell.vertex = true;
1568
1569			    	var edge = new mxCell('', new mxGeometry(0, 0, 0, 0), 'edgeStyle=orthogonalEdgeStyle;' +
1570						'startArrow=none;endArrow=none;rounded=0;targetPortConstraint=eastwest;sourcePortConstraint=northsouth;');
1571					edge.geometry.setTerminalPoint(new mxPoint(110, -40), true);
1572					edge.geometry.relative = true;
1573					edge.edge = true;
1574
1575					cell.insertEdge(edge, false);
1576
1577			    	var cell2 = new mxCell('Sub Section', new mxGeometry(120, 0, 100, 60),
1578			    		'whiteSpace=wrap;html=1;align=center;verticalAlign=middle;treeFolding=1;treeMoving=1;');
1579			    	cell2.vertex = true;
1580
1581			    	var edge2 = new mxCell('', new mxGeometry(0, 0, 0, 0), 'edgeStyle=orthogonalEdgeStyle;' +
1582						'startArrow=none;endArrow=none;rounded=0;targetPortConstraint=eastwest;sourcePortConstraint=northsouth;');
1583					edge2.geometry.setTerminalPoint(new mxPoint(110, -40), true);
1584					edge2.geometry.relative = true;
1585					edge2.edge = true;
1586
1587					cell2.insertEdge(edge2, false);
1588
1589				    	return sb.createVertexTemplateFromCells([edge, edge2, cell, cell2], 220, 60, 'Sub Sections');
1590				})
1591			]);
1592		};
1593	}
1594})();
1595