Home » jakarta-jmeter-2.3.4_src » org.apache.jmeter.gui » [javadoc | source]

    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    *
    9    *   http://www.apache.org/licenses/LICENSE-2.0
   10    *
   11    * Unless required by applicable law or agreed to in writing, software
   12    * distributed under the License is distributed on an "AS IS" BASIS,
   13    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    * See the License for the specific language governing permissions and
   15    * limitations under the License.
   16    *
   17    */
   18   
   19   package org.apache.jmeter.gui;
   20   
   21   import java.awt.BorderLayout;
   22   import java.awt.Component;
   23   import java.awt.Dimension;
   24   import java.awt.Font;
   25   import java.awt.Insets;
   26   import java.awt.event.ActionEvent;
   27   import java.awt.event.ActionListener;
   28   import java.awt.event.MouseEvent;
   29   import java.awt.event.WindowAdapter;
   30   import java.awt.event.WindowEvent;
   31   import java.util.HashSet;
   32   import java.util.Set;
   33   
   34   import javax.swing.BorderFactory;
   35   import javax.swing.Box;
   36   import javax.swing.BoxLayout;
   37   import javax.swing.ImageIcon;
   38   import javax.swing.JButton;
   39   import javax.swing.JComponent;
   40   import javax.swing.JDialog;
   41   import javax.swing.JFrame;
   42   import javax.swing.JLabel;
   43   import javax.swing.JMenu;
   44   import javax.swing.JPanel;
   45   import javax.swing.JPopupMenu;
   46   import javax.swing.JScrollPane;
   47   import javax.swing.JSplitPane;
   48   import javax.swing.JTree;
   49   import javax.swing.MenuElement;
   50   import javax.swing.SwingUtilities;
   51   import javax.swing.tree.DefaultMutableTreeNode;
   52   import javax.swing.tree.DefaultTreeCellRenderer;
   53   import javax.swing.tree.TreeCellRenderer;
   54   import javax.swing.tree.TreeModel;
   55   import javax.swing.tree.TreePath;
   56   
   57   import org.apache.jmeter.engine.event.LoopIterationEvent;
   58   import org.apache.jmeter.gui.action.ActionNames;
   59   import org.apache.jmeter.gui.action.ActionRouter;
   60   import org.apache.jmeter.gui.tree.JMeterCellRenderer;
   61   import org.apache.jmeter.gui.tree.JMeterTreeListener;
   62   import org.apache.jmeter.gui.util.JMeterMenuBar;
   63   import org.apache.jmeter.samplers.Remoteable;
   64   import org.apache.jmeter.testelement.TestElement;
   65   import org.apache.jmeter.testelement.TestListener;
   66   import org.apache.jmeter.threads.JMeterContextService;
   67   import org.apache.jmeter.util.JMeterUtils;
   68   import org.apache.jorphan.gui.ComponentUtil;
   69   
   70   /**
   71    * The main JMeter frame, containing the menu bar, test tree, and an area for
   72    * JMeter component GUIs.
   73    *
   74    */
   75   public class MainFrame extends JFrame implements TestListener, Remoteable {
   76   
   77       // This is used to keep track of local (non-remote) tests
   78       // The name is chosen to be an unlikely host-name
   79       private static final String LOCAL = "*local*"; // $NON-NLS-1$
   80   
   81       // The default title for the Menu bar
   82       private static final String DEFAULT_TITLE =
   83           "Apache JMeter ("+JMeterUtils.getJMeterVersion()+")"; // $NON-NLS-1$ $NON-NLS-2$
   84   
   85       /** The menu bar. */
   86       private JMeterMenuBar menuBar;
   87   
   88       /** The main panel where components display their GUIs. */
   89       private JScrollPane mainPanel;
   90   
   91       /** The panel where the test tree is shown. */
   92       private JScrollPane treePanel;
   93   
   94       /** The test tree. */
   95       private JTree tree;
   96   
   97       /** An image which is displayed when a test is running. */
   98       private ImageIcon runningIcon = JMeterUtils.getImage("thread.enabled.gif");// $NON-NLS-1$
   99   
  100       /** An image which is displayed when a test is not currently running. */
  101       private ImageIcon stoppedIcon = JMeterUtils.getImage("thread.disabled.gif");// $NON-NLS-1$
  102   
  103       /** The button used to display the running/stopped image. */
  104       private JButton runningIndicator;
  105   
  106       /** The x coordinate of the last location where a component was dragged. */
  107       private int previousDragXLocation = 0;
  108   
  109       /** The y coordinate of the last location where a component was dragged. */
  110       private int previousDragYLocation = 0;
  111   
  112       /** The set of currently running hosts. */
  113       private Set hosts = new HashSet();
  114   
  115       /** A message dialog shown while JMeter threads are stopping. */
  116       private JDialog stoppingMessage;
  117   
  118       private JLabel totalThreads;
  119       private JLabel activeThreads;
  120   
  121       /**
  122        * Create a new JMeter frame.
  123        *
  124        * @param actionHandler
  125        *            this parameter is not used
  126        * @param treeModel
  127        *            the model for the test tree
  128        * @param treeListener
  129        *            the listener for the test tree
  130        */
  131       public MainFrame(ActionListener actionHandler, TreeModel treeModel, JMeterTreeListener treeListener) {
  132           // TODO: actionHandler isn't used -- remove it from the parameter list
  133           // this.actionHandler = actionHandler;
  134   
  135           // TODO: Make the running indicator its own class instead of a JButton
  136           runningIndicator = new JButton(stoppedIcon);
  137           runningIndicator.setMargin(new Insets(0, 0, 0, 0));
  138           runningIndicator.setBorder(BorderFactory.createEmptyBorder());
  139   
  140           totalThreads = new JLabel("0"); // $NON-NLS-1$
  141           activeThreads = new JLabel("0"); // $NON-NLS-1$
  142   
  143           tree = makeTree(treeModel, treeListener);
  144   
  145           GuiPackage.getInstance().setMainFrame(this);
  146           init();
  147   
  148           setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
  149       }
  150   
  151       /**
  152        * Default constructor for the JMeter frame. This constructor will not
  153        * properly initialize the tree, so don't use it.
  154        *
  155        * @deprecated Do not use - only needed for JUnit tests
  156        */
  157       public MainFrame() {
  158       }
  159   
  160       // MenuBar related methods
  161       // TODO: Do we really need to have all these menubar methods duplicated
  162       // here? Perhaps we can make the menu bar accessible through GuiPackage?
  163   
  164       /**
  165        * Specify whether or not the File|Load menu item should be enabled.
  166        *
  167        * @param enabled
  168        *            true if the menu item should be enabled, false otherwise
  169        */
  170       public void setFileLoadEnabled(boolean enabled) {
  171           menuBar.setFileLoadEnabled(enabled);
  172       }
  173   
  174       /**
  175        * Specify whether or not the File|Save menu item should be enabled.
  176        *
  177        * @param enabled
  178        *            true if the menu item should be enabled, false otherwise
  179        */
  180       public void setFileSaveEnabled(boolean enabled) {
  181           menuBar.setFileSaveEnabled(enabled);
  182       }
  183   
  184       /**
  185        * Specify whether or not the File|Revert item should be enabled.
  186        *
  187        * @param enabled
  188        *            true if the menu item should be enabled, false otherwise
  189        */
  190       public void setFileRevertEnabled(boolean enabled) {
  191           menuBar.setFileRevertEnabled(enabled);
  192       }
  193   
  194       /**
  195        * Specify the project file that was just loaded
  196        *
  197        * @param file - the full path to the file that was loaded
  198        */
  199       public void setProjectFileLoaded(String file) {
  200           menuBar.setProjectFileLoaded(file);
  201       }
  202   
  203       /**
  204        * Set the menu that should be used for the Edit menu.
  205        *
  206        * @param menu
  207        *            the new Edit menu
  208        */
  209       public void setEditMenu(JPopupMenu menu) {
  210           menuBar.setEditMenu(menu);
  211       }
  212   
  213       /**
  214        * Specify whether or not the Edit menu item should be enabled.
  215        *
  216        * @param enabled
  217        *            true if the menu item should be enabled, false otherwise
  218        */
  219       public void setEditEnabled(boolean enabled) {
  220           menuBar.setEditEnabled(enabled);
  221       }
  222   
  223       /**
  224        * Set the menu that should be used for the Edit|Add menu.
  225        *
  226        * @param menu
  227        *            the new Edit|Add menu
  228        */
  229       public void setEditAddMenu(JMenu menu) {
  230           menuBar.setEditAddMenu(menu);
  231       }
  232   
  233       /**
  234        * Specify whether or not the Edit|Add menu item should be enabled.
  235        *
  236        * @param enabled
  237        *            true if the menu item should be enabled, false otherwise
  238        */
  239       public void setEditAddEnabled(boolean enabled) {
  240           menuBar.setEditAddEnabled(enabled);
  241       }
  242   
  243       /**
  244        * Specify whether or not the Edit|Remove menu item should be enabled.
  245        *
  246        * @param enabled
  247        *            true if the menu item should be enabled, false otherwise
  248        */
  249       public void setEditRemoveEnabled(boolean enabled) {
  250           menuBar.setEditRemoveEnabled(enabled);
  251       }
  252   
  253       /**
  254        * Close the currently selected menu.
  255        */
  256       public void closeMenu() {
  257           if (menuBar.isSelected()) {
  258               MenuElement[] menuElement = menuBar.getSubElements();
  259               if (menuElement != null) {
  260                   for (int i = 0; i < menuElement.length; i++) {
  261                       JMenu menu = (JMenu) menuElement[i];
  262                       if (menu.isSelected()) {
  263                           menu.setPopupMenuVisible(false);
  264                           menu.setSelected(false);
  265                           break;
  266                       }
  267                   }
  268               }
  269           }
  270       }
  271   
  272       /**
  273        * Show a dialog indicating that JMeter threads are stopping on a particular
  274        * host.
  275        *
  276        * @param host
  277        *            the host where JMeter threads are stopping
  278        */
  279       public void showStoppingMessage(String host) {
  280           if (stoppingMessage != null){
  281               stoppingMessage.dispose();
  282           }
  283           stoppingMessage = new JDialog(this, JMeterUtils.getResString("stopping_test_title"), true); //$NON-NLS-1$
  284           JLabel stopLabel = new JLabel(JMeterUtils.getResString("stopping_test") + ": " + host); //$NON-NLS-1$$NON-NLS-2$
  285           stopLabel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
  286           stoppingMessage.getContentPane().add(stopLabel);
  287           stoppingMessage.pack();
  288           ComponentUtil.centerComponentInComponent(this, stoppingMessage);
  289           SwingUtilities.invokeLater(new Runnable() {
  290               public void run() {
  291                   if (stoppingMessage != null) {// TODO - how can this be null?
  292                       stoppingMessage.show();
  293                   }
  294               }
  295           });
  296       }
  297   
  298       public void updateCounts() {
  299           SwingUtilities.invokeLater(new Runnable() {
  300               public void run() {
  301                   activeThreads.setText(Integer.toString(JMeterContextService.getNumberOfThreads()));
  302                   totalThreads.setText(Integer.toString(JMeterContextService.getTotalThreads()));
  303               }
  304           });
  305       }
  306   
  307       public void setMainPanel(JComponent comp) {
  308           mainPanel.setViewportView(comp);
  309       }
  310   
  311       public JTree getTree() {
  312           return tree;
  313       }
  314   
  315       // TestListener implementation
  316   
  317       /**
  318        * Called when a test is started on the local system. This implementation
  319        * sets the running indicator and ensures that the menubar is enabled and in
  320        * the running state.
  321        */
  322       public void testStarted() {
  323           testStarted(LOCAL);
  324           menuBar.setEnabled(true);
  325       }
  326   
  327       /**
  328        * Called when a test is started on a specific host. This implementation
  329        * sets the running indicator and ensures that the menubar is in the running
  330        * state.
  331        *
  332        * @param host
  333        *            the host where the test is starting
  334        */
  335       public void testStarted(String host) {
  336           hosts.add(host);
  337           runningIndicator.setIcon(runningIcon);
  338           activeThreads.setText("0"); // $NON-NLS-1$
  339           totalThreads.setText("0"); // $NON-NLS-1$
  340           menuBar.setRunning(true, host);
  341       }
  342   
  343       /**
  344        * Called when a test is ended on the local system. This implementation
  345        * disables the menubar, stops the running indicator, and closes the
  346        * stopping message dialog.
  347        */
  348       public void testEnded() {
  349           testEnded(LOCAL);
  350           menuBar.setEnabled(false);
  351       }
  352   
  353       /**
  354        * Called when a test is ended on the remote system. This implementation
  355        * stops the running indicator and closes the stopping message dialog.
  356        *
  357        * @param host
  358        *            the host where the test is ending
  359        */
  360       public void testEnded(String host) {
  361           hosts.remove(host);
  362           if (hosts.size() == 0) {
  363               runningIndicator.setIcon(stoppedIcon);
  364               JMeterContextService.endTest();
  365           }
  366           menuBar.setRunning(false, host);
  367           if (stoppingMessage != null) {
  368               stoppingMessage.dispose();
  369               stoppingMessage = null;
  370           }
  371       }
  372   
  373       /* Implements TestListener#testIterationStart(LoopIterationEvent) */
  374       public void testIterationStart(LoopIterationEvent event) {
  375       }
  376   
  377       /**
  378        * Create the GUI components and layout.
  379        */
  380       private void init() {
  381           menuBar = new JMeterMenuBar();
  382           setJMenuBar(menuBar);
  383   
  384           JPanel all = new JPanel(new BorderLayout());
  385           all.add(createToolBar(), BorderLayout.NORTH);
  386   
  387           JSplitPane treeAndMain = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
  388   
  389           treePanel = createTreePanel();
  390           treeAndMain.setLeftComponent(treePanel);
  391   
  392           mainPanel = createMainPanel();
  393           treeAndMain.setRightComponent(mainPanel);
  394   
  395           treeAndMain.setResizeWeight(.2);
  396           treeAndMain.setContinuousLayout(true);
  397           all.add(treeAndMain, BorderLayout.CENTER);
  398   
  399           getContentPane().add(all);
  400   
  401           tree.setSelectionRow(1);
  402           addWindowListener(new WindowHappenings());
  403   
  404           setTitle(DEFAULT_TITLE);
  405           setIconImage(JMeterUtils.getImage("jmeter.jpg").getImage());// $NON-NLS-1$
  406       }
  407   
  408       public void setExtendedFrameTitle(String fname) {
  409           // file New operation may set to null, so just return app name
  410           if (fname == null) {
  411               setTitle(DEFAULT_TITLE);
  412               return;
  413           }
  414   
  415           // allow for windows / chars in filename
  416           String temp = fname.replace('\\', '/'); // $NON-NLS-1$ // $NON-NLS-2$
  417           String simpleName = temp.substring(temp.lastIndexOf("/") + 1);// $NON-NLS-1$
  418           setTitle(simpleName + " (" + fname + ") - " + DEFAULT_TITLE); // $NON-NLS-1$ // $NON-NLS-2$
  419       }
  420   
  421       /**
  422        * Create the JMeter tool bar pane containing the running indicator.
  423        *
  424        * @return a panel containing the running indicator
  425        */
  426       private Component createToolBar() {
  427           Box toolPanel = new Box(BoxLayout.X_AXIS);
  428           toolPanel.add(Box.createRigidArea(new Dimension(10, 15)));
  429           toolPanel.add(Box.createGlue());
  430           toolPanel.add(activeThreads);
  431           toolPanel.add(new JLabel(" / "));
  432           toolPanel.add(totalThreads);
  433           toolPanel.add(Box.createRigidArea(new Dimension(10, 15)));
  434           toolPanel.add(runningIndicator);
  435           return toolPanel;
  436       }
  437   
  438       /**
  439        * Create the panel where the GUI representation of the test tree is
  440        * displayed. The tree should already be created before calling this method.
  441        *
  442        * @return a scroll pane containing the test tree GUI
  443        */
  444       private JScrollPane createTreePanel() {
  445           JScrollPane treeP = new JScrollPane(tree);
  446           treeP.setMinimumSize(new Dimension(100, 0));
  447           return treeP;
  448       }
  449   
  450       /**
  451        * Create the main panel where components can display their GUIs.
  452        *
  453        * @return the main scroll pane
  454        */
  455       private JScrollPane createMainPanel() {
  456           return new JScrollPane();
  457       }
  458   
  459       /**
  460        * Create and initialize the GUI representation of the test tree.
  461        *
  462        * @param treeModel
  463        *            the test tree model
  464        * @param treeListener
  465        *            the test tree listener
  466        *
  467        * @return the initialized test tree GUI
  468        */
  469       private JTree makeTree(TreeModel treeModel, JMeterTreeListener treeListener) {
  470           JTree treevar = new JTree(treeModel) {
  471               public String getToolTipText(MouseEvent event) {
  472                   TreePath path = this.getPathForLocation(event.getX(), event.getY());
  473                   if (path != null) {
  474                       Object treeNode = path.getLastPathComponent();
  475                       if (treeNode instanceof DefaultMutableTreeNode) {
  476                           Object testElement = ((DefaultMutableTreeNode) treeNode).getUserObject();
  477                           if (testElement instanceof TestElement) {
  478                               String comment = ((TestElement) testElement).getComment();
  479                               if (comment != null && comment.length() > 0) {
  480                                   return comment;
  481                                   }
  482                               }
  483                           }
  484                       }
  485                   return null;
  486                   }
  487               };
  488              treevar.setToolTipText("");
  489           treevar.setCellRenderer(getCellRenderer());
  490           treevar.setRootVisible(false);
  491           treevar.setShowsRootHandles(true);
  492   
  493           treeListener.setJTree(treevar);
  494           treevar.addTreeSelectionListener(treeListener);
  495           treevar.addMouseListener(treeListener);
  496           treevar.addMouseMotionListener(treeListener);
  497           treevar.addKeyListener(treeListener);
  498   
  499           return treevar;
  500       }
  501   
  502       /**
  503        * Create the tree cell renderer used to draw the nodes in the test tree.
  504        *
  505        * @return a renderer to draw the test tree nodes
  506        */
  507       private TreeCellRenderer getCellRenderer() {
  508           DefaultTreeCellRenderer rend = new JMeterCellRenderer();
  509           rend.setFont(new Font("Dialog", Font.PLAIN, 11));
  510           return rend;
  511       }
  512   
  513       /**
  514        * Repaint pieces of the GUI as needed while dragging. This method should
  515        * only be called from the Swing event thread.
  516        *
  517        * @param dragIcon
  518        *            the component being dragged
  519        * @param x
  520        *            the current mouse x coordinate
  521        * @param y
  522        *            the current mouse y coordinate
  523        */
  524       public void drawDraggedComponent(Component dragIcon, int x, int y) {
  525           Dimension size = dragIcon.getPreferredSize();
  526           treePanel.paintImmediately(previousDragXLocation, previousDragYLocation, size.width, size.height);
  527           this.getLayeredPane().setLayer(dragIcon, 400);
  528           SwingUtilities.paintComponent(treePanel.getGraphics(), dragIcon, treePanel, x, y, size.width, size.height);
  529           previousDragXLocation = x;
  530           previousDragYLocation = y;
  531       }
  532   
  533       /**
  534        * A window adapter used to detect when the main JMeter frame is being
  535        * closed.
  536        */
  537       private static class WindowHappenings extends WindowAdapter {
  538           /**
  539            * Called when the main JMeter frame is being closed. Sends a
  540            * notification so that JMeter can react appropriately.
  541            *
  542            * @param event
  543            *            the WindowEvent to handle
  544            */
  545           public void windowClosing(WindowEvent event) {
  546               ActionRouter.getInstance().actionPerformed(new ActionEvent(this, event.getID(), ActionNames.EXIT));
  547           }
  548       }
  549   }

Home » jakarta-jmeter-2.3.4_src » org.apache.jmeter.gui » [javadoc | source]