Logo Search packages:      
Sourcecode: cacao-oj6 version File versions

BP_SummarySubpanel.java

/*
 * $Id$
 *
 * Copyright 1996-2008 Sun Microsystems, Inc.  All Rights Reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Sun designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Sun in the LICENSE file that accompanied this code.
 *
 * This code 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
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
 * CA 95054 USA or visit www.sun.com if you need additional information or
 * have any questions.
 */
package com.sun.javatest.exec;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.Insets;
import java.awt.image.BufferedImage;
import java.util.Arrays;

import javax.swing.BorderFactory; 
import javax.swing.Box; 
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
//import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingConstants;
import javax.swing.plaf.metal.MetalLookAndFeel;

import com.sun.javatest.JavaTestError;
import com.sun.javatest.Parameters;
import com.sun.javatest.Status;
import com.sun.javatest.TestSuite;
import com.sun.javatest.TestResultTable;
import com.sun.javatest.tool.I18NUtils;
import com.sun.javatest.tool.PieChart;
import com.sun.javatest.tool.UIFactory;
import com.sun.javatest.util.Debug;

/**
 * Subpanel of BranchPanel.  This panel displays a summary of tests below the given
 * node which have passed, failed, errored, etc...
 */
00069 class BP_SummarySubpanel extends BP_BranchSubpanel {
    BP_SummarySubpanel(UIFactory uif, BP_Model bpm, TestTreeModel ttm) {
      super("stats", uif, bpm, ttm, "br.summ");
      init();
    }

    void init() {
      if (pieColors == null) {
          pieColors = new Color[I18NUtils.NUM_STATES];
          pieColors[Status.PASSED] = I18NUtils.getStatusColor(Status.PASSED);
          pieColors[Status.FAILED] = I18NUtils.getStatusColor(Status.FAILED);
          pieColors[Status.ERROR] = I18NUtils.getStatusColor(Status.ERROR);
          pieColors[Status.NOT_RUN] = I18NUtils.getStatusColor(Status.NOT_RUN);
          pieColors[pieColors.length-1] = I18NUtils.getStatusColor(I18NUtils.FILTERED_OUT);
      }

      JPanel bodyPanel = uif.createPanel("br.summ.body", false);
      bodyPanel.setLayout(new GridBagLayout());

      JPanel statsPanel = uif.createPanel("br.summStats", false);
      statsPanel.setLayout(new GridBagLayout());
      statsPanel.setOpaque(false);

      GridBagConstraints gbc = new GridBagConstraints();

      // number of components in y-axis of layout before the text fields begin
      int pbarOffset = 3;

      gbc.gridx = 0;
      gbc.gridy = 0;
      gbc.ipady = 3;
      gbc.gridwidth=2;
      gbc.gridheight = 1;

      // --- could be static from here... ---
      sTypes = new JLabel[NUM_FIELDS];

      for (int i = 0; i < Status.NUM_STATES; i++) {
            // NOTE: intentional extra space in the line below
            //       to defeat static i18n checking in build
          sTypes[i] = uif.createLabel( "br.summ.status" + i);
          sTypes[i].setHorizontalAlignment(SwingConstants.LEFT);
          sTypes[i].setDisplayedMnemonic(uif.getI18NString(
                              "br.summ.status" + i + ".mne").charAt(0));
          sTypes[i].setIcon(new LegendIcon(I18NUtils.getStatusBarColor(i), true));
          uif.setAccessibleDescription(sTypes[i], "br.summ.status" + i);
          // other label config here
      }   // for

      sTypes[SUBTOTAL_INDEX] = uif.createLabel("br.summ.subtotal");
      sTypes[FILTERED_INDEX] = uif.createLabel("br.summ.filtered");
      sTypes[TOTAL_INDEX] = uif.createLabel("br.summ.total");

      sTypes[FILTERED_INDEX].setIcon(
          new LegendIcon(I18NUtils.getStatusColor(I18NUtils.FILTERED_OUT), true));

      // a11y
      sTypes[SUBTOTAL_INDEX].setDisplayedMnemonic(uif.getI18NString(
                            "br.summ.subtotal.mne").charAt(0));
      sTypes[FILTERED_INDEX].setDisplayedMnemonic(uif.getI18NString(
                            "br.summ.filtered.mne").charAt(0));
      sTypes[TOTAL_INDEX].setDisplayedMnemonic(uif.getI18NString(
                            "br.summ.total.mne").charAt(0));
      uif.setAccessibleDescription(sTypes[SUBTOTAL_INDEX], "br.summ.subtotal");
      uif.setAccessibleDescription(sTypes[FILTERED_INDEX], "br.summ.filtered");
      uif.setAccessibleDescription(sTypes[TOTAL_INDEX], "br.summ.total");

      sTypes[SUBTOTAL_INDEX].setBackground(MetalLookAndFeel.getPrimaryControlDarkShadow());
      sTypes[SUBTOTAL_INDEX].setForeground(MetalLookAndFeel.getWindowBackground());
      sTypes[SUBTOTAL_INDEX].setOpaque(true);
      sTypes[TOTAL_INDEX].setBackground(MetalLookAndFeel.getPrimaryControlDarkShadow());
      sTypes[TOTAL_INDEX].setForeground(MetalLookAndFeel.getWindowBackground());
      sTypes[TOTAL_INDEX].setOpaque(true);
      // --- to here ---

      sValues = new JTextField[NUM_FIELDS];

      for (int i = 0; i < Status.NUM_STATES; i++) {
          sValues[i] = createPlainField(i);
      }   // for
      sValues[FILTERED_INDEX] = createPlainField(FILTERED_INDEX);
      sValues[SUBTOTAL_INDEX] = createTotalField(SUBTOTAL_INDEX);
      sValues[TOTAL_INDEX] = createTotalField(TOTAL_INDEX);

      // use blank icons to get indentation effect
      sTypes[SUBTOTAL_INDEX].setIcon(
          new LegendIcon(sTypes[SUBTOTAL_INDEX].getBackground(), false));
      sTypes[TOTAL_INDEX].setIcon(
          new LegendIcon(sTypes[TOTAL_INDEX].getBackground(), false));

      gbc.fill = GridBagConstraints.NONE;
      gbc.anchor = GridBagConstraints.WEST;
      gbc.gridwidth = 1;
      gbc.ipadx = 10;
      gbc.weightx = 0.0;

      // put it all into the layout
      for (int i = 0; i < NUM_FIELDS; i++) {
          gbc.gridy = i + pbarOffset;
          gbc.gridx = 1;
          gbc.insets.right = NONTOTAL_FIELD_RMARGIN;

          if (i == SUBTOTAL_INDEX || i == TOTAL_INDEX)
            gbc.fill = GridBagConstraints.NONE;
          else
            gbc.fill = GridBagConstraints.HORIZONTAL;
          
          // add label
          statsPanel.add(sTypes[i], gbc);

          gbc.gridx = 2;

          if (sValues[i] != subtotalTf &&
            sValues[i] != totalTf) {
            gbc.insets.right = NONTOTAL_FIELD_RMARGIN;
          }
          else {
            gbc.insets.right = TOTAL_FIELD_RMARGIN;
          }

          // add value
          statsPanel.add(sValues[i], gbc);

          // a11y
          sTypes[i].setLabelFor(sValues[i]);
      }   // for

      // ----- now configure outer panel ----
      gbc = new GridBagConstraints();
      gbc.anchor = GridBagConstraints.SOUTH;
      gbc.weighty = 10.0;
      gbc.fill = GridBagConstraints.VERTICAL;
      gbc.ipadx = 10;

      // component to fill extra vertical space
      gbc.gridx = 1;
      gbc.gridy = 0;
      gbc.weighty = 10.0;
      gbc.gridwidth = 3;
      Component strut = Box.createVerticalStrut(1);
      bodyPanel.add(strut, gbc);

      // components to fill extra horizontal space
      gbc.gridx = 0;
      gbc.weighty = 1.0;
      gbc.gridwidth = 1;
      gbc.weightx = 3.0;
      gbc.fill = GridBagConstraints.HORIZONTAL;
      strut = Box.createHorizontalStrut(1);
      bodyPanel.add(strut, gbc);  // left
      gbc.gridx = 4;
      strut = Box.createHorizontalStrut(1);
      bodyPanel.add(strut, gbc);     // right

      gbc.weighty = 0.0;

      // add folder and filter fields
      // folder name display
      JLabel lab = uif.createLabel("br.summ.fldlbl", true);
      lab.setOpaque(false);
      folderNameTf = uif.createOutputField("br.summ.fldtf", 35, lab);
      folderNameTf.setOpaque(false);
      folderNameTf.setBorder(BorderFactory.createEmptyBorder());
      gbc.fill = GridBagConstraints.NONE;
      gbc.anchor = GridBagConstraints.SOUTHEAST;
      gbc.weightx = 1.0;
      gbc.gridy = 1;
      gbc.gridx = 1;
      bodyPanel.add(lab, gbc);

      // output field
      gbc.gridx = 2;
      gbc.gridwidth = 2;
      gbc.weightx = 5.0;
      gbc.fill = GridBagConstraints.HORIZONTAL;
      gbc.anchor = GridBagConstraints.SOUTHWEST;
      bodyPanel.add(folderNameTf, gbc);

      // view filter display
      lab = uif.createLabel("br.summ.ftrlbl", true);
      lab.setOpaque(false);
      filterNameTf = uif.createOutputField("br.summ.ftrtf", 35, lab);
      filterNameTf.setOpaque(false);
      filterNameTf.setBorder(BorderFactory.createEmptyBorder());
      gbc.gridx = 1;
      gbc.gridy = 2;
      gbc.gridwidth = 1;
      gbc.weightx = 1.0;
      gbc.anchor = GridBagConstraints.SOUTHEAST;
      gbc.fill = GridBagConstraints.NONE;
      bodyPanel.add(lab, gbc);

      // output field
      gbc.gridx = 2;
      gbc.gridwidth = 2;
      gbc.weightx = 5.0;
      gbc.anchor = GridBagConstraints.SOUTHWEST;
      gbc.fill = GridBagConstraints.HORIZONTAL;
      bodyPanel.add(filterNameTf, gbc);

      filterDescTf = uif.createOutputField("br.summ.fdesc", 35);
      filterDescTf.setOpaque(false);
      filterDescTf.setBorder(BorderFactory.createEmptyBorder());
      gbc.gridy = 3;
      gbc.gridx = 2;
      gbc.weightx = 0.0;
      gbc.anchor = GridBagConstraints.SOUTHWEST;
      gbc.fill = GridBagConstraints.NONE;
      bodyPanel.add(filterDescTf, gbc);

      gbc.gridx = 1;
      gbc.gridy = 4;
      gbc.gridwidth = 3;
      gbc.fill = GridBagConstraints.HORIZONTAL;
      gbc.anchor = GridBagConstraints.CENTER;
      JComponent div = new Divider(1, 5);
      div.getInsets().top = 5;
      div.getInsets().bottom = 5;
      bodyPanel.add(div, gbc);

      // spacer
      /*
      gbc.gridx = 0;
      gbc.gridy = 4;
      gbc.gridwidth = 5;
      gbc.weightx = 1.0;
      gbc.weighty = 0.0;
      strut = Box.createVerticalStrut(12);
      bodyPanel.add(strut, gbc);
      */

      gbc.gridx = 0;
      gbc.weighty = 1.0;
      gbc.gridwidth = 1;
      gbc.weightx = 3.0;
      gbc.fill = GridBagConstraints.HORIZONTAL;
      strut = Box.createHorizontalStrut(1);
      bodyPanel.add(strut, gbc);  // left

      JPanel pan = uif.createPanel("br.statpie", new GridBagLayout(), false);
      pan.setOpaque(false);
      GridBagConstraints gl = new GridBagConstraints();
      gl.fill = GridBagConstraints.NONE;
      gl.anchor = GridBagConstraints.CENTER;
      gl.gridy = 0;
      gl.gridx = 0;
      gl.weightx = 1.0;
      statsPanel.setMinimumSize(new Dimension(80,80));
      pan.add(statsPanel, gl);
      statsPanel.setMinimumSize(new Dimension(150,100));
      pie = new PieChart(new int[] {100},
                     new Color[] {I18NUtils.getStatusColor(I18NUtils.FILTERED_OUT)});
      //pie.setOpaque(false);
      gl.fill = GridBagConstraints.BOTH;
      gl.weightx = 2.0;
      gl.gridx = 1;
      pan.add(pie, gl);

      gbc.gridx = 1;
      gbc.gridy = 5;
      gbc.anchor = GridBagConstraints.CENTER;
      gbc.fill = GridBagConstraints.HORIZONTAL;
      gbc.gridheight = 1;
      gbc.gridwidth = 3;
      bodyPanel.add(pan, gbc);

      // stats
      /*
      gbc.weighty = 0.0;
      gbc.weightx = 2.0;
      gbc.gridx = 1;
      gbc.gridy = 4;
      gbc.gridheight = 1;
      gbc.gridwidth = 2;
      gbc.anchor = GridBagConstraints.EAST;
      gbc.fill = GridBagConstraints.HORIZONTAL;
      bodyPanel.add(statsPanel, gbc);

      // pie
      pie = new PieChart(new int[] {100},
                     new Color[] {I18NUtils.getStatusColor(I18NUtils.FILTERED_OUT)});
      pie.setOpaque(false);
      gbc.fill = GridBagConstraints.BOTH;
      gbc.anchor = GridBagConstraints.CENTER;
      gbc.gridwidth = 2;
      gbc.gridheight = 1;
      gbc.weightx = 2.0;
      gbc.weighty = 5.0;
      gbc.gridx = 3;
      bodyPanel.add(pie, gbc);
      */

      // spacer to take up space
      gbc.gridwidth = 5;
      gbc.gridy = 6;
      gbc.gridx = 0;
      gbc.weightx = 10.0;
      gbc.weighty = 10.0;
      strut = Box.createVerticalStrut(5);
      bodyPanel.add(strut, gbc);

      /*
      // create the message area
      JTextArea ta = uif.createMessageArea("br.statInfo");
      ta.setColumns(30);
      ta.setRows(2);

      // add message area to bottom of panel
      gbc.weighty = 2.0;
      gbc.weightx = 10.0;
      gbc.gridy = 3;
      gbc.fill = GridBagConstraints.NONE;

      bodyPanel.add(ta, gbc);

      setBackground(Color.green);
      setOpaque(true);
      */

      // this is necessary to make sure that the split pane can resize
      // this panel.  without setting the min., the panel seems to take
      // all it is given, and never gives it back.
      bodyPanel.setMinimumSize(new Dimension(150,100));
      bodyPanel.setBackground(Color.WHITE);
      bodyPanel.setOpaque(true);

      JScrollPane sp = uif.createScrollPane(bodyPanel,
            ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
            ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
      sp.setMinimumSize(new Dimension(150,100));
      setLayout(new BorderLayout());
      add(sp, BorderLayout.CENTER);
      setMinimumSize(new Dimension(150,100));
    }

    void dispose() {
      if (ct != null) {
          ct.interrupt();
          ct = null;
      }
    }

    protected JTextField createPlainField(int id) {
      JTextField f = uif.createOutputField("br.summ." + id, NTFIELD_WIDTH);
      f.setHorizontalAlignment(SwingConstants.RIGHT);
      f.setBorder(BorderFactory.createEmptyBorder());
      f.setOpaque(false);
      // other field config here

      return f;
    }

    protected JTextField createTotalField(int id) {
      JTextField f = uif.createOutputField("br.summ." + id, TFIELD_WIDTH);
      f.setHorizontalAlignment(JTextField.RIGHT);
      f.setBorder(null);
      f.setBackground(MetalLookAndFeel.getPrimaryControlDarkShadow());
      f.setForeground(MetalLookAndFeel.getWindowBackground());
      f.setEnabled(true);
      // other field config here

      return f;
    }

    protected void updateSubpanel(TestResultTable.TreeNode currNode) {
      super.updateSubpanel(currNode);

      // XXX consider doing it in the background anyway
      //     and altering the thread priority based on visibility
      //if (!isVisible())
          //return;

      //if (ct != null && subpanelNode == ct.getNode())
       //   return;

      if (debug > 1) {
          Debug.println("BP_SP - updateSubpanel() called");
      }

      if (filterNameTf != null && filterDescTf != null &&
          !(ttm.getTestFilter().getName().equals(filterNameTf.getText())) ) {
          filterNameTf.setText(ttm.getTestFilter().getName());
          filterDescTf.setText(ttm.getTestFilter().getDescription());
      }

      // for efficiency, we won't restart the thread on an update request.
      // this may lead to synchronization issues where the numbers will
      // be slightly off.
      // as a possibly solution, we might want to set a flag so once the
      //    current thread finishes, it restarts a new counter thread.
      // alternatively, we can assume that another update will occur
      //    in a short period of time without intervention
      /*
      if (ct != null && ct.isAlive())
          ct.halt();
      */

      if (ct != null && ct.getNode() == subpanelNode) {
          // same node and we are counting
          return;
      }
      else {
          if (debug > 0) {
            Debug.println("BP_SP - updating panel");
          }

          // we are watching a new node, or need to update the current stats
          if (ct == null) {
            ct = new CounterThread(subpanelNode, sValues);
            ct.setPriority(Thread.MIN_PRIORITY + 3);
            ct.start();
          }

          // in all cases, tell the thread what to look at
          ct.setNode(subpanelNode);
          String spn = subpanelNode.getName();
          if (spn != null)
            folderNameTf.setText(spn);
          else {
            Parameters p = ttm.getParameters();
            if (p != null) {
                TestSuite ts = p.getTestSuite();
                folderNameTf.setText((ts == null ? "" :
                  uif.getI18NString("br.summ.fldtf.root", ts.getName())));
            }
          }

      }
    }

    /**
     * Iterates to get the necessary data and updates the GUI.
     * The behavior depends on whether the harness is running or not.  If it is not
     * running tests, the GUI is incrementally updated.  If it is running, the
     * GUI is only updated after the new data is available.  The result should be
     * better behavior from the user's standpoint.
     */
00506     private class CounterThread extends Thread {
      /**
       * @param tn The node whose stats are to be scanned and placed onscreen.
       * @param fs Filters used to correctly generate stats.
       * @param fields Components to be updated with stats.
       */
00512       CounterThread(TestResultTable.TreeNode tn, JTextField[] fields) {
          super("BP_SP.CounterThread");
          node = tn;
          tfs = fields;
      }

      /**
       * Discover the node this thread is scanning.
       */
00521       TestResultTable.TreeNode getNode() {
          return node;
      }

      public void run() {
          if (debug) {
            Debug.println("BP_SP.CT - thread running");
            Debug.println("   -> " + this);
          }

          if (stopping) {
            halt();
            return;
          }

          // high priority cache request
          synchronized (this) {
            cache = ttm.getNodeInfo(node, true);
          }

          int[] stats;
          int[] combinedStats;

          // do not overwrite the info onscreen if we are in the middle of a run
          // otherwise reset numbers to zero
          if (!model.isRunning()) {
            EventQueue.invokeLater(
                new BranchPanel.TextUpdater(BranchPanel.TextUpdater.CLEAR,
                                    tfs, null, uif));
            showMessage(uif.getI18NString("br.summ.working"));
          }

          while (true) {
            if (stopping) {       
                if (debug) {
                  Debug.println("BP_SP.CT - thread terminating in run() due to halt()");
                  Debug.println("   -> " + this);
                }
                // terminates the thread
                break;
            }

            // refresh reference from model
            // cache == null usually indicates we changed nodes


            boolean isComplete = false;
            synchronized(this) {
                //refresh everytime
                //if (cache == null || !cache.isValid())
                  cache = ttm.getNodeInfo(node, true);

                if (cache == null)
                  continue;

                // update the GUI stats
                stats = cache.getStats();
                combinedStats = fillStats(stats, cache.getRejectCount(), true, true);
                isComplete = cache.isComplete();
            }   // sync
            
            if (!Arrays.equals(lastStats, combinedStats)) {
                notifyUpdate(stats, combinedStats);
                lastStats = combinedStats;
                updateMessage(stats, !isComplete);
            }
            else  {
                // bypass update message
            }

            synchronized (this) {
                try {
                  if (cache == null || cache.isComplete())
                      wait(INACTIVE_FREQUENCY);
                  else
                      wait(ACTIVE_FREQUENCY);
                }
                catch (InterruptedException e) {
                  // someone wants this thread dead
                  return;
                } // catch
            }
          }   // while

          // checkpoint
          if (stopping) {
            // warning, possible incomplete data in GUI
            halt();
            return;
          }
          // update the GUI stats
          // synchronzied to protect again NPE when setNode() nulls the cache ref.
          synchronized (this) {
            if (cache == null)
                cache = ttm.getNodeInfo(node, true);

            stats = cache.getStats();
            notifyUpdate(stats,
                fillStats(stats, cache.getRejectCount(), true, true));
          } // sync

          updateMessage(stats, false);

          if (debug)
            Debug.println("counter thread done...");
      }     // run()

      /**
       * Request that this list scanning thread terminate.
       * The run method should exit promptly.
       */
00632       public void halt() {
          if (debug) {
            Debug.println("BP_SP.CT - thread stopping");
            Debug.println("   -> " + this);
          }

          stopping = true;
      }

      synchronized void setNode(TestResultTable.TreeNode tn) {
          if (tn != node) {
            cache = null;
            node = tn;
          }
      }

      /**
       * Create an array of length tfs.length.  Containing the bsaic + filter stats,
       * the subtotal and total fields empty.
       *
       * @param basic Array of length Status.NUM_STATES, probably output from
       *        TreeIterator.getResultStats().
       * @param filtered Number of tests filtered out.  Should be zero or greater.
       * @param validSub Is the subtotal okay to calculate and display?
       * @param validTot Is the total okay to calculate and display?
       */
00658       private int[] fillStats(int[] basic, int filtered, boolean validSub,
                        boolean validTot) {
          int[] result = new int[tfs.length];

          System.arraycopy(basic, 0, result, 0, basic.length);

          // subtotal position
          if (validSub) {
            int sub = 0;
            for (int i = 0; i < basic.length; i++)
                sub += basic[i];

            result[SUBTOTAL_INDEX] = sub;
          }
          else        // disable this field
            result[SUBTOTAL_INDEX] = -1;

          result[FILTERED_INDEX] = filtered;

          // total position
          if (validTot)
            result[TOTAL_INDEX] = result[FILTERED_INDEX] + result[SUBTOTAL_INDEX];
          else        // disable this field
            result[TOTAL_INDEX] = -1;

          return result;
      }

      private void updateMessage(int[] stats, boolean stillRunning) {
          // calculate the message at the bottom
          // XXX this needs to be moved to the outer class, but stats are
          // convienient here.  also this panel may not always be updated if
          // not visible, so this code will not run on time
          int worstIndex = -1;
          for (int i = 0; i < stateOrdering.length; i++) {
            if (stats[stateOrdering[i]] > 0) {
                worstIndex = stateOrdering[i];
                break;
            }
          } // for

          // checkpoint
          if (stopping) {
            halt();
            return;
          }

          if (worstIndex != -1) {
            // NOTE: this is the switch is used instead of this line to allow static
            // i18n string checking to work
            //statusTf.setText(uif.getI18NString("br.worst." + worstIndex));

            if (Status.NUM_STATES > 4)
                throw new JavaTestError(uif.getI18NString("br.worstNum"));

            String msg = null;

            switch (worstIndex) {
                case 0: msg = uif.getI18NString("br.worst.0"); break;
                case 1: msg = uif.getI18NString("br.worst.1"); break;
                case 2: msg = uif.getI18NString("br.worst.2"); break;
                case 3: msg = uif.getI18NString("br.worst.3"); break;
                default:
                  throw new JavaTestError(uif.getI18NString("br.worstNum"));
            }

            if (stillRunning) {
                msg = uif.getI18NString("br.stillWork") + msg;
            }

            showMessage(msg);

          }
          else
            showMessage(uif.getI18NString("br.none"));

      }

      private void notifyUpdate(final int[] basic, final int[] values) {
          EventQueue.invokeLater(
            new BranchPanel.TextUpdater(BranchPanel.TextUpdater.UPDATE,
                                  tfs,
                                  values,
                                  uif));
          final int[] pieStats = new int[I18NUtils.NUM_STATES];
          System.arraycopy(basic, 0, pieStats, 0, basic.length);
          pieStats[I18NUtils.FILTERED_OUT] = values[FILTERED_INDEX];
          EventQueue.invokeLater(new Runnable() {
            public void run() {
                pie.setValue(pieStats, pieColors);
            /*
                int sum = 0;
                for (int i = 0; i < pieStats[i]; i++)
                  sum += pieStats[i];

                // hide pie if all filtered out or not run
                if (pieStats[FILTERED_INDEX] == sum ||
                  pieStats[I18NUtils.NOT_RUN] == sum)
                  pie.setVisible(false);
                else
                  pie.setVisible(true);
            */
            }
          });
      }

      private volatile boolean stopping;
      private TestResultTable.TreeNode node;
      private TT_NodeCache cache;
      private JTextField[] tfs;
      private int[] lastStats;      // to optimize out extra GUI refreshes
      private boolean debug = Debug.getBoolean(BP_SummarySubpanel.class, "CounterThread");
    }

    class Divider extends JComponent {
      /**
       * Creates a default 2 wide pair of lines.
       */
      public Divider() {
      }

      public Divider(int thickness, int spacing) {
          thick = thickness;
          space = spacing;
      }

      protected void paintComponent(Graphics g) {
          if (isOpaque()) {
            g.setColor(getBackground());
            g.fillRect(0,0, getWidth(), getHeight());
          }

          Insets inset = getInsets();
          int width = getWidth() - inset.left - inset.right;
          int height = getHeight() - inset.left - inset.right;

          g.setColor(Color.BLACK);

          /*
          if (height < 2) 
            return;
          else if (height < ((thick * 2) + space)) {
            */
            // not enough space for two lines, draw one
            int mid = height / 2;
            g.fillRect(inset.left, mid-(thick/2), width, thick);
          /*
            g.fillRect(inset.left, mid-(thick/2), width, thick);
          }
          //else if (height < ((thick * 2) + space) ) {
          else {
            // draws two lines vertically centered, spanning the entire
            // usable width
            int mid = height / 2;
            g.fillRect(inset.left, mid-(space/2)-thick, width, thick);
            g.fillRect(inset.left, mid+(space/2), width, thick);
          }
          */
      }

      public Dimension getPreferredSize() {
          return getMinimumSize();
      }

      public Dimension getMinimumSize() {
          Insets inset = getInsets();
          return new Dimension(10+inset.left+inset.right,
                         thick*2+space+inset.top+inset.bottom);
      }

      int thick = 2;
      int space = 4;
    }

    // incomplete
    class Divider2 extends JComponent {
      public Divider2() {
      }

      public Divider2(int thickness) {
          thick = thickness;
      }

      protected void paintComponent(Graphics g) {
          if (isOpaque()) {
            g.setColor(getBackground());
            g.fillRect(0,0, getWidth(), getHeight());
          }

          Insets inset = getInsets();
          int width = getWidth() - inset.left - inset.right;
          int height = getHeight() - inset.left - inset.right;

          g.setColor(MetalLookAndFeel.getSeparatorForeground());

          if (height < 2) 
            return;
          else if (height < (thick * 2)) {
            // not enough space for two lines, draw one
            int mid = height / 2;
            g.fillRect(inset.left, mid-(thick/2), width, thick);
          }
          else {
            // usable width
            int mid = height / 2;
            g.fillRect(inset.left + arcWidth, mid-thick*2,
                     width-arcWidth, thick);
            g.fillArc(inset.left, mid-(thick*2), width, thick*2, -90, 0);
          }
      }

      public Dimension getPreferredSize() {
          return getMinimumSize();
      }

      public Dimension getMinimumSize() {
          Insets inset = getInsets();
          return new Dimension(arcWidth*2+inset.left+inset.right,
                         thick*2+inset.top+inset.bottom);
      }

      int thick = 2;
      int arcWidth = 15;
    }

    private class LegendIcon implements Icon {
      LegendIcon(Color c, boolean shadow) {
          color = c;
          shadowColor = new Color(0x555555); 
          paintShadow = shadow;
      }

      // creates a transparent icon
      LegendIcon() {
          color = shadowColor = null;
      }

      public int getIconWidth() { return 16; }
      public int getIconHeight() { return 16; }

      public void paintIcon(Component c, Graphics g, int x, int y) {
          if (image == null) {
            image = new BufferedImage(getIconWidth(), getIconHeight(),
                                BufferedImage.TYPE_INT_ARGB);
            Graphics imageG = image.getGraphics();
            paintIt(imageG, paintShadow, color);
            imageG.dispose();
          }

            g.drawImage(image, x, y, null);
      }

      private void paintIt(Graphics g, boolean shadow, Color c) {
          if (c == null) {
            return;
          }

          int x = 2, y = 2, width, height;
          if (shadow) {
            width = height = 10;
          }
          else
            width = height = 12;

          if (shadow) {
            g.setColor(shadowColor);
            g.fillRect(x+2,y+2,width,height);
          }
 
          /*
          if (c.equals(Color.WHITE)) {
            // outline for a white icon
            g.setColor(Color.BLACK);
            g.fillRect(x,y,width,height);
            g.setColor(c);
            g.fillRect(x,y,width-1,height-1);
          }
          else {
            */
            g.setColor(c);
            g.fillRect(x,y,width,height);
          //}
      }

      private Color color, shadowColor;
        private Image image;
      private boolean paintShadow;
    }

    private CounterThread ct;
    private int[] stats;
    private int filtered;

    private JLabel progLabel;
    private ProgressMeter pMeter;

    private /* static */ JLabel[] sTypes;
    private JTextField[] sValues;
    private JTextField subtotalTf;
    private JTextField totalTf;
    private JTextField folderNameTf;
    private JTextField filterNameTf;
    private JTextField filterDescTf;
    private PieChart pie;
    private static Color[] pieColors;
    // seven fields:
    // pass, fail, error, not run, subtotal, filtered out, total
    private static final int NUM_FIELDS = 7;
    private static final int SUBTOTAL_INDEX = 4;
    private static final int FILTERED_INDEX = 5;
    private static final int TOTAL_INDEX = 6;
    private static final int NONTOTAL_FIELD_RMARGIN = 10;
    private static final int TOTAL_FIELD_RMARGIN = 2;

    private static final int ACTIVE_FREQUENCY = 1000;     // while iterator running
    private static final int INACTIVE_FREQUENCY = 2500;         // while just waiting for updates

    private final int NTFIELD_WIDTH = 5;
    private final int TFIELD_WIDTH = 7;
    protected final int[] stateOrdering = {Status.ERROR, Status.FAILED, Status.NOT_RUN, Status.PASSED};
    private static int debug = Debug.getInt(BP_SummarySubpanel.class);

}

Generated by  Doxygen 1.6.0   Back to index