source: trunk/org/expeditee/gui/FrameMouseActions.java@ 4

Last change on this file since 4 was 4, checked in by davidb, 16 years ago

Starting source code to Expeditee

File size: 51.1 KB
Line 
1package org.expeditee.gui;
2
3import java.awt.event.ActionEvent;
4import java.awt.event.ActionListener;
5import java.awt.event.MouseEvent;
6import java.awt.event.MouseListener;
7import java.awt.event.MouseMotionListener;
8import java.awt.event.MouseWheelEvent;
9import java.awt.event.MouseWheelListener;
10import java.util.ArrayList;
11import java.util.Date;
12import java.util.LinkedList;
13import java.util.List;
14
15import javax.swing.Timer;
16
17import org.expeditee.actions.Actions;
18import org.expeditee.actions.NavigationActions;
19import org.expeditee.items.Constraint;
20import org.expeditee.items.Dot;
21import org.expeditee.items.Item;
22import org.expeditee.items.ItemPermission;
23import org.expeditee.items.ItemUtils;
24import org.expeditee.items.Line;
25import org.expeditee.items.Picture;
26import org.expeditee.items.Text;
27import org.expeditee.stats.SessionStats;
28
29public class FrameMouseActions implements MouseListener, MouseMotionListener,
30 MouseWheelListener {
31
32 // TODO say where/how used
33 private static final int MOUSE_WHEEL_THRESHOLD = 3;
34
35 private static final int MINIMUM_RANGE_DEPRESS_TIME = 250;
36
37 private static final int RECTANGLE_TO_POINT_THRESHOLD = 20;
38
39 private static Date _lastMouseClickDate = new Date();
40
41 public static final int LITTLE_MOUSE_PAUSE = 500;
42
43 public static final int ZERO_MOUSE_PAUSE = 0;
44
45 public static final int BIG_MOUSE_PAUSE = 750;
46
47 public static final int CONTEXT_FREESPACE = 0;
48
49 public static final int CONTEXT_AT_TEXT = 1;
50
51 public static final int CONTEXT_AT_LINE = 2;
52
53 public static final int CONTEXT_AT_DOT = 3;
54
55 public static final int CONTEXT_AT_ENCLOSURE = 4;
56
57 public static int _alpha = -1;
58
59 /**
60 * The last known mouse X coordinate
61 */
62 public static int MouseX;
63
64 /**
65 * The last known mouse Y coordinate. Relative to the top of the
66 * application.
67 */
68 public static int MouseY;
69
70 // Offset coordinates from the mouse position when grabbing items
71 private static int _offX;
72
73 private static int _offY;
74
75 // Keeps track of mouse button events when a delete occurs
76 private static boolean _isDelete = false;
77
78 // Keeps track of mouse button events when the user extracts attributes
79 // occurs
80 private static boolean _isAttribute = false;
81
82 /**
83 * A flag to indicate that the last mouseUp event was part of a two button
84 * click sequence hence the next mouse up should be ignored*
85 */
86 private static boolean _wasDouble = false;
87
88 private static boolean _isNoOp = false;
89
90 // keeps track of the last highlighted Item
91 private static Item _lastHighlightedItem = null;
92
93 // keeps track of the item being 'ranged out' if there is one.
94 private static Text _lastRanged = null;
95
96 // keeps track of the picture being cropped if there is one
97 private static Picture _lastCropped = null;
98
99 // true if lastItem only has highlighting removed when a new item is
100 // highlighted
101 private static boolean _lastHoldsHighlight = false;
102
103 private static Item _tdfcItem = null;
104
105 private static boolean _forceArrowCursor = true;
106
107 // the current context of the cursor
108 private static int _context = 0;
109
110 public static void setForceArrow(boolean val) {
111 _forceArrowCursor = val;
112 }
113
114 public static int getContext() {
115 return _context;
116 }
117
118 private static MouseEvent _lastMouseClick = null;
119
120 private static ItemPermission _lastClickedOn = null;
121
122 private static List<ItemPermission> _lastClickedIn = null;
123
124 private static boolean _pulseOn = false;
125
126 private static int _pulseAmount = 2;
127
128 private static Timer _MouseTimer = new Timer(LITTLE_MOUSE_PAUSE,
129 new ActionListener() {
130 public void actionPerformed(ActionEvent ae) {
131 // check if we are in free space
132 if (_lastClickedOn == null && Frame.FreeItems.size() == 0) {
133 System.out.println("SuperBack!");
134 leftButton(null);
135 _MouseTimer.setDelay(ZERO_MOUSE_PAUSE);
136 } else {
137 _pulseOn = !_pulseOn;
138
139 if (_MouseTimer.getDelay() == LITTLE_MOUSE_PAUSE)
140 _MouseTimer.setDelay(LITTLE_MOUSE_PAUSE + 1);
141 else
142 _MouseTimer.setDelay(BIG_MOUSE_PAUSE);
143 if (FrameUtils.getCurrentItem() == null) {
144 for (Item i : Frame.FreeItems) {
145 if (i instanceof Line) {
146 Line line = (Line) i;
147 if (_pulseAmount < 4
148 && line.getThickness() < 0)
149 _pulseAmount = 4;
150
151 if (_pulseOn)
152 line.setThickness(line.getThickness()
153 + _pulseAmount);
154 else
155 line.setThickness(line.getThickness()
156 - _pulseAmount);
157
158 line.toggleArrow();
159 }
160 }
161 FrameGraphics.Repaint();
162 }
163 _MouseTimer.stop();
164 }
165 }
166 });
167
168 public void mouseClicked(MouseEvent e) {
169 }
170
171 /**
172 * Each Item on the Frame is checked to determine if the mouse x,y
173 * coordinates are on the Item (or within the Shape surrounding it). If the
174 * coordinates are on the Item then the Item is checked for a link, if it
175 * has a link the link is followed, if not, nothing is done.
176 */
177 public void mousePressed(MouseEvent e) {
178 _lastMouseClickDate = new Date();
179 _lastClickedOn = FrameUtils.getCurrentItem();
180 // load any frame if necessary
181 ItemPermission on = _lastClickedOn;
182
183 _lastClickedIn = FrameUtils.getCurrentItems();
184
185 SessionStats.MouseClicked(e.getButton());
186 if (e.getButton() == MouseEvent.BUTTON1) {
187 SessionStats.AddFrameEvent("Ld");
188 } else if (e.getButton() == MouseEvent.BUTTON2) {
189 SessionStats.AddFrameEvent("Md");
190 } else if (e.getButton() == MouseEvent.BUTTON3) {
191 SessionStats.AddFrameEvent("Rd");
192 }
193
194 _lastMouseClick = e;
195 _MouseTimer.start();
196
197 // pre-cache the frame if it is linked
198 if (on != null && on.Item.getLink() != null && on.Item.isLinkValid()) {
199 FrameIO.Precache(on.Item.getLink());
200 }
201
202 // check for delete command
203 if (isDelete(e)) {
204 _isDelete = true;
205 // _lastRanged = null;
206 _lastCropped = null;
207 _wasDouble = false;
208 // check for attributes command
209 } else if (isGetAttributes(e)) {
210 _isAttribute = true;
211 _wasDouble = false;
212 } else if (isTwoClickNoOp(e)) {
213 _isAttribute = false;
214 _wasDouble = false;
215 _isDelete = false;
216 _isNoOp = true;
217 } else
218 _isDelete = false;
219
220 {
221 // This must happen before the previous code
222 if (_context == CONTEXT_FREESPACE && Frame.itemAttachedToCursor()) {
223 _lastHighlightedItem = Frame.getItemAttachedToCursor();
224 }
225 // show depressed highlighting
226 if (_lastHighlightedItem != null) {
227 _lastHighlightedItem.showDepressedHighlight(true);
228 FrameGraphics.Repaint();
229 }
230 }
231
232 // if the user is ranging text
233 if (on != null && on.Item instanceof Text && !_isDelete) {
234 _lastRanged = (Text) on.Item;
235 // set start-drag point
236 _lastRanged.setSelectionStart(DisplayIO.getMouseX(), DisplayIO
237 .getMouseY());
238 }
239
240 if (on != null && on.Item instanceof Picture
241 && e.getButton() == MouseEvent.BUTTON3 && !_isDelete) {
242 _lastCropped = (Picture) on.Item;
243 // set start crop point
244 _lastCropped.setStartCrop(DisplayIO.getMouseX(), DisplayIO
245 .getMouseY());
246 _lastCropped.setShowCrop(true);
247 }
248 }
249
250 // This is where all the processing happens
251 public void mouseReleased(MouseEvent e) {
252 updateCursor();
253
254 Text lastRanged = _lastRanged;
255 _lastRanged = null;
256 // Dont do ranging if the user moves really quickly...
257 // They are probably trying to pick something up in this case
258 if (lastRanged != null) {
259 long depressTime = (new Date()).getTime()
260 - _lastMouseClickDate.getTime();
261 // double changeInDistance =
262 // e.getPoint().distance(_currentMouseClick.getPoint());
263 // double speed = changeInDistance * 1000 / changeInTime;
264
265 // System.out.println(depressTime);
266
267 if (depressTime < MINIMUM_RANGE_DEPRESS_TIME
268 || lastRanged.getSelectedSize() <= 0) {// Text.MINIMUM_RANGED_CHARS)
269 // {
270 lastRanged.clearSelection();
271 lastRanged = null;
272 }
273 }
274
275 FrameUtils.ResponseTimer.restart();
276
277 _MouseTimer.stop();
278 _MouseTimer.setDelay(LITTLE_MOUSE_PAUSE);
279
280 if (_pulseOn) {
281 for (Item i : Frame.FreeItems) {
282 if (i instanceof Line) {
283 Line line = (Line) i;
284 line.setThickness(line.getThickness() - _pulseAmount);
285 }
286 }
287 _pulseOn = false;
288 }
289
290 // if the user was performing actions, stop now
291 if (_pulseAmount < 0) {
292 _pulseAmount = 2;
293 return;
294 }
295
296 // reset pulse value
297 _pulseAmount = 2;
298
299 if (Actions.isAgentRunning()) {
300 Actions.stopAgent();
301 return;
302 }
303
304 // if the last action was a delete, then ignore the next mouseup
305 if (_wasDouble) {
306 _wasDouble = false;
307 return;
308 }
309
310 /*
311 * if (_isNoOp) { if (e.getButton() != MouseEvent.NOBUTTON) { _isNoOp =
312 * false; _wasDouble = true; // lastRanged.clearSelection();
313 * FrameGraphics.Repaint(); return; } }
314 */
315
316 // get whatever the user was pointing at
317 ItemPermission clickedOn = _lastClickedOn;
318 List<ItemPermission> clickedIn = _lastClickedIn;
319
320 MouseX = e.getX();
321 MouseY = e.getY();
322
323 List<ItemPermission> releasedIn = FrameUtils.getCurrentItems();
324 ItemPermission releasedOn = FrameUtils.getCurrentItem();
325
326 if (_isNoOp
327 && ((releasedOn != null && clickedOn != null && releasedOn.Item != clickedOn.Item) || (releasedOn == null && releasedIn == null))) {
328 if (_isDelete) {
329 _isDelete = false;
330 _wasDouble = true;
331 }
332
333 _isNoOp = false;
334
335 if (_lastHighlightedItem != null)
336 FrameGraphics.Highlight(_lastHighlightedItem, false, false);
337 // TODO Michael thinks this code should never be reached and can be
338 // removed
339 if (Frame.itemAttachedToCursor()) {
340 move(Frame.FreeItems);
341 }
342
343 FrameGraphics
344 .DisplayMessage("Action cancelled, mouse moved more than "
345 + UserSettings.NoOpThreshold + " pixels.");
346 FrameGraphics.Repaint();
347 return;
348 } else
349 _isNoOp = false;
350
351 // if this is a delete command
352 if (_isDelete) {
353 if (lastRanged != null) {
354 lastRanged.cutSelectedText();
355 lastRanged.clearSelection();
356 FrameGraphics.Repaint();
357
358 } else {
359 delete(clickedOn);
360 }
361 _wasDouble = true;
362 _isDelete = false;
363 return;
364 }
365
366 // if this is an attribute extraction command
367 if (_isAttribute) {
368 extractAttributes(clickedOn);
369 _wasDouble = true;
370 _isAttribute = false;
371 return;
372 }
373
374 // if the user is ranging-out text
375 if (lastRanged != null) {
376
377 Text ranged = lastRanged.copy();
378
379 // if the user is cutting text from the item
380 if (e.getButton() == MouseEvent.BUTTON2) {
381 // if the entire text is selected then pickup the item
382 if (lastRanged.getSelectedSize() == lastRanged.getLength()) {
383 pickup(lastRanged);
384 lastRanged.clearSelection();
385 FrameGraphics.Repaint();
386 return;
387 }
388
389 ranged.setText(lastRanged.cutSelectedText());
390 // if the user is copying text from the item
391 } else if (e.getButton() == MouseEvent.BUTTON3)
392 ranged.setText(lastRanged.copySelectedText());
393
394 ranged.setLink(null);
395 ranged.setParent(null);
396 ranged.setPosition(DisplayIO.getMouseX(), DisplayIO.getMouseY());
397 pickup(ranged);
398
399 lastRanged.clearSelection();
400 FrameGraphics.Repaint();
401 return;
402 }
403
404 // if the user is cropping an imate
405 if (clickedOn != null && clickedOn.Item == _lastCropped
406 && _lastCropped.getCroppedSize() > 0) {
407 Picture cropped = _lastCropped.copy();
408
409 cropped.setParent(null);
410 pickup(cropped);
411
412 }
413
414 // if the user has cropped an imate, either the above happend or this is
415 // a no-op
416 if (_lastCropped != null && _lastCropped.getCroppedSize() > 0) {
417 _lastCropped.clearCropping();
418 _lastCropped = null;
419 FrameGraphics.Repaint();
420 return;
421 }
422
423 // if the user is left-clicking
424 if (e.getButton() == MouseEvent.BUTTON1) {
425 SessionStats.AddFrameEvent("Lu");
426 leftButton(clickedOn);
427 return;
428 }
429
430 if (e.getButton() == MouseEvent.BUTTON2) {
431 SessionStats.AddFrameEvent("Mu");
432 middleButton(clickedOn, clickedIn);
433 return;
434 }
435
436 if (e.getButton() == MouseEvent.BUTTON3) {
437 SessionStats.AddFrameEvent("Ru");
438 rightButton(clickedOn, clickedIn);
439 return;
440 }
441
442 // error, we should have returned by now
443 System.out.println("Error: mouseReleased should have returned by now. "
444 + e);
445 }
446
447 /**
448 * This method handles all left-click actions
449 */
450 public static void leftButton(ItemPermission clicked) {
451 // if the user is pointing at something then either follow the link or
452 // do TDFC
453 if (clicked != null) {
454 // check item permissions
455 if (clicked.Permission < ItemPermission.PERMISSION_FOLLOW_LINKS) {
456 FrameGraphics
457 .DisplayMessage("Insufficient Permissions for action on item");
458 return;
459 }
460
461 Item clickedOn = clicked.Item;
462 // actions take priority
463 if (_lastMouseClick != null && !_lastMouseClick.isShiftDown()
464 && clickedOn.getAction() != null) {
465 clickedOn.performActions();
466 return;
467 } else if (clickedOn.getLink() != null) {
468 // Dont save the frame if we are moving to an old version of
469 // this frame
470 // because everytime we save with the old tag... the frame is
471 // backed up
472 if (!clickedOn.isOldTag())
473 FrameIO.SaveFrame(DisplayIO.getCurrentFrame());
474
475 NavigationActions.setLastNavigationItem(clickedOn);
476 load(clickedOn.getAbsoluteLink());
477 // DisplayIO.UpdateTitle();
478 return;
479 // no link is found, perform TDFC
480 } else {
481 // check for TDFC permission
482 if (clicked.Permission < ItemPermission.PERMISSION_TDFC) {
483 FrameGraphics
484 .DisplayMessage("Insufficient permission to TDFC from that item");
485 return;
486 }
487
488 if (clickedOn.isOldTag())
489 return;
490
491 // if the user is clicking on the frame name
492 if (clickedOn.isFrameName()) {
493 Frame next = FrameIO.LoadNext();
494 FrameUtils.DisplayFrame(next, true);
495 return;
496 }
497
498 tdfc(clickedOn);
499 DisplayIO.UpdateTitle();
500 return;
501 }
502 // if the user is not pointing at something, then this is a back
503 // command
504 } else {
505 back();
506 DisplayIO.UpdateTitle();
507 return;
508 }
509 }
510
511 private static boolean doMerging(ItemPermission clicked) {
512 if (clicked == null)
513 return false;
514
515 // System.out.println(Frame.FreeItems.size());
516 if (isRubberBandingRectangle()
517 && clicked.Item.getAllConnected().contains(
518 Frame.getItemAttachedToCursor()))
519 return true;
520
521 if (Frame.FreeItems.size() > 2)
522 return false;
523
524 Item attachedToCursor = Frame.getItemAttachedToCursor();
525
526 if (clicked.Item instanceof Text && !(attachedToCursor instanceof Text)) {
527 return false;
528 }
529
530 return true;
531 }
532
533 /**
534 * This method handles all middle-click actions
535 */
536 private static void middleButton(ItemPermission clicked,
537 List<ItemPermission> clickedIn) {
538 // if the cursor has Items attached
539 if (Frame.itemAttachedToCursor()) {
540 // if the user is pointing at something, merge the items (if
541 // possible)
542 if (doMerging(clicked)) {
543 // check permissions
544 if (clicked.Permission < ItemPermission.PERMISSION_FULL
545 && clicked.Item.getParent() != null
546 && clicked.Item.getParent().getName() != clicked.Item) {
547 FrameGraphics.DisplayMessage("Insufficient Permission");
548 return;
549 }
550
551 List<Item> left = merge(Frame.FreeItems, clicked.Item);
552 anchor(left);
553
554 Frame.FreeItems.clear();
555 FrameGraphics.Repaint();
556 updateCursor();
557 return;
558 // otherwise, anchor the items
559 } else {
560 // if a line is being rubber-banded, check for auto
561 // straightening
562 anchor(Frame.FreeItems);
563 Frame.FreeItems.clear();
564 updateCursor();
565 _offX = _offY = 0;
566 return;
567 }
568 } else {
569 // otherwise if the user is pointing at something,pick it up
570 if (clicked != null) {
571 // check permissions
572 if (clicked.Permission < ItemPermission.PERMISSION_FULL) {
573 FrameGraphics
574 .DisplayMessage("Insufficient Permission to pick up item");
575 return;
576 }
577
578 pickup(clicked.Item);
579 return;
580 // otherwise create a line
581 } else {
582 if (clickedIn != null) {
583 ArrayList<Item> toPickup = new ArrayList<Item>(clickedIn
584 .size());
585 for (ItemPermission ip : clickedIn)
586 if (ip.Permission >= ItemPermission.PERMISSION_FULL)
587 toPickup.add(ip.Item);
588
589 pickup(toPickup);
590 // otherwise the user is creating a line
591 } else
592 createLine();
593 return;
594 }
595 }
596 }
597
598 private static Dot getFirstFreeDot() {
599 for (Item i : Frame.FreeItems)
600 if (i instanceof Dot)
601 return (Dot) i;
602 return null;
603 }
604
605 private static boolean isRubberBandingRectangle() {
606 if (Frame.FreeItems.size() != 3)
607 return false;
608 Dot d = null;
609 // only one dot will be present for rectangles
610 for (Item i : Frame.FreeItems)
611 if (i instanceof Dot && d == null)
612 d = (Dot) i;
613 else if (i instanceof Dot && d != null)
614 d = null;
615
616 // System.out.println(d.getAllConnected());
617
618 // if this is indeed a rectangle anchor
619 if (d != null && d.getAllConnected().size() > 5)
620 return true;
621
622 return false;
623 }
624
625 /**
626 * This method handles all right-click action
627 */
628 private static void rightButton(ItemPermission clicked,
629 List<ItemPermission> clickedIn) {
630 // if the cursor has Items attached, then anchor a copy of them
631 if (Frame.itemAttachedToCursor()) {
632 // if the user is clicking on something, merge the items
633 // unless it is a point onto somethin other than a point
634 if (clicked != null
635 && (!(Frame.getItemAttachedToCursor() instanceof Dot && !(clicked.Item instanceof Dot)))) {
636 // check permissions
637 if (clicked.Permission < ItemPermission.PERMISSION_FULL
638 && clicked.Item.getParent().getName() != clicked.Item) {
639 FrameGraphics
640 .DisplayMessage("Insufficient Permission to merge items");
641 return;
642 }
643
644 if (clicked.Item instanceof Text || clicked.Item instanceof Dot) {
645 List<Item> copies = null;
646
647 if (isRubberBandingRectangle()) {
648 List<Item> remain = merge(Frame.FreeItems, clicked.Item);
649
650 Dot d = getFirstFreeDot();
651 // anchor the points
652 anchor(remain);
653 Frame.FreeItems.clear();
654 updateCursor();
655 // pick up a copy of all enclosed items
656 List<ItemPermission> items = FrameUtils
657 .getItemsEnclosedBy(
658 DisplayIO.getCurrentFrame(), d
659 .getEnclosedShape());
660 if (items != null) {
661 ArrayList<Item> toCopy = new ArrayList<Item>(items
662 .size());
663 for (ItemPermission ip : items)
664 if (ip.Permission >= ItemPermission.PERMISSION_COPY)
665 toCopy.add(ip.Item);
666
667 copies = copy(toCopy);
668 pickup(copies);
669 }
670
671 } else if (Frame.FreeItems.size() == 2) {
672 copies = ItemUtils.UnreelLine(Frame.FreeItems);
673 List<Item> leftOver = merge(Frame.FreeItems,
674 clicked.Item);
675 anchor(leftOver);
676 if (copies == null)
677 copies = copy(Frame.FreeItems);
678 Frame.FreeItems.clear();
679 for (Item i : copies)
680 i.setOffset(0, 0);
681 // need to move to prevent cursor dislocation
682 move(copies);
683 pickup(copies);
684
685 } else if (Frame.FreeItems.size() == 1) {
686 copies = copy(Frame.FreeItems);
687 List<Item> remain = merge(copies, clicked.Item);
688
689 // ignore items that could not be merged.
690 anchor(remain);
691 } else {
692 // NoOp
693 }
694 updateCursor();
695 FrameGraphics.Repaint();
696 } else {
697 List<Item> copies = ItemUtils.UnreelLine(Frame.FreeItems);
698 if (copies == null)
699 copies = copy(Frame.FreeItems);
700 for (Item i : copies) {
701 i.setOffset(0, 0);
702 }
703 anchor(Frame.FreeItems);
704 Frame.FreeItems.clear();
705 updateCursor();
706
707 FrameGraphics.Repaint();
708
709 clearParent(copies);
710 pickup(copies);
711 }
712 return;
713
714 // otherwise, anchor the items
715 } else {
716
717 // check if this is anchoring a rectangle
718 if (isRubberBandingRectangle()) {
719 Dot d = getFirstFreeDot();
720
721 // anchor the points
722 anchor(Frame.FreeItems);
723 Frame.FreeItems.clear();
724 updateCursor();
725 // pick up a copy of all enclosed items
726 List<ItemPermission> items = FrameUtils.getItemsEnclosedBy(
727 DisplayIO.getCurrentFrame(), d.getEnclosedShape());
728 if (items != null) {
729 ArrayList<Item> toCopy = new ArrayList<Item>(items
730 .size());
731 for (ItemPermission ip : items)
732 if (ip.Permission >= ItemPermission.PERMISSION_COPY)
733 toCopy.add(ip.Item);
734 toCopy.removeAll(d.getAllConnected());
735
736 if (toCopy.size() > 0) {
737 pickup(copy(toCopy));
738 DisplayIO.getCurrentFrame().removeAllItems(d.getAllConnected());
739 } else {
740 pickup(copy(d.getAllConnected()));
741 }
742 }
743 return;
744 }
745 List<Item> copies = null;
746 if (Frame.FreeItems.size() == 2) {
747 if (clicked != null) {
748 List<Item> leftOver = merge(Frame.FreeItems,
749 clicked.Item);
750 anchor(leftOver);
751 }
752 // This is executed when the user is putting down a line
753 // endpoint and unreeling. ie. Normal unreeling
754 copies = ItemUtils.UnreelLine(Frame.FreeItems);
755
756 if (copies == null)
757 copies = copy(Frame.FreeItems);
758 anchor(Frame.FreeItems);
759 for (Item i : copies)
760 i.setOffset(0, 0);
761 // need to move to prevent cursor dislocation
762 move(copies);
763 pickup(copies);
764 FrameGraphics.Repaint();
765 return;
766 }
767
768 if (copies == null)
769 copies = copy(Frame.FreeItems);
770 // MIKE: what does the below 2 lines do?
771 for (Item i : copies)
772 i.setOffset(0, 0);
773 // The below code has a little problem withflicker when stamp
774 // and dragging
775 move(Frame.FreeItems);
776 anchor(copies);
777 updateCursor();
778 FrameGraphics.Repaint();
779 return;
780 }
781
782 } else {
783 // if the user is pointing at something, this is a copy
784 if (clicked != null) {
785 // check permissions
786 if (clicked.Permission < ItemPermission.PERMISSION_COPY) {
787 FrameGraphics
788 .DisplayMessage("Insufficient permission to copy item");
789 return;
790 }
791
792 // This happens when the user right clicks on the endpoint of an
793 // existing line
794 // check for unreeling
795 List<Item> copies = ItemUtils.UnreelLine(clicked.Item);
796
797 if (copies == null) {
798 // check if this is picking up a rectangle
799 if (clicked.Item instanceof Dot
800 && clicked.Item.getConnected().size() == 3) {
801 Dot d = null;
802 // only one dot will be present for rectangles
803 for (Item i : clicked.Item.getConnected())
804 if (i instanceof Dot && d == null)
805 d = (Dot) i;
806 else if (i instanceof Dot && d != null)
807 d = null;
808
809 // if this is indeed a rectangle anchor
810 if (d != null) {
811 // pick up a copy of all enclosed items
812 List<ItemPermission> items = FrameUtils
813 .getItemsEnclosedBy(DisplayIO
814 .getCurrentFrame(), d
815 .getEnclosedShape());
816 if (items != null) {
817 ArrayList<Item> toCopy = new ArrayList<Item>(
818 items.size());
819 for (ItemPermission ip : items)
820 if (ip.Permission >= ItemPermission.PERMISSION_COPY)
821 toCopy.add(ip.Item);
822
823 List<Item> toPickup = copy(toCopy);
824 clearParent(toPickup);
825 pickup(toPickup);
826 }
827 return;
828 }
829 }
830 copies = copy(clicked.Item);
831 }
832
833 pickup(copies);
834 return;
835
836 } else {
837 // if the user is pointing inside a closed shape, copy the items
838 // inside
839 if (clickedIn != null) {
840 List<Item> toCopy = new ArrayList<Item>(clickedIn.size());
841 for (ItemPermission ip : clickedIn)
842 if (ip.Permission >= ItemPermission.PERMISSION_COPY)
843 toCopy.add(ip.Item);
844
845 List<Item> copies = copy(toCopy);
846 clearParent(copies);
847 pickup(copies);
848 // otherwise, create a rectangle
849 } else {
850
851 int x = DisplayIO.getMouseX();
852 int y = DisplayIO.getMouseY();
853
854 // create dots
855 Dot d1 = new Dot(x, y, DisplayIO.getCurrentFrame()
856 .getNextItemID());
857 Dot d2 = new Dot(x, y, DisplayIO.getCurrentFrame()
858 .getNextItemID());
859 Dot d3 = new Dot(x, y, DisplayIO.getCurrentFrame()
860 .getNextItemID());
861 Dot d4 = new Dot(x, y, DisplayIO.getCurrentFrame()
862 .getNextItemID());
863
864 // create lines
865 Line l1 = new Line(d1, d2, DisplayIO.getCurrentFrame()
866 .getNextItemID());
867 Line l2 = new Line(d2, d3, DisplayIO.getCurrentFrame()
868 .getNextItemID());
869 Line l3 = new Line(d3, d4, DisplayIO.getCurrentFrame()
870 .getNextItemID());
871 Line l4 = new Line(d4, d1, DisplayIO.getCurrentFrame()
872 .getNextItemID());
873
874 new Constraint(d1, d2, DisplayIO.getCurrentFrame()
875 .getNextItemID(), Constraint.HORIZONTAL);
876 new Constraint(d3, d4, DisplayIO.getCurrentFrame()
877 .getNextItemID(), Constraint.HORIZONTAL);
878 new Constraint(d2, d3, DisplayIO.getCurrentFrame()
879 .getNextItemID(), Constraint.VERTICAL);
880 new Constraint(d4, d1, DisplayIO.getCurrentFrame()
881 .getNextItemID(), Constraint.VERTICAL);
882
883 anchor(d1);
884 anchor(d2);
885 anchor(d3);
886 anchor(d4);
887
888 anchor(l1);
889 anchor(l2);
890 anchor(l3);
891 anchor(l4);
892
893 pickup(d4);
894
895 FrameGraphics.Repaint();
896 return;
897 }
898 }
899 }
900 }
901
902 private static void clearParent(List<Item> items) {
903 for (Item i : items)
904 i.setParent(null);
905 }
906
907 public void mouseEntered(MouseEvent e) {
908 }
909
910 public void mouseExited(MouseEvent e) {
911 }
912
913 public void mouseDragged(MouseEvent e) {
914 // System.out.println("MouseDragged");
915
916 // check if user is dragging across a text item
917 if (_lastRanged != null) {
918 // System.out.println(MouseY - e.getY());
919
920 MouseX = e.getX();
921 MouseY = e.getY();
922
923 int distance = _lastRanged.getY() - DisplayIO.getMouseY();
924 if (distance <= 0)
925 distance = DisplayIO.getMouseY() - _lastRanged.getY()
926 - _lastRanged.getBoundsHeight();
927
928 if (distance > UserSettings.NoOpThreshold) {
929 _lastRanged.clearSelectionEnd();
930 _isNoOp = true;
931 } else {
932 // update the ranged section
933 _lastRanged.setSelectionEnd(DisplayIO.getMouseX(), DisplayIO
934 .getMouseY());
935 _isNoOp = false;
936 }
937
938 DisplayIO.setTextCursor(_lastRanged.getSize());
939 FrameGraphics.Repaint();
940 return;
941 }
942
943 // if the user is dragging across a picture
944 if (_lastCropped != null) {
945 MouseX = e.getX();
946 MouseY = e.getY();
947
948 // update the ranged section
949 _lastCropped.setEndCrop(DisplayIO.getMouseX(), DisplayIO
950 .getMouseY());
951 DisplayIO.setCursor(Item.CROP_CURSOR);
952 FrameGraphics.Repaint();
953 return;
954 }
955
956 /*
957 * // Euclidean distance int distance = (int)
958 * Math.sqrt(Math.pow(Math.abs(MouseX - e.getX()), 2) +
959 * Math.pow(Math.abs(MouseY - e.getY()), 2));
960 *
961 * if (distance > UserSettings.NoOpThreshold)
962 */
963 // Use the below calculation for better speed. If it causes problems
964 // switch back to the Euclidean distance calculation
965 if (Math.abs(MouseX - e.getX()) > UserSettings.NoOpThreshold
966 || Math.abs(MouseY - e.getY()) > UserSettings.NoOpThreshold)
967 _isNoOp = true;
968 }
969
970 MouseEvent _lastMouseEvent = null;
971
972 /**
973 * Updates the stored mouse position and highlights any items as necessary.
974 */
975 public void mouseMoved(MouseEvent e) {
976 // System.out.println("MouseMoved");
977
978 MouseX = e.getX();
979 MouseY = e.getY();
980
981 if (_lastMouseEvent == null)
982 _lastMouseEvent = e;
983
984 /*
985 * int distance = (int) Math.sqrt(Math.pow(Math
986 * .abs(_lastMouseEvent.getX() - e.getX()), 2) +
987 * Math.pow(Math.abs(_lastMouseEvent.getY() - e.getY()), 2));
988 */
989
990 // Just do the sum of the distance moved in x and y direction for
991 // speed!!
992 int distance = Math.abs(_lastMouseEvent.getX() - e.getX())
993 + Math.abs(_lastMouseEvent.getY() - e.getY());
994
995 boolean checkHighlight = true;
996
997 // Mike: This code checks if the mouse is moving above a
998 // threshold speed. If so it doesnt execute the code that checks if
999 // items underneath the cursor need to be highlighted.
1000 if (Frame.itemAttachedToCursor()) {
1001 long time = e.getWhen() - _lastMouseEvent.getWhen();
1002 // System.out.println(time + " D:" + distance);
1003 if (time > 0 && distance * 3 > time) {
1004 checkHighlight = false;
1005 // System.out.println("Dont check highlight!");
1006 if (_lastHighlightedItem != null && !_lastHoldsHighlight) {
1007 FrameGraphics.Highlight(_lastHighlightedItem, false, true);
1008 }
1009 }
1010 }
1011
1012 _lastMouseEvent = e;
1013
1014 if (checkHighlight) {
1015 // ByMike: Get the item the mouse is hovering over
1016 ItemPermission click = FrameUtils.getCurrentItem();
1017 Item on = null;
1018
1019 if (click != null) {
1020 on = click.Item;
1021 // set the context
1022 if (on instanceof Line)
1023 _context = CONTEXT_AT_LINE;
1024 else if (on instanceof Dot)
1025 _context = CONTEXT_AT_DOT;
1026 else if (on instanceof Text) {
1027 // Checks that we are actually pointing on a character
1028 // not just space in the text box's bounding box
1029 if (((Text) on).contains(DisplayIO.getMouseX(), DisplayIO
1030 .getMouseY())) {
1031 _context = CONTEXT_AT_TEXT;
1032 } else {
1033 // if we are pointing in space in the text box... it is
1034 // the same as pointing in freespace
1035 on = null;
1036 _context = CONTEXT_FREESPACE;
1037 }
1038 }
1039
1040 _alpha = 60;
1041 } else {
1042 _context = CONTEXT_FREESPACE;
1043 _alpha = -1;
1044 }
1045
1046 // if the user is pointing at an item, highlight it
1047 if (on != null && !Frame.FreeItems.contains(on)) {
1048 // if the user can spot-weld, show the virtual spot
1049 if (Frame.FreeItems.size() == 2 && on instanceof Line) {
1050 Line line = (Line) on;
1051 if (Frame.FreeItems.get(0) instanceof Dot)
1052 line.showVirtualSpot((Dot) Frame.FreeItems.get(0),
1053 DisplayIO.getMouseX(), DisplayIO.getMouseY());
1054 else if (Frame.FreeItems.get(1) instanceof Dot)
1055 line.showVirtualSpot((Dot) Frame.FreeItems.get(1),
1056 DisplayIO.getMouseX(), DisplayIO.getMouseY());
1057 else
1058 FrameGraphics.Highlight(on, true, true);
1059 } else
1060 FrameGraphics.Highlight(on, true, true);
1061
1062 // if the last item highlighted is still highlighted, clear it
1063 if (_lastHoldsHighlight) {
1064 _lastHoldsHighlight = false;
1065 for (Item i : DisplayIO.getCurrentFrame().getItems())
1066 if (i.isHighlighted() && i != on)
1067 FrameGraphics.Highlight(i, false, false);
1068 }
1069
1070 // if the user is not pointing at an item, check for enclosure
1071 // highlighting
1072 } else if (on == null) {
1073 List<Dot> enclosure = FrameUtils.getEnclosingDots();
1074 if (enclosure != null && enclosure.size() > 1) {
1075 if (enclosure.get(0).getLines().size() > 1) {
1076 on = enclosure.get(0).getLines().get(0);
1077 // FrameGraphics.Highlight(enclosure.get(0).getLines().get(0),
1078 // true, true);
1079 FrameGraphics.Highlight(on, true, true);
1080 }
1081 // for(Dot d : enclosure){
1082 // FrameGraphics.Highlight(d, true, true);
1083 // break;
1084 // }
1085 } else if (_lastHighlightedItem != null) {
1086 _lastHoldsHighlight = false;
1087 }
1088 }
1089
1090 // disable cursor changes when the cursor has items attached
1091 if (Frame.itemAttachedToCursor()
1092 && DisplayIO.getCursor() != Item.TEXT_CURSOR)
1093 _forceArrowCursor = false;
1094
1095 if (_lastHighlightedItem != null && _lastHighlightedItem != on
1096 && !_lastHoldsHighlight) {
1097 FrameGraphics.Highlight(_lastHighlightedItem, false, true);
1098 }
1099
1100 _lastHighlightedItem = on;
1101
1102 }
1103
1104 if (Frame.itemAttachedToCursor()) {
1105 move(Frame.FreeItems);
1106 }
1107
1108 if (_forceArrowCursor)
1109 updateCursor();
1110
1111 // if (_lastItem == null)
1112 // DisplayIO.UpdateTitle();
1113
1114 _forceArrowCursor = true;
1115 }
1116
1117 /**
1118 * Updates the current mouse cursor to whatever it should be. i.e. Hidden
1119 * when rubber-banding lines, otherwise default (arrow)
1120 */
1121 private static void updateCursor() {
1122 // if rubber-banding, there will be exactly 2 items on the cursor
1123 if (Frame.FreeItems.size() != 2)
1124 DisplayIO.setCursor(Item.DEFAULT_CURSOR);
1125 else {
1126 Dot d = null;
1127 // check that it is indeed a line being rubber-banded
1128 if (Frame.FreeItems.get(0) instanceof Line
1129 && Frame.FreeItems.get(1) instanceof Dot)
1130 d = (Dot) Frame.FreeItems.get(1);
1131 else if (Frame.FreeItems.get(1) instanceof Line
1132 && Frame.FreeItems.get(0) instanceof Dot)
1133 d = (Dot) Frame.FreeItems.get(0);
1134
1135 if (d != null) {
1136 DisplayIO.setCursor(Item.HIDDEN_CURSOR);
1137 } else
1138 DisplayIO.setCursor(Item.DEFAULT_CURSOR);
1139 }
1140
1141 }
1142
1143 public static void setHighlightHold(boolean hold) {
1144 _lastHoldsHighlight = hold;
1145 }
1146
1147 public static void resetOffset() {
1148 if (Frame.itemAttachedToCursor()) {
1149 _offX = DisplayIO.getMouseX() - Frame.FreeItems.get(0).getX()
1150 + Frame.FreeItems.get(0).getOffset().x;
1151 _offY = MouseY - Frame.FreeItems.get(0).getY()
1152 + Frame.FreeItems.get(0).getOffset().y;
1153 }
1154 }
1155
1156 private static void move(List<Item> toMove) {
1157 int deltax = toMove.get(0).getX() - (DisplayIO.getMouseX() - _offX);
1158 int deltay = toMove.get(0).getY() - (MouseY - _offY);
1159
1160 for (Item move : toMove) {
1161 move.setPosition(move.getX() - deltax, move.getY() - deltay);
1162
1163 if (move instanceof Text)
1164 ((Text) move).setAlpha(_alpha);
1165 }
1166
1167 FrameGraphics.Repaint();
1168 }
1169
1170 private static void load(String toLoad) {
1171 checkTDFCItemWaiting();
1172 FrameUtils.DisplayFrame(toLoad);
1173 }
1174
1175 private static void checkTDFCItemWaiting() {
1176 // if there is a TDFC Item waiting
1177 if (_tdfcItem != null) {
1178 Frame currentFrame = DisplayIO.getCurrentFrame();
1179 boolean change = currentFrame.hasChanged();
1180 boolean saved = currentFrame.isSaved();
1181 // Save the parent of the item if it has not been saved
1182 // TODO change it so it doesnt use load frame here... if
1183 // possible
1184 if (!change && !saved) {
1185 _tdfcItem.setLink(null);
1186 _tdfcItem.getParent().setChanged(true);
1187 FrameIO.SaveFrame(_tdfcItem.getParent());
1188 FrameGraphics.Repaint();
1189 } else {
1190 SessionStats.CreatedFrame();
1191 // DisplayIO.UpdateTitle();
1192 }
1193
1194 _tdfcItem = null;
1195 }
1196 }
1197
1198 private static void back() {
1199 checkTDFCItemWaiting();
1200 DisplayIO.Back();
1201
1202 // repaint things if necessary
1203 if (Frame.itemAttachedToCursor())
1204 move(Frame.FreeItems);
1205 }
1206
1207 /**
1208 * Returns true if the mouse moved during TDFC. This will happen if there is
1209 * a start annotation item on the frame.
1210 *
1211 * @param linker
1212 * @return
1213 */
1214 public static boolean tdfc(Item linker) {
1215 if (linker instanceof Line)
1216 return false;
1217
1218 // if this is a non-usable item
1219 if (linker.getID() < 0)
1220 return false;
1221
1222 linker.getParent().setChanged(true);
1223 checkTDFCItemWaiting();
1224
1225 Frame next = FrameIO.CreateNewFrame(linker);
1226
1227 linker.setLink("" + next.getFrameNumber());
1228 _tdfcItem = linker;
1229
1230 FrameUtils.DisplayFrame(next, true);
1231
1232 boolean mouseMoved = next.moveMouseToDefaultLocation();
1233 // this needs to be done if the user doesnt move the mouse before doing
1234 // tdfc while the cursor is set to the text cursor
1235 DisplayIO.setCursor(Item.DEFAULT_CURSOR);
1236 // This needs to be done in case there was a @start on the frame which
1237 // triggers changed to be set to true when it should stay as false
1238 next.setChanged(false);
1239
1240 return mouseMoved;
1241 }
1242
1243 /**
1244 * Creates a new Text item and fills it with particular attributes extracted
1245 * from the given Item. Note: Users always have permission to extract
1246 * attributes, so it is not checked.
1247 *
1248 * @param toExtract
1249 * ItemPermission containing the Item to extract the attributes
1250 * from.
1251 */
1252 private static void extractAttributes(ItemPermission toExtract) {
1253 if (toExtract == null || toExtract.Item == null)
1254 return;
1255
1256 if (Frame.itemAttachedToCursor())
1257 return;
1258
1259 Text attribs;
1260 Item item = toExtract.Item;
1261 // Extract the frames attributes when the user clicks on the frame name
1262 if (item.isFrameName())
1263 attribs = AttributeUtils.ExtractAttributes(item.getParent());
1264 else
1265 attribs = AttributeUtils.ExtractAttributes(item);
1266
1267 if (attribs == null)
1268 FrameGraphics
1269 .DisplayMessage("All attributes of that item are default values.");
1270 else {
1271 // Give the attribute text item the color of the item for which
1272 // attributes are being extracted.
1273 attribs.setColor(item.getColor());
1274 pickup(attribs);
1275 }
1276 }
1277
1278 private static void delete(ItemPermission toDelete) {
1279 FrameUtils.LastEdited = null;
1280 _offX = _offY = 0;
1281
1282 // check if the user is pointing at the frame's framename
1283 if (toDelete != null
1284 && toDelete.Item == DisplayIO.getCurrentFrame().getName()) {
1285 DisplayIO.getCurrentFrame().clear();
1286 FrameGraphics.Repaint();
1287 return;
1288 }
1289
1290 // if the user is deleting items attached to the cursor
1291 if (Frame.itemAttachedToCursor()) {
1292 // if this is an item-swap
1293 if (Frame.FreeItems.size() == 1
1294 && Frame.FreeItems.get(0) instanceof Text
1295 && toDelete != null && toDelete.Item instanceof Text) {
1296
1297 // check permissions
1298 if (toDelete.Permission < ItemPermission.PERMISSION_FULL) {
1299 FrameGraphics
1300 .DisplayMessage("Insufficient permission to swap Item text");
1301 return;
1302 }
1303
1304 Text anchored = (Text) toDelete.Item;
1305 Text free = (Text) Frame.FreeItems.get(0);
1306
1307 // List<String> temp = anchored.getText();
1308 anchored.setTextList(free.getText());
1309
1310 // free.setTextList(temp);
1311 Frame.FreeItems.clear();
1312
1313 anchored.getParent().setChanged(true);
1314
1315 // update the offset since the text has changed
1316 _offX = DisplayIO.getMouseX() - anchored.getX()
1317 + anchored.getOffset().x;
1318 _offY = MouseY - anchored.getY() + anchored.getOffset().y;
1319 } else {
1320 deleteItems(Frame.FreeItems);
1321 }
1322 // reset the mouse cursor
1323 updateCursor();
1324 FrameGraphics.Repaint();
1325 return;
1326 // the user is not pointing at an item
1327 } else if (toDelete == null) {
1328
1329 // if the user is pointing inside a closed shape, delete all
1330 // items inside it
1331 List<ItemPermission> items = FrameUtils.getCurrentItems();
1332
1333 if (items != null) {
1334 ArrayList<Item> toRemove = new ArrayList<Item>(items.size());
1335 for (ItemPermission ip : items)
1336 if (ip.Permission >= ItemPermission.PERMISSION_FULL) {
1337 toRemove.add(ip.Item);
1338 }
1339
1340 deleteItems(toRemove);
1341
1342 // reset the mouse cursor
1343 updateCursor();
1344 FrameGraphics.Repaint();
1345
1346 // otherwise this is an undo command
1347 } else {
1348 DisplayIO.getCurrentFrame().undo();
1349 }
1350 return;
1351 // this is a delete command
1352 } else {
1353 // check permissions
1354 if (toDelete.Permission < ItemPermission.PERMISSION_FULL) {
1355 FrameGraphics
1356 .DisplayMessage("Insufficient permission to delete item");
1357 return;
1358 }
1359
1360 Frame current = toDelete.Item.getParent();
1361
1362 current.setChanged(true);
1363
1364 List<Item> toUndo = new LinkedList<Item>();
1365
1366 if (toDelete.Item instanceof Dot) {
1367 toUndo.addAll(deleteDot((Dot) toDelete.Item));
1368 } else
1369 toUndo.addAll(copy(toDelete.Item.getConnected()));
1370
1371 current.addAllToUndo(toUndo);
1372 current.removeAllItems(toDelete.Item.getConnected());
1373 // reset the mouse cursor
1374 updateCursor();
1375 FrameGraphics.Repaint();
1376
1377 ItemUtils.EnclosedCheck(current.getItems());
1378 FrameGraphics.Repaint();
1379 }
1380 // check
1381 DisplayIO.setCursor(Item.DEFAULT_CURSOR);
1382 }
1383
1384 private static void deleteItems(List<Item> itemList) {
1385 Frame current = DisplayIO.getCurrentFrame();
1386 List<Item> toUndo = new LinkedList<Item>();
1387 List<Item> seen = new LinkedList<Item>();
1388
1389 // disconnect any connected items
1390 for (Item i : itemList) {
1391 if (i.getLines().size() > 0) {
1392
1393 // check for rectangle deletion
1394 if (itemList.size() == 3) {
1395 boolean rectangle = false;
1396 // check that this is indeed a rectangle
1397 for (Item check : itemList)
1398 if (check != i && !i.getLines().contains(check)) {
1399 rectangle = false;
1400 break;
1401 } else
1402 rectangle = true;
1403
1404 // if this is a rectangle, remove the entire
1405 // rectangle
1406 if (rectangle) {
1407 List<Item> copy = copy(i.getAllConnected());
1408 current.addAllToUndo(copy);
1409 current.removeAllItems(i.getAllConnected());
1410 itemList.clear();
1411 // reset the mouse cursor
1412 updateCursor();
1413 FrameGraphics.Repaint();
1414 return;
1415 }
1416 }
1417
1418 List<Item> copy = deleteDot((Dot) i);
1419 // add the copied items to the undo stack
1420 for (Item cop : copy)
1421 if (!toUndo.contains(cop))
1422 toUndo.add(cop);
1423 } else {
1424 if (!seen.contains(i))
1425 toUndo.addAll(copy(i));
1426 }
1427
1428 seen.add(i);
1429 }
1430
1431 // check for rectangle deletion
1432 if (itemList.size() == 3) {
1433 boolean rectangle = false;
1434 Dot dot = null;
1435 // check that this is indeed a rectangle
1436 for (Item check : itemList) {
1437 if (dot == null && check instanceof Dot)
1438 dot = (Dot) check;
1439 else if (check != dot && !dot.getLines().contains(check)) {
1440 rectangle = false;
1441 break;
1442 } else
1443 rectangle = true;
1444 }
1445
1446 // if this is a rectangle, remove the entire rectangle
1447 if (rectangle) {
1448 // List<Item> copy = copy(dot.getAllConnected());
1449 current.addAllToUndo(dot.getAllConnected());
1450 current.removeAllItems(dot.getAllConnected());
1451 itemList.clear();
1452 // reset the mouse cursor
1453 updateCursor();
1454 FrameGraphics.Repaint();
1455 return;
1456 }
1457 }
1458
1459 current.removeAllItems(itemList);
1460 current.addAllToUndo(itemList);
1461 itemList.clear();
1462 }
1463
1464 private static List<Item> deleteDot(Dot dot) {
1465 // create a backup copy of the dot
1466 List<Item> copy = copy(dot.getConnected());
1467 // remove lines that are connected to anchored dots
1468 // note: the line is kept so that it can be properly restored
1469 for (Item ic : copy) {
1470 if (ic instanceof Line) {
1471 Line line = (Line) ic;
1472 if (!copy.contains(line.getStartItem()))
1473 line.getStartItem().removeLine(line);
1474 if (!copy.contains(line.getEndItem()))
1475 line.getEndItem().removeLine(line);
1476 }
1477 }
1478
1479 // remove all lines being deleted
1480 for (Item ic : dot.getConnected()) {
1481 if (ic instanceof Line && ((Line) ic).getOppositeEnd(dot) != null) {
1482 Line line = (Line) ic;
1483
1484 Item d = line.getOppositeEnd(dot);
1485 d.removeLine(line);
1486
1487 // if the dot was only part of one line, it can be
1488 // removed
1489 if (d.getLines().size() == 0) {
1490 if (d.getParent() != null)
1491 d.getParent().removeItem(d);
1492 if (!copy.contains(d))
1493 copy.add(d);
1494 }
1495
1496 if (dot.getParent() != null)
1497 dot.getParent().removeItem(ic);
1498 }
1499 }
1500 return copy;
1501 }
1502
1503 private static void removeAllLinesExcept(Item from, Item but) {
1504 List<Line> lines = new LinkedList<Line>();
1505 lines.addAll(from.getLines());
1506 for (Line line : lines)
1507 if (line.getOppositeEnd(from) != but)
1508 from.removeLine(line);
1509
1510 List<Constraint> consts = new LinkedList<Constraint>();
1511 consts.addAll(from.getConstraints());
1512 for (Constraint c : consts)
1513 if (c.getOppositeEnd(from) != but)
1514 from.removeConstraint(c);
1515 }
1516
1517 public static List<Item> merge(List<Item> merger, Item mergee) {
1518 if (mergee.getParent().getName() == mergee) {
1519 return mergee.getParent().merge(merger);
1520 }
1521
1522 // check for rectangle merging
1523 if (merger.size() == 3 && mergee.getLines().size() == 2) {
1524 boolean rectangle = false;
1525 Dot dot = null;
1526 // check that this is indeed a rectangle
1527 for (Item check : merger) {
1528 if (dot == null && check instanceof Dot)
1529 dot = (Dot) check;
1530 else if (check != dot && !dot.getLines().contains(check)) {
1531 rectangle = false;
1532 break;
1533 } else
1534 rectangle = true;
1535 }
1536
1537 // if this is a rectangle
1538 if (rectangle) {
1539 List<Item> connected = dot.getAllConnected();
1540 DisplayIO.getCurrentFrame().removeAllItems(connected);
1541
1542 // find the point opposite the point that was clicked
1543 // (mergee)...
1544 Dot opposite = null;
1545 List<Line> lines = dot.getLines();
1546 for (Line l : lines) {
1547 if (l.getOppositeEnd(dot) != mergee) {
1548 opposite = (Dot) l.getOppositeEnd(dot);
1549 break;
1550 }
1551 }
1552
1553 // check if the rectangle is small enough that it should be
1554 // collapsed to a single point
1555 int x1 = Math.abs(opposite.getX() - mergee.getX());
1556 int x2 = Math.abs(opposite.getY() - mergee.getY());
1557 int distance = (int) Math.sqrt(Math.pow(x1, 2)
1558 + Math.pow(x2, 2));
1559
1560 if (distance < RECTANGLE_TO_POINT_THRESHOLD) {
1561 mergee.removeAllConstraints();
1562 mergee.removeAllLines();
1563 return mergee.getAllConnected();
1564 } else {
1565
1566 // otherwise, replace the rectangle with a constrained
1567 // line
1568 Item other = null;
1569 // there should be only one line left
1570 for (Line line : mergee.getLines())
1571 if (!merger.contains(line.getOppositeEnd(mergee)))
1572 other = line.getOppositeEnd(mergee);
1573
1574 removeAllLinesExcept(mergee, other);
1575 removeAllLinesExcept(other, mergee);
1576
1577 return mergee.getAllConnected();
1578 }
1579 }
1580 }
1581
1582 List<Item> remain = new ArrayList<Item>();
1583 Item res = null;
1584
1585 for (Item i : merger) {
1586 // check for link merging
1587 if (i instanceof Text
1588 && FrameIO.isValidFrameName((((Text) i).getFirstLine()))
1589 && FrameIO.DoesFrameExist((((Text) i).getFirstLine()))) {
1590 // check that we can actually access the frame this link
1591 // corresponds to
1592
1593 mergee.setLink(((Text) i).getFirstLine());
1594 } else {
1595 // check for attribute merging
1596 if (i instanceof Text) {
1597 Text txt = (Text) i;
1598
1599 // if this is not an attribute merge
1600 if (!AttributeUtils.SetAttribute(mergee, txt)) {
1601 // set mouse position for text merges
1602 if (mergee instanceof Text)
1603 // 18Feb Rob doesnt want cursor to jump when
1604 // inserting text
1605 ((Text) mergee).insertText(txt.getTextNoList(),
1606 DisplayIO.getMouseX(), DisplayIO
1607 .getMouseY());
1608
1609 else if (mergee instanceof Dot) {
1610 mergee.getParent().removeItem(mergee);
1611 break;
1612 }
1613
1614 // TODO tidy this up... the text override of this method
1615 // doesnt use the parametres MouseY and MouseX!!
1616 res = mergee.merge(i, DisplayIO.getMouseX(), MouseY
1617 - DisplayIO.getOffset());
1618 if (res != null) {
1619 remain.add(res);
1620 }
1621 }
1622 } else {
1623 res = mergee.merge(i, DisplayIO.getMouseY(), MouseY
1624 - DisplayIO.getOffset());
1625 if (res != null)
1626 remain.addAll(res.getConnected());
1627
1628 }
1629 }
1630
1631 }
1632
1633 updateCursor();
1634 mergee.getParent().setChanged(true);
1635 ItemUtils.EnclosedCheck(mergee.getParent().getItems());
1636 FrameUtils.Parse(mergee.getParent());
1637
1638 return remain;
1639 }
1640
1641 /**
1642 * Picks up an item on a frame.
1643 *
1644 * @param toGrab
1645 * item to be picked up
1646 * @param removeItem
1647 * true if the item should be removed from the frame
1648 */
1649 public static void pickup(Item toGrab) {
1650 pickup(toGrab.getConnected());
1651 }
1652
1653 public static void pickup(List<Item> toGrab) {
1654 for (Item i : toGrab) {
1655 // Check if it has a relative link if so make it absolute
1656 i.setAbsoluteLink();
1657
1658 // parent may be null
1659 if (i.getParent() != null)
1660 i.getParent().removeItem(i);
1661
1662 Frame.FreeItems.add(i);
1663 i.setParent(null);
1664 if (i instanceof Dot)
1665 ((Dot) i).setFloating(true);
1666 }
1667
1668 updateCursor();
1669
1670 // if there are multiple items in the list, determine which to use for
1671 // offset calculations
1672 if (toGrab.size() > 1) {
1673 for (Item i : toGrab) {
1674 if (!(i instanceof Line)) {
1675 _offX = DisplayIO.getMouseX() - i.getX() + i.getOffset().x;
1676 _offY = MouseY - i.getY() + i.getOffset().y;
1677
1678 // make the offset item the first item in the list (so
1679 // moving code knows which item to use)
1680 Frame.FreeItems.set(Frame.FreeItems.indexOf(i),
1681 Frame.FreeItems.get(0));
1682 Frame.FreeItems.set(0, i);
1683 break;
1684 }
1685 }
1686
1687 move(Frame.FreeItems);
1688 // otherwise, just use the first item
1689 } else if (toGrab.size() == 1) {
1690 _offX = DisplayIO.getMouseX() - toGrab.get(0).getX()
1691 + toGrab.get(0).getOffset().x;
1692 _offY = MouseY - toGrab.get(0).getY() + toGrab.get(0).getOffset().y;
1693 }
1694
1695 ItemUtils.EnclosedCheck(toGrab);
1696 }
1697
1698 private static void createLine() {
1699 // create the two endpoints
1700 Dot end = new Dot(DisplayIO.getRealMouseX(), DisplayIO.getMouseY(),
1701 DisplayIO.getCurrentFrame().getNextItemID());
1702 Dot start = new Dot(DisplayIO.getRealMouseX(), DisplayIO.getMouseY(),
1703 DisplayIO.getCurrentFrame().getNextItemID());
1704 // create the Line
1705 Line line = new Line(start, end, DisplayIO.getCurrentFrame()
1706 .getNextItemID());
1707 line.autoArrowheadLength();
1708
1709 // anchor the start
1710 anchor(start);
1711
1712 // attach the line to the cursor
1713 pickup(end);
1714 }
1715
1716 private static List<Item> copy(Item toCopy) {
1717 return copy(toCopy.getConnected());
1718 }
1719
1720 /**
1721 * Returns a list of copies of the list passed in
1722 *
1723 * @param toCopy
1724 * The list of items to copy
1725 * @return A List of copied Items
1726 */
1727 private static List<Item> copy(List<Item> toCopy) {
1728 return ItemUtils.CopyItems(toCopy);
1729 }
1730
1731 public static void anchor(Item toAnchor) {
1732 Frame current = DisplayIO.getCurrentFrame();
1733 // toAnchor.anchor(current);
1734
1735 // update the items ID to prevent conflicts with the current frame
1736 if (toAnchor.getID() < 0 || current.getItems().contains(toAnchor))
1737 ;
1738 toAnchor.setID(current.getNextItemID());
1739
1740 toAnchor.setParent(current);
1741 toAnchor.setOffset(0, 0);
1742 current.addItem(toAnchor);
1743 current.setResort(true);
1744
1745 toAnchor.setRelativeLink();
1746
1747 if (toAnchor instanceof Dot) {
1748 for (Line line : ((Dot) toAnchor).getLines()) {
1749 if (line.getID() < 0 && !current.getItems().contains(line)) {
1750 line.setID(current.getNextItemID());
1751 line.showHighlight(true);
1752 // Mike: Why was this line here?
1753 // anchor(line);
1754 }
1755 }
1756 ((Dot) toAnchor).setFloating(false);
1757 } else if (toAnchor instanceof Text) {
1758 // ensure all text items have their selection cleared
1759 ((Text) toAnchor).clearSelection();
1760 ((Text) toAnchor).setAlpha(0);
1761 } else if (toAnchor instanceof Line) {
1762 ((Line) toAnchor).fixArrowheadLength();
1763 }
1764
1765 FrameGraphics.Repaint();
1766 ItemUtils.EnclosedCheck(current.getItems());
1767 }
1768
1769 public static void anchor(List<Item> toAnchor) {
1770 for (Item i : toAnchor)
1771 anchor(i);
1772 toAnchor.clear();
1773 }
1774
1775 /*
1776 * private boolean mouseMovedRecently() { Date now = new Date();
1777 *
1778 * return now.getTime() - _lastMouseMovement.getTime() < 150; }
1779 */
1780
1781 public void mouseWheelMoved(MouseWheelEvent arg0) {
1782 // System.out.println(arg0.getClickCount() + " " +
1783 // arg0.getWheelRotation());
1784 int clicks = arg0.getClickCount();
1785
1786 // if a line is being rubber-banded, check for auto straightening
1787 if (Frame.FreeItems.size() == 2) {
1788 if ((Frame.FreeItems.get(0) instanceof Dot && Frame.FreeItems
1789 .get(1) instanceof Line)
1790 || (Frame.FreeItems.get(1) instanceof Dot && Frame.FreeItems
1791 .get(0) instanceof Line)) {
1792
1793 Line line;
1794 if (Frame.FreeItems.get(0) instanceof Line)
1795 line = (Line) Frame.FreeItems.get(0);
1796 else
1797 line = (Line) Frame.FreeItems.get(1);
1798
1799 // User must do multiple clicks to toggle the line
1800 if (clicks == MOUSE_WHEEL_THRESHOLD) {
1801 if (arg0.isShiftDown())
1802 line.toggleArrowHeadRatio(arg0.getWheelRotation());
1803 else
1804 line.toggleArrowHeadLength(arg0.getWheelRotation());
1805 FrameGraphics.Repaint();
1806 }
1807 }
1808 } else if (arg0.getWheelRotation() != 0 && arg0.isShiftDown()) {
1809
1810 int rotationType = FrameKeyboardActions.SIZE_UP;
1811 if (arg0.getWheelRotation() > 0) {
1812 rotationType = FrameKeyboardActions.SIZE_DOWN;
1813 }
1814
1815 for (int i = 0; i < clicks; i++)
1816 FrameKeyboardActions.functionKey(rotationType);
1817 } else if (clicks == MOUSE_WHEEL_THRESHOLD) {
1818 ItemPermission ip = FrameUtils.getCurrentItem();
1819
1820 // if the user is not pointing to any item
1821 if (ip == null) {
1822 FrameGraphics
1823 .DisplayMessage("There are no Items selected on the Frame");
1824 return;
1825 } else {
1826 // check permissions
1827 if (ip.Permission < ItemPermission.PERMISSION_FULL) {
1828 FrameGraphics
1829 .DisplayMessage("Insufficient permission to change the size of that item");
1830 return;
1831 }
1832 }
1833
1834 if (ip.Item instanceof Line) {
1835 Line line = (Line) ip.Item;
1836 line.toggleDashed(arg0.getWheelRotation());
1837 FrameGraphics.Repaint();
1838 return;
1839 }
1840 }
1841 }
1842
1843 /**
1844 *
1845 * @return the integer value for the last mouse button clicked.
1846 */
1847 public static int getLastMouseButton() {
1848 if (_lastMouseClick == null)
1849 return MouseEvent.NOBUTTON;
1850
1851 return _lastMouseClick.getButton();
1852 }
1853
1854 public static boolean isDelete(MouseEvent e) {
1855 if (e == null)
1856 return false;
1857 int onMask = MouseEvent.BUTTON3_DOWN_MASK
1858 | MouseEvent.BUTTON2_DOWN_MASK;
1859 return (e.getModifiersEx() & onMask) == onMask;
1860 }
1861
1862 public static boolean isGetAttributes(MouseEvent e) {
1863 if (e == null)
1864 return false;
1865 int onMask = MouseEvent.BUTTON3_DOWN_MASK
1866 | MouseEvent.BUTTON1_DOWN_MASK;
1867 return (e.getModifiersEx() & onMask) == onMask;
1868 }
1869
1870 public static boolean isTwoClickNoOp(MouseEvent e) {
1871 if (e == null)
1872 return false;
1873 int onMask = MouseEvent.BUTTON2_DOWN_MASK
1874 | MouseEvent.BUTTON1_DOWN_MASK;
1875 return (e.getModifiersEx() & onMask) == onMask;
1876 }
1877
1878 public static boolean wasDeleteClicked() {
1879 return isDelete(_lastMouseClick);
1880 }
1881}
Note: See TracBrowser for help on using the repository browser.