1
28 package demo.view.mindmap;
29
30 import y.base.Command;
31 import y.base.Edge;
32 import y.base.EdgeList;
33 import y.base.Node;
34 import y.base.NodeCursor;
35 import y.base.NodeList;
36 import y.view.BendList;
37 import y.view.CreateEdgeMode;
38 import y.view.EdgeRealizer;
39 import y.view.EditMode;
40 import y.view.GenericEdgeRealizer;
41 import y.view.Graph2D;
42 import y.view.Graph2DUndoManager;
43 import y.view.HitInfo;
44 import y.view.MoveSelectionMode;
45 import y.view.NodeRealizer;
46 import y.view.ViewMode;
47
48 import java.awt.event.MouseEvent;
49
50
53 class MoveNodeMode extends EditMode {
54 private final Graph2DUndoManager undoManager;
55
56 MoveNodeMode( final Graph2DUndoManager undoManager ) {
57 this.undoManager = undoManager;
58 }
59
60 public void mouseClicked( final MouseEvent e ) {
61 super.mouseClicked(e);
62 }
63
64
74 protected void paperDragged(
75 final Graph2D graph,
76 final double x,
77 final double y,
78 final boolean firstDrag
79 ) {
80
81 }
82
83
86 protected ViewMode createCreateEdgeMode() {
87 return new MyCreateEdgeMode();
88 }
89
90
94 public void startCrossEdgeCreation(Node startNode) {
95 final NodeRealizer realizer = getGraph2D().getRealizer(startNode);
96 setChild(createEdgeMode,null,null);
98 createEdgeMode.mousePressedLeft(realizer.getCenterX(), realizer.getCenterY());
100 }
101
102
107 protected ViewMode createMoveSelectionMode() {
108 return new MindMapSelectionMode();
109 }
110
111
117 public void mouseShiftReleasedLeft(final double x, final double y) {
118 final Graph2D graph2D = view.getGraph2D();
119 final NodeCursor selectedNodes = graph2D.selectedNodes();
120 if (selectedNodes.ok()) {
121 final Node startNode = selectedNodes.node();
122 final HitInfo hitInfo = getHitInfo(x, y);
123 if (hitInfo.hasHitNodes()) {
124 final Node endNode = hitInfo.getHitNode();
125 if (endNode != startNode) {
126 final Edge edge = graph2D.createEdge(startNode, endNode);
127 ViewModel.instance.setCrossReference(edge);
128 graph2D.setSelected(startNode, false);
129 }
130 }
131 } else {
132 super.mouseShiftPressedLeft(x, y);
133 }
134 }
135
136
137 private class MindMapSelectionMode extends MoveSelectionMode {
138
143 public static final int MAX_KEEP_DISTANCE = 200;
144
147 private Node node;
148
151 private boolean oldSide;
152
153 private MindMapSelectionMode() {
154 }
155
156 public void mouseShiftPressedLeft(final double x, final double y) {
157 setChild(createEdgeMode, lastPressEvent, lastDragEvent);
158 }
159
160
163 protected void selectionMoveStarted(double x, double y) {
164 if (node == null) {
165 return;
166 }
167 final Graph2D graph2D = view.getGraph2D();
168 graph2D.backupRealizers();
170 oldSide = ViewModel.instance.isLeft(node);
171 }
172
173
184 protected void selectionOnMove(double dx, double dy, double x, double y) {
185 if (node != null) {
186 final Graph2D graph = view.getGraph2D();
187 final ViewModel model = ViewModel.instance;
188 final NodeRealizer rootRealizer = graph.getRealizer(model.getRoot());
189 final boolean isRight = x > rootRealizer.getCenterX();
190 final boolean wasLeft = model.isLeft(node);
191 Edge inEdge = MindMapUtil.inEdge(node);
192 if (wasLeft == isRight) {
194 MindMapUtil.updateVisualsRecursive(graph, node, !wasLeft);
196
197 LayoutUtil.layoutSubtree(graph, node);
198
199 if (oldSide != model.isLeft(node)) {
201 undoManager.push(new SideChangeAction(!oldSide, node));
202 }
203
204 mousePressedLeft(x, y);
209 }
210
211 final Node parent = calcClosestParent(node);
213
214 if (parent == null) {
218 if (inEdge != null) {
219 graph.removeEdge(inEdge);
220 }
221 } else {
223 final Node source = (inEdge != null) ? inEdge.source() : null;
224 if (parent != source) {
225 if (graph.containsEdge(parent, node)) {
226 if (inEdge != null && graph.contains(inEdge)) {
227 graph.removeEdge(inEdge);
228 }
229 } else {
230 if (inEdge == null) {
231 inEdge = graph.createEdge(
232 parent, node, new GenericEdgeRealizer("BezierGradientEdge"));
233 } else {
234 if (!graph.contains(inEdge)) {
235 graph.reInsertEdge(inEdge);
236 }
237 graph.changeEdge(inEdge, parent, node);
238 }
239
240 final EdgeRealizer er = graph.getRealizer(inEdge);
242 er.clearBends();
243 if (model.isRoot(parent)) {
244 er.getSourcePort().setOffsets(0, 0);
245 } else {
246 final NodeRealizer src = graph.getRealizer(parent);
247 final double srcX = src.getWidth() * 0.5 * (isRight ? 1 : -1);
248 er.getSourcePort().setOffsets(srcX, src.getHeight() * 0.5);
249 }
250 final NodeRealizer tgt = graph.getRealizer(node);
251 final double tgtX = tgt.getWidth() * 0.5 * (isRight ? -1 : 1);
252 er.getTargetPort().setOffsets(tgtX, tgt.getHeight() * 0.5);
253 }
254 }
255 }
256 }
257 }
258
259
270 protected void selectionMovedAction(double dx, double dy, double x, double y) {
271 final Node node = this.node;
272 if (node != null) {
273 final Graph2D graph = view.getGraph2D();
274 final ViewModel model = ViewModel.instance;
275
276 Node parent = null;
277 if (!model.isRoot(node)) {
278 final Edge inEdge = MindMapUtil.inEdge(node);
280 parent = inEdge == null ? null : inEdge.source();
281 if (parent != null) {
282 final boolean isLeft = model.isLeft(node);
284 MindMapUtil.updateVisualsRecursive(graph, node, isLeft);
285
286 if (model.isCollapsed(parent)) {
289 MindMapUtil.expandNode(graph, parent);
290 }
291 }
292 }
293
294 if (parent == null && !model.isRoot(node)) {
296 MindMapUtil.removeSubtree(graph, node);
297 }
298
299 LayoutUtil.layout(graph);
300
301 this.node = null;
302 }
303 }
304
305
310 protected NodeList getNodesToBeMoved() {
311 NodeList nodes = new NodeList();
312 final HitInfo lastHitInfo = getLastHitInfo();
313 node = lastHitInfo.getHitNode();
314 if (ViewModel.instance.isRoot(node)) {
316 node = null;
317 }
318 if (node != null) {
319 NodeList stack = new NodeList(node);
320 while (!stack.isEmpty()) {
321 Node n = stack.popNode();
322 for (EdgeList edges = MindMapUtil.outEdges(n); !edges.isEmpty();) {
323 stack.push(edges.popEdge().target());
324 }
325 nodes.push(n);
326 }
327 } else {
328 nodes = new NodeList();
329 }
330 return nodes;
331 }
332
333
337 protected BendList getBendsToBeMoved() {
338 if (node != null) {
339 BendList bends = new BendList();
340 final NodeList nodesToBeMoved = getNodesToBeMoved();
341 while (!nodesToBeMoved.isEmpty()) {
342 for (EdgeList edges = MindMapUtil.outEdges(nodesToBeMoved.popNode());!edges.isEmpty();) {
343 bends.addAll(getGraph2D().getRealizer(edges.popEdge()).bends());
344 }
345 }
346 return bends;
347 } else {
348 return super.getBendsToBeMoved();
349 }
350 }
351
352
357 private Node calcClosestParent(Node node) {
358 final NodeList possibleParents = calcPossibleParents(node);
359 Node bestParent = possibleParents.popNode();
360 final Graph2D graph2D = view.getGraph2D();
361 final NodeRealizer nodeRealizer = graph2D.getRealizer(node);
362 double dist = calcDist(nodeRealizer, graph2D.getRealizer(bestParent));
363 while (!possibleParents.isEmpty()) {
364 final Node otherParent = (Node) possibleParents.pop();
365 final double otherDist = calcDist(nodeRealizer, graph2D.getRealizer(otherParent));
366 if (otherDist < dist) {
367 bestParent = otherParent;
368 dist = otherDist;
369 }
370 }
371 final NodeRealizer bestParentRealizer = graph2D.getRealizer(bestParent);
372 dist -= ((bestParentRealizer.getWidth() + nodeRealizer.getWidth()) * 0.5);
374 if (dist < MAX_KEEP_DISTANCE) {
375 return bestParent;
376 } else {
377 return null;
378 }
379 }
380
381
387 private double calcDist(final NodeRealizer firstRealizer, final NodeRealizer secondRealizer) {
388 final double dx = firstRealizer.getCenterX() - secondRealizer.getCenterX();
389 final double dy = firstRealizer.getCenterY() - secondRealizer.getCenterY();
390 return Math.sqrt(dx * dx + dy * dy);
391 }
392
393
400 private NodeList calcPossibleParents(Node node) {
401 final Graph2D graph2D = getGraph2D();
402 final ViewModel model = ViewModel.instance;
403 final NodeRealizer nodeRealizer = graph2D.getRealizer(node);
404 final boolean nodeIsLeft = model.isLeft(node);
405
406 final NodeList possibleParents = new NodeList();
407 final NodeList stack = new NodeList();
408 final Node root = model.getRoot();
409 stack.add(root);
410 possibleParents.add(root);
412 while (!stack.isEmpty()) {
413 Node n = stack.popNode();
414 for (EdgeList edges = MindMapUtil.outEdges(n); !edges.isEmpty(); ) {
415 n = edges.popEdge().target();
416 final NodeRealizer nr = graph2D.getRealizer(n);
417 if (nodeIsLeft) {
418 if (model.isLeft(n) &&
420 nodeRealizer.getX() + nodeRealizer.getWidth() < nr.getX()) {
421 possibleParents.add(n);
422 stack.add(n);
423 }
424 } else if (!model.isLeft(n) && ((nr.getX() + nr.getWidth()) < nodeRealizer.getX())) {
426 possibleParents.add(n);
427 stack.add(n);
428 }
429 }
430 }
431 return possibleParents;
432 }
433 }
434
435
438 private class SideChangeAction implements Command {
439 private final boolean newSide;
440 private final Node node;
441
442 private SideChangeAction(final boolean newSide, final Node node) {
443 this.newSide = newSide;
444 this.node = node;
445 }
446
447 public void execute() {}
448
449 public void undo() {
450 MindMapUtil.updateVisualsRecursive(view.getGraph2D(), node, !newSide);
451 }
452
453 public void redo() {
454 MindMapUtil.updateVisualsRecursive(view.getGraph2D(), node, newSide);
455 }
456 }
457
458
461 private static final class MyCreateEdgeMode extends CreateEdgeMode {
462
466 protected void edgeCreated( final Edge edge ) {
467 ViewModel.instance.setCrossReference(edge);
468 }
469 }
470 }
471