net.grinder.console.swingui.TestGraphPanel Maven / Gradle / Ivy
// Copyright (C) 2001 - 2011 Philip Aston
// All rights reserved.
//
// This file is part of The Grinder software distribution. Refer to
// the file LICENSE which is part of The Grinder distribution for
// licensing details. The Grinder distribution is available on the
// Internet at http://grinder.sourceforge.net/
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
package net.grinder.console.swingui;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Insets;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import net.grinder.common.Test;
import net.grinder.console.common.Resources;
import net.grinder.console.model.ModelTestIndex;
import net.grinder.console.model.SampleListener;
import net.grinder.console.model.SampleModel;
import net.grinder.console.model.SampleModelViews;
import net.grinder.statistics.StatisticsSet;
/**
* A panel of test graphs.
*
* @author Philip Aston
*/
public class TestGraphPanel extends JPanel implements SampleModel.Listener {
private final JComponent m_parentComponent;
private final BorderLayout m_borderLayout = new BorderLayout();
private final FlowLayout m_flowLayout = new FlowLayout(FlowLayout.LEFT);
private final JLabel m_logoLabel;
private final Dimension m_preferredSize = new Dimension();
private final SampleModel m_model;
private final SampleModelViews m_sampleModelViews;
private final Resources m_resources;
private final SwingDispatcherFactory m_swingDispatcherFactory;
private final String m_testLabel;
private final Map m_components =
new HashMap();
TestGraphPanel(JComponent parentComponent,
SampleModel model,
SampleModelViews sampleModelViews,
Resources resources,
SwingDispatcherFactory swingDispatcherFactory) {
m_parentComponent = parentComponent;
m_model = model;
m_sampleModelViews = sampleModelViews;
m_resources = resources;
m_swingDispatcherFactory = swingDispatcherFactory;
m_testLabel = m_resources.getString("graph.test.label") + " ";
m_model.addModelListener(
swingDispatcherFactory.create(SampleModel.Listener.class, this));
m_model.addTotalSampleListener(
new SampleListener() {
public void update(StatisticsSet intervalStatistics,
StatisticsSet cumulativeStatistics) {
// No requirement to dispatch in Swing thread.
LabelledGraph.resetPeak();
}
});
m_logoLabel = new JLabel(m_resources.getImageIcon("logo-large.image"));
}
/**
* {@link net.grinder.console.model.SampleModel.Listener} interface.
* Called when the model state has changed.
*/
public void stateChanged() {
}
/**
* {@link net.grinder.console.model.SampleModel.Listener} interface.
* Called when the model has a new sample.
*/
public final void newSample() {
}
/**
* {@link net.grinder.console.model.SampleModel.Listener} interface.
* Existing Test
s and StatisticsView
s have
* been discarded.
*/
public final void resetTests() {
m_components.clear();
removeAll();
setLayout(m_borderLayout);
add(m_logoLabel, BorderLayout.CENTER);
invalidate();
}
/**
* {@link net.grinder.console.model.SampleModel.Listener} interface.
* Called when new tests have been registered.
*
* @param newTests
* The new tests.
* @param modelTestIndex
* Updated test index.
*/
public void newTests(Set newTests, ModelTestIndex modelTestIndex) {
remove(m_logoLabel);
setLayout(m_flowLayout);
for (Test test : newTests) {
final String description = test.getDescription();
final String label =
m_testLabel + test.getNumber() +
(description != null ? " (" + description + ")" : "");
final LabelledGraph testGraph =
new LabelledGraph(label,
m_resources,
m_model.getTPSExpression(),
m_model.getPeakTPSExpression(),
m_sampleModelViews.getTestStatisticsQueries());
m_model.addSampleListener(
test,
m_swingDispatcherFactory.create(
SampleListener.class,
new SampleListener() {
public void update(final StatisticsSet intervalStatistics,
final StatisticsSet cumulativeStatistics) {
testGraph.add(intervalStatistics, cumulativeStatistics,
m_sampleModelViews.getNumberFormat());
}
}));
m_components.put(test, testGraph);
}
final int numberOfTests = modelTestIndex.getNumberOfTests();
// We add all the tests components again. The container ignores
// duplicates, but inserts the new components in the correct
// order.
for (int i = 0; i < numberOfTests; i++) {
add(m_components.get(modelTestIndex.getTest(i)));
}
// Invalidate preferred size cache.
m_preferredSize.width = -1;
validate();
}
/**
* Specify our preferred size to prevent our FlowLayout from laying
* us out horizontally. We fix our width to that of our containing
* tab, and calculate our vertical height. The intermediate scroll
* pane uses the preferred size.
*
* @return a Dimension
value
*/
public final Dimension getPreferredSize() {
if (m_components.size() == 0) {
return super.getPreferredSize();
}
// Width is whatever our parent says.
final Insets parentComponentInsets = m_parentComponent.getInsets();
final int preferredWidth =
m_parentComponent.getWidth() -
parentComponentInsets.left - parentComponentInsets.right;
if (m_preferredSize.width == preferredWidth) {
// Nothing's changed.
return m_preferredSize;
}
m_preferredSize.width = preferredWidth;
// Now ape the FlowLayout algorithm to calculate desired height,
// *sigh*.
final int n = getComponentCount();
final int hgap = m_flowLayout.getHgap();
final Insets insets = getInsets();
final int fudgeFactor = 6; // I've no idea where this extra space
// comes from, but we need it.
int availableWidth =
preferredWidth - insets.left - insets.right - hgap + fudgeFactor;
if (n > 0) {
// Assume we have a homogeneous set of fixed size components.
final int componentWidth = getComponent(0).getWidth();
final int componentHeight = getComponent(0).getHeight();
int numberAcross = -1;
while (componentWidth > 0 && availableWidth > 0) {
++numberAcross;
availableWidth -= componentWidth;
availableWidth -= hgap;
}
if (numberAcross > 0) {
final int numberDown = (n + numberAcross - 1) / numberAcross;
// numberDown is always >= 1.
m_preferredSize.height =
numberDown * componentHeight +
(numberDown - 1) * m_flowLayout.getVgap();
}
}
return m_preferredSize;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy