示例#1
0
  /**
   * Handle the keys which change the terminal font size.
   *
   * @param event The key event (key pressed/released/typed)
   * @param ch The key code (for pressed/release events) or character (for key typed events)
   */
  private boolean handleFontsizeKeys(KeyEvent event, int ch) {
    boolean handled = false;

    // Note the following works because VK_EQUALS, VK_PLUS and VK_MINUS
    // are actually defined as their ASCII (and thus unicode) equivalent.
    // Since they are final constants this cannot become untrue in the
    // future.

    switch (ch) {
      case KeyEvent.VK_EQUALS: // increase the font size
      case KeyEvent.VK_PLUS: // increase the font size (non-uk keyboards)
        if (event.getModifiers() == SHORTCUT_MASK) {
          PrefMgr.setEditorFontSize(terminalFontSize + 1);
          event.consume();
          handled = true;
          break;
        }

      case KeyEvent.VK_MINUS: // decrease the font size
        if (event.getModifiers() == SHORTCUT_MASK) {
          PrefMgr.setEditorFontSize(terminalFontSize - 1);
          event.consume();
          handled = true;
          break;
        }
    }

    return handled;
  }
示例#2
0
  /**
   * Adds a single item to this roles popup menu.
   *
   * <p>This method is used by ClassTarget to add some standard menus as well as by the roles to add
   * menus. It should be overridden with caution.
   *
   * @param menu the popup menu the item is to be added to
   * @param action the action to be registered with this menu item
   * @param itemString the String to be displayed on menu item
   * @param enabled boolean value representing whether item should be enabled
   */
  public void addMenuItem(JPopupMenu menu, Action action, boolean enabled) {
    JMenuItem item;

    item = new JMenuItem();
    item.setAction(action);
    item.setFont(PrefMgr.getPopupMenuFont());
    item.setForeground(envOpColour);
    item.setEnabled(enabled);

    menu.add(item);
  }
示例#3
0
  /**
   * Create the menu items for the given members (constructors or methods).
   *
   * @return true if any items were created
   */
  public static boolean createMenuItems(
      JPopupMenu menu,
      CallableView[] members,
      ViewFilter filter,
      int first,
      int last,
      String prefix,
      InvokeListener il) {
    // Debug.message("Inside ClassTarget.createMenuItems\n first = " + first
    // + " last = " + last);
    boolean hasEntries = false;
    JMenuItem item;

    for (int i = first; i < last; i++) {
      try {
        CallableView m = members[last - i - 1];
        if (!filter.accept(m)) continue;
        // Debug.message("createSubMenu - creating MenuItem");

        Action callAction = null;
        if (m instanceof MethodView)
          callAction = new InvokeAction((MethodView) m, il, prefix + m.getLongDesc());
        else if (m instanceof ConstructorView)
          callAction = new ConstructAction((ConstructorView) m, il, prefix + m.getLongDesc());

        if (callAction != null) {
          item = menu.add(callAction);
          item.setFont(PrefMgr.getPopupMenuFont());
          hasEntries = true;
        }
      } catch (Exception e) {
        Debug.reportError("Exception accessing methods: " + e);
        e.printStackTrace();
      }
    }
    return hasEntries;
  }
示例#4
0
/**
 * The Frame part of the Terminal window used for I/O when running programs under BlueJ.
 *
 * @author Michael Kolling
 * @author Philip Stevens
 */
@SuppressWarnings("serial")
public final class Terminal extends JFrame
    implements KeyListener, BlueJEventListener, DebuggerTerminal {
  private static final String WINDOWTITLE =
      Config.getApplicationName() + ": " + Config.getString("terminal.title");
  private static final int SHORTCUT_MASK = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
  // private static final int ALT_SHORTCUT_MASK =
  //        SHORTCUT_MASK == Event.CTRL_MASK ? Event.CTRL_MASK : Event.META_MASK;

  private static final String TERMINALFONTPROPNAME = "bluej.terminal.font";
  private static final String TERMINALFONTSIZEPROPNAME = "bluej.editor.fontsize";

  private static final String RECORDMETHODCALLSPROPNAME = "bluej.terminal.recordcalls";
  private static final String CLEARONMETHODCALLSPROPNAME = "bluej.terminal.clearscreen";
  private static final String UNLIMITEDBUFFERINGCALLPROPNAME = "bluej.terminal.buffering";

  // initialise to config value or zero.
  private static int terminalFontSize =
      Config.getPropInteger(TERMINALFONTSIZEPROPNAME, PrefMgr.getEditorFontSize());

  private static boolean isMacOs = Config.isMacOS();

  // -- instance --

  private Project project;

  private TermTextArea text;
  private TermTextArea errorText;
  private JScrollPane errorScrollPane;
  private JScrollPane scrollPane;
  private JSplitPane splitPane;
  private boolean isActive = false;
  private static boolean recordMethodCalls = Config.getPropBoolean(RECORDMETHODCALLSPROPNAME);
  private static boolean clearOnMethodCall = Config.getPropBoolean(CLEARONMETHODCALLSPROPNAME);
  private static boolean unlimitedBufferingCall =
      Config.getPropBoolean(UNLIMITEDBUFFERINGCALLPROPNAME);
  private boolean newMethodCall = true;
  private boolean errorShown = false;
  private InputBuffer buffer;

  private JCheckBoxMenuItem autoClear;
  private JCheckBoxMenuItem recordCalls;
  private JCheckBoxMenuItem unlimitedBuffering;

  private Reader in = new TerminalReader();
  private Writer out = new TerminalWriter(false);
  private Writer err = new TerminalWriter(true);

  /** Used for lazy initialisation */
  private boolean initialised = false;

  /** Create a new terminal window with default specifications. */
  public Terminal(Project project) {
    super(WINDOWTITLE + " - " + project.getProjectName());
    this.project = project;
    BlueJEvent.addListener(this);
  }

  /** Get the terminal font */
  private static Font getTerminalFont() {
    // reload terminal fontsize from configurations.

    terminalFontSize = Config.getPropInteger(TERMINALFONTSIZEPROPNAME, PrefMgr.getEditorFontSize());
    return Config.getFont(TERMINALFONTPROPNAME, "Monospaced", terminalFontSize);
  }

  /*
   * Set the terminal font size to equal either the passed parameter, or the
   * editor font size if the passed parameter is too low. Place the updated
   * value into the configuration.
   */
  public static void setTerminalFontSize(int size) {
    if (size <= 6) {
      return;
    } else {
      terminalFontSize = size;
    }
    Config.putPropInteger(TERMINALFONTSIZEPROPNAME, terminalFontSize);
  }

  /** Initialise the terminal; create the UI. */
  private synchronized void initialise() {
    if (!initialised) {
      buffer = new InputBuffer(256);
      int width = Config.isGreenfoot() ? 80 : Config.getPropInteger("bluej.terminal.width", 80);
      int height = Config.isGreenfoot() ? 10 : Config.getPropInteger("bluej.terminal.height", 22);
      makeWindow(width, height);
      initialised = true;
      text.setUnlimitedBuffering(unlimitedBufferingCall);
    }
  }

  /** Show or hide the Terminal window. */
  public void showHide(boolean show) {
    DataCollector.showHideTerminal(project, show);

    initialise();
    setVisible(show);
    if (show) {
      text.requestFocus();
    }
  }

  /** Return true if the window is currently displayed. */
  public boolean isShown() {
    initialise();
    return isShowing();
  }

  /** Make the window active. */
  public void activate(boolean active) {
    if (active != isActive) {
      initialise();
      text.setEditable(active);
      if (!active) {
        text.getCaret().setVisible(false);
      }
      isActive = active;
    }
  }

  /** Check whether the terminal is active (accepting input). */
  public boolean checkActive() {
    return isActive;
  }

  /** Reset the font according to preferences. */
  public void resetFont() {
    initialise();
    Font terminalFont = getTerminalFont();
    text.setFont(terminalFont);
    if (errorText != null) {
      errorText.setFont(terminalFont);
    }
  }

  /** Clear the terminal. */
  public void clear() {
    initialise();
    text.setText("");
    if (errorText != null) {
      errorText.setText("");
    }
    hideErrorPane();
  }

  /** Save the terminal text to file. */
  public void save() {
    initialise();
    String fileName =
        FileUtility.getFileName(
            this,
            Config.getString("terminal.save.title"),
            Config.getString("terminal.save.buttonText"),
            null,
            false);
    if (fileName != null) {
      File f = new File(fileName);
      if (f.exists()) {
        if (DialogManager.askQuestion(this, "error-file-exists") != 0) return;
      }
      try {
        FileWriter writer = new FileWriter(fileName);
        text.write(writer);
        writer.close();
      } catch (IOException ex) {
        DialogManager.showError(this, "error-save-file");
      }
    }
  }

  public void print() {
    PrinterJob job = PrinterJob.getPrinterJob();
    int printFontSize = Config.getPropInteger("bluej.fontsize.printText", 10);
    Font font = new Font("Monospaced", Font.PLAIN, printFontSize);
    if (job.printDialog()) {
      TerminalPrinter.printTerminal(job, text, job.defaultPage(), font);
    }
  }

  /** Write some text to the terminal. */
  private void writeToPane(boolean stdout, String s) {
    prepare();
    if (!stdout) showErrorPane();

    // The form-feed character should clear the screen.
    int n = s.lastIndexOf('\f');
    if (n != -1) {
      clear();
      s = s.substring(n + 1);
    }

    TermTextArea tta = stdout ? text : errorText;

    tta.append(s);
    tta.setCaretPosition(tta.getDocument().getLength());
  }

  public void writeToTerminal(String s) {
    writeToPane(true, s);
  }

  /** Prepare the terminal for I/O. */
  private void prepare() {
    if (newMethodCall) { // prepare only once per method call
      showHide(true);
      newMethodCall = false;
    } else if (Config.isGreenfoot()) {
      // In greenfoot new output should always show the terminal
      if (!isVisible()) {
        showHide(true);
      }
    }
  }

  /** An interactive method call has been made by a user. */
  private void methodCall(String callString) {
    newMethodCall = false;
    if (clearOnMethodCall) {
      clear();
    }
    if (recordMethodCalls) {
      text.appendMethodCall(callString + "\n");
    }
    newMethodCall = true;
  }

  private void constructorCall(InvokerRecord ir) {
    newMethodCall = false;
    if (clearOnMethodCall) {
      clear();
    }
    if (recordMethodCalls) {
      String callString =
          ir.getResultTypeString() + " " + ir.getResultName() + " = " + ir.toExpression() + ";";
      text.appendMethodCall(callString + "\n");
    }
    newMethodCall = true;
  }

  private void methodResult(ExecutionEvent event) {
    if (recordMethodCalls) {
      String result = null;
      String resultType = event.getResult();

      if (resultType == ExecutionEvent.NORMAL_EXIT) {
        DebuggerObject object = event.getResultObject();
        if (object != null) {
          if (event.getClassName() != null && event.getMethodName() == null) {
            // Constructor call - the result object is the created object.
            // Don't display the result separately:
            return;
          } else {
            // if the method returns a void, we must handle it differently
            if (object.isNullObject()) {
              return; // Don't show result of void calls
            } else {
              // other - the result object is a wrapper with a single result field
              DebuggerField resultField = object.getField(0);
              result = "    returned " + resultField.getType().toString(true) + " ";
              result += resultField.getValueString();
            }
          }
        }
      } else if (resultType == ExecutionEvent.EXCEPTION_EXIT) {
        result = "    Exception occurred.";
      } else if (resultType == ExecutionEvent.TERMINATED_EXIT) {
        result = "    VM terminated.";
      }

      if (result != null) {
        text.appendMethodCall(result + "\n");
      }
    }
  }

  /** Return the input stream that can be used to read from this terminal. */
  public Reader getReader() {
    return in;
  }

  /** Return the output stream that can be used to write to this terminal */
  public Writer getWriter() {
    return out;
  }

  /** Return the output stream that can be used to write error output to this terminal */
  public Writer getErrorWriter() {
    return err;
  }

  // ---- KeyListener interface ----

  @Override
  public void keyPressed(KeyEvent event) {
    if (isMacOs) {
      handleFontsizeKeys(event, event.getKeyCode());
    }
  }

  @Override
  public void keyReleased(KeyEvent event) {}

  /**
   * Handle the keys which change the terminal font size.
   *
   * @param event The key event (key pressed/released/typed)
   * @param ch The key code (for pressed/release events) or character (for key typed events)
   */
  private boolean handleFontsizeKeys(KeyEvent event, int ch) {
    boolean handled = false;

    // Note the following works because VK_EQUALS, VK_PLUS and VK_MINUS
    // are actually defined as their ASCII (and thus unicode) equivalent.
    // Since they are final constants this cannot become untrue in the
    // future.

    switch (ch) {
      case KeyEvent.VK_EQUALS: // increase the font size
      case KeyEvent.VK_PLUS: // increase the font size (non-uk keyboards)
        if (event.getModifiers() == SHORTCUT_MASK) {
          PrefMgr.setEditorFontSize(terminalFontSize + 1);
          event.consume();
          handled = true;
          break;
        }

      case KeyEvent.VK_MINUS: // decrease the font size
        if (event.getModifiers() == SHORTCUT_MASK) {
          PrefMgr.setEditorFontSize(terminalFontSize - 1);
          event.consume();
          handled = true;
          break;
        }
    }

    return handled;
  }

  @Override
  public void keyTyped(KeyEvent event) {
    // We handle most things we are interested in here. The InputMap filters out
    // most other unwanted actions (but allows copy/paste).

    char ch = event.getKeyChar();

    if ((!isMacOs) && handleFontsizeKeys(event, ch)) {
      // Note: On Mac OS with Java 7+, we don't see command+= / command+- as a
      // key-typed event and so we handle it in keyReleased instead.
      return;
    }

    if ((event.getModifiers() & Event.META_MASK) != 0) {
      return; // return without consuming the event
    }
    if (isActive) {
      switch (ch) {
        case 4: // CTRL-D (unix/Mac EOF)
        case 26: // CTRL-Z (DOS/Windows EOF)
          buffer.signalEOF();
          writeToTerminal("\n");
          event.consume();
          break;

        case '\b': // backspace
          if (buffer.backSpace()) {
            try {
              int length = text.getDocument().getLength();
              text.replaceRange("", length - 1, length);
            } catch (Exception exc) {
              Debug.reportError("bad location " + exc);
            }
          }
          event.consume();
          break;

        case '\r': // carriage return
        case '\n': // newline
          if (buffer.putChar('\n')) {
            writeToTerminal(String.valueOf(ch));
            buffer.notifyReaders();
          }
          event.consume();
          break;

        default:
          if (ch >= 32) {
            if (buffer.putChar(ch)) {
              writeToTerminal(String.valueOf(ch));
            }
            event.consume();
          }
          break;
      }
    }
  }

  // ---- BlueJEventListener interface ----

  /**
   * Called when a BlueJ event is raised. The event can be any BlueJEvent type. The implementation
   * of this method should check first whether the event type is of interest an return immediately
   * if it isn't.
   *
   * @param eventId A constant identifying the event. One of the event id constants defined in
   *     BlueJEvent.
   * @param arg An event specific parameter. See BlueJEvent for definition.
   */
  @Override
  public void blueJEvent(int eventId, Object arg) {
    initialise();
    if (eventId == BlueJEvent.METHOD_CALL) {
      InvokerRecord ir = (InvokerRecord) arg;
      if (ir.getResultName() != null) {
        constructorCall(ir);
      } else {
        boolean isVoid = ir.hasVoidResult();
        if (isVoid) {
          methodCall(ir.toStatement());
        } else {
          methodCall(ir.toExpression());
        }
      }
    } else if (eventId == BlueJEvent.EXECUTION_RESULT) {
      methodResult((ExecutionEvent) arg);
    }
  }

  // ---- make window frame ----

  /** Create the Swing window. */
  private void makeWindow(int columns, int rows) {
    Image icon = BlueJTheme.getIconImage();
    if (icon != null) {
      setIconImage(icon);
    }
    text = new TermTextArea(rows, columns, buffer, project, this, false);
    final InputMap origInputMap = text.getInputMap();
    text.setInputMap(
        JComponent.WHEN_FOCUSED,
        new InputMap() {
          {
            setParent(origInputMap);
          }

          @Override
          public Object get(KeyStroke keyStroke) {
            Object actionName = super.get(keyStroke);

            if (actionName == null) {
              return null;
            }

            char keyChar = keyStroke.getKeyChar();
            if (keyChar == KeyEvent.CHAR_UNDEFINED || keyChar < 32) {
              // We might want to filter the action
              if ("copy-to-clipboard".equals(actionName)) {
                return actionName;
              }
              if ("paste-from-clipboard".equals(actionName)) {
                // Handled via paste() in TermTextArea
                return actionName;
              }
              return PrefMgr.getFlag(PrefMgr.ACCESSIBILITY_SUPPORT) ? actionName : null;
            }

            return actionName;
          }
        });

    scrollPane = new JScrollPane(text);
    text.setFont(getTerminalFont());
    text.setEditable(false);
    text.setMargin(new Insets(6, 6, 6, 6));
    text.addKeyListener(this);

    getContentPane().add(scrollPane, BorderLayout.CENTER);

    setJMenuBar(makeMenuBar());

    // Close Action when close button is pressed
    addWindowListener(
        new WindowAdapter() {
          @Override
          public void windowClosing(WindowEvent event) {
            Window win = (Window) event.getSource();

            // don't allow them to close the window if the debug machine
            // is running.. tries to stop them from closing down the
            // input window before finishing off input in the terminal
            if (project != null) {
              if (project.getDebugger().getStatus() == Debugger.RUNNING) return;
            }
            DataCollector.showHideTerminal(project, false);
            win.setVisible(false);
          }
        });

    // save position when window is moved
    addComponentListener(
        new ComponentAdapter() {
          @Override
          public void componentMoved(ComponentEvent event) {
            Config.putLocation("bluej.terminal", getLocation());
          }
        });

    setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);

    setLocation(Config.getLocation("bluej.terminal"));

    pack();
  }

  /** Create a second scrolled text area to the window, for error output. */
  private void createErrorPane() {
    errorText = new TermTextArea(Config.isGreenfoot() ? 20 : 5, 80, null, project, this, true);
    errorScrollPane = new JScrollPane(errorText);
    errorText.setFont(getTerminalFont());
    errorText.setEditable(false);
    errorText.setMargin(new Insets(6, 6, 6, 6));
    errorText.setUnlimitedBuffering(true);

    splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, scrollPane, errorScrollPane);
  }

  /** Show the errorPane for error output */
  private void showErrorPane() {
    if (errorShown) {
      return;
    }

    // the first time the errortext is shown we need to pack() it
    // to make it have the right size.
    boolean isFirstShow = false;
    if (errorText == null) {
      isFirstShow = true;
      createErrorPane();
    }

    getContentPane().remove(scrollPane);

    // We want to know if it is not the first time
    // This means a "clear" has been used to remove the splitpane
    // when this re-adds the scrollPane to the terminal area
    // it implicitly removes it from the splitpane as it can only have one
    // owner. The side-effect of this is the splitpane's
    // top component becomes null.
    if (!isFirstShow) splitPane.setTopComponent(scrollPane);
    getContentPane().add(splitPane, BorderLayout.CENTER);
    splitPane.resetToPreferredSizes();

    if (isFirstShow) {
      pack();
    } else {
      validate();
    }

    errorShown = true;
  }

  /** Hide the pane with the error output. */
  private void hideErrorPane() {
    if (!errorShown) {
      return;
    }
    getContentPane().remove(splitPane);
    getContentPane().add(scrollPane, BorderLayout.CENTER);
    errorShown = false;
    validate();
  }

  /** Create the terminal's menubar, all menus and items. */
  private JMenuBar makeMenuBar() {
    JMenuBar menubar = new JMenuBar();
    JMenu menu = new JMenu(Config.getString("terminal.options"));
    JMenuItem item;
    item = menu.add(new ClearAction());
    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_K, SHORTCUT_MASK));
    item = menu.add(getCopyAction());
    item.setText(Config.getString("terminal.copy"));
    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, SHORTCUT_MASK));
    item = menu.add(new SaveAction());
    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, SHORTCUT_MASK));
    menu.add(new PrintAction());
    menu.add(new JSeparator());

    autoClear = new JCheckBoxMenuItem(new AutoClearAction());
    autoClear.setSelected(clearOnMethodCall);
    menu.add(autoClear);

    recordCalls = new JCheckBoxMenuItem(new RecordCallAction());
    recordCalls.setSelected(recordMethodCalls);
    menu.add(recordCalls);

    unlimitedBuffering = new JCheckBoxMenuItem(new BufferAction());
    unlimitedBuffering.setSelected(unlimitedBufferingCall);
    menu.add(unlimitedBuffering);

    menu.add(new JSeparator());
    item = menu.add(new CloseAction());
    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_W, SHORTCUT_MASK));

    menubar.add(menu);
    return menubar;
  }

  private class ClearAction extends AbstractAction {
    public ClearAction() {
      super(Config.getString("terminal.clear"));
    }

    public void actionPerformed(ActionEvent e) {
      clear();
    }
  }

  private class SaveAction extends AbstractAction {
    public SaveAction() {
      super(Config.getString("terminal.save"));
    }

    public void actionPerformed(ActionEvent e) {
      save();
    }
  }

  private class PrintAction extends AbstractAction {
    public PrintAction() {
      super(Config.getString("terminal.print"));
    }

    public void actionPerformed(ActionEvent e) {
      print();
    }
  }

  private class CloseAction extends AbstractAction {
    public CloseAction() {
      super(Config.getString("terminal.close"));
    }

    public void actionPerformed(ActionEvent e) {
      showHide(false);
    }
  }

  private Action getCopyAction() {
    Action[] textActions = text.getActions();
    for (int i = 0; i < textActions.length; i++) {
      if (textActions[i].getValue(Action.NAME).equals("copy-to-clipboard")) {
        return textActions[i];
      }
    }

    return null;
  }

  private class AutoClearAction extends AbstractAction {
    public AutoClearAction() {
      super(Config.getString("terminal.clearScreen"));
    }

    public void actionPerformed(ActionEvent e) {
      clearOnMethodCall = autoClear.isSelected();
      Config.putPropBoolean(CLEARONMETHODCALLSPROPNAME, clearOnMethodCall);
    }
  }

  private class RecordCallAction extends AbstractAction {
    public RecordCallAction() {
      super(Config.getString("terminal.recordCalls"));
    }

    public void actionPerformed(ActionEvent e) {
      recordMethodCalls = recordCalls.isSelected();
      Config.putPropBoolean(RECORDMETHODCALLSPROPNAME, recordMethodCalls);
    }
  }

  private class BufferAction extends AbstractAction {
    public BufferAction() {
      super(Config.getString("terminal.buffering"));
    }

    public void actionPerformed(ActionEvent e) {
      unlimitedBufferingCall = unlimitedBuffering.isSelected();
      text.setUnlimitedBuffering(unlimitedBufferingCall);
      Config.putPropBoolean(UNLIMITEDBUFFERINGCALLPROPNAME, unlimitedBufferingCall);
    }
  }

  /** A Reader which reads from the terminal. */
  private class TerminalReader extends Reader {
    public int read(char[] cbuf, int off, int len) {
      initialise();
      int charsRead = 0;

      while (charsRead < len) {
        cbuf[off + charsRead] = buffer.getChar();
        charsRead++;
        if (buffer.isEmpty()) break;
      }
      return charsRead;
    }

    @Override
    public boolean ready() {
      return !buffer.isEmpty();
    }

    public void close() {}
  }

  /**
   * A writer which writes to the terminal. It can be flagged for error output. The idea is that
   * error output could be presented differently from standard output.
   */
  private class TerminalWriter extends Writer {
    private boolean isErrorOut;

    TerminalWriter(boolean isError) {
      super();
      isErrorOut = isError;
    }

    public void write(final char[] cbuf, final int off, final int len) {
      try {
        // We use invokeAndWait so that terminal output is limited to
        // the processing speed of the event queue. This means the UI
        // will still respond to user input even if the output is really
        // gushing.
        EventQueue.invokeAndWait(
            new Runnable() {
              public void run() {
                initialise();
                writeToPane(!isErrorOut, new String(cbuf, off, len));
              }
            });
      } catch (InvocationTargetException ite) {
        ite.printStackTrace();
      } catch (InterruptedException ie) {
      }
    }

    public void flush() {}

    public void close() {}
  }
}
示例#5
0
  /** Get the terminal font */
  private static Font getTerminalFont() {
    // reload terminal fontsize from configurations.

    terminalFontSize = Config.getPropInteger(TERMINALFONTSIZEPROPNAME, PrefMgr.getEditorFontSize());
    return Config.getFont(TERMINALFONTPROPNAME, "Monospaced", terminalFontSize);
  }
 private void addMenuItem(JPopupMenu menu, Action action) {
   JMenuItem item = menu.add(action);
   item.setFont(PrefMgr.getPopupMenuFont());
   item.setForeground(envOpColour);
 }
 /**
  * Sets the value of expanded/collapsed to the current view and to the prefmgr
  *
  * @param expanded
  */
 protected void setExpanded(boolean expanded) {
   // saving the value of the naviview (expanded/collapsed) to the prefmgr
   // so it is there when the next editor may be opened
   PrefMgr.setNaviviewExpanded(expanded);
   this.expanded = expanded;
 }
示例#8
0
/**
 * Class to provide simple UI customisations such as colours and fonts. Specifically created to
 * allow access to default Fonts for user interface components for i18n purposes.
 *
 * @author Bruce Quig
 * @version $Id: BlueJTheme.java 6215 2009-03-30 13:28:25Z polle $
 */
public class BlueJTheme extends DefaultMetalTheme {
  private final FontUIResource controlFont = new FontUIResource(PrefMgr.getStandardFont());
  private final FontUIResource systemFont = new FontUIResource(controlFont);
  private final FontUIResource userFont = new FontUIResource(controlFont);
  private final FontUIResource menuFont = new FontUIResource(PrefMgr.getStandardMenuFont());

  // icon to be used for BlueJ windows
  private static Image iconImage = null;

  // common strings - must be accessed through getOkLabel()
  private static String okayLabel;
  private static String cancelLabel;
  private static String closeLabel;
  private static String continueLabel;

  // a dimension for ok and cancel buttons that is as large as
  // needed to display either
  private static Dimension okCancelDimension;

  // JSplitPane divider width constant
  public static final int splitPaneDividerWidth = 3;

  // Other general spacing constants. We should try to use these for consistency
  public static final int generalSpacingWidth = 5;

  public static final Border generalBorder = BorderFactory.createEmptyBorder(10, 10, 10, 10);

  public static final Border generalBorderWithStatusBar =
      BorderFactory.createEmptyBorder(10, 10, 0, 10);

  public static final Border dialogBorder = BorderFactory.createEmptyBorder(12, 12, 12, 12);

  private static Border roundedShadowBorder;
  private static Border shadowBorder;

  public static final int commandButtonSpacing = 5;
  public static final int commandButtonPadding = 12;

  public static final int componentSpacingSmall = 5;
  public static final int componentSpacingLarge = 11;

  public static final int dialogCommandButtonsVertical = 17;

  /** Name of theme */
  public String getName() {
    return "BlueJTheme";
  }

  public FontUIResource getControlTextFont() {
    return controlFont;
  }

  public FontUIResource getSystemTextFont() {
    return systemFont;
  }

  public FontUIResource getUserTextFont() {
    return userFont;
  }

  public FontUIResource getMenuTextFont() {
    return menuFont;
  }

  /**
   * Get the icon for most BlueJ frames.
   *
   * @return an icon to be used as the frame icon for most BlueJ windows
   */
  public static Image getIconImage() {
    if (iconImage == null) iconImage = Config.getImageAsIcon("image.icon").getImage();

    return iconImage;
  }

  public static void setIconImage(Image newIconImage) {
    iconImage = newIconImage;
  }

  public static String getOkLabel() {
    if (okayLabel == null) {
      okayLabel = Config.getString("okay");
    }
    return okayLabel;
  }

  public static String getCancelLabel() {
    if (cancelLabel == null) {
      cancelLabel = Config.getString("cancel");
    }
    return cancelLabel;
  }

  public static String getCloseLabel() {
    if (closeLabel == null) {
      closeLabel = Config.getString("close");
    }
    return closeLabel;
  }

  public static String getContinueLabel() {
    if (continueLabel == null) {
      continueLabel = Config.getString("continue");
    }
    return continueLabel;
  }

  /**
   * Get a standard BlueJ "ok" button.
   *
   * @return A JButton that says "ok"
   */
  public static JButton getOkButton() {
    computeButtonWidths();

    JButton okButton = new JButton(getOkLabel());
    // try to make the OK, cancel and continue buttons have equal size
    okButton.setPreferredSize(okCancelDimension);
    return okButton;
  }

  /**
   * Get a standard BlueJ "cancel" button.
   *
   * @return A JButton that says "cancel"
   */
  public static JButton getCancelButton() {
    computeButtonWidths();

    JButton cancelButton = new JButton(getCancelLabel());
    // try to make the OK, cancel and continue  buttons have equal size
    cancelButton.setPreferredSize(okCancelDimension);
    return cancelButton;
  }

  /**
   * Get a standard BlueJ "close" button.
   *
   * @return A JButton that says "cancel"
   */
  public static JButton getCloseButton() {
    computeButtonWidths();

    JButton closeButton = new JButton(getCloseLabel());
    // try to make the OK, cancel and continue  buttons have equal size
    closeButton.setPreferredSize(okCancelDimension);
    return closeButton;
  }

  /**
   * Get a standard BlueJ "continue" button.
   *
   * @return A JButton that says "Continue"
   */
  public static JButton getContinueButton() {
    computeButtonWidths();

    JButton continueButton = new JButton(getContinueLabel());
    // try to make the OK, cancel and continue  buttons have equal size
    continueButton.setPreferredSize(okCancelDimension);
    return continueButton;
  }

  public static synchronized Border getRoundedShadowBorder() {
    if (roundedShadowBorder == null) {
      roundedShadowBorder = new RoundedShadowBorder();
    }
    return roundedShadowBorder;
  }

  public static synchronized Border getShadowBorder() {
    if (roundedShadowBorder == null) {
      shadowBorder = new ShadowBorder();
    }
    return roundedShadowBorder;
  }

  /**
   * Computer the maximum width of the ok, cancel and continue buttons and set the okCancelDimension
   * to be representative of that size.
   */
  private static void computeButtonWidths() {
    if (okCancelDimension != null) return;

    JButton okButton = new JButton(getOkLabel());
    JButton cancelButton = new JButton(getCancelLabel());
    JButton continueButton = new JButton(getContinueLabel());

    int maxWidth =
        Math.max(cancelButton.getPreferredSize().width, okButton.getPreferredSize().width);
    maxWidth = Math.max(maxWidth, continueButton.getPreferredSize().width);

    okCancelDimension = new Dimension(maxWidth, okButton.getPreferredSize().height);
  }

  /**
   * A border with rounded corners and a shadow
   *
   * @author Poul Henriksen
   */
  private static class RoundedShadowBorder extends AbstractBorder {
    private Insets insets;
    private ImageIcon topLeftCorner = Config.getImageAsIcon("image.border.topleft");
    private ImageIcon topRightCorner = Config.getImageAsIcon("image.border.topright");
    private ImageIcon bottomLeftCorner = Config.getImageAsIcon("image.border.bottomleft");
    private ImageIcon bottomRightCorner = Config.getImageAsIcon("image.border.bottomright");
    private Color shadowColor = new Color(145, 145, 145);
    private Color backgroundColor = Color.white;
    private Color borderColor = Color.black;
    private int backgroundThickness = 5; // extra space around the frame

    public RoundedShadowBorder() {
      insets = new Insets(0, 0, 0, 0);
      insets.bottom = bottomLeftCorner.getIconHeight() + backgroundThickness;
      insets.top = topLeftCorner.getIconHeight() + backgroundThickness;
      insets.left = topLeftCorner.getIconHeight() + backgroundThickness;
      insets.right = topRightCorner.getIconHeight() + backgroundThickness;
    }

    /**
     * Reinitializes the insets parameter with this Border's current Insets.
     *
     * @param c the component for which this border insets value applies
     * @param insets the object to be reinitialized
     * @return the <code>insets</code> object
     */
    public Insets getBorderInsets(Component c, Insets insets) {
      insets.bottom = this.insets.bottom;
      insets.top = this.insets.top;
      insets.left = this.insets.left;
      insets.right = this.insets.right;
      return insets;
    }

    /**
     * Returns a new <code>Insets</code> instance.
     *
     * @param c the component for which this border insets value applies
     * @return the new <code>Insets</code> object
     */
    public Insets getBorderInsets(Component c) {
      return (Insets) insets.clone();
    }

    /** Returns false. */
    public boolean isBorderOpaque() {
      return false;
    }

    /** Paints the border */
    public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {

      x += backgroundThickness;
      y += backgroundThickness;
      height -= 2 * backgroundThickness;
      width -= 2 * backgroundThickness;
      // Top
      g.setColor(backgroundColor);
      g.drawLine(x, y, x + width, y);
      g.drawLine(x, y + 1, x + width, y + 1);
      g.drawLine(x, y + 2, x + width, y + 2);
      g.setColor(borderColor);
      g.drawLine(x, y + 3, x + width, y + 3);

      // Bottom
      g.setColor(borderColor);
      g.drawLine(x, y + height - 4, x + width, y + height - 4);
      g.setColor(shadowColor);
      g.drawLine(x, y + height - 3, x + width, y + height - 3);
      g.drawLine(x, y + height - 2, x + width, y + height - 2);

      // Left
      g.setColor(backgroundColor);
      g.drawLine(x, y, x, y + height);
      g.drawLine(x + 1, y, x + 1, y + height);
      g.drawLine(x + 2, y, x + 2, y + height);
      g.setColor(borderColor);
      g.drawLine(x + 3, y, x + 3, y + height);

      // Right
      g.setColor(borderColor);
      g.drawLine(x + width - 4, y, x + width - 4, y + height);
      g.setColor(shadowColor);
      g.drawLine(x + width - 3, y, x + width - 3, y + height);
      g.drawLine(x + width - 2, y, x + width - 2, y + height);

      // Background around the border
      g.setColor(backgroundColor);
      for (int i = 0; i < backgroundThickness + 1; i++) {
        g.drawRect(x - i, y - i, width - 1 + 2 * i, height - 1 + 2 * i);
      }

      // Corners
      height += backgroundThickness;
      width += backgroundThickness;
      topLeftCorner.paintIcon(c, g, x, y);
      topRightCorner.paintIcon(c, g, x + width - insets.right, y);
      bottomLeftCorner.paintIcon(c, g, x, y + height - insets.bottom);
      bottomRightCorner.paintIcon(c, g, x + width - insets.right, y + height - insets.bottom);
    }
  }

  /**
   * A border with rounded corners and a shadow *
   *
   * @author Poul Henriksen
   */
  private static class ShadowBorder extends AbstractBorder {
    private Insets insets;
    private Color shadowColor = new Color(145, 145, 145);
    private Color backgroundColor = Color.white;
    private Color borderColor = Color.black;
    private int backgroundThickness = 5; // extra space around the frame

    public ShadowBorder() {
      insets =
          new Insets(
              4 + backgroundThickness,
              4 + backgroundThickness,
              4 + backgroundThickness,
              4 + backgroundThickness);
    }

    /**
     * Reinitializes the insets parameter with this Border's current Insets.
     *
     * @param c the component for which this border insets value applies
     * @param insets the object to be reinitialized
     * @return the <code>insets</code> object
     */
    public Insets getBorderInsets(Component c, Insets insets) {
      insets.bottom = this.insets.bottom;
      insets.top = this.insets.top;
      insets.left = this.insets.left;
      insets.right = this.insets.right;
      return insets;
    }

    /**
     * Returns a new <code>Insets</code> instance.
     *
     * @param c the component for which this border insets value applies
     * @return the new <code>Insets</code> object
     */
    public Insets getBorderInsets(Component c) {
      return (Insets) insets.clone();
    }

    /** Returns false. */
    public boolean isBorderOpaque() {
      return false;
    }

    /** Paints the border */
    public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {

      x += backgroundThickness;
      y += backgroundThickness;
      height -= 2 * backgroundThickness;
      width -= 2 * backgroundThickness;

      // Right
      g.setColor(borderColor);
      g.drawLine(x + width - 4, y, x + width - 4, y + height);
      g.setColor(shadowColor);
      g.drawLine(x + width - 3, y, x + width - 3, y + height);
      g.drawLine(x + width - 2, y, x + width - 2, y + height);
      g.setColor(backgroundColor);
      g.drawLine(x + width - 1, y, x + width - 1, y + height);
      g.fillRect(x + width - 3, y, x + width, y + 5);

      // Bottom
      g.setColor(borderColor);
      g.drawLine(x + 3, y + height - 4, x + width - 4, y + height - 4);
      g.setColor(shadowColor);
      g.drawLine(x, y + height - 3, x + width - 2, y + height - 3);
      g.drawLine(x, y + height - 2, x + width - 2, y + height - 2);
      g.setColor(backgroundColor);
      g.drawLine(x, y + height - 1, x + width, y + height - 1);
      g.fillRect(x, y + height - 3, x + 5, y + height);

      // Top
      g.setColor(backgroundColor);
      g.drawLine(x, y, x + width, y);
      g.drawLine(x, y + 1, x + width, y + 1);
      g.drawLine(x, y + 2, x + width, y + 2);
      g.setColor(borderColor);
      g.drawLine(x, y + 3, x + width - 4, y + 3);

      // Left
      g.setColor(backgroundColor);
      g.drawLine(x, y, x, y + height);
      g.drawLine(x + 1, y, x + 1, y + height);
      g.drawLine(x + 2, y, x + 2, y + height);
      g.setColor(borderColor);
      g.drawLine(x + 3, y + 3, x + 3, y + height - 4);

      // Background around the border
      g.setColor(backgroundColor);
      for (int i = 0; i < backgroundThickness + 1; i++) {
        g.drawRect(x - i, y - i, width - 1 + 2 * i, height - 1 + 2 * i);
      }
    }
  }
}