/** * FrameKeyboardActions.java * Copyright (C) 2010 New Zealand Digital Library, http://expeditee.org * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package org.expeditee.gui; import java.awt.Toolkit; import java.awt.datatransfer.StringSelection; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.text.NumberFormat; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import org.expeditee.actions.Actions; import org.expeditee.actions.Navigation; import org.expeditee.actions.Simple; import org.expeditee.core.AxisAlignedBoxBounds; import org.expeditee.core.Colour; import org.expeditee.core.Point; import org.expeditee.gui.indirect.keyboard.IndirectKeyboardActions; import org.expeditee.gui.indirect.keyboard.KeyboardAction; import org.expeditee.gui.indirect.keyboard.KeyboardInfo; import org.expeditee.io.ItemSelection; import org.expeditee.items.Circle; import org.expeditee.items.Dot; import org.expeditee.items.Item; import org.expeditee.items.ItemUtils; import org.expeditee.items.Line; import org.expeditee.items.Picture; import org.expeditee.items.Text; import org.expeditee.items.UserAppliedPermission; import org.expeditee.items.XRayable; import org.expeditee.items.MagneticConstraint.MagneticConstraints; /*import org.expeditee.items.widgets.InteractiveWidget; TODO: Reinstate. cts16 import org.expeditee.items.widgets.WidgetCorner; import org.expeditee.items.widgets.WidgetEdge;*/ import org.expeditee.settings.experimental.ExperimentalFeatures; import org.expeditee.settings.templates.TemplateSettings; import org.expeditee.stats.Formatter; import org.expeditee.stats.Logger; import org.expeditee.stats.SessionStats; public class FrameKeyboardActions { private static FrameKeyboardActions _instance = new FrameKeyboardActions(); protected FrameKeyboardActions() { /*IndirectKeyboardActions.getInstance().setDropDownAction( new KeyboardAction() { @Override public Text exec(final KeyboardInfo info, final char c) { // Get the last text item and drop from in Item lastText = null; for (Item i : info.enclosed) { if (i instanceof Text) { lastText = i; } } // Drop from the item if there was a text item in the // box if (lastText != null) { Drop(lastText, false); } else { // Move to the top of the box AxisAlignedBoxBounds rect = info.firstConnected.getBounds(); int newX = rect.getMinX() + Text.MARGIN_LEFT; int newY = Text.MARGIN_LEFT + rect.getMinY() + DisplayIO.getCurrentFrame() .getItemTemplate() .getBoundsHeight(); moveCursorAndFreeItems(newX, newY); // TODO can resetOffset be put inside // moveCursorAndFreeItems FrameMouseActions.resetOffset(); } return null; } }); IndirectKeyboardActions.getInstance().setSizeUpAction( new KeyboardAction() { @Override public Text exec(final KeyboardInfo info, final char c) { SetSize(info.firstConnected, info.repeat, false, true, info.isControlDown); return null; } }); IndirectKeyboardActions.getInstance().setSizeDownAction( new KeyboardAction() { @Override public Text exec(final KeyboardInfo info, final char c) { SetSize(info.firstConnected, -info.repeat, false, true, info.isControlDown); return null; } }); IndirectKeyboardActions.getInstance().setChangeColorAction( new KeyboardAction() { @Override public Text exec(final KeyboardInfo info, final char c) { if (info.connected.size() > 0) { for (Item d : info.lineEnds) { if (info.isControlDown) SetGradientColor(d, info.isShiftDown); else SetFillColor(d, info.isShiftDown); break; } } return null; } }); IndirectKeyboardActions.getInstance().setToggleAnnotationAction( new KeyboardAction() { @Override public Text exec(final KeyboardInfo info, final char c) { ToggleAnnotation(info.firstConnected); return null; } }); IndirectKeyboardActions.getInstance().setChangeFontStyleAction( new KeyboardAction() { @Override public Text exec(final KeyboardInfo info, final char c) { ToggleFontStyle(info.firstConnected); return null; } }); IndirectKeyboardActions.getInstance().setChangeFontFamilyAction( new KeyboardAction() { @Override public Text exec(final KeyboardInfo info, final char c) { ToggleFontFamily(info.firstConnected); return null; } }); IndirectKeyboardActions.getInstance().setInsertDateAction( new KeyboardAction() { @Override public Text exec(final KeyboardInfo info, final char c) { AddDate(info.firstConnected); return null; } }); IndirectKeyboardActions.getInstance().setSaveAction( new KeyboardAction() { @Override public Text exec(final KeyboardInfo info, final char c) { Save(); return null; } });*/ IndirectKeyboardActions.getInstance().setCreateNewTextAction( new KeyboardAction() { @Override public Text exec(KeyboardInfo info, char c) { Text t = DisplayIO.getCurrentFrame().createBlankText( "" + c); Point newMouse = t.insertChar(c, DisplayIO.getMouseX(), FrameMouseActions.getY()); DisplayIO.setCursorPosition(newMouse.x, newMouse.y, false); return t; } }); IndirectKeyboardActions.getInstance().setInsertCharacterAction( new KeyboardAction() { @Override public Text exec(final KeyboardInfo info, final char c) { float oldY = FrameMouseActions.MouseY; Point newMouse = null; if (c == '\t') { if (info.isShiftDown) { newMouse = ((Text)info.firstConnected).removeTab(c, DisplayIO.getFloatMouseX(), FrameMouseActions.MouseY); } else { newMouse = ((Text)info.firstConnected).insertTab(c, DisplayIO.getFloatMouseX(), FrameMouseActions.MouseY); } } else { newMouse = ((Text)info.firstConnected).insertChar(c, DisplayIO.getFloatMouseX(), FrameMouseActions.MouseY); } /* * check if the user hit enter and the cursor is now on another text * item */ if (oldY < newMouse.y) { // float diff = newMouse.y - oldY; // System.out.print("c"); AxisAlignedBoxBounds rect = info.firstConnected.getBounds(); // Text lastEdited = FrameUtils.getLastEdited(); // FrameUtils.setLastEdited(null); Item justBelow = FrameUtils.onItem(DisplayIO.getCurrentFrame(), info.firstConnected.getX() + 10, rect.getMinY() + rect.getHeight() + 1, false); // FrameUtils.setLastEdited(lastEdited); // Dont drop unless if (justBelow != null && justBelow instanceof Text && justBelow != info.firstConnected) { // Drop all the items below it down! // Get the list of items that must be dropped List column = DisplayIO.getCurrentFrame().getColumn(info.firstConnected); FrameUtils.Align(column, false, 0); } } DisplayIO.setCursorPosition(newMouse.x, newMouse.y, false); return (Text) info.firstConnected; } }); } public static FrameKeyboardActions getInstance() { return _instance; } public synchronized void keyTyped(KeyEvent e) { if (Simple.isProgramRunning()) { if (e.isControlDown() && (e.getKeyChar() == KeyEvent.VK_ESCAPE || e.getKeyChar() == KeyEvent.VK_C)) { Simple.stop(); return; } else if (e.isControlDown() && e.getKeyChar() == KeyEvent.VK_SPACE) { Simple.nextStatement(); return; } else { Simple.KeyStroke(e.getKeyChar()); } if (Simple.consumeKeyboardInput()) return; } // ignore escape character and control characters if (e.getKeyChar() == KeyEvent.VK_ESCAPE || e.isControlDown()) { return; } // Deal with splitting text items when typing too fast // Mike: thinks this problem may have been solved and was due to // rounding errors in the text class... // It may have been fixed by changing to the use of floats instead of // ints for text positioning etc // if (FrameMouseActions.isWaitingForRobot()) { // System.out.println("Waiting: " + e.getKeyChar()); // return; // } e.consume(); char ch = e.getKeyChar(); // System.out.println(ch); if (!e.isAltDown()) processChar(ch, e.isShiftDown()); // FrameGraphics.Repaint(); } /** * Receives and processes any Function, Control, and Escape key presses * * @param e * The KeyEvent received from the keyboard */ public void keyPressed(KeyEvent e) { int keyCode = e.getKeyCode(); // Empty the list of enclosed items if not a size-up or size-down press /* if (keyCode != KeyEvent.VK_F1 && keyCode != KeyEvent.VK_F2) { resetEnclosedItems(); } // Notify the change in stats // TODO: Will changing this to the Expeditee KBMInputEvent upset stats? cts16 SessionStats.AddFrameEvent("k" + KeyEvent.getKeyText(keyCode)); // Used for calculating frame stats (response time) FrameUtils.ResponseTimer.restart(); // e.consume(); // Things that should consume input before main Expeditee if (Actions.isAgentRunning()) { if (keyCode == KeyEvent.VK_ESCAPE) Actions.stopAgent(); else Actions.interruptAgent(); return; } else if (Simple.consumeKeyboardInput()) { return; } // Function keys are handled here if (keyCode >= KeyEvent.VK_F1 && keyCode <= KeyEvent.VK_F12) { functionKey(FunctionKey.values()[keyCode - KeyEvent.VK_F1 + 1], e.isShiftDown(), e.isControlDown()); return; }*/ // Keyboard for mouse emulation // TODO: Do we need individual mouse button clicks? Are the corresponding gestures enough? cts16 if (e.isAltDown()) { int distance = e.isShiftDown() ? 1 : 20; switch (keyCode) { case KeyEvent.VK_1: FrameMouseActions.leftButton(); // DisplayIO.clickMouse(InputEvent.BUTTON1_MASK); break; case KeyEvent.VK_2: // DisplayIO.clickMouse(InputEvent.BUTTON2_MASK); FrameMouseActions.middleButton(); break; case KeyEvent.VK_3: // DisplayIO.clickMouse(InputEvent.BUTTON3_MASK); FrameMouseActions.rightButton(); break; /* case KeyEvent.VK_LEFT: DisplayIO.translateCursor(-distance, 0); break; case KeyEvent.VK_RIGHT: DisplayIO.translateCursor(distance, 0); break; case KeyEvent.VK_UP: DisplayIO.translateCursor(0, -distance); break; case KeyEvent.VK_DOWN: DisplayIO.translateCursor(0, distance); break;*/ } return; } // Notify the mouse handler of the control/shift key state switch (keyCode) { case KeyEvent.VK_CONTROL: FrameMouseActions.control(e); break; case KeyEvent.VK_SHIFT: FrameMouseActions.shift(e); break; } // Handles all CTRL+KEY combinations if (e.isControlDown()) { controlChar(e.getKeyCode(), e.isShiftDown()); return; } // Handles all other keystrokes (with possible shift modifier) // Note: At this point e.isControlDown() must be false /* switch (keyCode) { case KeyEvent.VK_ESCAPE: // Do escape after control so Ctrl+Escape does not perform DropDown functionKey(FunctionKey.DropDown, e.isShiftDown(), false); SessionStats.Escape(); break; case KeyEvent.VK_LEFT: move(Text.LEFT, e.isShiftDown(), false); break; case KeyEvent.VK_RIGHT: move(Text.RIGHT, e.isShiftDown(), false); break; case KeyEvent.VK_PAGE_DOWN: navigateFrame(Text.PAGE_DOWN); break; case KeyEvent.VK_PAGE_UP: navigateFrame(Text.PAGE_UP); break; case KeyEvent.VK_UP: move(Text.UP, e.isShiftDown(), false); break; case KeyEvent.VK_DOWN: move(Text.DOWN, e.isShiftDown(), false); break; case KeyEvent.VK_END: move(Text.LINE_END, e.isShiftDown(), false); break; case KeyEvent.VK_HOME: move(Text.LINE_HOME, e.isShiftDown(), false); break; // TODO remove this when upgrading Java // This is a patch because Java6 wont trigger KeyTyped event for // Shift+Tab case KeyEvent.VK_TAB: if (e.isShiftDown()) { e.setKeyChar('\t'); keyTyped(e); } break; }*/ } public void keyReleased(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_CONTROL) { FrameMouseActions.control(e); } else if (e.getKeyCode() == KeyEvent.VK_SHIFT) { FrameMouseActions.shift(e); } else if (e.isAltDown() || e.isControlDown()) { // switch (e.getKeyCode()) { // case KeyEvent.VK_1: // DisplayIO.releaseMouse(InputEvent.BUTTON1_MASK); // break; // case KeyEvent.VK_2: // DisplayIO.releaseMouse(InputEvent.BUTTON2_MASK); // break; // case KeyEvent.VK_3: // DisplayIO.releaseMouse(InputEvent.BUTTON3_MASK); // break; // } } } /** * Processes all control character keystrokes. Currently Ctrl+C and Ctrl+V * are copy and paste, all other keystrokes are ignored. * * @param ch * The character being pressed along with the control key */ private void controlChar(int key, boolean isShiftDown) { //Logger.Log(Logger.USER, Logger.CONTROL_CHAR, "User pressing: Ctrl+" + KeyEvent.getKeyText(key)); // // if (FrameUtils.getCurrentItem() == null // && !Frame.itemAttachedToCursor()) { // Item t = DisplayIO.getCurrentFrame().createNewText(ch + ": "); // FrameMouseActions.pickup(t); // } else { // remove the link for ctrl+l Item current = FrameUtils.getCurrentItem(); Frame currentFrame = DisplayIO.getCurrentFrame(); int distance = isShiftDown ? 1 : 20; switch (key) { /* case KeyEvent.VK_HOME: if (current != null && current instanceof Text) { move(Text.HOME, isShiftDown, true); } else { while (DisplayIO.Back()) ; } break; case KeyEvent.VK_END: if (current != null && current instanceof Text) { move(Text.END, isShiftDown, true); } else { while (DisplayIO.Forward()) ; } break; case KeyEvent.VK_PAGE_UP: DisplayIO.Back(); break; case KeyEvent.VK_PAGE_DOWN: DisplayIO.Forward(); break; case KeyEvent.VK_TAB: calculateItem(current); break; case KeyEvent.VK_ESCAPE: // Do escape after control so Ctrl+Escape does not perform DropDown functionKey(FunctionKey.DropDown, isShiftDown, true); SessionStats.Escape();*/ break; case KeyEvent.VK_1: FrameMouseActions.leftButton(); // DisplayIO.clickMouse(InputEvent.BUTTON1_MASK); break; case KeyEvent.VK_2: FrameMouseActions.middleButton(); // DisplayIO.clickMouse(InputEvent.BUTTON2_MASK); break; case KeyEvent.VK_3: FrameMouseActions.rightButton(); // DisplayIO.clickMouse(InputEvent.BUTTON3_MASK); break; case KeyEvent.VK_LEFT: /* if (current instanceof Text) { DisplayIO.setTextCursor((Text) current, Text.LEFT, false, isShiftDown, true, true); } else */{ DisplayIO.translateCursor(-distance, 0); } break; case KeyEvent.VK_RIGHT: /* if (current instanceof Text) { DisplayIO.setTextCursor((Text) current, Text.RIGHT, false, isShiftDown, true, true); } else */{ DisplayIO.translateCursor(distance, 0); } break; /* case KeyEvent.VK_UP: // if (current instanceof Text) { NextTextItem(FrameUtils.getCurrentItem(), false); // } else { // DisplayIO.translateCursor(0, -distance); // } break; case KeyEvent.VK_DOWN: // if (current instanceof Text) { NextTextItem(FrameUtils.getCurrentItem(), true); // } else { // DisplayIO.translateCursor(0, distance); // } break; case KeyEvent.VK_L: // If its not linked then link it to itself if (current instanceof Text && current.getLink() == null) { String text = ((Text) current).getText(); // Ignore the annotation if there is one if (text.charAt(0) == '@') text = text.substring(1); if (FrameIO.isValidFrameName(text)) { current.setLink(text); } else if (FrameIO.isValidFramesetName(text)) { current.setLink(text + '1'); } } else if (current != null) { // If its linked remove the link current.setLink(null); } break; case KeyEvent.VK_G: // Same as CTRL+L but follows it afterwards // If its not linked then link it to itself if (current instanceof Text) { String text = ((Text) current).getText(); if (text.charAt(0) == '@') text = text.substring(1); if (FrameIO.isValidFrameName(text)) { current.setLink(text); } else if (FrameIO.isValidFramesetName(text)) { current.setLink(text + '1'); } } if (current != null && current.getLink() != null) { Navigation.Goto(current.getAbsoluteLink()); return; } break; case KeyEvent.VK_A: // If its not linked then link it to its self if (current instanceof Text) { if (!current.hasAction()) { String text = ((Text) current).getText().trim(); // first trim the annotation if (text.startsWith("@")) { text = text.substring(1).trim(); } // then trim the action String lowerCaseText = text.toLowerCase(); if (lowerCaseText.startsWith("a:")) { text = text.substring("a:".length()).trim(); } else if (lowerCaseText.startsWith("action:")) { text = text.substring("action:".length()).trim(); } current.setAction(text); } else { // If its linked remove the link current.setActions(null); } } break; case KeyEvent.VK_B: if (current instanceof Text) { ((Text) current).toggleBold(); } break; case KeyEvent.VK_I: if (current instanceof Text) { ((Text) current).toggleItalics(); } break; case KeyEvent.VK_V: ItemSelection.paste(); return; case KeyEvent.VK_C: if (FreeItems.hasItemsAttachedToCursor()) { ItemSelection.copyClone(); return; } if (current instanceof Text) { copyItemToClipboard(current); } Text item = null; // Check if its a line to be turned into a circle if (current instanceof Dot && current.getLines().size() == 1) { item = replaceDot(current, '@'); } else if (current instanceof Line && current.getAllConnected().size() == 3) { Item end = ((Line) current).getEndItem(); if (end instanceof Dot) { item = replaceDot(end, '@'); } else if (end instanceof Text) { item = (Text) end; } } if (item != null) { item.setText("@c"); DisplayIO.setCursorPosition(item.getX(), item.getY()); FrameUtils.setLastEdited(null); Refresh(); } return; case KeyEvent.VK_X: ItemSelection.cut(); return; case KeyEvent.VK_M: if (current == null) return; if (current != null && !current.hasPermission(UserAppliedPermission.full)) { MessageBay.displayMessage("Insufficient permission toggle the items mark"); return; } boolean newValue = !(current.getLinkMark() || current.getActionMark()); current.setLinkMark(newValue); current.setActionMark(newValue); break; case KeyEvent.VK_Z: if (isShiftDown) { DisplayIO.getCurrentFrame().redo(); } else { DisplayIO.getCurrentFrame().undo(); } return; case KeyEvent.VK_D: // perform a delete operation processChar((char) KeyEvent.VK_DELETE, isShiftDown); break; case KeyEvent.VK_DELETE: // perform a delete operation FrameMouseActions.delete(current); break;*/ case KeyEvent.VK_SPACE: if (isShiftDown) { FrameMouseActions.rightButton(); } else { FrameMouseActions.middleButton(); } break; /* case KeyEvent.VK_F: // perform a format operation if (isShiftDown) { Actions.PerformActionCatchErrors(currentFrame, null, "HFormat"); } else { Actions.PerformActionCatchErrors(currentFrame, null, "Format"); } return; case KeyEvent.VK_J: Text text = getCurrentTextItem(); if (text == null) { for (Text t : currentFrame.getBodyTextItems(false)) { t.justify(true); } return; } // if (text.getWidth() < 0) // text.setWidth(text.getBoundsWidth() - Item.MARGIN_RIGHT // - UserSettings.Gravity); text.justify(true); break; case KeyEvent.VK_R: // TODO: What is this? Similar to above? cts16 Text textCurrent = getCurrentTextItem(); if (textCurrent == null) { for (Text t : currentFrame.getBodyTextItems(false)) { t.setWidth(null); t.justify(true); } return; } textCurrent.setWidth(null); textCurrent.justify(true); break; case KeyEvent.VK_S: // Only split when shift is down... it is too easy to accidentally // hit Ctrl+S after completing a paragraph because this is the // shortcut for saving a document in most word processors and text // editors! if (!isShiftDown) { Save(); return; } Text text2 = getCurrentTextItem(); // split the current text item if (text2 == null) return; List textLines = text2.getTextList(); if (textLines.size() <= 1) return; // remove all except the first line of text from the item being // split text2.setText(textLines.get(0)); int y = text2.getY(); for (int i = 1; i < textLines.size(); i++) { Text newText = text2.copy(); newText.setText(textLines.get(i)); y += newText.getBoundsHeight(); newText.setY(y); // update the items ID to prevent conflicts with the current // frame newText.setID(currentFrame.getNextItemID()); currentFrame.addItem(newText); } break;*/ case KeyEvent.VK_ENTER: FrameMouseActions.leftButton(); break; /* case KeyEvent.VK_BACK_SPACE: DisplayIO.Back(); break;*/ } FrameGraphics.Repaint(); } /** * Gets the currently selected item if the user is allowed to modify it. * * @return null if the currently selected item is not a Text item that the * user has permission to modify */ private static Text getCurrentTextItem() { Item item = FrameUtils.getCurrentItem(); if (item != null && !item.hasPermission(UserAppliedPermission.full)) { MessageBay.displayMessage("Insufficient permission to copy that item"); return null; } Item on = null; if (item != null) on = item; if (on == null || !(on instanceof Text)) return null; return (Text) on; } /* public static void functionKey(FunctionKey key, boolean isShiftDown, boolean isControlDown) { functionKey(key, 1, isShiftDown, isControlDown); } */ /** * Called when a Function key has been pressed, and performs the specific * action based on the key. */ /* public static void functionKey(FunctionKey key, int repeat, boolean isShiftDown, boolean isControlDown) { // get whatever the user is pointing at Item on = FrameUtils.getCurrentItem(); String displayMessage = "F" + key.ordinal() + ": " + key.toString(); // check for enclosed mode if (on == null && key.ordinal() < FunctionKey.AudienceMode.ordinal()) { Collection enclosed = FrameUtils.getCurrentItems(on); if (enclosed != null && enclosed.size() > 0) { // ensure only one dot\line is present in the list Collection lineEnds = FrameUtils.getEnclosingLineEnds(); Item firstConnected = lineEnds.iterator().next(); Collection connected = firstConnected.getAllConnected(); switch (key) { case DropDown: IndirectKeyboardActions .getInstance() .getDropDownAction() .exec(new KeyboardInfo(key, repeat, isShiftDown, isControlDown, enclosed, firstConnected, connected, lineEnds), (char) 0); break; case SizeUp: IndirectKeyboardActions .getInstance() .getSizeUpAction() .exec(new KeyboardInfo(key, repeat, isShiftDown, isControlDown, enclosed, firstConnected, connected, lineEnds), (char) 0); break; case SizeDown: IndirectKeyboardActions .getInstance() .getSizeDownAction() .exec(new KeyboardInfo(key, repeat, isShiftDown, isControlDown, enclosed, firstConnected, connected, lineEnds), (char) 0); break; case ChangeColor: IndirectKeyboardActions .getInstance() .getChangeColorAction() .exec(new KeyboardInfo(key, repeat, isShiftDown, isControlDown, enclosed, firstConnected, connected, lineEnds), (char) 0); break; case ToggleAnnotation: IndirectKeyboardActions .getInstance() .getToggleAnnotationAction() .exec(new KeyboardInfo(key, repeat, isShiftDown, isControlDown, enclosed, firstConnected, connected, lineEnds), (char) 0); break; case ChangeFontStyle: IndirectKeyboardActions .getInstance() .getChangeFontStyleAction() .exec(new KeyboardInfo(key, repeat, isShiftDown, isControlDown, enclosed, firstConnected, connected, lineEnds), (char) 0); break; case ChangeFontFamily: IndirectKeyboardActions .getInstance() .getChangeFontFamilyAction() .exec(new KeyboardInfo(key, repeat, isShiftDown, isControlDown, enclosed, firstConnected, connected, lineEnds), (char) 0); break; case InsertDate: IndirectKeyboardActions .getInstance() .getInsertDateAction() .exec(new KeyboardInfo(key, repeat, isShiftDown, isControlDown, enclosed, firstConnected, connected, lineEnds), (char) 0); break; case Save: IndirectKeyboardActions .getInstance() .getSaveAction() .exec(new KeyboardInfo(key, repeat, isShiftDown, isControlDown, enclosed, firstConnected, connected, lineEnds), (char) 0); MessageBay.displayMessage(displayMessage); break; } return; } } // Show a description of the function key pressed if the user is in free // space and return for the F keys that dont do anything in free space. if (on == null) { // int mouse_x = FrameMouseActions.getX(), mouse_y = FrameMouseActions.getY(); switch (key) { // These function keys still work in free space // case DropDown: // case InsertDate: case XRayMode: case AudienceMode: case Refresh: // case Save: break; case SizeDown: zoomFrameIfEnabled(DisplayIO.getCurrentFrame(), 0.909090909f, mouse_x,mouse_y); // if (isControlDown) { // UserSettings.ScaleFactor.set(UserSettings.ScaleFactor.get() - // 0.05f); // Misc.repaint(); // return; // } return; case SizeUp: zoomFrameIfEnabled(DisplayIO.getCurrentFrame(), 1.1f, mouse_x,mouse_y); // if (isControlDown) { // UserSettings.ScaleFactor.set(UserSettings.ScaleFactor.get() + // 0.05f); // Misc.repaint(); // return; // } return; default: MessageBay.displayMessageOnce(displayMessage); return; } } switch (key) { case DropDown: if (isShiftDown || isControlDown) { if (on != null) { calculateItem(on); } } // Drop(on, false); return; case SizeUp: SetSize(on, repeat, true, false, isControlDown); if (on instanceof Text) { DisplayIO.setTextCursor((Text) on, Text.NONE, true, false, false, true); } break; case SizeDown: SetSize(on, -repeat, true, false, isControlDown); if (on instanceof Text) { DisplayIO.setTextCursor((Text) on, Text.NONE, true, false, false, true); } break; case ChangeColor: SetColor(on, isShiftDown, isControlDown); break; case ToggleAnnotation: ToggleAnnotation(on); break; case ChangeFontStyle: ToggleFontStyle(on); break; case ChangeFontFamily: ToggleFontFamily(on); break; case InsertDate: AddDate(on); return; case NewFrameset: CreateFrameset(on); break; case XRayMode: FrameGraphics.ToggleXRayMode(); break; case AudienceMode: FrameGraphics.ToggleAudienceMode(); break; case Refresh: if (isControlDown) { MessageBay.displayMessage("Forced reload before forced refresh"); DisplayIO.Reload(0); } Refresh(); break; case Save: Save(); break; } on = FrameUtils.getCurrentItem(); Collection enclosed = FrameUtils.getCurrentItems(on); if (on == null && (enclosed == null || enclosed.size() == 0)) MessageBay.displayMessage(displayMessage); } }*/