source: trunk/src/org/expeditee/gui/FrameKeyboardActions.java@ 247

Last change on this file since 247 was 247, checked in by ra33, 16 years ago

Added more import and mail stuff... including text importer

File size: 55.4 KB
Line 
1package org.expeditee.gui;
2
3import java.awt.Color;
4import java.awt.Polygon;
5import java.awt.Rectangle;
6import java.awt.Toolkit;
7import java.awt.datatransfer.DataFlavor;
8import java.awt.datatransfer.StringSelection;
9import java.awt.event.KeyEvent;
10import java.awt.event.KeyListener;
11import java.awt.geom.Point2D;
12import java.util.ArrayList;
13import java.util.Collection;
14import java.util.Collections;
15import java.util.HashSet;
16import java.util.LinkedList;
17import java.util.List;
18import java.util.StringTokenizer;
19
20import org.expeditee.actions.Actions;
21import org.expeditee.actions.NavigationActions;
22import org.expeditee.actions.Simple;
23import org.expeditee.io.Logger;
24import org.expeditee.items.Circle;
25import org.expeditee.items.Dot;
26import org.expeditee.items.Item;
27import org.expeditee.items.ItemUtils;
28import org.expeditee.items.Line;
29import org.expeditee.items.Permission;
30import org.expeditee.items.StringUtils;
31import org.expeditee.items.Text;
32import org.expeditee.items.XRayable;
33import org.expeditee.items.widgets.WidgetCorner;
34import org.expeditee.stats.SessionStats;
35
36public class FrameKeyboardActions implements KeyListener {
37
38 private static Text _toRemove = null;
39
40 public synchronized void keyTyped(KeyEvent e) {
41 if (Simple.isProgramRunning()) {
42 if (e.isControlDown()
43 && (e.getKeyChar() == KeyEvent.VK_ESCAPE || e.getKeyChar() == KeyEvent.VK_C)) {
44 Simple.stop();
45 return;
46 } else if (e.isControlDown() && e.getKeyChar() == KeyEvent.VK_SPACE) {
47 Simple.nextStatement();
48 return;
49 } else {
50 Simple.KeyStroke(e.getKeyChar());
51 }
52 if (Simple.consumeKeyboardInput())
53 return;
54 }
55
56 // ignore escape character and control characters
57 if (e.getKeyChar() == KeyEvent.VK_ESCAPE || e.isControlDown()) {
58 return;
59 }
60
61 // Deal with splitting text items when typing too fast
62 // Mike: thinks this problem may have been solved and was due to
63 // rounding errors in the text class...
64 // It may have been fixed by changing to the use of floats instead of
65 // ints for text positioning etc
66 // if (FrameMouseActions.isWaitingForRobot()) {
67 // System.out.println("Waiting: " + e.getKeyChar());
68 // return;
69 // }
70 e.consume();
71 char ch = e.getKeyChar();
72 // System.out.println(ch);
73
74 if (e.isAltDown()) {
75
76 } else {
77 processChar(ch, e.isShiftDown());
78 }
79 // FrameGraphics.Repaint();
80 }
81
82 public static void processChar(char ch, boolean isShiftDown) {
83 NavigationActions.ResetLastAddToBack();
84 Item on = FrameUtils.getCurrentItem();
85
86 // permission check
87 if (on != null && !on.hasPermission(Permission.full)) {
88 MessageBay
89 .displayMessage("Insufficient permission to edit this item");
90 return;
91 }
92
93 if (_toRemove != null && on != _toRemove) {
94 assert (_toRemove.getLength() == 0);
95 // This line is to protect mistaken removal of items if there is a
96 // bug...
97 if (_toRemove.getLength() == 0)
98 DisplayIO.getCurrentFrame().removeItem(_toRemove);
99 }
100 _toRemove = null;
101
102 // ignore delete and backspace if in free space
103 if ((on == null || !(on instanceof Text))
104 && (ch == KeyEvent.VK_BACK_SPACE || ch == KeyEvent.VK_TAB || ch == KeyEvent.VK_DELETE))
105 return;
106
107 SessionStats.TypedChar(ch);
108
109 // check for dot's being replaced with text
110 if (on != null && on instanceof Dot && !(on instanceof WidgetCorner)) {
111 if (ch == KeyEvent.VK_BACK_SPACE || ch == KeyEvent.VK_DELETE) {
112 return;
113 }
114 replaceDot((Item) on, ch);
115 return;
116 }
117
118 // only text can interact with keyboard events
119 if (on != null && !(on instanceof Text))
120 on = null;
121
122 // DisplayIO.UpdateTitle();
123
124 Text text = (Text) on;
125 // if this text is empty but has not been removed (such as from
126 // ESC-pushdown)
127 if (text != null && text.isEmpty()
128 && (ch == KeyEvent.VK_BACK_SPACE || ch == KeyEvent.VK_DELETE)) {
129 if (text.getLines().size() > 0)
130 replaceText(text);
131 else {
132 DisplayIO.setCursor(Item.DEFAULT_CURSOR);
133 }
134 return;
135 }
136
137 FrameUtils.setLastEdited(text);
138
139 // if the user is in free space, create a new text item
140 if (on == null || !on.isHighlighted()) {
141 // DisplayIO.UpdateTitle();
142 text = createText(ch);
143 justify(text);
144
145 FrameUtils.setLastEdited(text);
146 DisplayIO.setTextCursor(text, Text.NONE);
147 return;
148 }
149
150 DisplayIO.setTextCursor(text, Text.NONE);
151 Point2D.Float newMouse = null;
152 if (ch == '\t') {
153 if (isShiftDown) {
154 newMouse = text.removeTab(ch, DisplayIO.getFloatMouseX(),
155 FrameMouseActions.MouseY);
156 } else {
157 newMouse = text.insertTab(ch, DisplayIO.getFloatMouseX(),
158 FrameMouseActions.MouseY);
159 }
160 } else {
161 newMouse = text.insertChar(ch, DisplayIO.getFloatMouseX(),
162 FrameMouseActions.MouseY);
163 }
164 DisplayIO.setCursorPosition(newMouse.x, newMouse.y, false);
165
166 // This repaint is needed for WINDOWS only?!?!? Mike is not sure why!
167 if (ch == KeyEvent.VK_DELETE)
168 FrameGraphics.requestRefresh(true);
169
170 // a change has occured to the Frame
171 text.getParent().setChanged(true);
172
173 // check that the Text item still exists (hasn't been deleted\backspaced
174 // away)
175 if (text.isEmpty()) {
176 _toRemove = text;
177
178 if (text.hasAction())
179 text.setActionMark(true);
180 else if (text.getLink() != null)
181 text.setLinkMark(true);
182 else if (text.getLines().size() > 0)
183 replaceText(text);
184 else {
185 // DisplayIO.getCurrentFrame().removeItem(text);
186 DisplayIO.setCursor(Item.DEFAULT_CURSOR);
187 }
188 }
189 }
190
191 /**
192 * @param text
193 */
194 private static void justify(Text text) {
195 // Check if that text item is inside an enclosing rectangle...
196 // Set its max width accordingly
197 Polygon enclosure = FrameUtils.getEnlosingPolygon();
198 if (enclosure != null) {
199 Rectangle bounds = enclosure.getBounds();
200 text.setRightMargin(bounds.x + bounds.width);
201 } else {
202 text.setRightMargin(FrameGraphics.getMaxFrameSize().width);
203 }
204 }
205
206 public static Text replaceDot(Item dot, char ch) {
207 Text text = createText(ch);
208 Item.DuplicateItem(dot, text);
209 FrameUtils.setLastEdited(text);
210
211 // Copy the lines list so it can be modified
212 List<Line> lines = new LinkedList<Line>(dot.getLines());
213 for (Line line : lines)
214 line.replaceLineEnd(dot, text);
215 Frame current = dot.getParentOrCurrentFrame();
216 current.removeItem(dot);
217 ItemUtils.EnclosedCheck(current.getItems());
218 return text;
219 }
220
221 /**
222 * Replaces the given text item with a dot
223 */
224 public static Item replaceText(Item text) {
225 Item dot = new Dot(text.getX(), text.getY(), text.getID());
226 Item.DuplicateItem(text, dot);
227
228 List<Line> lines = new LinkedList<Line>();
229 lines.addAll(text.getLines());
230 if (lines.size() > 0)
231 dot.setColor(lines.get(0).getColor());
232 for (Line line : lines) {
233 line.replaceLineEnd(text, dot);
234 }
235 text.delete();
236 Frame current = text.getParentOrCurrentFrame();
237 current.addItem(dot);
238 DisplayIO.setCursor(Item.DEFAULT_CURSOR);
239 ItemUtils.EnclosedCheck(current.getItems());
240 return dot;
241 }
242
243 /**
244 * Creates a new Text Item whose text contains the given character. This
245 * method also moves the mouse cursor to be pointing at the newly created
246 * Text Item ready to insert the next character.
247 *
248 * @param start
249 * The character to use as the initial text of this Item.
250 * @return The newly created Text Item
251 */
252 private static Text createText(char start) {
253 Text t = DisplayIO.getCurrentFrame().createBlankText("" + start);
254
255 Point2D.Float newMouse = t.insertChar(start, DisplayIO.getMouseX(),
256 FrameMouseActions.getY());
257 DisplayIO.setCursorPosition(newMouse.x, newMouse.y, false);
258
259 return t;
260 }
261
262 /**
263 * Creates a new Text Item with no text. The newly created Item is a copy of
264 * any ItemTemplate if one is present, and inherits all the attributes of
265 * the Template
266 *
267 * @return The newly created Text Item
268 */
269 private static Text createText() {
270 return DisplayIO.getCurrentFrame().createNewText();
271 }
272
273 private void move(int direction, boolean isShiftDown) {
274 Item on = FrameUtils.getCurrentItem();
275
276 if (on == null) {
277 navigateFrame(direction);
278 return;
279 }
280
281 if (on instanceof Text) {
282 Text text = (Text) on;
283 // When the user hits the left and right button with mouse
284 // positions over the the frame name navigation occurs
285 if (text.isFrameName()) {
286 navigateFrame(direction);
287 return;
288 } else {
289 FrameUtils.setLastEdited(text);
290 if (!isShiftDown)
291 text.clearSelection();
292 DisplayIO.setTextCursor(text, direction, false, isShiftDown);
293 }
294 }
295 }
296
297 private void navigateFrame(int direction) {
298 switch (direction) {
299 case Text.RIGHT:
300 case Text.PAGE_UP:
301 NavigationActions.NextFrame(false);
302 break;
303 case Text.LEFT:
304 case Text.PAGE_DOWN:
305 NavigationActions.PreviousFrame(false);
306 break;
307 case Text.HOME:
308 case Text.LINE_HOME:
309 NavigationActions.ZeroFrame();
310 break;
311 case Text.END:
312 case Text.LINE_END:
313 NavigationActions.LastFrame();
314 break;
315 }
316 }
317
318 /**
319 * Receives and processes any Function, Control, and Escape key presses
320 *
321 * @param e
322 * The KeyEvent received from the keyboard
323 */
324 public void keyPressed(KeyEvent e) {
325 int keyCode = e.getKeyCode();
326 SessionStats.AddFrameEvent("k" + KeyEvent.getKeyText(keyCode));
327
328 FrameUtils.ResponseTimer.restart();
329 // e.consume();
330
331 if (Actions.isAgentRunning()) {
332 if (keyCode == KeyEvent.VK_ESCAPE)
333 Actions.stopAgent();
334 else
335 Actions.interruptAgent();
336 return;
337 } else if (Simple.consumeKeyboardInput()) {
338 return;
339 }
340
341 if (keyCode >= KeyEvent.VK_F1 && keyCode <= KeyEvent.VK_F12) {
342 functionKey(FunctionKey.values()[keyCode - KeyEvent.VK_F1 + 1], e
343 .isShiftDown(), e.isControlDown());
344 return;
345 } else if (e.isAltDown()) {
346 int distance = e.isShiftDown() ? 1 : 20;
347 switch (keyCode) {
348 case KeyEvent.VK_1:
349 FrameMouseActions.leftButton();
350 // DisplayIO.clickMouse(InputEvent.BUTTON1_MASK);
351 break;
352 case KeyEvent.VK_2:
353 // DisplayIO.clickMouse(InputEvent.BUTTON2_MASK);
354 FrameMouseActions.middleButton();
355 break;
356 case KeyEvent.VK_3:
357 // DisplayIO.clickMouse(InputEvent.BUTTON3_MASK);
358 FrameMouseActions.rightButton();
359 break;
360 case KeyEvent.VK_LEFT:
361 DisplayIO.translateCursor(-distance, 0);
362 break;
363 case KeyEvent.VK_RIGHT:
364 DisplayIO.translateCursor(distance, 0);
365 break;
366 case KeyEvent.VK_UP:
367 DisplayIO.translateCursor(0, -distance);
368 break;
369 case KeyEvent.VK_DOWN:
370 DisplayIO.translateCursor(0, distance);
371 break;
372 }
373 return;
374 } else if (e.isControlDown()) {
375 if (keyCode == KeyEvent.VK_CONTROL) {
376 FrameMouseActions.control(e);
377 } else {
378 controlChar(e.getKeyCode(), e.isShiftDown());
379 }
380 return;
381 }
382
383 switch (keyCode) {
384 case KeyEvent.VK_ESCAPE:
385 // Do escape after control so Ctl+Escape does not perform DropDown
386 functionKey(FunctionKey.DropDown, e.isShiftDown(), e
387 .isControlDown());
388 SessionStats.Escape();
389 break;
390 case KeyEvent.VK_LEFT:
391 move(Text.LEFT, e.isShiftDown());
392 break;
393 case KeyEvent.VK_RIGHT:
394 move(Text.RIGHT, e.isShiftDown());
395 break;
396 case KeyEvent.VK_PAGE_DOWN:
397 navigateFrame(Text.PAGE_DOWN);
398 break;
399 case KeyEvent.VK_PAGE_UP:
400 navigateFrame(Text.PAGE_UP);
401 break;
402 case KeyEvent.VK_UP:
403 if (e.isControlDown()) {
404 NextTextItem(FrameUtils.getCurrentItem(), false);
405 } else {
406 move(Text.UP, e.isShiftDown());
407 }
408 break;
409 case KeyEvent.VK_DOWN:
410 if (e.isControlDown()) {
411 NextTextItem(FrameUtils.getCurrentItem(), true);
412 } else {
413 move(Text.DOWN, e.isShiftDown());
414 }
415 break;
416 case KeyEvent.VK_END:
417 if (e.isControlDown())
418 move(Text.END, e.isShiftDown());
419 else
420 move(Text.LINE_END, e.isShiftDown());
421 break;
422 case KeyEvent.VK_HOME:
423 if (e.isControlDown())
424 move(Text.HOME, e.isShiftDown());
425 else
426 move(Text.LINE_HOME, e.isShiftDown());
427 break;
428 // TODO remove this when upgrading Java
429 // This is a patch because Java6 wont trigger KeyTyped event for
430 // Shift+Tab
431 case KeyEvent.VK_TAB:
432 if (e.isShiftDown()) {
433 e.setKeyChar('\t');
434 keyTyped(e);
435 }
436 break;
437 }
438 }
439
440 /**
441 * Moves the cursor to the next text item on the frame
442 *
443 * @param currentItem
444 * @param direction
445 * move up if direction is negative, down if direction is
446 * positive
447 */
448 public static void NextTextItem(Item currentItem, boolean down) {
449 // Move the cursor to the next text item
450 Frame current = DisplayIO.getCurrentFrame();
451 Item title = current.getTitleItem();
452
453 Collection<Text> currentItems = FrameUtils.getCurrentTextItems();
454 List<Text> textItems = new ArrayList<Text>();
455 // Move to the next text item in the box if
456 if (currentItems.contains(currentItem)) {
457 textItems.addAll(currentItems);
458 } else {
459 textItems.add(current.getTitleItem());
460 textItems.addAll(current.getBodyTextItems(true));
461 }
462
463 Collections.sort(textItems);
464
465 if (textItems.size() == 0) {
466 // If there are no text items on the frame its a NoOp
467 if (title == null)
468 return;
469 DisplayIO.MoveCursorToEndOfItem(title);
470 FrameGraphics.Repaint();
471 return;
472 }
473
474 // If the user is mouse wheeling in free space...
475 if (currentItem == null) {
476 // find the nearest item in the correct direction
477 int currY = FrameMouseActions.getY();
478 for (int i = 0; i < textItems.size(); i++) {
479 Item t = textItems.get(i);
480 if (currY < t.getY()) {
481 if (down) {
482 DisplayIO.MoveCursorToEndOfItem(t);
483 } else {
484 if (i == 0) {
485 DisplayIO.MoveCursorToEndOfItem(current
486 .getTitleItem());
487 } else {
488 DisplayIO.MoveCursorToEndOfItem(textItems
489 .get(i - 1));
490 }
491 }
492 FrameGraphics.Repaint();
493 return;
494 }
495 }
496 // If we are at the botton of the screen and the user scrolls down
497 // then scroll backup to the title
498 if (textItems.size() > 0) {
499 DisplayIO.MoveCursorToEndOfItem(textItems
500 .get(textItems.size() - 1));
501 }
502 return;
503 }
504
505 // Find the current item... then move to the next item
506 int i = textItems.indexOf(currentItem);
507
508 int nextIndex = i + (down ? 1 : -1);
509 if (nextIndex >= 0 && nextIndex < textItems.size()) {
510 DisplayIO.MoveCursorToEndOfItem(textItems.get(nextIndex));
511 } else {
512 DisplayIO.MoveCursorToEndOfItem(currentItem);
513 }
514 return;
515
516 }
517
518 /**
519 * Currently ignored.
520 */
521 public void keyReleased(KeyEvent e) {
522 if (e.getKeyCode() == KeyEvent.VK_CONTROL) {
523 FrameMouseActions.control(e);
524 } else if (e.isAltDown() || e.isControlDown()) {
525 // switch (e.getKeyCode()) {
526 // case KeyEvent.VK_1:
527 // DisplayIO.releaseMouse(InputEvent.BUTTON1_MASK);
528 // break;
529 // case KeyEvent.VK_2:
530 // DisplayIO.releaseMouse(InputEvent.BUTTON2_MASK);
531 // break;
532 // case KeyEvent.VK_3:
533 // DisplayIO.releaseMouse(InputEvent.BUTTON3_MASK);
534 // break;
535 // }
536 }
537 }
538
539 /**
540 * Used to add items to a frame when pasting text from the clipboard.
541 *
542 * @param text
543 * the next paragraph of text to be pasted.
544 * @param lastItem
545 * the item to drop from when pasting the next paragraph of text.
546 * @return the new text item created from pasting the text.
547 */
548 private static Item addTextItemToCurrentFrame(String text, Item lastItem,
549 boolean bDrop) {
550 if (text.trim().length() > 0) {
551 if (lastItem != null && bDrop)
552 Drop(lastItem, true);
553
554 Text textItem = createText();
555 textItem.setText(text.substring(0, text.length() - 1));
556
557 if (lastItem != null && !bDrop) {
558 textItem.setY(lastItem.getY() + lastItem.getBoundsHeight());
559 } else {
560 textItem.setY(FrameMouseActions.getY());
561 }
562 textItem.setX(FrameMouseActions.getX());
563 justify(textItem);
564 DisplayIO.getCurrentFrame().addItem(textItem);
565 return textItem;
566 }
567 return lastItem;
568 }
569
570 private static void copyItemToClipboard(Item on) {
571 if (on == null || !(on instanceof Text))
572 return;
573
574 Text text = (Text) on;
575 String string = text.copySelectedText();
576
577 if (string == null || string.length() == 0)
578 string = text.getText();
579
580 // add the text of the item to the clipboard
581 StringSelection selection = new StringSelection(string);
582 Toolkit.getDefaultToolkit().getSystemClipboard().setContents(selection,
583 null);
584 }
585
586 /**
587 * Processes all control character keystrokes. Currently Ctrl+C and Ctrl+V
588 * are copy and paste, all other keystrokes are ignored.
589 *
590 * @param ch
591 * The character being pressed along with the control key
592 */
593 private void controlChar(int key, boolean isShiftDown) {
594 Logger.Log(Logger.USER, Logger.CONTROL_CHAR, "User pressing: Ctrl+"
595 + KeyEvent.getKeyText(key));
596 //
597 // if (FrameUtils.getCurrentItem() == null
598 // && !Frame.itemAttachedToCursor()) {
599 // Item t = DisplayIO.getCurrentFrame().createNewText(ch + ": ");
600 // FrameMouseActions.pickup(t);
601 // } else {
602 // remove the link for alt+l
603 Item current = FrameUtils.getCurrentItem();
604 Frame currentFrame = DisplayIO.getCurrentFrame();
605 int distance = isShiftDown ? 1 : 20;
606 switch (key) {
607 case KeyEvent.VK_HOME:
608 if (current != null && current instanceof Text) {
609 move(Text.HOME, isShiftDown);
610 } else {
611 while (DisplayIO.Back())
612 ;
613 }
614 break;
615 case KeyEvent.VK_END:
616 if (current != null && current instanceof Text) {
617 move(Text.END, isShiftDown);
618 } else {
619 while (DisplayIO.Forward())
620 ;
621 }
622 break;
623 case KeyEvent.VK_PAGE_UP:
624 DisplayIO.Back();
625 break;
626 case KeyEvent.VK_PAGE_DOWN:
627 DisplayIO.Forward();
628 break;
629 case KeyEvent.VK_TAB:
630 FrameUtils.getCurrentItem().update();
631 break;
632 case KeyEvent.VK_ESCAPE:
633 // Do escape after control so Ctl+Escape does not perform DropDown
634 functionKey(FunctionKey.DropDown, isShiftDown, true);
635 SessionStats.Escape();
636 break;
637 case KeyEvent.VK_1:
638 FrameMouseActions.leftButton();
639 // DisplayIO.clickMouse(InputEvent.BUTTON1_MASK);
640 break;
641 case KeyEvent.VK_2:
642 FrameMouseActions.middleButton();
643 // DisplayIO.clickMouse(InputEvent.BUTTON2_MASK);
644 break;
645 case KeyEvent.VK_3:
646 FrameMouseActions.rightButton();
647 // DisplayIO.clickMouse(InputEvent.BUTTON3_MASK);
648 break;
649 case KeyEvent.VK_LEFT:
650 DisplayIO.translateCursor(-distance, 0);
651 break;
652 case KeyEvent.VK_RIGHT:
653 DisplayIO.translateCursor(distance, 0);
654 break;
655 case KeyEvent.VK_UP:
656 if (current instanceof Text) {
657 NextTextItem(FrameUtils.getCurrentItem(), false);
658 } else {
659 DisplayIO.translateCursor(0, -distance);
660 }
661 break;
662 case KeyEvent.VK_DOWN:
663 if (current instanceof Text) {
664 NextTextItem(FrameUtils.getCurrentItem(), true);
665 } else {
666 DisplayIO.translateCursor(0, distance);
667 }
668 break;
669 case KeyEvent.VK_L:
670 // If its not linked then link it to its self
671 if (current instanceof Text && current.getLink() == null) {
672 String text = ((Text) current).getText();
673 // Ignore the annotation if there is one
674 if (text.charAt(0) == '@')
675 text = text.substring(1);
676
677 if (FrameIO.isValidFrameName(text)) {
678 current.setLink(text);
679 } else if (FrameIO.isValidFramesetName(text)) {
680 current.setLink(text + '1');
681 }
682 } else {
683 // If its linked remove the link
684 current.setLink(null);
685 }
686 break;
687 case KeyEvent.VK_G:
688 // If its not linked then link it to its self
689 if (current instanceof Text) {
690 String text = ((Text) current).getText();
691 if (text.charAt(0) == '@')
692 text = text.substring(1);
693
694 if (FrameIO.isValidFrameName(text)) {
695 current.setLink(text);
696 } else if (FrameIO.isValidFramesetName(text)) {
697 current.setLink(text + '1');
698 }
699 }
700 if (current.getLink() != null) {
701 NavigationActions.Goto(current.getAbsoluteLink());
702 return;
703 }
704 break;
705 case KeyEvent.VK_A:
706 // If its not linked then link it to its self
707 if (current instanceof Text) {
708 if (!current.hasAction()) {
709 String text = ((Text) current).getText().trim();
710 // first trim the annotation
711 if (text.startsWith("@")) {
712 text = text.substring(1).trim();
713 }
714 // then trim the action
715 String lowerCaseText = text.toLowerCase();
716 if (lowerCaseText.startsWith("a:")) {
717 text = text.substring("a:".length()).trim();
718 } else if (lowerCaseText.startsWith("action:")) {
719 text = text.substring("action:".length()).trim();
720
721 }
722 current.setAction(text);
723 } else {
724 // If its linked remove the link
725 current.setActions(null);
726 }
727 }
728 break;
729 case KeyEvent.VK_V:
730 try {
731 // read in the data from the clipboard
732 String clip = ((String) Toolkit.getDefaultToolkit()
733 .getSystemClipboard().getContents(null)
734 .getTransferData(DataFlavor.stringFlavor));
735 // Covert the line separator char when pasting in
736 // windows (\r\n) or max (\r)
737 clip = StringUtils.convertNewLineChars(clip);
738
739 Item clicked = FrameUtils.getCurrentItem();
740
741 if (clicked != null) {
742 // check permissions
743 if (!clicked.hasPermission(Permission.full)
744 && clicked.getParent() != null
745 && clicked.getParent().getNameItem() != clicked) {
746 MessageBay.displayMessage("Insufficient Permission");
747 return;
748 }
749
750 Text text = createText();
751 text.setText(clip);
752 List<Item> clipboard = new ArrayList<Item>();
753 clipboard.add(text);
754 FrameMouseActions.merge(clipboard, clicked);
755 text.delete();
756 } else {
757 StringTokenizer st = new StringTokenizer(clip, "\n", true);
758
759 String temp = "";
760 // int y = FrameMouseActions.getY();
761 Item lastItem = null;
762
763 boolean drop = currentFrame.hasAnnotation("more");
764 // separate the clipboard content into items based on
765 // blank lines
766 while (st.hasMoreTokens()) {
767 String s = st.nextToken();
768 // if this is a blank line, then it is an item separator
769 if (s.trim().length() == 0) {
770 lastItem = addTextItemToCurrentFrame(temp,
771 lastItem, drop);
772 temp = "";
773 } else {
774 temp += s + "\n";
775 if (st.hasMoreTokens())
776 st.nextToken();
777 }
778 }
779 // the last item will not be finished by the above loop
780 addTextItemToCurrentFrame(temp, lastItem, drop);
781 FrameIO.ForceSaveFrame(DisplayIO.getCurrentFrame());
782 DisplayIO.setCurrentFrame(currentFrame, false);
783 }
784 } catch (Exception ex) {
785 }
786 // if this is a copy command
787 break;
788 case KeyEvent.VK_C:
789 if (current == null)
790 return;
791
792 if (current instanceof Text) {
793 if (current != null && !current.hasPermission(Permission.copy)) {
794 MessageBay
795 .displayMessage("Insufficient permission to copy that item");
796 return;
797 }
798 copyItemToClipboard(current);
799 // MessageBay.displayMessage("Item copied to clipboard");
800 return;
801 }
802 if (current != null && !current.hasPermission(Permission.full)) {
803 MessageBay
804 .displayMessage("Insufficient permission edit that item");
805 return;
806 }
807 Text item = null;
808 // Check if its a line to be turned into a circle
809 if (current instanceof Dot && current.getLines().size() == 1) {
810 item = replaceDot(current, '@');
811 } else if (current instanceof Line
812 && current.getAllConnected().size() == 3) {
813 Item end = ((Line) current).getEndItem();
814 if (end instanceof Dot) {
815 item = replaceDot(end, '@');
816 } else if (end instanceof Text) {
817 item = (Text) end;
818 }
819 }
820 item.setText("@c");
821 DisplayIO.setCursorPosition(item.getX(), item.getY());
822 FrameUtils.setLastEdited(null);
823 Refresh();
824 return;
825 case KeyEvent.VK_X:
826 if (current == null)
827 return;
828 if (current != null && !current.hasPermission(Permission.full)) {
829 MessageBay
830 .displayMessage("Insufficient permission to cut that item");
831 return;
832 }
833 copyItemToClipboard(current);
834 if (current instanceof Text && ((Text) current).hasSelection()) {
835 ((Text) current).cutSelectedText();
836 ((Text) current).clearSelection();
837 } else {
838 FrameMouseActions.delete(current);
839 }
840 return;
841 case KeyEvent.VK_M:
842 if (current == null)
843 return;
844 if (current != null && !current.hasPermission(Permission.full)) {
845 MessageBay
846 .displayMessage("Insufficient permission toggle the items mark");
847 return;
848 }
849 boolean newValue = !(current.getLinkMark() || current
850 .getActionMark());
851 current.setLinkMark(newValue);
852 current.setActionMark(newValue);
853 break;
854 case KeyEvent.VK_Z:
855 DisplayIO.getCurrentFrame().undo();
856 return;
857 case KeyEvent.VK_D:
858 // perform a delete operation
859 processChar((char) KeyEvent.VK_DELETE, isShiftDown);
860 break;
861 case KeyEvent.VK_DELETE:
862 // perform a delete operation
863 FrameMouseActions.delete(current);
864 break;
865 case KeyEvent.VK_SPACE:
866 if (isShiftDown) {
867 FrameMouseActions.rightButton();
868 } else {
869 FrameMouseActions.middleButton();
870 }
871 break;
872 case KeyEvent.VK_F:
873 // perform a delete operation
874 Actions.PerformActionCatchErrors(currentFrame, null, "Format");
875 return;
876 case KeyEvent.VK_J:
877 Text text = getCurrentTextItem();
878 if (text == null) {
879 for (Text t : FrameUtils.getCurrentTextItems()) {
880 justify(t);
881 }
882
883 return;
884 }
885
886 // if (text.getWidth() < 0)
887 // text.setWidth(text.getBoundsWidth() - Item.MARGIN_RIGHT
888 // - UserSettings.Gravity);
889 justify(text);
890 break;
891 case KeyEvent.VK_S:
892 Text text2 = getCurrentTextItem();
893 // split the current text item
894 if (text2 == null)
895 return;
896 List<String> textLines = text2.getTextList();
897 if (textLines.size() <= 1)
898 return;
899 // remove all except the first line of text from the item being
900 // split
901 text2.setText(textLines.get(0));
902 int y = text2.getY();
903 for (int i = 1; i < textLines.size(); i++) {
904 Text newText = text2.copy();
905 newText.setText(textLines.get(i));
906 y += newText.getBoundsHeight();
907 newText.setY(y);
908 // update the items ID to prevent conflicts with the current
909 // frame
910 newText.setID(currentFrame.getNextItemID());
911 currentFrame.addItem(newText);
912 }
913 break;
914 case KeyEvent.VK_ENTER:
915 FrameMouseActions.leftButton();
916 break;
917 case KeyEvent.VK_BACK_SPACE:
918 DisplayIO.Back();
919 break;
920 }
921 FrameGraphics.Repaint();
922 }
923
924 /**
925 * Gets the currently selected item if the user is allowed to modify it.
926 *
927 * @return null if the currently selected item is not a Text item that the
928 * user has permission to modify
929 */
930 private static Text getCurrentTextItem() {
931 Item item = FrameUtils.getCurrentItem();
932
933 if (item != null && !item.hasPermission(Permission.full)) {
934 MessageBay
935 .displayMessage("Insufficient permission to copy that item");
936 return null;
937 }
938
939 Item on = null;
940 if (item != null)
941 on = item;
942
943 if (on == null || !(on instanceof Text))
944 return null;
945
946 return (Text) on;
947 }
948
949 public static void functionKey(FunctionKey key, boolean isShiftDown,
950 boolean isControlDown) {
951 functionKey(key, 1, isShiftDown, isControlDown);
952 }
953
954 /**
955 * Called when a Function key has been pressed, and performs the specific
956 * action based on the key.
957 */
958 public static void functionKey(FunctionKey key, int repeat,
959 boolean isShiftDown, boolean isControlDown) {
960 // get whatever the user is pointing at
961 Item on = FrameUtils.getCurrentItem();
962
963 // check for enclosed mode
964 if (on == null && key.ordinal() < FunctionKey.AudienceMode.ordinal()) {
965 Collection<Item> enclosed = FrameUtils.getCurrentItems(on);
966
967 if (enclosed != null && enclosed.size() > 0) {
968 // ensure only one dot\line is present in the list
969 Collection<Item> lineEnds = FrameUtils.getEnclosingLineEnds();
970 Item firstConnected = lineEnds.iterator().next();
971 Collection<Item> connected = firstConnected.getAllConnected();
972
973 switch (key) {
974 case DropDown:
975 // Get the last text item and drop from in
976 Item lastText = null;
977 for (Item i : enclosed) {
978 if (i instanceof Text) {
979 lastText = i;
980 }
981 }
982 // Drop from the item if there was a text item in the box
983 if (lastText != null) {
984 Drop(lastText, false);
985 } else {
986 // Move to the top of the box
987 Rectangle rect = firstConnected.getEnclosedShape()
988 .getBounds();
989 DisplayIO.setCursorPosition(rect.x + Text.MARGIN_LEFT,
990 Text.MARGIN_LEFT
991 + rect.y
992 + DisplayIO.getCurrentFrame()
993 .getItemTemplate()
994 .getBoundsHeight());
995 }
996 break;
997 case SizeUp:
998 SetSize(firstConnected, repeat, false, true);
999 break;
1000 case SizeDown:
1001 SetSize(firstConnected, -repeat, false, true);
1002 break;
1003 case ChangeColor:
1004 if (connected.size() > 0) {
1005 for (Item d : lineEnds) {
1006 if (isControlDown)
1007 SetGradientColor(d, isShiftDown);
1008 else
1009 SetFillColor(d, isShiftDown);
1010 break;
1011 }
1012 }
1013 break;
1014 case ToggleAnnotation:
1015 ToggleAnnotation(firstConnected);
1016 break;
1017 case ChangeFontStyle:
1018 ToggleFontStyle(firstConnected);
1019 break;
1020 case ChangeFontFamily:
1021 ToggleFontFamily(firstConnected);
1022 break;
1023 case InsertDate:
1024 AddDate(firstConnected);
1025 break;
1026 }
1027 return;
1028 }
1029 }
1030 String displayMessage = "F" + key.ordinal() + ": " + key.toString();
1031 // Show a description of the function key pressed if the user is in free
1032 // space and return for the F keys that dont do anything in free space.
1033 if (on == null) {
1034 switch (key) {
1035 // These function keys still work in free space
1036 case DropDown:
1037 case InsertDate:
1038 case XRayMode:
1039 case AudienceMode:
1040 case Refresh:
1041 break;
1042 default:
1043 MessageBay.displayMessageOnce(displayMessage);
1044 return;
1045 }
1046 }
1047
1048 switch (key) {
1049 case DropDown:
1050 if (isShiftDown || isControlDown) {
1051 if (on != null) {
1052 on.update();
1053 }
1054 }
1055 Drop(on, false);
1056 return;
1057 case SizeUp:
1058 SetSize(on, repeat, true, false);
1059 if (on instanceof Text) {
1060 DisplayIO.setTextCursor((Text) on, Text.NONE, true, false);
1061 }
1062 break;
1063 case SizeDown:
1064 SetSize(on, -repeat, true, false);
1065 if (on instanceof Text) {
1066 DisplayIO.setTextCursor((Text) on, Text.NONE, true, false);
1067 }
1068 break;
1069 case ChangeColor:
1070 SetColor(on, isShiftDown, isControlDown);
1071 break;
1072 case ToggleAnnotation:
1073 ToggleAnnotation(on);
1074 break;
1075 case ChangeFontStyle:
1076 ToggleFontStyle(on);
1077 break;
1078 case ChangeFontFamily:
1079 ToggleFontFamily(on);
1080 break;
1081 case InsertDate:
1082 AddDate(on);
1083 return;
1084 case NewFrameset:
1085 CreateFrameset(on);
1086 break;
1087 case XRayMode:
1088 FrameGraphics.ToggleXRayMode();
1089 break;
1090 case AudienceMode:
1091 FrameGraphics.ToggleAudienceMode();
1092 break;
1093 case Refresh:
1094 Refresh();
1095 break;
1096 }
1097 on = FrameUtils.getCurrentItem();
1098 Collection<Item> enclosed = FrameUtils.getCurrentItems(on);
1099 if (on == null && (enclosed == null || enclosed.size() == 0))
1100 MessageBay.displayMessage(displayMessage);
1101 }
1102
1103 public static final String DEFAULT_NEW_ITEM_TEXT = "";
1104
1105 public static final String SHORT_DATE_FORMAT = "ddMMMyyyy";
1106
1107 public static final String LONG_DATE_FORMAT = "ddMMMyyyy[HH:mm]";
1108
1109 /**
1110 * Performs the dropping action: If the cursor is in free space then: the
1111 * cursor is repositioned below the last non-annotation text item. If the
1112 * cursor is on an item, and has items attached then: the cusor is
1113 * positioned below the pointed to item, and the items below are 'pushed
1114 * down' to make room.
1115 *
1116 * @param toDropFrom
1117 * The Item being pointed at by the mouse, may be null to
1118 * indicate the cursor is in free space.
1119 */
1120 private static void Drop(Item toDropFrom, boolean bPasting) {
1121 try {
1122 FrameUtils.setLastEdited(null);
1123
1124 String newItemText = DEFAULT_NEW_ITEM_TEXT;
1125
1126 // if a line is being rubber-banded, this is a no-op
1127 if (Frame.rubberbandingLine())
1128 return; // No-op
1129
1130 // if the cursor is in free space then the drop will happen from the
1131 // last non annotation text item on the frame
1132 if (toDropFrom == null) {
1133 toDropFrom = DisplayIO.getCurrentFrame()
1134 .getLastNonAnnotationTextItem();
1135 }
1136
1137 // if no item was found, return
1138 if (toDropFrom == null) {
1139 MessageBay.errorMessage("No item could be found to drop from");
1140 return;
1141 }
1142
1143 if (!(toDropFrom instanceof Text)) {
1144 MessageBay
1145 .displayMessage("Only text items can be dropped from");
1146 return;
1147 }
1148
1149 // Get the list of items that must be dropped
1150 List<Text> column = DisplayIO.getCurrentFrame().getColumn(
1151 toDropFrom);
1152
1153 if (column == null) {
1154 MessageBay.errorMessage("No column found to align items to");
1155 return;
1156 }
1157
1158 Item title = DisplayIO.getCurrentFrame().getTitleItem();
1159
1160 // We wont do auto bulleting when dropping from titles
1161 if (!bPasting && toDropFrom != title) {
1162 newItemText = getAutoBullet(((Text) toDropFrom).getFirstLine());
1163 }
1164
1165 Text dummyItem = null;
1166
1167 if (!bPasting && FreeItems.textOnlyAttachedToCursor()) {
1168 dummyItem = (Text) FreeItems.getItemAttachedToCursor();
1169 String autoBullet = getAutoBullet(dummyItem.getText());
1170
1171 if (autoBullet.length() > 0)
1172 newItemText = "";
1173 dummyItem.setText(newItemText + dummyItem.getText());
1174 }
1175 dummyItem = createText();
1176 if (FreeItems.textOnlyAttachedToCursor()) {
1177 Text t = (Text) FreeItems.getItemAttachedToCursor();
1178 dummyItem.setSize(t.getSize());
1179 int lines = t.getTextList().size();
1180 for (int i = 0; i < lines; i++) {
1181 newItemText += '\n';
1182 }
1183 }
1184
1185 dummyItem.setText(newItemText);
1186
1187 // If the only item on the frame is the title and the frame name
1188 // goto the zero frame and drop to the @start if there is one
1189 // or a fixed amount if there is not
1190 if (column.size() == 0) {
1191 Frame current = DisplayIO.getCurrentFrame();
1192 Item itemTemplate = current.getItemTemplate();
1193 int xPos = title.getX();
1194 int yPos = title.getY() + title.getBoundsHeight()
1195 + itemTemplate.getBoundsHeight();
1196 // Check for @start on the zero frame
1197 Frame zero = FrameIO.LoadFrame(current.getFramesetName() + '0');
1198 Text start = zero.getAnnotation("start");
1199 if (start != null) {
1200 xPos = start.getX();
1201 yPos = start.getY();
1202 }
1203
1204 dummyItem.setPosition(xPos, yPos);
1205 DisplayIO.setCursorPosition(xPos, yPos);
1206 } else {
1207 int yPos = column.get(0).getY() + 1;
1208 // Either position the new item below the title or just above
1209 // the first item below the title
1210 if (toDropFrom == title)
1211 yPos = Math.min(column.get(0).getY() - 1, title.getY()
1212 + title.getBoundsHeight()
1213 + dummyItem.getBoundsHeight());
1214 dummyItem.setPosition(column.get(0).getX(), yPos);
1215 column.add(dummyItem);
1216 FrameUtils.Align(column, false, 0);
1217 // Check if it will be outside the frame area
1218 if (dummyItem.getY() < 0
1219 || dummyItem.getY() > FrameGraphics.getMaxFrameSize()
1220 .getHeight()) {
1221 // Check for the @more tag!
1222 Frame current = DisplayIO.getCurrentFrame();
1223 Item i = current.getAnnotation("more");
1224
1225 if (i != null) {
1226 Frame firstFrame = current;
1227 boolean mouseMoved = FrameMouseActions.tdfc(i);
1228 Frame moreFrame = DisplayIO.getCurrentFrame();
1229 // Add the @more if we are pasting
1230 if (bPasting) {
1231 Item copy = i.copy();
1232 copy.setLink(null);
1233 moreFrame.addItem(copy);
1234 }
1235
1236 moreFrame.setTitle(firstFrame.getTitleItem().getText());
1237 // need to move the mouse to the top of the frame if
1238 // there
1239 // wasnt an @start on it
1240 if (!mouseMoved) {
1241 Item moreTitle = moreFrame.getTitleItem();
1242 moreTitle.setPermission(Permission.full);
1243 Drop(moreTitle, bPasting);
1244 }
1245 // Add the bullet text to the item
1246 dummyItem.setPosition(DisplayIO.getMouseX(),
1247 FrameMouseActions.getY());
1248 } else {
1249 MessageBay
1250 .warningMessage("Can not create items outside the frame area");
1251 // ensures correct repainting when items don't move
1252 DisplayIO.setCursorPosition(DisplayIO.getMouseX(),
1253 FrameMouseActions.getY());
1254 return;
1255 }
1256 }
1257 if (!FreeItems.textOnlyAttachedToCursor()
1258 && !dummyItem.isEmpty()) {
1259 DisplayIO.getCurrentFrame().addItem(dummyItem);
1260 }
1261
1262 // Move the item to the cursor position
1263 if (FreeItems.itemsAttachedToCursor()) {
1264 DisplayIO.setCursorPosition(dummyItem.getX(), dummyItem
1265 .getY());
1266 Item firstItem = FreeItems.getItemAttachedToCursor();
1267 int deltaX = firstItem.getX() - dummyItem.getX();
1268 int deltaY = firstItem.getY() - dummyItem.getY();
1269
1270 for (Item i : FreeItems.getInstance()) {
1271 i.setPosition(i.getX() - deltaX, i.getY() - deltaY);
1272 }
1273 } else {
1274 DisplayIO.MoveCursorToEndOfItem(dummyItem);
1275 }
1276 }
1277 if (dummyItem.getText().length() == 0
1278 || FreeItems.itemsAttachedToCursor()) {
1279 dummyItem.getParentOrCurrentFrame().removeItem(dummyItem);
1280 dummyItem.setRightMargin(FrameGraphics.getMaxFrameSize().width);
1281 } else {
1282 dummyItem.setWidth(toDropFrom.getWidth());
1283 }
1284
1285 DisplayIO.resetCursorOffset();
1286 FrameGraphics.Repaint();
1287 } catch (RuntimeException e) {
1288 // MessageBay.errorMessage(e.getMessage());
1289 e.printStackTrace();
1290 }
1291 }
1292
1293 /**
1294 * Gets the next letter sequence for a given string to be used in auto
1295 * lettering.
1296 *
1297 * @param s
1298 * a sequence of letters
1299 * @return the next sequence of letters
1300 */
1301 static private String nextLetterSequence(String s) {
1302 if (s.length() > 1)
1303 return s;
1304
1305 if (s.equals("z"))
1306 return "a";
1307
1308 return (char) ((int) s.charAt(0) + 1) + "";
1309 }
1310
1311 public static String getBullet(String s) {
1312 return getBullet(s, false);
1313 }
1314
1315 public static String getAutoBullet(String s) {
1316 return getBullet(s, true);
1317 }
1318
1319 private static String getBullet(String s, boolean nextBullet) {
1320 String newItemText = DEFAULT_NEW_ITEM_TEXT;
1321
1322 if (s == null)
1323 return newItemText;
1324 /*
1325 * Item i = ItemUtils.FindTag(DisplayIO.getCurrentFrame().getItems(),
1326 * "@NoAutoBullets"); if (i != null) return newItemText;
1327 */
1328 // Separate the space at the start of the text item
1329 String preceedingSpace = "";
1330 for (int i = 0; i < s.length(); i++) {
1331 if (!Character.isSpaceChar(s.charAt(i))) {
1332 preceedingSpace = s.substring(0, i);
1333 s = s.substring(i);
1334 break;
1335 }
1336 }
1337
1338 // figure out the type of the text item
1339 // This allows us to do auto bulleting
1340 if (s != null && s.length() > 1) {
1341 // First check for text beginning with * @ # etc
1342 // These are simple auto bullets
1343 if (!Character.isLetterOrDigit(s.charAt(0))
1344 && !Character.isSpaceChar(s.charAt(0))) {
1345 if (Text.isBulletChar(s.charAt(0))) {
1346 int nonSpaceIndex = 1;
1347 // Find the end of the bullet and space after the bullet
1348 while (nonSpaceIndex < s.length()
1349 && s.charAt(nonSpaceIndex) == ' ') {
1350 nonSpaceIndex++;
1351 }
1352 // we must have a special char followed by >= 1 space
1353 if (nonSpaceIndex > 1)
1354 newItemText = s.substring(0, nonSpaceIndex);
1355 }
1356 // Auto numbering and lettering
1357 } else {
1358 if (Character.isDigit(s.charAt(0))) {
1359 newItemText = getAutoNumber(s, nextBullet);
1360 // Auto lettering
1361 } else if (Character.isLetter(s.charAt(0))) {
1362 newItemText = getAutoLetter(s, nextBullet);
1363 }
1364 }
1365 }
1366 return preceedingSpace + newItemText;
1367 }
1368
1369 private static boolean isAutoNumberOrLetterChar(char c) {
1370 return c == ':' || c == '-' || c == '.' || c == ')' || c == '>';
1371 }
1372
1373 /**
1374 * Gets the string to be used to start the next auto numbered text item.
1375 *
1376 * @param s
1377 * the previous text item
1378 * @return the beginning of the next auto numbered text item
1379 */
1380 private static String getAutoNumber(String s, boolean nextBullet) {
1381 String newItemText = DEFAULT_NEW_ITEM_TEXT;
1382
1383 int nonDigitIndex = 1;
1384 while (Character.isDigit(s.charAt(nonDigitIndex))) {
1385 nonDigitIndex++;
1386
1387 if (nonDigitIndex + 1 >= s.length())
1388 return DEFAULT_NEW_ITEM_TEXT;
1389 }
1390
1391 if (isAutoNumberOrLetterChar(s.charAt(nonDigitIndex))) {
1392
1393 // we must have a number followed one non letter
1394 // then one or more spaces
1395 int nonSpaceIndex = nonDigitIndex + 1;
1396 while (nonSpaceIndex < s.length() && s.charAt(nonSpaceIndex) == ' ') {
1397 nonSpaceIndex++;
1398 }
1399
1400 if (nonSpaceIndex > nonDigitIndex + 1) {
1401 if (nextBullet)
1402 newItemText = (Integer.parseInt(s.substring(0,
1403 nonDigitIndex)) + 1)
1404 + s.substring(nonDigitIndex, nonSpaceIndex);
1405 else
1406 newItemText = s.substring(0, nonSpaceIndex);
1407 }
1408 }
1409 return newItemText;
1410 }
1411
1412 /**
1413 * Gets the string to be used to start the next auto lettered text item.
1414 *
1415 * @param s
1416 * the previous text items
1417 * @return the initial text for the new text item
1418 */
1419 private static String getAutoLetter(String s, boolean nextBullet) {
1420 String newItemText = DEFAULT_NEW_ITEM_TEXT;
1421
1422 int nonLetterIndex = 1;
1423
1424 if (isAutoNumberOrLetterChar(s.charAt(nonLetterIndex))) {
1425
1426 // Now search for the next non space character
1427 int nonSpaceIndex = nonLetterIndex + 1;
1428 while (nonSpaceIndex < s.length() && s.charAt(nonSpaceIndex) == ' ') {
1429 nonSpaceIndex++;
1430 }
1431
1432 // If there was a space then we have reached the end of our auto
1433 // text
1434 if (nonSpaceIndex > nonLetterIndex + 1) {
1435 if (nextBullet)
1436 newItemText = nextLetterSequence(s.substring(0,
1437 nonLetterIndex))
1438 + s.substring(nonLetterIndex, nonSpaceIndex);
1439 else
1440 newItemText = s.substring(0, nonSpaceIndex);
1441 }
1442 }
1443 return newItemText;
1444 }
1445
1446 /**
1447 * Adjusts the size of the given Item, by the given amount. Note: The amount
1448 * is relative and can be positive or negative.
1449 *
1450 * @param toSet
1451 * The Item whose size is to be adjusted
1452 * @param diff
1453 * The amount to adjust the Item's size by
1454 * @param moveCursor
1455 * true if the cursor position should be automatically adjusted
1456 * with resizing
1457 */
1458 public static void SetSize(Item item, int diff, boolean moveCursor,
1459 boolean insideEnclosure) {
1460 Collection<Item> toSize = new HashSet<Item>();
1461 // the mouse is only moved when the Item is on the frame, not free
1462 // boolean moveMouse = false;
1463 Item toSet = null;
1464
1465 // if the user is not pointing to any item
1466 if (item == null) {
1467 if (FreeItems.itemsAttachedToCursor())
1468 toSize.addAll(FreeItems.getInstance());
1469 else {
1470 MessageBay
1471 .displayMessage("There are no Items selected on the Frame or on the Cursor");
1472 return;
1473 }
1474 } else {
1475 if (item.isFrameName()) {
1476 MessageBay.displayMessage("Can not resize the frame name");
1477 return;
1478 }
1479 // check permissions
1480 if (!item.hasPermission(Permission.full)) {
1481 MessageBay
1482 .displayMessage("Insufficient permission to change the size of that item");
1483 return;
1484 }
1485 toSet = item;
1486 // For resizing enclosures pick up everything that is attached to
1487 // items partly in the enclosure
1488 // TODO make this only pick up stuff COMPLETELY enclosed... if we
1489 // change copying to copy only the stuff completely enclosed
1490 if (insideEnclosure) {
1491 for (Item i : FrameUtils.getCurrentItems(toSet)) {
1492 if (i.hasPermission(Permission.full) && !toSize.contains(i))
1493 toSize.addAll(i.getAllConnected());
1494 }
1495 }// Enclosed circle centers are resized with the center as origin
1496 // Just add the circle center to the list of items to size
1497 else if (!toSet.hasEnclosures() && !(toSet instanceof Text)
1498 && toSet.isLineEnd()) {
1499 toSize.addAll(toSet.getLines());
1500 } else if (toSet instanceof Line) {
1501 Line line = (Line) toSet;
1502 float current = Math.abs(line.getThickness());
1503 current = Math.max(current + diff, Item.MINIMUM_THICKNESS);
1504 line.setThickness(current);
1505 FrameGraphics.Repaint();
1506 return;
1507 } else {
1508 toSize.add(toSet);
1509 }
1510 }
1511
1512 Point2D origin = new Point2D.Float(FrameMouseActions.MouseX,
1513 FrameMouseActions.MouseY);
1514 // Inside enclosures increase the size of the enclosure
1515 double ratio = (100.0 + diff * 2) / 100.0;
1516 if (insideEnclosure) {
1517 Collection<Item> done = new HashSet<Item>();
1518 // adjust the size of all the items
1519 for (Item i : toSize) {
1520 if (done.contains(i))
1521 continue;
1522
1523 if (i.isLineEnd()) {
1524 Collection<Item> allConnected = i.getAllConnected();
1525 done.addAll(allConnected);
1526 for (Item it : allConnected) {
1527 it.translate(origin, ratio);
1528 it
1529 .setArrowheadLength((float) (it
1530 .getArrowheadLength() * ratio));
1531 }
1532 i.setThickness((float) (i.getThickness() * ratio));
1533 } else if (i instanceof XRayable) {
1534 i.translate(origin, ratio);
1535 i.setThickness((float) (i.getThickness() * ratio));
1536 done.add(i);
1537 } else if (i instanceof Text) {
1538 i.translate(origin, ratio);
1539 i.setSize((float) (i.getSize() * ratio));
1540 done.add(i);
1541 }
1542 }
1543 FrameGraphics.Repaint();
1544 return;
1545 }
1546
1547 // adjust the size of all the items
1548 for (Item i : toSize) {
1549 // Lines and dots use thickness, not size
1550 if (i.hasEnclosures()) {
1551 Circle c = (Circle) i.getEnclosures().iterator().next();
1552 c.setSize(c.getSize() * (float) ratio);
1553 } else if (i instanceof Line || i instanceof Circle
1554 && !insideEnclosure) {
1555 float current = Math.abs(i.getThickness());
1556 current = Math.max(current + diff, Item.MINIMUM_THICKNESS);
1557 i.setThickness(current);
1558 } else if (i instanceof Dot) {
1559 Item dot = (Item) i;
1560 float current = Math.abs(dot.getThickness());
1561 current = Math.max(current + diff, Item.MINIMUM_THICKNESS);
1562 dot.setThickness(current);
1563 } else {
1564 float oldSize = Math.abs(i.getSize());
1565 float newSize = Math
1566 .max(oldSize + diff, Item.MINIMUM_THICKNESS);
1567 float resizeRatio = newSize / oldSize;
1568 // Set size for Picture also translates
1569 i.setSize(newSize);
1570 if (i instanceof Text && i.getSize() != oldSize) {
1571 i.translate(origin, resizeRatio);
1572 }
1573 }
1574 }
1575
1576 if (toSet != null)
1577 toSet.getParent().setChanged(true);
1578
1579 FrameGraphics.Repaint();
1580 }
1581
1582 private static void SetFillColor(Item item, boolean setTransparent) {
1583 if (item == null)
1584 return;
1585
1586 if (!item.hasPermission(Permission.full)) {
1587 MessageBay
1588 .displayMessage("Insufficient permission to change fill color");
1589 return;
1590 }
1591
1592 Item toSet = item;
1593 Color color = toSet.getFillColor();
1594 if (setTransparent)
1595 color = null;
1596 else
1597 color = ColorUtils.getNextColor(color, Item.FILL_COLOR_WHEEL, toSet
1598 .getGradientColor());
1599
1600 // if (color == null) {
1601 // MessageBay.displayMessage("FillColor is now transparent");
1602 // }
1603
1604 toSet.setFillColor(color);
1605 toSet.getParent().setChanged(true);
1606
1607 FrameGraphics.Repaint();
1608 }
1609
1610 private static void SetGradientColor(Item item, boolean setTransparent) {
1611 if (item == null)
1612 return;
1613
1614 if (!item.hasPermission(Permission.full)) {
1615 MessageBay
1616 .displayMessage("Insufficient permission to change gradient color");
1617 return;
1618 }
1619
1620 Item toSet = item;
1621 Color color = toSet.getGradientColor();
1622 if (setTransparent)
1623 color = null;
1624 else
1625 color = ColorUtils.getNextColor(color, Item.COLOR_WHEEL, toSet
1626 .getFillColor());
1627
1628 // if (color == null) {
1629 // MessageBay.displayMessage("FillColor is now transparent");
1630 // }
1631
1632 toSet.setGradientColor(color);
1633 toSet.getParent().setChanged(true);
1634
1635 FrameGraphics.Repaint();
1636 }
1637
1638 /**
1639 * Sets the colour of the current Item based on its current colour. The
1640 * colours proceed in the order stored in COLOR_WHEEL.
1641 *
1642 * @param toSet
1643 * The Item whose colour is to be changed
1644 */
1645 private static void SetColor(Item item, boolean setTransparent,
1646 boolean setBackgroundColor) {
1647 // first determine the next color
1648 Color color = null;
1649 Frame currentFrame = DisplayIO.getCurrentFrame();
1650 if (item == null) {
1651 if (FreeItems.itemsAttachedToCursor()) {
1652 color = FreeItems.getInstance().get(0).getColor();
1653 } else {
1654 return;
1655 }
1656 // change the background color if the user is pointing on the
1657 // frame name
1658 } else if (item == currentFrame.getNameItem()) {
1659 // check permissions
1660 if (!item.hasPermission(Permission.full)) {
1661 MessageBay
1662 .displayMessage("Insufficient permission to the frame's background color");
1663 return;
1664 }
1665 if (setTransparent)
1666 currentFrame.setBackgroundColor(null);
1667 else
1668 currentFrame.toggleBackgroundColor();
1669 // Display a message if the color has changed to transparent
1670 // if (currentFrame.getBackgroundColor() == null)
1671 // FrameGraphics
1672 // .displayMessage("Background color is now transparent");
1673 FrameGraphics.Repaint();
1674 return;
1675 } else {
1676 // check permissions
1677 if (!item.hasPermission(Permission.full)) {
1678 MessageBay
1679 .displayMessage("Insufficient permission to change that item's color");
1680 return;
1681 }
1682 // Toggling color of circle center changes the circle fill color
1683 if (item.hasEnclosures()) {
1684 if (setBackgroundColor) {
1685 SetGradientColor(item.getEnclosures().iterator().next(),
1686 setTransparent);
1687 } else {
1688 SetFillColor(item.getEnclosures().iterator().next(),
1689 setTransparent);
1690 }
1691 } else if (setBackgroundColor) {
1692 color = item.getPaintBackgroundColor();
1693 } else {
1694 color = item.getPaintColor();
1695 }
1696 }
1697 if (setTransparent)
1698 color = null;
1699 else if (setBackgroundColor) {
1700 color = ColorUtils.getNextColor(color, Item.FILL_COLOR_WHEEL, item
1701 .getPaintColor());
1702 } else {
1703 color = ColorUtils.getNextColor(color, Item.COLOR_WHEEL,
1704 currentFrame.getPaintBackgroundColor());
1705 }
1706 // if (currentFrame.getPaintForegroundColor().equals(color))
1707 // color = null;
1708
1709 // if color is being set to default display a message to indicate that
1710 // if (color == null) {
1711 // MessageBay.displayMessage("Color is set to default");
1712 // }
1713
1714 if (setBackgroundColor) {
1715 if (item == null && FreeItems.itemsAttachedToCursor()) {
1716 for (Item i : FreeItems.getInstance())
1717 i.setBackgroundColor(color);
1718 } else {
1719 item.setBackgroundColor(color);
1720 item.getParent().setChanged(true);
1721 }
1722 } else {
1723 if (item == null && FreeItems.itemsAttachedToCursor()) {
1724 for (Item i : FreeItems.getInstance())
1725 i.setColor(color);
1726 } else {
1727 item.setColor(color);
1728 item.getParent().setChanged(true);
1729 }
1730 }
1731 FrameGraphics.Repaint();
1732 }
1733
1734 /**
1735 * Toggles the given Item's annotation status on\off.
1736 *
1737 * @param toToggle
1738 * The Item to toggle
1739 */
1740 private static void ToggleAnnotation(Item toToggle) {
1741 if (toToggle == null) {
1742 MessageBay.displayMessage("There is no Item selected to toggle");
1743 return;
1744 }
1745
1746 // check permissions
1747 if (!toToggle.hasPermission(Permission.full)) {
1748 MessageBay
1749 .displayMessage("Insufficient permission to toggle that item's annotation");
1750 return;
1751 }
1752 toToggle.setAnnotation(!toToggle.isAnnotation());
1753
1754 toToggle.getParent().setChanged(true);
1755 FrameGraphics.Repaint();
1756 }
1757
1758 /**
1759 * Toggles the face style of a text item
1760 *
1761 * @param toToggle
1762 * The Item to toggle
1763 */
1764 private static void ToggleFontStyle(Item toToggle) {
1765 if (toToggle == null) {
1766 MessageBay.displayMessage("There is no Item selected to toggle");
1767 return;
1768 }
1769
1770 // check permissions
1771 if (!toToggle.hasPermission(Permission.full)) {
1772 MessageBay
1773 .displayMessage("Insufficient permission to toggle that item's annotation");
1774 return;
1775 }
1776
1777 if (toToggle instanceof Text) {
1778 Text text = (Text) toToggle;
1779 text.toggleFontStyle();
1780
1781 text.getParent().setChanged(true);
1782 FrameGraphics.Repaint();
1783 }
1784 }
1785
1786 /**
1787 * Toggles the face style of a text item
1788 *
1789 * @param toToggle
1790 * The Item to toggle
1791 */
1792 private static void ToggleFontFamily(Item toToggle) {
1793 if (toToggle == null) {
1794 MessageBay.displayMessage("There is no Item selected to toggle");
1795 return;
1796 }
1797
1798 // check permissions
1799 if (!toToggle.hasPermission(Permission.full)) {
1800 MessageBay
1801 .displayMessage("Insufficient permission to toggle that item's annotation");
1802 return;
1803 }
1804
1805 if (toToggle instanceof Text) {
1806 Text text = (Text) toToggle;
1807 text.toggleFontFamily();
1808
1809 text.getParent().setChanged(true);
1810 FrameGraphics.Repaint();
1811 }
1812 }
1813
1814 /**
1815 * If the given Item is null, then a new Text item is created with the
1816 * current date If the given Item is not null, then the current date is
1817 * prepended to the Item's text
1818 *
1819 * @param toAdd
1820 * The Item to prepend the date to, or null
1821 */
1822 private static void AddDate(Item toAdd) {
1823 String date1 = Logger.EasyDateFormat(LONG_DATE_FORMAT);
1824 String date2 = Logger.EasyDateFormat(SHORT_DATE_FORMAT);
1825 final String leftSeparator = " :";
1826 final String rightSeparator = ": ";
1827 String dateToAdd = date1 + rightSeparator;
1828 boolean prepend = false;
1829 boolean append = false;
1830
1831 // if the user is pointing at an item, add the date where ever the
1832 // cursor is pointing
1833 if (toAdd != null) {
1834 if (toAdd instanceof Text) {
1835 // permission check
1836 if (!toAdd.hasPermission(Permission.full)) {
1837 MessageBay
1838 .displayMessage("Insufficicent permission to add the date to that item");
1839 return;
1840 }
1841
1842 Text textItem = (Text) toAdd;
1843
1844 String text = textItem.getText();
1845
1846 // check if the default date has already been put on this item
1847 if (text.startsWith(date1 + rightSeparator)) {
1848 textItem.removeText(date1 + rightSeparator);
1849 dateToAdd = date2 + rightSeparator;
1850 prepend = true;
1851 } else if (text.startsWith(date2 + rightSeparator)) {
1852 textItem.removeText(date2 + rightSeparator);
1853 dateToAdd = leftSeparator + date2;
1854 append = true;
1855 } else if (text.endsWith(leftSeparator + date2)) {
1856 textItem.removeEndText(leftSeparator + date2);
1857 append = true;
1858 dateToAdd = leftSeparator + date1;
1859 } else if (text.endsWith(leftSeparator + date1)) {
1860 textItem.removeEndText(leftSeparator + date1);
1861 if (textItem.getLength() > 0) {
1862 dateToAdd = "";
1863 prepend = true;
1864 } else {
1865 // use the default date format
1866 prepend = true;
1867 }
1868 }
1869
1870 if (prepend) {
1871 // add the date to the text item
1872 textItem.prependText(dateToAdd);
1873 if (dateToAdd.length() == textItem.getLength())
1874 DisplayIO.setCursorPosition(textItem
1875 .getParagraphEndPosition());
1876 } else if (append) {
1877 textItem.appendText(dateToAdd);
1878 if (dateToAdd.length() == textItem.getLength())
1879 DisplayIO.setCursorPosition(textItem.getPosition());
1880 } else {
1881 for (int i = 0; i < date1.length(); i++) {
1882 processChar(date1.charAt(i), false);
1883 }
1884 }
1885
1886 textItem.getParent().setChanged(true);
1887 FrameGraphics.Repaint();
1888 } else {
1889 MessageBay
1890 .displayMessage("Only text items can have the date prepended to them");
1891 }
1892 // otherwise, create a new text item
1893 } else {
1894 Text newText = createText();
1895 newText.setText(dateToAdd);
1896 DisplayIO.getCurrentFrame().addItem(newText);
1897 DisplayIO.getCurrentFrame().setChanged(true);
1898 FrameGraphics.Repaint();
1899
1900 DisplayIO.setCursorPosition(newText.getParagraphEndPosition());
1901 }
1902
1903 }
1904
1905 /**
1906 * Creates a new Frameset with the name given by the Item
1907 *
1908 * @param name
1909 */
1910 private static void CreateFrameset(Item item) {
1911 if (item == null) {
1912 MessageBay
1913 .displayMessage("There is no selected item to use for the frameset name");
1914 return;
1915 }
1916
1917 if (!(item instanceof Text)) {
1918 MessageBay
1919 .displayMessage("Framesets can only be created from text items");
1920 return;
1921 }
1922
1923 // dont create frameset if the item is linked
1924 if (item.getLink() != null) {
1925 MessageBay
1926 .displayMessage("A frameset can not be created from a linked item");
1927 return;
1928 }
1929
1930 // check permissions
1931 if (!item.hasPermission(Permission.full)) {
1932 MessageBay
1933 .displayMessage("Insufficient permission to create a frameset from this item");
1934 return;
1935 }
1936
1937 Text text = (Text) item;
1938 try {
1939 // create the new frameset
1940 Frame linkTo = FrameIO.CreateNewFrameset(text.getFirstLine());
1941 DisplayIO.setCursor(Item.DEFAULT_CURSOR);
1942 text.setLink(linkTo.getName());
1943 text.getParent().setChanged(true);
1944 FrameUtils.DisplayFrame(linkTo, true);
1945 linkTo.moveMouseToDefaultLocation();
1946 // this needs to be done if the user doesnt move the mouse before
1947 // doing Tdfc while the cursor is set to the text cursor
1948 DisplayIO.setCursor(Item.DEFAULT_CURSOR);
1949 } catch (Exception e) {
1950 MessageBay.errorMessage(e.getMessage());
1951 }
1952 }
1953
1954 /**
1955 * Forces a re-parse and repaint of the current Frame.
1956 */
1957 public static void Refresh() {
1958 Frame currentFrame = DisplayIO.getCurrentFrame();
1959 if (FrameIO.isProfileFrame(currentFrame)) {
1960 // TODO ensure that users can not delete the first frame in a
1961 // frameset...
1962 // TODO handle the case when users manually delete the first frame
1963 // in a frameset from the filesystem
1964 Frame profile = FrameIO.LoadFrame(currentFrame.getFramesetName()
1965 + "1");
1966 assert (profile != null);
1967 FrameUtils.Parse(currentFrame);
1968 FrameUtils.ParseProfile(profile);
1969 } else {
1970 FrameUtils.Parse(currentFrame);
1971 }
1972 // Need to update the cursor for when text items change to @b pictures
1973 // etc and the text cursor is showing
1974 FrameMouseActions.updateCursor();
1975 FrameMouseActions.getInstance().refreshHighlights();
1976 FrameGraphics.ForceRepaint();
1977 }
1978}
Note: See TracBrowser for help on using the repository browser.