ScriptEditorFrame.java :  » Testing » abbot-1.0.1 » abbot » editor » Java Open Source

Java Open Source » Testing » abbot 1.0.1 
abbot 1.0.1 » abbot » editor » ScriptEditorFrame.java
package abbot.editor;

import java.awt.*;
import java.awt.event.*;
import java.util.*;

import javax.swing.*;
import javax.swing.border.EmptyBorder;

import abbot.*;
import abbot.editor.actions.*;
import abbot.editor.widgets.*;
import abbot.i18n.Strings;

/**
 * Provides the primary frame for the Costello script editor.  Maintains the
 * LAF used when first created, restoring it temporarily when displaying any
 * new components. 
 *
 * FIXME needs major refactoring:
 * Export actions (via ActionMap) 
 * Use generic menu setup provided by a special array of actions
 *
 * @author Kyle Girard, twall
 */
public class ScriptEditorFrame
    extends JFrame implements EditorConstants, abbot.Version {

    private static int STEP_EDITOR_MIN_HEIGHT = 75;

    private JLabel                  currentTestSuiteLabel;
    private JTextField              testScriptDescription;
    private JButton                 testSuiteSelectionButton;
    private JButton                 runButton;
    private JComboBox               testScriptSelector;
    // script on left, step editor on right
    private JSplitPane              scriptSplit;
    // script split above, component browser below
    private JSplitPane              scriptBrowserSplit;
    private ScriptTable             scriptTable;
    private JTextArea               statusBar;
    private JDialog                 statusWindow;
    private boolean                 statusShown;
    private JTextArea               statusText;
    private ComponentBrowser       componentBrowser;
    private ActionMap               actionMap;
    private Preferences             prefs;
    private ImageIcon               logo;
    private JMenu insertMenu;
    private int INSERT_BASE_COUNT;
    private JMenu captureMenu;
    private JMenu actionMenu;
    private TwoStateEditorMenu assertMenu;
    private TwoStateEditorMenu waitMenu;
    private JDialog aboutBox;
    private JPanel lastEditor;

    /**
     * Constructs a ScriptEditorFrame with a title and a scriptable
     */
    public ScriptEditorFrame(String[][] menus, ActionMap actionMap,
                             ActionListener listener,
                             String title, ScriptTable scriptTable,
                             Preferences preferences) {
        super(title);   
        setName("ScriptEditor");
        prefs = preferences;

        this.scriptTable = scriptTable;
        this.actionMap = actionMap;
        java.net.URL url = getClass().getResource("icons/abbot.gif");
        logo = new ImageIcon(url);
        setIconImage(logo.getImage());
        // Allow us to cancel out of a close.
        setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);

        initComponents(listener);
        setJMenuBar(createMenus(menus));

        // LookAndFeelPreserver causes OSX to chew CPU cycles
        if (!Platform.isMacintosh()) {
            // Make sure we always use the same LAF, regardless of changes made by
            // the code under test.
            getRootPane().putClientProperty("LAFpreserver", new LookAndFeelPreserver(this));
        }
    }

    private JMenuBar createMenus(String[][] menus) {
        JMenuBar menuBar = new JMenuBar();
        for (int i=0;i < menus.length;i++) {
            String[] keys = menus[i];
            if (keys.length > 0) {
                JMenu menu = new EditorMenu(keys[0]);
                for (int j=1;j < keys.length;j++) {
                    String key = keys[j];
                    if (key == null) {
                        menu.add(new JSeparator());
                    }
                    else {
                        Action action = actionMap.get(key);
                        menu.add(createMenuItem(action));
                    }
                }
                if (i == menus.length-1) {
                    menuBar.add(Box.createHorizontalGlue());
                }
                menuBar.add(menu);
            }
        }
        return menuBar;
    }

    /**
     * Returns the componentBrowser.
     * @return ComponentBrowser
     */
    public ComponentBrowser getComponentBrowser() {
        return componentBrowser;
    }
    
    /**
     * Sets the componentBrowser.
     * @param componentBrowser The componentBrowser to set
     */
    public void setComponentBrowser(ComponentBrowser componentBrowser) {
        this.componentBrowser = componentBrowser;
        scriptBrowserSplit.setBottomComponent(componentBrowser);
    }

    /**
     * Returns the scriptTable.
     * @return ScriptTable
     */
    public ScriptTable getScriptTable() {
        return scriptTable;
    }

    public String getStatus() {
        return statusBar.getText();
    }

    /** Set the initial size based on saved prefs. */
    private void setInitialBounds() {
        Log.debug("bounds=" + getBounds());
        Dimension size =
            new Dimension(prefs.getIntegerProperty("width", getWidth()),
                          prefs.getIntegerProperty("height", getHeight()));
        if (size.width < 200 || size.height < 200) {
            Log.warn("Size is rather small: " + size
                     + ", using defaults");
        }
        else {
            setSize(size);
        }

        Rectangle screen = getGraphicsConfiguration().getBounds();
        int x = screen.x + (screen.width - getWidth()) / 2;
        int y = screen.y + (screen.height - getHeight()) / 2;
        Point where = new Point(prefs.getIntegerProperty("x", x),
                                prefs.getIntegerProperty("y", y));
        setLocation(where);

        int split1 = prefs.getIntegerProperty("split.script.stepeditor", -1);
        if (split1 < 10 || split1 > getHeight() - 10)
            split1 = -1;
        scriptSplit.setDividerLocation(split1);

        int split2 = prefs.getIntegerProperty("split.script.browser", -1);
        if (split2 < 10 || split2 > getWidth() - 10)
            split2 = -1;
        scriptBrowserSplit.setDividerLocation(split2);
        Log.debug("post=" + getBounds()
                  + " split1=" + split1 + " split2=" + split2);
    }

    /** Save size and position information before hiding. */
    boolean firstShow = true;
    /** @deprecated */
    public void show() {
        if (firstShow) {
            firstShow = false;
            setInitialBounds();
        }
        super.show();
    }

    /** @deprecated */
    public void hide() {
        if (isShowing()) {
            prefs.setProperty("x", String.valueOf(getX()));
            prefs.setProperty("y", String.valueOf(getY()));
            prefs.setProperty("width", String.valueOf(getWidth()));
            prefs.setProperty("height", String.valueOf(getHeight()));
            prefs.setProperty("split.script.stepeditor",
                              String.valueOf(scriptSplit.getDividerLocation()));
            prefs.setProperty("split.script.browser",
                              String.valueOf(scriptBrowserSplit.getDividerLocation()));
            prefs.save();
        }
        super.hide();
    }

    /** Set the text for the status window.  The first argument is the short
        text and the second is additional optional text to be displayed in a
        larger dialog. 
    */
    public void setStatus(final String msg, final String extended,
                          final Color color) {
        // setText is thread-safe w/r/t the dispatch thread, but setForeground
        // is not 
        statusBar.setText(msg);
        statusText.setText(msg + (extended != null
                                  ? "\n" + extended : ""));
        Runnable action = new Runnable() {
            public void run() {
                statusBar.setForeground(color);
                statusText.setForeground(color);
                if (statusWindow.isShowing()) 
                    resizeStatusWindow();
            }
        };
        if (!color.equals(statusBar.getForeground()))
            abbot.util.AWT.invokeAction(action);
    }
    
    public Dimension getPreferredSize() {
        Dimension pref = super.getPreferredSize();
        Rectangle screen = getGraphicsConfiguration().getBounds();
        pref.width = Math.min(pref.width, screen.width);
        pref.height = Math.min(pref.height, screen.height);
        return pref;
    }

    /**
     * Returns the testSuiteDescription.
     * @return JLabel
     */
    public JLabel getCurrentTestSuiteLabel() {
        return currentTestSuiteLabel;
    }

    /**
     * Returns the testScriptSelector.
     * @return JComboBox
     */
    public JComboBox getTestScriptSelector() {
        return testScriptSelector;
    }
    
    /**
     * Returns the testScriptDescription.
     * @return JTextField
     */
    public JTextField getTestScriptDescription() {
        return testScriptDescription;
    }

    private void initComponents(ActionListener al) {
        JPanel pane = (JPanel)getContentPane();

        JPanel top = new JPanel();
        top.setLayout(new BoxLayout(top, BoxLayout.X_AXIS));
        top.setBorder(new EmptyBorder(4,4,4,4));
        {
            JLabel suiteLabel = new JLabel(getString("AbbotSuite")) {
                public Dimension getMaximumSize() {
                    return super.getPreferredSize();
                }
            };
            suiteLabel.setHorizontalAlignment(SwingConstants.RIGHT);
            currentTestSuiteLabel = new JLabel(getString("NoSuite"));
            currentTestSuiteLabel.setHorizontalAlignment(SwingConstants.LEFT);
            top.add(suiteLabel);
            top.add(Box.createHorizontalStrut(8));
            top.add(currentTestSuiteLabel);
            top.add(Box.createHorizontalGlue());
            top.add(Box.createHorizontalStrut(8));

            Action action = actionMap.get(ScriptEditor.ACTION_SELECT_TESTSUITE);
            if (action != null) {
                testSuiteSelectionButton = new EditorButton(action);
                top.add(testSuiteSelectionButton);
                top.add(Box.createHorizontalStrut(8));
            }

            action = actionMap.get(ScriptEditor.ACTION_RUN);
            if (action != null) {
                runButton = new EditorButton(action);
                top.add(runButton);
            }
        }

        JPanel center = new JPanel(new BorderLayout());
        {
            testScriptSelector = new JComboBox();
            JPanel scriptPane = new JPanel(new BorderLayout());
            {
                testScriptDescription = new abbot.editor.widgets.TextField("");
                testScriptDescription.addActionListener(al);
                String tip = TextFormat.
                    tooltip(Strings.get("editor.script_description.tip"));
                testScriptDescription.setToolTipText(tip);
                
                JScrollPane scroll = new JScrollPane(scriptTable) {
                    public Dimension getPreferredSize() {
                        return new Dimension(250, 200);
                    }
                    public Dimension getMinimumSize() {
                        return new Dimension(250, super.getMinimumSize().height);
                    }
                };
                scroll.setBorder(null);
                scroll.getViewport().setBackground(scriptTable.getBackground());
                
                scriptSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
                // script gets extra space
                scriptSplit.setResizeWeight(1.0);
                scriptSplit.setDividerSize(4);
                scriptSplit.setBorder(null);
                scriptSplit.setLeftComponent(scroll);
                scriptBrowserSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
                // script gets extra space
                scriptBrowserSplit.setResizeWeight(1.0);
                scriptBrowserSplit.setDividerSize(4);
                scriptBrowserSplit.setBorder(null);
                scriptBrowserSplit.setTopComponent(scriptSplit);
                scriptPane.add(testScriptDescription, BorderLayout.NORTH);
                scriptPane.add(scriptBrowserSplit, BorderLayout.CENTER);
            }
            //center.add(buttons, BorderLayout.NORTH);
            center.add(testScriptSelector, BorderLayout.NORTH);
            center.add(scriptPane, BorderLayout.CENTER);
        }

        statusText = new JTextArea("");
        statusText.setEditable(false);
        statusText.setBackground(getContentPane().getBackground());
        statusText.setColumns(80);
        statusText.setLineWrap(true);
        statusText.setWrapStyleWord(true);
        statusWindow = createStatusWindow();
        JPanel wp = (JPanel)statusWindow.getContentPane();
        wp.add(new JScrollPane(statusText));

        statusBar = new JTextArea(getString("Initializing"));
        statusBar.setEditable(false);
        statusBar.setBackground(getContentPane().getBackground());
        statusBar.addMouseListener(new MouseAdapter() {
            public void mouseClicked(MouseEvent me) {
                boolean hasMoreText =
                    !statusBar.getText().equals(statusText.getText());
                boolean hasWideText =
                    statusBar.getPreferredSize().width > statusBar.getSize().width;
                Log.debug("has more=" + hasMoreText + ", hasWide=" + hasWideText);
                if (hasMoreText || hasWideText) {
                    resizeStatusWindow();
                    statusWindow.setVisible(true);
                    resizeStatusWindow();
                }
            }
        });
        statusBar.setToolTipText(getString("Status.tip"));

        pane.setLayout(new BorderLayout());
        pane.setBorder(new EmptyBorder(4,4,4,4));
        pane.add(top, BorderLayout.NORTH);
        pane.add(center, BorderLayout.CENTER);
        pane.add(statusBar, BorderLayout.SOUTH);

        componentBrowser = null;
    }

    /** Create a checkbox or regular menu item as appropriate. */
    private JMenuItem createMenuItem(javax.swing.Action action) {
        JMenuItem item = action instanceof EditorToggleAction
            ? (JMenuItem)new CustomCheckBoxMenuItem((EditorToggleAction)action)
            : (JMenuItem)new EditorMenuItem(action);
        return item;
    }

    public void showAboutBox() { 
        if (aboutBox == null) {
            String title = Strings.get("actions.editor-about.title");
            aboutBox = new JDialog(this, title, true);
            JPanel pane = (JPanel)aboutBox.getContentPane();
            pane.setLayout(new BorderLayout());
            pane.add(new LogoLabel(), BorderLayout.CENTER);
            JLabel label = new JLabel(VERSION);
            label.setHorizontalAlignment(SwingConstants.CENTER);
            pane.add(label, BorderLayout.SOUTH);
            pane.setBorder(new EmptyBorder(4,4,4,4));
            aboutBox.addMouseListener(new MouseAdapter() {
                public void mouseClicked(MouseEvent me) {
                    aboutBox.setVisible(false);
                }
            });
            aboutBox.pack();
            aboutBox.setResizable(false);
        }
        // Center on the parent frame
        aboutBox.setLocation(getLocation().x + getWidth()/2
                             - aboutBox.getWidth()/2,
                             getLocation().y + getHeight()/2
                             - aboutBox.getHeight()*2/3);
        aboutBox.setVisible(true);
    }

    public void setAssertOptions(boolean wait, boolean invert) {
        getComponentBrowser().updateAssertText(wait, invert);
        assertMenu.setSecondary(invert);
        waitMenu.setSecondary(invert);
    }

    private void populateMenu(JMenu menu, ArrayList actions) {
        Iterator iter = actions.iterator();
        while (iter.hasNext()) {
            Action action = (Action)iter.next();
            if (action == null) 
                menu.add(new JSeparator());
            else {
                JMenuItem mi = new EditorMenuItem(action);
                menu.add(mi);
            }
        }
    }

    /** Fill the menu with available actionXXX methods for the given class. */
    public void populateInsertMenu(ArrayList actions) {
        if (INSERT_BASE_COUNT == 0) {
            INSERT_BASE_COUNT = insertMenu.getItemCount();
        }
        else {
            while (insertMenu.getItemCount() > INSERT_BASE_COUNT) {
                insertMenu.remove(INSERT_BASE_COUNT);
            }
        }
        insertMenu.add(new JSeparator());
        insertMenu.add(actionMenu = new EditorMenu("menus.insert-action"));
        insertMenu.add(assertMenu =
                       new TwoStateEditorMenu("menus.insert-assert",
                                              "menus.insert-assert.neg"));
        insertMenu.add(waitMenu =
                       new TwoStateEditorMenu("menus.insert-wait",
                                              "menus.insert-wait.neg"));

        Collections.sort(actions);
        populateMenu(actionMenu, actions);
    }

    /** Fill the menu with available assertXXX methods for the given class. */
    public void populateAssertMenu(ArrayList actions) {
        assertMenu.removeAll();
        populateMenu(assertMenu, actions);
    }

    /** Same as populateAssertMenu, but makes them waits instead. */
    public void populateWaitMenu(ArrayList actions) {
        waitMenu.removeAll();
        populateMenu(waitMenu, actions);
    }

    /** Create the list of recordable GUI actions. */
    public void populateCaptureMenu(ArrayList actions) {
        captureMenu.removeAll();
        populateMenu(captureMenu, actions);
    }

    public JPanel getEditor() { return lastEditor; }
    public void setEditor(final JPanel editor) {
        if (editor != null) {
            // preserve the divider location as the editor is changed
            JScrollPane scroll = new JScrollPane(editor);
            int loc = scriptSplit.getDividerLocation();
            scroll.getViewport().setBackground(editor.getBackground());
            Dimension minSize = editor.getMinimumSize();
            minSize.height = STEP_EDITOR_MIN_HEIGHT;
            scroll.getViewport().setMinimumSize(minSize);
            scriptSplit.setRightComponent(scroll);
            // Preserve the divider location as the editor changes
            if (lastEditor != null)
                scriptSplit.setDividerLocation(loc);
        }
        else {
            scriptSplit.setRightComponent(null);
        }
        lastEditor = editor;
    }

    /** If a resource happens to be missing, use its key instead. */
    private static String getString(String key) {
        String value = Strings.get(key);
        if (value == null) 
            value = key;
        return value;
    }

    private void resizeStatusWindow() {
        statusWindow.setResizable(true);
        statusWindow.pack();
        if (!statusShown) {
            Dimension size = statusWindow.getSize();
            Point vwhere = getLocationOnScreen();
            if (size.width < getWidth()) {
                size.width = getWidth();
                statusWindow.setSize(size);
            }
            Point where = new Point();
            where.x = vwhere.x + 10;
            where.y = vwhere.y + getHeight() - size.height;
            if (where.y < vwhere.y + 10) {
                where.y = vwhere.y + 10;
            }
            statusWindow.setLocation(where);
            statusShown = true;
        }
        statusWindow.setResizable(false);
        statusWindow.repaint();
    }

    private JDialog createStatusWindow() {
        JDialog dialog = 
            new JDialog(this, Strings.get("Status.title"), false) {
                public Dimension getMaximumSize() {
                    Dimension max = super.getMaximumSize();
                    Rectangle screen = getGraphicsConfiguration().getBounds();
                    max.height = Math.min(Math.min(max.height,
                                                   screen.height * 3 / 4),
                                          ScriptEditorFrame.this.
                                          getMaximumSize().height);
                    max.width = Math.min(Math.min(max.width,
                                                  screen.width * 3 / 4),
                                         ScriptEditorFrame.this.
                                         getMaximumSize().width);
                    Log.debug("maximum size is " + max);
                    return max;
                }
                public Dimension getMinimumSize() {
                    Dimension min = super.getMinimumSize();
                    min.height = Math.max(150, min.height);
                    Log.debug("minimum size is " + min);
                    return min;
                }
                public Dimension getPreferredSize() {
                    Dimension pref = super.getPreferredSize();
                    pref.width = Math.min(pref.width,
                                          ScriptEditorFrame.this.
                                          getPreferredSize().width);
                                          
                    Log.debug("preferred size is " + pref);
                    return pref;
                }
            };
        return dialog;
    }

    /** Display a confirmation dialog. */
    public int showConfirmation(String msg) {
        return showConfirmation(msg, JOptionPane.YES_NO_OPTION);
    }

    /** Display a confirmation dialog. */
    public int showConfirmation(String msg, int opts) {
        msg = TextFormat.dialog(msg);
        return JOptionPane.showConfirmDialog(this, msg,
                                             Strings.get("Confirm"), opts);
    }

    /** Global facility for obtaining a user input String. */
    public String showInputDialog(String title, String msg,
                                  String initial) {
        msg = TextFormat.dialog(msg);
        return (String)JOptionPane.showInputDialog(this, msg, title,
                                                   JOptionPane.PLAIN_MESSAGE,
                                                   null, null, initial);
    }

    /** Global facility for message dialogs. */
    public void showMessage(String title, String msg) {
        msg = TextFormat.dialog(msg);
        JOptionPane.showMessageDialog(this, msg);
    }

    /** Global facility for warning dialog. */
    public void showWarning(String msg) {
        showWarning(Strings.get("Warning.title"), msg);
    }

    /** Global facility for warning dialog. */
    public void showWarning(String title, String msg) {
        msg = TextFormat.dialog(msg);
        JOptionPane.showMessageDialog(this, msg, title,
                                      JOptionPane.WARNING_MESSAGE);
    }

    /** Global facility for error dialogs. */
    public void showError(String msg) {
        showError(Strings.get("Error.title"), msg);
    }

    /** Global facility for error dialogs. */
    public void showError(String title, String msg) {
        msg = TextFormat.dialog(msg);
        JOptionPane.showMessageDialog(this, msg, title, 
                                      JOptionPane.ERROR_MESSAGE);
    }

    private class EditorMenu extends JMenu {
        public EditorMenu(String key) {
            super(getString(key));
            setName(key);
            // sort of a hack; update member variables when these special
            // menus get created.
            if (key.equals(MENU_INSERT)) {
                insertMenu = this;
            }
            else if (key.equals(MENU_CAPTURE)) {
                captureMenu = this;
            }
            setMnemonic(key);
        }
        protected void setMnemonic(String key) {
            Mnemonic mnemonic = Mnemonic.getMnemonic(Strings.get(key));
            mnemonic.setMnemonic(this);

            // This can go away once the properties files have been
            // updated to use ampersands instead of VK keycodes
            if (mnemonic.keycode == KeyEvent.VK_UNDEFINED) {
                int code = EditorAction.getMnemonic(key);
                if (code != KeyEvent.VK_UNDEFINED) {
                    setMnemonic(code);
                }
            }
        }
    }
    private class TwoStateEditorMenu extends EditorMenu {
        private String primary, secondary;
        public TwoStateEditorMenu(String primary, String secondary) {
            super(primary);
            this.primary = primary;
            this.secondary = secondary;
        }
        public void setSecondary(boolean state) {
            setMnemonic(state ? secondary : primary);
        }
    }
    private class EditorButton extends JButton {
        public EditorButton(Action action) {
            super(action);
            setName((String)action.getValue(EditorAction.NAME));
            Integer i = (Integer)action.getValue(EditorAction.MNEMONIC_INDEX);
            if (i != null)
                Mnemonic.setDisplayedMnemonicIndex(this, i.intValue());
        }
    }
    private class EditorMenuItem extends JMenuItem {
        public EditorMenuItem(Action action) {
            super(action);
            setName((String)action.getValue(EditorAction.NAME));
            Integer i = (Integer)action.getValue(EditorAction.MNEMONIC_INDEX);
            if (i != null)
                Mnemonic.setDisplayedMnemonicIndex(this, i.intValue());
            // prior to 1.4, the accelerator key is not automatically set
            setAccelerator((KeyStroke)action.getValue(Action.ACCELERATOR_KEY));
        }
    }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.