source: trunk/src/org/expeditee/gui/DisplayIO.java@ 570

Last change on this file since 570 was 570, checked in by jts21, 11 years ago

Add settings package which uses reflection to allow changing settings without hard coding the code to change every setting.

  • Currently only works for String/Int/Boolean/Double values
  • Supports default values by looking for fields with the prefix 'default', and will reset unset values to their default if a default exists.
  • For more complex settings (e.g. proxy settings), there is a "onParsed()" callback which can be used to run additional code, and (in the case of the password widget) parse abnormal items.
  • Some of the settings code in FrameUtils.ParseProfile has already been commented out since it's handled by default with the new Settings package. The rest could be moved over to UserSettings.onParsed(). Given the number of settings that remain to be moved, it may be a good idea to add the possibility for setting-specific onParsed() callbacks (could be done quite easily, similarly to how default values are handled).
File size: 25.4 KB
RevLine 
[4]1package org.expeditee.gui;
2
3import java.awt.AWTException;
4import java.awt.Color;
5import java.awt.Cursor;
[468]6import java.awt.Dimension;
[4]7import java.awt.Image;
8import java.awt.Point;
9import java.awt.Robot;
10import java.awt.Toolkit;
[336]11import java.awt.event.KeyEvent;
[108]12import java.awt.geom.Point2D;
[4]13import java.awt.image.MemoryImageSource;
[121]14import java.util.ArrayList;
[115]15import java.util.Collection;
[363]16import java.util.Collections;
[219]17import java.util.HashSet;
[34]18import java.util.LinkedList;
[4]19import java.util.List;
20import java.util.Stack;
21
22import javax.swing.JOptionPane;
23
24import org.expeditee.items.Item;
[55]25import org.expeditee.items.ItemParentStateChangedEvent;
[7]26import org.expeditee.items.Picture;
[86]27import org.expeditee.items.Text;
[570]28import org.expeditee.settings.UserSettings;
[4]29import org.expeditee.stats.SessionStats;
[139]30import org.expeditee.taskmanagement.EntitySaveManager;
[4]31
32/**
33 * This Interface is used by the Frame to control all display input and output.
34 *
35 * @author jdm18
36 *
37 */
38public class DisplayIO {
39
40 private static final int SMALL_CURSOR_SIZE = 16;
41
42 private static final int MEDIUM_CURSOR_SIZE = 32;
43
44 private static final int LARGE_CURSOR_SIZE = 64;
45
46 /**
47 * The color to be used to highlight the linked parent item, when the user
48 * navigates backwards.
49 */
50 public static final Color BACK_HIGHLIGHT_COLOR = Color.MAGENTA;
51
52 private static Browser _Browser;
53
54 // The current Frame being displayed on the screen.
55 private static Frame _CurrentFrames[] = new Frame[2];
56
57 // Maintains the list of frames visited thus-far for back-tracking
58 @SuppressWarnings("unchecked")
59 private static Stack<String>[] _VisitedFrames = new Stack[2];
[336]60
[176]61 @SuppressWarnings("unchecked")
62 private static Stack<String>[] _BackedUpFrames = new Stack[2];
[336]63
[4]64 // used to change the mouse cursor position on the screen
65 private static Robot _Robot;
66
67 private static boolean _TwinFrames = false;
[336]68
[219]69 /** Notified whenever the frame changes */
70 private static HashSet<DisplayIOObserver> _displayIOObservers = new HashSet<DisplayIOObserver>();
[4]71
72 /**
73 * The title to display in the Title bar.
74 */
[400]75 public static String TITLE = "ExpDev";
[4]76
77 private DisplayIO() {
78 }
79
80 public static void Init(Browser browser) {
81 _Browser = browser;
82 try {
83 _Robot = new Robot();
84 } catch (AWTException e) {
85 e.printStackTrace();
86 }
87
88 Point mouse = _Browser.getMousePosition();
89 if (mouse != null) {
90 FrameMouseActions.MouseX = mouse.x;
91 FrameMouseActions.MouseY = mouse.y;
92 }
93
94 _VisitedFrames[0] = new Stack<String>();
95 _VisitedFrames[1] = new Stack<String>();
[176]96 _BackedUpFrames[0] = new Stack<String>();
97 _BackedUpFrames[1] = new Stack<String>();
[4]98 }
99
[219]100 /**
101 * Notifies observers that the frame has changed.
102 */
103 private static void fireFrameChanged() {
104 for (DisplayIOObserver observer : _displayIOObservers) {
105 observer.frameChanged();
106 }
107 }
[336]108
[219]109 /**
110 * Adds a DisplayIOObserver to the DisplayIO. DisplayIOObserver's are
111 * notified when frame changes.
112 *
113 * @see #removeDisplayIOObserver(DisplayIOObserver)
114 *
115 * @param observer
[336]116 * The observer to add
[219]117 *
118 * @throws NullPointerException
[336]119 * If observer is null.
[219]120 */
121 public static void addDisplayIOObserver(DisplayIOObserver observer) {
[336]122 if (observer == null)
123 throw new NullPointerException("observer");
[219]124 _displayIOObservers.add(observer);
125 }
[336]126
[219]127 /**
[336]128 * Removes a DisplayIOObserver from the DisplayIO.
[219]129 *
130 * @see #addDisplayIOObserver(DisplayIOObserver)
131 *
132 * @param observer
[336]133 * The observer to add
[219]134 *
135 * @throws NullPointerException
[336]136 * If observer is null.
[219]137 */
138 public static void removeDisplayIOObserver(DisplayIOObserver observer) {
[336]139 if (observer == null)
140 throw new NullPointerException("observer");
[219]141 _displayIOObservers.remove(observer);
142 }
[336]143
[105]144 public static void setTextCursor(Text text, int cursorMovement) {
[376]145 setTextCursor(text, cursorMovement, false, false, false, false);
[86]146 }
147
[105]148 public static void setTextCursor(Text text, int cursorMovement,
[427]149 boolean newSize, boolean isShiftDown, boolean isCtrlDown,
150 boolean allowClearSelection) {
[105]151
[108]152 int size = Math.round(text.getSize());
[427]153 if (allowClearSelection && !isShiftDown && text.hasSelection())
[376]154 text.clearSelection();
[427]155
[115]156 Point2D.Float newMouse = text.moveCursor(cursorMovement, DisplayIO
[427]157 .getFloatMouseX(), FrameMouseActions.MouseY, isShiftDown,
158 isCtrlDown);
[105]159
160 if (!newSize && cursorType == Item.TEXT_CURSOR) {
161 if (cursorMovement != 0)
162 DisplayIO.setCursorPosition(newMouse, false);
[4]163 return;
[105]164 }
[4]165
166 cursorType = Item.TEXT_CURSOR;
167
[21]168 // Do some stuff to adjust the cursor size based on the font size
[4]169 final int MEDIUM_CURSOR_CUTOFF = 31;
170 final int LARGE_CURSOR_CUTOFF = 62;
171
172 int cursorSize = LARGE_CURSOR_SIZE;
173 int hotspotPos = 0;
174 int start = 0;
175
[468]176 Toolkit toolkit = Toolkit.getDefaultToolkit();
177 Dimension best_cursor_dim = toolkit.getBestCursorSize(cursorSize,cursorSize);
178 int best_cursor_height = best_cursor_dim.height;
179
180 if (best_cursor_height < cursorSize) {
181 // not able to provide the size of cursor Expeditee wants to
182 // => lock on to 'best_cursor_height' and use this to generate dependent values
183 cursorSize = best_cursor_height; // OS + Java version dependent: most likely MEDIUM_CURSOR_SIZE
184 if (size < best_cursor_height) {
185 start = cursorSize - size - 1;
186 hotspotPos = cursorSize - (size + 1) / 4;
187 }
188 else {
189 start = size - best_cursor_height;
190 hotspotPos = cursorSize -1;
191 }
192
193 }
194 else if (size < MEDIUM_CURSOR_CUTOFF) {
[4]195 cursorSize = MEDIUM_CURSOR_SIZE;
[468]196 start = cursorSize - size - 1;
197 hotspotPos = cursorSize - (size + 1) / 4;
[4]198 } else if (size < LARGE_CURSOR_CUTOFF) {
199 hotspotPos = cursorSize - (size - 5) / 4;
200 start = cursorSize - size - 2;
201 } else {
202 int FIXED_CURSOR_MIN = 77;
203 if (size >= FIXED_CURSOR_MIN) {
204 hotspotPos = cursorSize - 2;
205 } else {
206 hotspotPos = size - (FIXED_CURSOR_MIN - cursorSize);
207 }
208 }
[468]209
[4]210 int[] pixels = new int[cursorSize * cursorSize];
211
[468]212 for (int i = start; i < cursorSize; i++) {
[376]213 pixels[i * cursorSize] = pixels[i * cursorSize + 1] = 0xFF000000;
[468]214 }
[4]215
[468]216 MemoryImageSource memory_image = new MemoryImageSource(cursorSize, cursorSize, pixels, 0, cursorSize);
217 Image image = toolkit.createImage(memory_image);
218
219 Cursor textCursor = toolkit.createCustomCursor(image, new Point(0, hotspotPos), "textcursor");
[4]220 _Browser.setCursor(textCursor);
[468]221
222 if (cursorMovement != Text.NONE) {
[143]223 DisplayIO.setCursorPosition(newMouse, false);
[468]224 }
[4]225 }
226
227 /**
228 * Sets the type of cursor the display should be using
229 *
230 * @param type
231 * The type of cursor to display, using constants defined in the
232 * Cursor class.
233 */
234 public static void setCursor(int type) {
235 // avoid flicker when not changing
236 if (type == cursorType || type == Item.UNCHANGED_CURSOR)
237 return;
238
239 cursorType = type;
[427]240
241 if(_Browser != null){
242 refreshCursor();
243 }
244 }
245
246 public static void refreshCursor() {
247 if (cursorType == Item.HIDDEN_CURSOR
248 || (FreeItems.hasCursor() && cursorType == Item.DEFAULT_CURSOR)) {
[4]249 int[] pixels = new int[SMALL_CURSOR_SIZE * SMALL_CURSOR_SIZE];
250 Image image = Toolkit.getDefaultToolkit().createImage(
251 new MemoryImageSource(SMALL_CURSOR_SIZE, SMALL_CURSOR_SIZE,
252 pixels, 0, SMALL_CURSOR_SIZE));
253 Cursor transparentCursor = Toolkit.getDefaultToolkit()
254 .createCustomCursor(image, new Point(0, 0),
255 "invisiblecursor");
[427]256 _Browser.setCursor(transparentCursor);
257 } else
258 _Browser.setCursor(new Cursor(cursorType));
[4]259 }
260
261 private static int cursorType = Item.DEFAULT_CURSOR;
262
263 public static int getCursor() {
264 return cursorType;
265 }
266
267 /**
268 * Moves the mouse cursor to the given x,y coordinates on the screen
269 *
270 * @param x
271 * The x coordinate
272 * @param y
273 * The y coordinate
274 */
[105]275 public static void setCursorPosition(float x, float y) {
[4]276 setCursorPosition(x, y, true);
277 }
[74]278
[105]279 public static void setCursorPosition(float x, float y, boolean forceArrow) {
[74]280 // Adjust the position to move the mouse to to account for being in
281 // TwinFramesMode
282 if (_TwinFrames) {
283 if (getCurrentSide() == 1) {
284 int middle = getMiddle();
285 x += middle;
286 }
287 }
[86]288
[105]289 float deltax = x - FrameMouseActions.MouseX;
290 float deltay = y - FrameMouseActions.MouseY;
[4]291
[74]292 // When the Robot moves the cursor... a short time later a mouseMoved
293 // event is generated...
294 // We want to ignore this event by remembering the location the robot
295 // was shifted to.
296 FrameMouseActions.setLastRobotMove(x, y);
[4]297
[242]298 if (FreeItems.itemsAttachedToCursor()) {
[121]299 List<Item> toMove = FreeItems.getInstance();
[21]300 for (Item move : toMove) {
301 move.setPosition(move.getX() + deltax, move.getY() + deltay);
302 }
303 }
304
305 // cheat
306 FrameMouseActions.setForceArrow(forceArrow);
[72]307 int mouseX = (int) _Browser.getContentPane().getLocationOnScreen()
[21]308 .getX()
[106]309 + Math.round(x);
[72]310 int mouseY = (int) _Browser.getContentPane().getLocationOnScreen()
[21]311 .getY()
[106]312 + Math.round(y);
[72]313 _Robot.mouseMove(mouseX, mouseY);
[74]314 // System.out.println("MouseMoved: " + x + "," + y);
[4]315 }
316
317 public static void resetCursorOffset() {
318 FrameMouseActions.resetOffset();
319 }
320
[74]321 /**
322 * Sets the current cursor position in the current frame
323 *
324 * @param pos
325 */
[108]326 public static void setCursorPosition(Point2D.Float pos) {
327 setCursorPosition(pos.x, pos.y);
328 }
[115]329
[4]330 public static void setCursorPosition(Point pos) {
331 setCursorPosition(pos.x, pos.y);
332 }
333
334 public static void setCursorPosition(Point pos, boolean forceArrow) {
335 setCursorPosition(pos.x, pos.y, forceArrow);
336 }
[115]337
[108]338 public static void setCursorPosition(Point2D.Float pos, boolean forceArrow) {
339 setCursorPosition(pos.x, pos.y, forceArrow);
340 }
[4]341
342 /**
343 * Returns the top item (last added) of the Back-Stack (which is popped off)
344 *
345 * @return The name of the last Frame added to the back-stack
346 */
347 public static String getLastFrame() {
348 int side = getCurrentSide();
349
350 if (_VisitedFrames[side].size() > 0)
351 return _VisitedFrames[side].pop();
352 else
353 return null;
354 }
355
356 /**
357 * Adds the given Frame to the back-stack
358 *
359 * @param frame
360 * The Frame to add
361 */
362 public static void addToBack(Frame toAdd) {
363 int side = getCurrentSide();
364
[105]365 // // do not allow duplicate frames
366 // if (_VisitedFrames[side].size() > 0)
367 // if (_VisitedFrames[side].peek().equals(toAdd.getName())) {
368 // return;
369 // }
[4]370
[7]371 Item ip = FrameUtils.getCurrentItem();
372 if (ip == null)
[80]373 _VisitedFrames[side].push(toAdd.getName());
[4]374 else
[80]375 _VisitedFrames[side].push(toAdd.getName());
[105]376 // System.out.println("Added: " + _VisitedFrames[side].size());
[4]377 }
378
[176]379 public static String removeFromBack() {
[86]380 int side = getCurrentSide();
381
382 // there must be a frame to go back to
[176]383 if (_VisitedFrames[side].size() > 0) {
384 return _VisitedFrames[side].pop();
[86]385 }
[176]386 return null;
[86]387 }
388
[4]389 /**
390 * Returns a 'peek' at the end element on the back-stack of the current
391 * side. If the back-stack is empty, null is returned.
392 *
393 * @return The name of the most recent Frame added to the back-stack, or
394 * null if the back-stack is empty.
395 */
[70]396 public static String peekFromBackUpStack() {
[4]397 int side = getCurrentSide();
398
399 // check that the stack is not empty
400 if (_VisitedFrames[side].size() > 0)
401 return _VisitedFrames[side].peek();
402
403 // if the stack is empty, return null
404 return null;
405 }
[336]406
[154]407 public static void setCurrentFrame(Frame frame, boolean incrementStats) {
[4]408 if (frame == null)
409 return;
[336]410
[4]411 if (_TwinFrames) {
412 if (_CurrentFrames[0] == null) {
413 _CurrentFrames[0] = frame;
[219]414 fireFrameChanged();
[4]415 return;
416 }
417 if (_CurrentFrames[1] == null) {
418 _CurrentFrames[1] = frame;
[219]419 fireFrameChanged();
[4]420 return;
421 }
422 }
423
424 // if this is already the current frame
425 if (frame == getCurrentFrame()) {
426 FrameGraphics.Repaint();
[121]427 MessageBay.displayMessage(frame.getName()
[4]428 + " is already the current frame.");
429 return;
[336]430 } else if (incrementStats) {
[4]431 SessionStats.AccessedFrame();
432 }
433
[121]434 // Invalidate free items
435 if (!FreeItems.getInstance().isEmpty() && getCurrentFrame() != null) {
[143]436
437 // Empty free items temporarily so that the old frames buffer is
438 // repainted
[121]439 // without the free items.
[143]440 ArrayList<? extends Item> tmp = (ArrayList<? extends Item>) FreeItems
441 .getInstance().clone();
442 FreeItems.getInstance().clear(); // NOTE: This will invalidate
[145]443 // all the cleared free items
[121]444 FrameGraphics.refresh(true);
445 FreeItems.getInstance().addAll(tmp);
[143]446
[121]447 }
[145]448
[139]449 // Changing frames is a Save point for saveable entities:
450 EntitySaveManager.getInstance().saveAll();
[336]451
[4]452 if (_TwinFrames) {
453 // if the same frame is being shown in both sides, load a fresh
[115]454 // copy from disk
[4]455 if (_CurrentFrames[getOppositeSide()] == frame
[115]456 || _CurrentFrames[getOppositeSide()].hasOverlay(frame)) {
[4]457 FrameIO.SuspendCache();
[80]458 frame = FrameIO.LoadFrame(frame.getName());
[4]459 FrameIO.ResumeCache();
460 }
[21]461
[10]462 // If the frames are the same then the items for the
463 // frame that is just about to hide will still be in view
464 // so only notify items that they are hidden if the
465 // frames differ.
[21]466 if (_CurrentFrames[getCurrentSide()] != null
467 && _CurrentFrames[0] != _CurrentFrames[1]) {
[10]468 for (Item i : _CurrentFrames[getCurrentSide()].getItems()) {
[55]469 i.onParentStateChanged(new ItemParentStateChangedEvent(
[72]470 _CurrentFrames[getCurrentSide()],
[55]471 ItemParentStateChangedEvent.EVENT_TYPE_HIDDEN));
[10]472 }
473 }
[4]474 _CurrentFrames[getCurrentSide()] = frame;
[21]475
[121]476 // BROOK : TODO... overlays and loadable widgets
[10]477 for (Item i : _CurrentFrames[getCurrentSide()].getItems()) {
[55]478 i.onParentStateChanged(new ItemParentStateChangedEvent(
[72]479 _CurrentFrames[getCurrentSide()],
[55]480 ItemParentStateChangedEvent.EVENT_TYPE_SHOWN));
[10]481 }
[4]482 } else {
[34]483
[21]484 // Notifying items on the frame being hidden that they
[10]485 // are about to be hidden.
[34]486 // ie. Widgets use this method to remove themselves from the JPanel
487 List<Frame> currentOnlyOverlays = new LinkedList<Frame>();
488 List<Frame> nextOnlyOverlays = new LinkedList<Frame>();
489 List<Frame> sharedOverlays = new LinkedList<Frame>();
490
491 // Get all overlayed frames seen by the next frame
[115]492 for (Overlay o : frame.getOverlays()) {
[34]493 if (!nextOnlyOverlays.contains(o))
494 nextOnlyOverlays.add(o.Frame);
495 }
496
497 // Get all overlayed frames seen by the current frame
[10]498 if (_CurrentFrames[getCurrentSide()] != null) {
[115]499 for (Overlay o : _CurrentFrames[getCurrentSide()].getOverlays()) {
[34]500 if (!currentOnlyOverlays.contains(o))
501 currentOnlyOverlays.add(o.Frame);
502 }
503 }
504
505 // Extract shared overlays between the current and next frame
506 for (Frame of : currentOnlyOverlays) {
507 if (nextOnlyOverlays.contains(of)) {
508 sharedOverlays.add(of);
509 }
510 }
511
512 // The first set, currentOnlyOverlays, must be notified that they
513 // are hidden
[115]514 Collection<Item> items = new LinkedList<Item>();
[34]515
516 // Notify items that will not be in view any more
517 if (_CurrentFrames[getCurrentSide()] != null) {
518 List<Frame> seen = new LinkedList<Frame>();
519 seen.addAll(sharedOverlays); // Signify that seen all shared
[72]520 // overlays
[34]521 seen.remove(_CurrentFrames[getCurrentSide()]); // must ensure
[72]522 // excluded
[34]523
524 // Get all items seen from the current frame - including all
525 // possible non-shared overlays
[115]526 items = _CurrentFrames[getCurrentSide()].getAllItems();
527 for (Frame f : seen)
528 items.removeAll(f.getAllItems());
[34]529
530 // Notify items that they are hidden
531 for (Item i : items) {
[55]532 i.onParentStateChanged(new ItemParentStateChangedEvent(
[72]533 _CurrentFrames[getCurrentSide()],
[55]534 ItemParentStateChangedEvent.EVENT_TYPE_HIDDEN));
[10]535 }
536 }
[21]537
[34]538 // Set the new frame
[4]539 _CurrentFrames[getCurrentSide()] = frame;
[278]540 frame.refreshSize();
[10]541 // Notify items on the frame being displayed that they are in view
[21]542 // ie. widgets use this method to add themselves to the content pane
[34]543 items.clear();
544
545 // Notify overlay items that they are shown
[115]546 for (Item i : frame.getOverlayItems()) {
547 Overlay owner = frame.getOverlayOwner(i);
[34]548 // if (owner == null) i.onParentFameShown(false, 0);
549 // else ...
550 assert (owner != null);
[72]551 i
552 .onParentStateChanged(new ItemParentStateChangedEvent(
[115]553 frame,
[72]554 ItemParentStateChangedEvent.EVENT_TYPE_SHOWN_VIA_OVERLAY,
[115]555 owner.permission));
[10]556 }
[34]557
[115]558 for (Item i : frame.getItems()) {
559 i.onParentStateChanged(new ItemParentStateChangedEvent(frame,
[55]560 ItemParentStateChangedEvent.EVENT_TYPE_SHOWN));
[34]561 }
[4]562 }
[390]563 frame.reset();
[247]564 FrameMouseActions.getInstance().refreshHighlights();
[219]565 FrameGraphics.refresh(false);
566 fireFrameChanged();
[4]567 }
568
569 public static void UpdateTitle() {
[72]570 StringBuffer title = new StringBuffer(TITLE);
[4]571
572 if (FrameGraphics.isAudienceMode())
573 title.append(" - Audience Mode");
[80]574 else if (FrameGraphics.isXRayMode())
575 title.append(" - X-Ray Mode");
[7]576 else
[72]577 title.append(" [").append(SessionStats.getShortStats()).append(']');
[4]578
579 _Browser.setTitle(title.toString());
580 }
581
582 public static int getCurrentSide() {
583 if (_Browser == null)
584 return 0;
[336]585
[4]586 if (_TwinFrames
[147]587 && FrameMouseActions.MouseX >= (_Browser.getWidth() / 2F)
[4]588 && _CurrentFrames[1] != null)
589 return 1;
590
591 if (_CurrentFrames[0] == null && _CurrentFrames[1] != null)
592 return 1;
593
594 return 0;
595 }
596
597 private static int getOppositeSide() {
598 if (getCurrentSide() == 0)
599 return 1;
600
601 return 0;
602 }
603
604 public static int FrameOnSide(Frame toFind) {
605 if (_CurrentFrames[0] == toFind)
606 return 0;
607
608 if (_CurrentFrames[1] == toFind)
609 return 1;
610
611 return -1;
612 }
613
614 /**
615 * Returns the Frame currently being displayed on the screen.
616 *
617 * @return The Frame currently displayed.
618 */
619 public static Frame getCurrentFrame() {
620 return _CurrentFrames[getCurrentSide()];
621 }
622
623 public static Frame getOppositeFrame() {
624 return _CurrentFrames[getOppositeSide()];
625 }
626
627 public static Frame[] getFrames() {
628 return _CurrentFrames;
629 }
630
631 public static int getMiddle() {
632 return _Browser.getWidth() / 2;
633 }
634
635 public static int getHeight() {
636 return _Browser.getHeight();
637 }
638
639 /**
640 * Returns the current mouse X coordinate. This coordinate is relative to
641 * the left edge of the frame the mouse is in. It takes into account the
642 * user being in twin frames mode.
643 *
644 * @return The X coordinate of the mouse.
645 */
[105]646 public static float getFloatMouseX() {
647 if (_TwinFrames
648 && FrameMouseActions.MouseY < FrameGraphics.getMaxSize().height)
[4]649 return FrameMouseActions.MouseX % (_Browser.getWidth() / 2);
650
651 return FrameMouseActions.MouseX;
652 }
653
[468]654
[4]655 /**
[105]656 * Returns the current mouse X coordinate. This coordinate is relative to
657 * the left edge of the frame the mouse is in. It takes into account the
658 * user being in twin frames mode.
[4]659 *
[105]660 * @return The X coordinate of the mouse.
[4]661 */
[105]662 public static int getMouseX() {
663 return Math.round(getFloatMouseX());
[4]664 }
[468]665
666
667 /**
668 * Returns the current mouse Y coordinate. This coordinate is relative to
669 * the top edge of the frame the mouse is in.
670 *
671 * @return The Y coordinate of the mouse.
672 */
673 public static float getFloatMouseY() {
674
675 return FrameMouseActions.MouseY;
676 }
677
678 /**
679 * Returns the current mouse Y coordinate. This coordinate is relative to
680 * the top edge of the frame the mouse is in.
681 *
682 * @return The Y coordinate of the mouse.
683 */
684 public static int getMouseY() {
685 return Math.round(getFloatMouseY());
686 }
687
[176]688 public static boolean Back() {
[4]689 int side = getCurrentSide();
690
691 // there must be a frame to go back to
692 if (_VisitedFrames[side].size() < 1) {
[143]693 MessageBay.displayMessageOnce("You are already on the home frame");
[176]694 return false;
[4]695 }
696
697 if (!FrameUtils.LeavingFrame(getCurrentFrame())) {
[176]698 MessageBay.displayMessage("Error navigating back");
699 return false;
[4]700 }
701
[80]702 String oldFrame = getCurrentFrame().getName().toLowerCase();
[4]703
704 // do not get a cached version (in case it is in the other window)
705 if (isTwinFramesOn())
706 FrameIO.SuspendCache();
[176]707 Frame frame = FrameIO.LoadFrame(removeFromBack());
[105]708 // If the top frame on the backup stack is the current frame go back
[162]709 // again... or if it has been deleted
[336]710 // Recursively backup the stack
711 if (frame == null || frame.equals(getCurrentFrame())) {
[90]712 Back();
[176]713 return false;
[90]714 }
[72]715
[86]716 if (isTwinFramesOn()) {
[4]717 FrameIO.ResumeCache();
[86]718 }
[176]719 _BackedUpFrames[side].push(oldFrame);
[408]720 FrameUtils.DisplayFrame(frame, false, true);
[4]721 FrameMouseActions.setHighlightHold(true);
722
[86]723 for (Item i : frame.getItems()) {
[4]724 if (i.getLink() != null
[7]725 && i.getAbsoluteLink().toLowerCase().equals(oldFrame)) {
[115]726 if (i.getHighlightMode() != Item.HighlightMode.Normal) {
727 i.setHighlightMode(Item.HighlightMode.Normal,
[86]728 BACK_HIGHLIGHT_COLOR);
729 }
[21]730 // check if its an @f item and if so update the buffer
[7]731 if (i instanceof Picture) {
[21]732 Picture p = (Picture) i;
[7]733 p.refresh();
734 }
[4]735 }
[86]736 }
[176]737 FrameGraphics.requestRefresh(true);
738 return true;
[4]739 }
[336]740
[176]741 public static boolean Forward() {
742 int side = getCurrentSide();
[4]743
[176]744 // there must be a frame to go back to
745 if (_BackedUpFrames[side].size() == 0) {
746 return false;
747 }
748
749 if (!FrameUtils.LeavingFrame(getCurrentFrame())) {
750 MessageBay.displayMessage("Error navigating forward");
751 return false;
752 }
753
754 String oldFrame = getCurrentFrame().getName().toLowerCase();
755
756 // do not get a cached version (in case it is in the other window)
757 if (isTwinFramesOn())
758 FrameIO.SuspendCache();
759 Frame frame = FrameIO.LoadFrame(_BackedUpFrames[side].pop());
760 // If the top frame on the backup stack is the current frame go back
761 // again... or if it has been deleted
[336]762 // Recursively backup the stack
763 if (frame == null || frame.equals(getCurrentFrame())) {
[176]764 Forward();
765 return false;
766 }
767
768 if (isTwinFramesOn()) {
769 FrameIO.ResumeCache();
770 }
771 _VisitedFrames[side].push(oldFrame);
[408]772 FrameUtils.DisplayFrame(frame, false, true);
[176]773 FrameGraphics.requestRefresh(true);
774 return true;
775 }
776
[4]777 /**
778 * Toggles the display of frames between TwinFrames mode and Single frame
779 * mode.
780 */
781 public static void ToggleTwinFrames() {
782 // determine which side is the active side
783 int opposite = getOppositeSide();
784 int current = getCurrentSide();
785 _TwinFrames = !_TwinFrames;
786
787 // if TwinFrames is being turned on
788 if (_TwinFrames) {
789 // if this is the first time TwinFrames has been toggled on,
[154]790 // load the user's first frame
[4]791 if (_VisitedFrames[opposite].size() == 0) {
792 FrameIO.SuspendCache();
[309]793 setCurrentFrame(FrameIO.LoadFrame(UserSettings.HomeFrame), true);
[4]794 FrameIO.ResumeCache();
795 } else {
796 // otherwise, restore the frame from the side's back-stack
797 setCurrentFrame(FrameIO.LoadFrame(_VisitedFrames[opposite]
[154]798 .pop()), true);
[4]799 }
800
801 // else, TwinFrames is being turned off
802 } else {
803 // add the frame to the back-stack
804 Frame hiding = _CurrentFrames[opposite];
805 FrameUtils.LeavingFrame(hiding);
[80]806 _VisitedFrames[opposite].add(hiding.getName());
[4]807 _CurrentFrames[opposite] = null;
[278]808 _CurrentFrames[current].refreshSize();
[4]809 }
810 if (_CurrentFrames[current] != null)
[278]811 _CurrentFrames[current].refreshSize();
[4]812 if (_CurrentFrames[opposite] != null)
[336]813 _CurrentFrames[opposite].refreshSize();
[4]814
815 FrameGraphics.Clear();
[154]816 FrameGraphics.requestRefresh(false);
[4]817 FrameGraphics.Repaint();
818 }
819
820 public static boolean isTwinFramesOn() {
821 return _TwinFrames;
822 }
823
824 public static void Reload(int side) {
825 if (side < 0)
826 return;
827
828 FrameIO.SuspendCache();
[86]829 _CurrentFrames[side] = FrameIO
830 .LoadFrame(_CurrentFrames[side].getName());
[4]831 FrameIO.ResumeCache();
832 }
833
834 public static boolean DisplayConfirmDialog(String message, String title,
835 int type, int options, int res) {
836 return JOptionPane.showConfirmDialog(_Browser, message, title, options,
837 type) == res;
838 }
839
840 public static final int RESULT_OK = JOptionPane.OK_OPTION;
841
842 public static final int OPTIONS_OK_CANCEL = JOptionPane.OK_CANCEL_OPTION;
843
844 public static final int TYPE_WARNING = JOptionPane.WARNING_MESSAGE;
845
846 public static void pressMouse(int buttons) {
847 _Robot.mousePress(buttons);
848 }
849
850 public static void releaseMouse(int buttons) {
851 _Robot.mouseRelease(buttons);
852 }
853
[336]854 public static void clickMouse(int buttons) throws InterruptedException {
[4]855 _Robot.mousePress(buttons);
[336]856 Thread.sleep(100);
[4]857 _Robot.mouseRelease(buttons);
858 }
[86]859
[336]860 public static void typeKey(int key) throws InterruptedException {
861 _Robot.keyPress(key);
862 // _Robot.waitForIdle();
863 _Robot.keyRelease(key);
864 // _Robot.waitForIdle();
[348]865 Thread.sleep(200);
[336]866 }
867
868 public static void typeText(String s) throws InterruptedException {
869 for (int i = 0; i < s.length(); i++) {
870 char c = s.charAt(i);
[427]871 if (Character.isUpperCase(c))
[336]872 _Robot.keyPress(KeyEvent.VK_SHIFT);
873 typeKey(getKeyCode(c));
[427]874 if (Character.isUpperCase(c))
[336]875 _Robot.keyRelease(KeyEvent.VK_SHIFT);
876 }
877 }
878
879 protected static int getKeyCode(char c) {
[427]880 switch (c) {
[336]881 case '\n':
882 return KeyEvent.VK_ENTER;
883 case ' ':
884 return KeyEvent.VK_SPACE;
885 }
[427]886
887 if (Character.isSpaceChar(c))
888 return KeyEvent.VK_SPACE;
889 else if (Character.isDigit(c)) {
890 return (int) (KeyEvent.VK_0 + c - '0');
891 } else if (Character.isUpperCase(c)) {
[336]892 return c;
893 }
[427]894
895 return (int) (KeyEvent.VK_A + c - 'a');
[336]896 }
897
[86]898 /**
899 * Moves the cursor the end of this item.
900 *
901 * @param i
902 */
903 public static void MoveCursorToEndOfItem(Item i) {
[376]904 setTextCursor((Text) i, Text.END, true, false, false, false);
[86]905 }
[145]906
907 public static void translateCursor(int deltaX, int deltaY) {
908 setCursorPosition(FrameMouseActions.MouseX + deltaX,
909 FrameMouseActions.MouseY + deltaY, false);
910 }
[176]911
912 public static void clearBackedUpFrames() {
913 _BackedUpFrames[getCurrentSide()].clear();
914 }
[336]915
916 /**
917 * @param secondsDelay
918 * @param s
919 * @throws InterruptedException
920 */
[427]921 public static void typeStringDirect(double secondsDelay, String s)
922 throws InterruptedException {
[336]923 for (int i = 0; i < s.length(); i++) {
924 FrameKeyboardActions.processChar(s.charAt(i), false);
925 Thread.sleep((int) (secondsDelay * 1000));
926 }
927 }
[427]928
[363]929 public static List<String> getUnmodifiableVisitedList() {
930 return Collections.unmodifiableList(_VisitedFrames[getCurrentSide()]);
931 }
[4]932}
Note: See TracBrowser for help on using the repository browser.