Issue #728 - Implementation of Statistics graphs

peer review comments
Changing to use average value rather than sum.

Change-Id: I7f97e27c4f463fe60bec2cbc52f3eac66d8fa77f

Former-commit-id: f15ba1ee009abf4a562bb37450d65f97c7ffa217
This commit is contained in:
Mike Duff 2012-11-21 17:53:30 -06:00
parent d276bf25df
commit f000c1a9cf
47 changed files with 7242 additions and 65 deletions

View file

@ -231,4 +231,18 @@
install-size="0"
version="0.0.0"/>
<plugin
id="com.raytheon.uf.viz.stats"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
<plugin
id="com.raytheon.uf.common.stats"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
</feature>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="output" path="bin"/>
</classpath>

View file

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>com.raytheon.uf.viz.stats</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.ManifestBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.SchemaBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.pde.PluginNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View file

@ -0,0 +1,8 @@
#Mon Nov 05 11:14:57 CST 2012
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.6

View file

@ -0,0 +1,19 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Stats
Bundle-SymbolicName: com.raytheon.uf.viz.stats;singleton:=true
Bundle-Version: 1.0.0.qualifier
Bundle-Activator: com.raytheon.uf.viz.stats.Activator
Bundle-Vendor: RAYTHEON
Require-Bundle: org.eclipse.ui,
org.eclipse.core.runtime,
com.raytheon.uf.viz.core;bundle-version="1.12.1174",
com.raytheon.viz.ui;bundle-version="1.12.1174",
com.raytheon.uf.common.stats;bundle-version="1.0.0",
com.raytheon.uf.common.time;bundle-version="1.12.1174",
com.raytheon.uf.common.util;bundle-version="1.12.1174",
com.google.guava;bundle-version="1.0.0"
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Bundle-ActivationPolicy: lazy
Export-Package: com.raytheon.uf.viz.stats,
com.raytheon.uf.viz.stats.ui

View file

@ -0,0 +1,6 @@
source.. = src/
output.. = bin/
bin.includes = META-INF/,\
.,\
plugin.xml,\
build.properties

View file

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>
<extension
point="org.eclipse.ui.menus">
<menuContribution
allPopups="false"
locationURI="menu:CAVE?after=group1">
<command
commandId="com.raytheon.uf.viz.stats.statsui"
id="stats"
label="AWIPS Statistics..."
style="push">
</command>
</menuContribution>
</extension>
<extension
point="org.eclipse.ui.commands">
<command
id="com.raytheon.uf.viz.stats.statsui"
name="Statistics Display Command">
</command>
</extension>
<extension
point="org.eclipse.ui.handlers">
<handler
class="com.raytheon.uf.viz.stats.action.StatsAction"
commandId="com.raytheon.uf.viz.stats.statsui">
</handler>
</extension>
</plugin>

View file

@ -0,0 +1,50 @@
package com.raytheon.uf.viz.stats;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;
/**
* The activator class controls the plug-in life cycle
*/
public class Activator extends AbstractUIPlugin {
// The plug-in ID
public static final String PLUGIN_ID = "com.raytheon.uf.viz.stats"; //$NON-NLS-1$
// The shared instance
private static Activator plugin;
/**
* The constructor
*/
public Activator() {
}
/*
* (non-Javadoc)
* @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
*/
public void start(BundleContext context) throws Exception {
super.start(context);
plugin = this;
}
/*
* (non-Javadoc)
* @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
*/
public void stop(BundleContext context) throws Exception {
plugin = null;
super.stop(context);
}
/**
* Returns the shared instance
*
* @return the shared instance
*/
public static Activator getDefault() {
return plugin;
}
}

View file

@ -0,0 +1,99 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.stats.action;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;
import com.raytheon.uf.common.stats.GraphDataRequest;
import com.raytheon.uf.common.stats.GraphDataResponse;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.viz.core.exception.VizException;
import com.raytheon.uf.viz.core.requests.ThriftClient;
import com.raytheon.uf.viz.stats.ui.StatsControlDlg;
/**
* Stats Action Handler.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Sep 11, 2012 728 mpduff Initial creation
*
* </pre>
*
* @author mpduff
* @version 1.0
*/
public class StatsAction extends AbstractHandler {
private final IUFStatusHandler statusHandler = UFStatus
.getHandler(StatsAction.class);
/** Dialog instance */
private StatsControlDlg statsControlDlg = null;
@Override
public Object execute(ExecutionEvent event) throws ExecutionException {
if ((statsControlDlg == null) || (statsControlDlg.isDisposed() == true)) {
GraphDataRequest request = new GraphDataRequest();
request.setMetaDataRequest(true);
GraphDataResponse response = sendRequest(request);
if (response != null) {
Shell shell = PlatformUI.getWorkbench()
.getActiveWorkbenchWindow().getShell();
statsControlDlg = new StatsControlDlg(shell);
statsControlDlg.setConfigList(response.getConfigList());
statsControlDlg.open();
}
} else {
statsControlDlg.bringToTop();
}
return null;
}
/**
* Send GraphDataRequest.
*
* @param req
* The request to send
* @return The GraphDataResponse
*/
private GraphDataResponse sendRequest(GraphDataRequest req) {
try {
return (GraphDataResponse) ThriftClient.sendRequest(req);
} catch (VizException e) {
statusHandler.handle(Priority.ERROR, "Error Requesting Data", e);
}
return null;
}
}

View file

@ -0,0 +1,190 @@
package com.raytheon.uf.viz.stats.display;
public class ScaleManager {
/**
* Max number of major ticks, including first and last
*/
private final int MAX_MAJOR_TICK = 6;
private final double ZOOMED_FACTOR = 0.01;
private final double UNZOOMED_FACTOR = 5.0;
private double[] niceMajorIncrementArray = { 0.01, 0.02, 0.05, 0.1, 0.2,
0.5, 1.0, 2.0, 5.0 };
private double baseFactorStartingPoint = .01;
private double minDataValue;
private double maxDataValue;
private double minScaleValue;
private double maxScaleValue;
private int majorTickCount;
private double majorTickIncrement;
private boolean zoomFlag;
public ScaleManager(double minDataValue, double maxDataValue) {
this.minDataValue = minDataValue;
this.maxDataValue = maxDataValue;
rescale();
}
private synchronized void rescale() {
int multipleCount = 0;
// if zooming, use the ZOOMED_FACTOR value
if (zoomFlag) {
multipleCount = (int) Math.floor(minDataValue / ZOOMED_FACTOR);
minScaleValue = multipleCount * ZOOMED_FACTOR;
}
// if NOT zooming, use the UNZOOMED_FACTOR value
else {
multipleCount = (int) Math.floor(minDataValue / UNZOOMED_FACTOR);
minScaleValue = multipleCount * UNZOOMED_FACTOR;
if ((maxDataValue - minDataValue < 10) && (minDataValue > .5)) {
minScaleValue = minDataValue - .5;
}
}
double baseFactor = baseFactorStartingPoint;
boolean done = false;
int i = 0;
// set the range the values fit into
double range = maxDataValue - minScaleValue;
if (range < 1 && !zoomFlag) {
range = 1;
}
while (!done) {
double testIncrement = niceMajorIncrementArray[i] * (baseFactor);
int testTickCount = (int) Math.ceil(range / testIncrement + 1);
// if there are a reasonable number of tickCounts, then stop
if (testTickCount <= MAX_MAJOR_TICK) {
majorTickCount = testTickCount;
majorTickIncrement = testIncrement;
// first tick counts as a tick, so subtract 1
maxScaleValue = minScaleValue
+ ((majorTickCount - 1) * majorTickIncrement);
return;
}
i++;
if (i >= niceMajorIncrementArray.length) {
i = 0;
baseFactor *= 10.0;
}
} // end while !done
return;
}
public void setMaxDataValue(double maxDataValue) {
this.maxDataValue = maxDataValue;
rescale();
}
public double getMaxDataValue() {
return maxDataValue;
}
public void setMinDataValue(double minDataValue) {
this.minDataValue = minDataValue;
rescale();
}
public double getMinDataValue() {
return minDataValue;
}
public int getMajorTickCount() {
return majorTickCount;
}
public double getMajorTickIncrement() {
return majorTickIncrement;
}
public double getMaxScaleValue() {
return maxScaleValue;
}
public double getMinScaleValue() {
return minScaleValue;
}
public void setNiceMajorIncrementArray(double[] niceMajorIncrementArray) {
this.niceMajorIncrementArray = niceMajorIncrementArray;
rescale();
}
public double[] getNiceMajorIncrementArray() {
return niceMajorIncrementArray;
}
public boolean isZoomFlag() {
return zoomFlag;
}
public void setZoomFlag(boolean zoomFlag) {
this.zoomFlag = zoomFlag;
rescale();
}
/**
* @param baseFactorStartingPoint
* The baseFactorStartingPoint to set.
*/
public void setBaseFactorStartingPoint(double baseFactorStartingPoint) {
this.baseFactorStartingPoint = baseFactorStartingPoint;
}
/**
* @return Returns the baseFactorStartingPoint.
*/
public double getBaseFactorStartingPoint() {
return baseFactorStartingPoint;
}
@Override
public String toString() {
String outString = " minDataValue = " + getMinDataValue()
+ " maxDataValue = " + getMaxDataValue() + "\n"
+ " minScaleValue = " + getMinScaleValue()
+ " maxScaleValue = " + getMaxScaleValue() + "\n"
+ " majorTickCount = " + getMajorTickCount()
+ " majorTickIncrement = " + getMajorTickIncrement();
return outString;
}
// For testing
public static void main(String[] argArray) {
double minValue = 5.1;
double maxValue = 5.3;
ScaleManager scaler = new ScaleManager(minValue, maxValue);
System.out.println(scaler.toString());
}
}

View file

@ -0,0 +1,142 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.stats.ui;
/**
* Color Manager
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Oct 16, 2012 mpduff Initial creation.
*
* </pre>
*
* @version 1.0
*/
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.eclipse.swt.graphics.RGB;
public class ColorManager {
/** Color list */
private List<RGB> colorRGBs;
/**
* Constructor.
*/
public ColorManager() {
setupColors();
}
/**
* Initialize the colors
*/
private void setupColors() {
List<RGB> tempColorRGBs = new ArrayList<RGB>();
tempColorRGBs.add(new RGB(255, 0, 0)); // RED
tempColorRGBs.add(new RGB(255, 165, 0)); // ORANGE
tempColorRGBs.add(new RGB(0, 255, 0)); // GREEN
tempColorRGBs.add(new RGB(255, 255, 0)); // YELLOW
tempColorRGBs.add(new RGB(165, 42, 42)); // BROWN
tempColorRGBs.add(new RGB(0, 255, 255)); // CYAN
tempColorRGBs.add(new RGB(255, 0, 255)); // MAGENTA
tempColorRGBs.add(new RGB(0, 0, 255)); // BLUE
tempColorRGBs.add(new RGB(138, 43, 226)); // BLUEVIOLET
tempColorRGBs.add(new RGB(238, 130, 238)); // VIOLET
tempColorRGBs.add(new RGB(102, 205, 170)); // AQUAMARINE3
tempColorRGBs.add(new RGB(139, 125, 107)); // BISQUE4
tempColorRGBs.add(new RGB(238, 197, 145)); // BURLYWOOD2
tempColorRGBs.add(new RGB(205, 205, 0)); // YELLOW3
tempColorRGBs.add(new RGB(69, 139, 0)); // CHARTREUSE4
tempColorRGBs.add(new RGB(255, 127, 80)); // CORAL
tempColorRGBs.add(new RGB(100, 149, 237)); // CORNFLOWERBLUE
tempColorRGBs.add(new RGB(0, 139, 139)); // CYAN4
tempColorRGBs.add(new RGB(169, 169, 169)); // DARKGRAY
tempColorRGBs.add(new RGB(139, 0, 139)); // DARKMAGENTA
tempColorRGBs.add(new RGB(238, 118, 0)); // DARKORANGE2
tempColorRGBs.add(new RGB(139, 0, 0)); // DARKRED
tempColorRGBs.add(new RGB(233, 150, 122)); // DARKSALMON
tempColorRGBs.add(new RGB(255, 20, 147)); // DEEPPINK
tempColorRGBs.add(new RGB(0, 191, 255)); // DEEPSKYBLUE
tempColorRGBs.add(new RGB(255, 255, 255)); // WHITE
tempColorRGBs.add(new RGB(193, 205, 193)); // HONEYDEW3
tempColorRGBs.add(new RGB(139, 58, 98)); // HOTPINK4
tempColorRGBs.add(new RGB(144, 238, 144)); // LIGHTGREEN
tempColorRGBs.add(new RGB(255, 182, 193)); // LIGHTPINK
tempColorRGBs.add(new RGB(176, 196, 222)); // LIGHTSTEELBLUE
tempColorRGBs.add(new RGB(205, 133, 0)); // ORANGE3
tempColorRGBs.add(new RGB(139, 105, 105)); // ROSYBROWN4
tempColorRGBs.add(new RGB(210, 180, 140)); // TAN
tempColorRGBs.add(new RGB(0, 0, 0)); // BLACK
colorRGBs = Collections.unmodifiableList(tempColorRGBs);
}
/**
* Get the list of colors.
*
* @return the list of colors
*/
public List<RGB> getColorRGBs() {
return colorRGBs;
}
/**
* Get the color at the provided index.
*
* @param index
* The index
* @return the color for the index
*/
public RGB getColorAtIndex(int index) {
int indexRV = index % colorRGBs.size();
RGB returnColor = colorRGBs.get(indexRV);
if (returnColor == null) {
return new RGB(0, 0, 0);
}
return returnColor;
}
// for testing
public static void main(String[] args) {
ColorManager cm = new ColorManager();
List<RGB> colorRGBArray = cm.getColorRGBs();
for (RGB rgb : colorRGBArray) {
// String s = RGBColors.getColorName(rgb);
// System.out.println(String.format("%20S", s) + "\t" +
// rgb.toString());
System.out.println(rgb.toString());
}
}
}

View file

@ -0,0 +1,356 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.stats.ui;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.ColorDialog;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Layout;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Tree;
import com.raytheon.uf.common.stats.data.GraphData;
import com.raytheon.viz.ui.dialogs.CaveSWTDialogBase;
/**
* TODO Add Description
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Oct 18, 2012 mpduff Initial creation
*
* </pre>
*
* @author mpduff
* @version 1.0
*/
public class ColorManagerDlg extends CaveSWTDialogBase {
private Composite mainComp;
private final IColorSelection callback;
private Button individualRdo;
private Tree selectionTree;
private final GraphData graphData;
private final List<Button> radioList = new ArrayList<Button>();
/** Map of group -> composite */
private final Map<String, Composite> compMap = new HashMap<String, Composite>();
private final Map<String, Map<String, Label>> labelMap = new HashMap<String, Map<String, Label>>();
/** A map of unique keys, RGB for the check boxes that are checked. */
private final Map<String, RGB> keyRgbMap = new LinkedHashMap<String, RGB>();;
protected ColorManagerDlg(Shell parentShell, GraphData graphData,
IColorSelection callback) {
super(parentShell, SWT.DIALOG_TRIM | SWT.MIN | SWT.RESIZE,
CAVE.DO_NOT_BLOCK | CAVE.MODE_INDEPENDENT
| CAVE.INDEPENDENT_SHELL);
setText("Color Manager");
this.callback = callback;
this.graphData = graphData;
}
@Override
protected Layout constructShellLayout() {
// Create the main layout for the shell.
GridLayout mainLayout = new GridLayout(1, false);
mainLayout.marginHeight = 2;
mainLayout.marginWidth = 2;
return mainLayout;
}
@Override
protected void initializeComponents(Shell shell) {
mainComp = new Composite(shell, SWT.NONE);
GridLayout gl = new GridLayout(1, false);
gl.marginHeight = 0;
gl.marginWidth = 0;
gl.horizontalSpacing = 0;
gl.verticalSpacing = 5;
GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
mainComp.setLayout(gl);
mainComp.setLayoutData(gd);
createGroups();
createActionControls();
setupColorsAndKeyRgbMap();
}
private void createGroups() {
ScrolledComposite scrolledComp = new ScrolledComposite(mainComp,
SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
GridLayout gl = new GridLayout(1, false);
gl.verticalSpacing = 1;
scrolledComp.setLayout(gl);
GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
gd.widthHint = 220;
gd.heightHint = 350;
scrolledComp.setLayoutData(gd);
gl = new GridLayout(1, false);
gd = new GridData(SWT.FILL, SWT.FILL, true, true);
Composite composite = new Composite(scrolledComp, SWT.NONE);
composite.setLayout(gl);
composite.setLayoutData(gd);
scrolledComp.setContent(composite);
scrolledComp.setExpandHorizontal(true);
scrolledComp.setExpandVertical(true);
gl = new GridLayout(1, false);
gd = new GridData(SWT.FILL, SWT.FILL, true, false);
Composite indComp = new Composite(composite, SWT.NONE);
indComp.setLayout(gl);
indComp.setLayoutData(gd);
individualRdo = new Button(indComp, SWT.RADIO);
individualRdo.setText("Individual");
individualRdo.setSelection(true);
individualRdo.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
handleIndividualSelection();
}
});
Map<String, List<String>> groupMap = graphData.getGroupAndNamesMap();
for (String group : groupMap.keySet()) {
if (!labelMap.containsKey(group)) {
labelMap.put(group, new HashMap<String, Label>());
}
gl = new GridLayout(1, false);
gd = new GridData(SWT.FILL, SWT.FILL, true, true);
Composite comp = new Composite(composite, SWT.NONE);
comp.setLayout(gl);
comp.setLayoutData(gd);
Button btn1 = new Button(comp, SWT.RADIO);
btn1.setText(group);
btn1.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
handleGroupSelection(((Button) e.getSource()).getText());
}
});
radioList.add(btn1);
gd = new GridData(SWT.FILL, SWT.FILL, true, true);
gl = new GridLayout(1, false);
ScrolledComposite sc = new ScrolledComposite(comp, SWT.BORDER);
sc.setLayout(gl);
sc.setLayoutData(gd);
sc.setExpandHorizontal(true);
sc.setExpandVertical(true);
compMap.put(group, sc);
gd = new GridData(SWT.FILL, SWT.FILL, true, true);
gl = new GridLayout(2, false);
Composite memberComp = new Composite(sc, SWT.NONE);
memberComp.setLayout(gl);
memberComp.setLayoutData(gd);
sc.setContent(memberComp);
List<String> memberList = groupMap.get(group);
for (String member : memberList) {
gd = new GridData(20, 10);
Label lbl = new Label(memberComp, SWT.BORDER);
lbl.setLayoutData(gd);
lbl.addMouseListener(new MouseAdapter() {
@Override
public void mouseDown(MouseEvent e) {
Label lbl = (Label) e.getSource();
handleLabelClickEvent(lbl);
}
});
Label memberLbl = new Label(memberComp, SWT.NONE);
memberLbl.setText(member);
labelMap.get(group).put(member, lbl);
}
sc.layout();
}
scrolledComp.layout();
}
private void createActionControls() {
Composite buttonComp = new Composite(shell, SWT.NONE);
buttonComp.setLayout(new GridLayout(3, false));
buttonComp.setLayoutData(new GridData(SWT.CENTER, SWT.DEFAULT, true,
false));
int buttonWidth = 80;
GridData gd = new GridData(buttonWidth, SWT.DEFAULT);
Button okBtn = new Button(buttonComp, SWT.PUSH);
okBtn.setText("OK");
okBtn.setLayoutData(gd);
okBtn.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
handleApply();
close();
}
});
gd = new GridData(buttonWidth, SWT.DEFAULT);
Button applyBtn = new Button(buttonComp, SWT.PUSH);
applyBtn.setText("Apply");
applyBtn.setLayoutData(gd);
applyBtn.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
handleApply();
}
});
gd = new GridData(buttonWidth, SWT.DEFAULT);
Button cancelBtn = new Button(buttonComp, SWT.PUSH);
cancelBtn.setText("Cancel");
cancelBtn.setLayoutData(gd);
cancelBtn.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
close();
}
});
}
/**
* Setup the colors for the labels and put the key, RGB in the selected map.
*/
private void setupColorsAndKeyRgbMap() {
ColorManager cm = new ColorManager();
int count = 0;
Color c;
for (String key : labelMap.keySet()) {
count = 0;
for (String memberKey : labelMap.get(key).keySet()) {
c = new Color(this.getDisplay(), cm.getColorAtIndex(count));
labelMap.get(key).get(memberKey).setBackground(c);
++count;
c.dispose();
keyRgbMap.put(key + "::" + memberKey, labelMap.get(key).get(memberKey).getBackground().getRGB());
}
}
for (String key : labelMap.keySet()) {
for (String memberKey : labelMap.get(key).keySet()) {
keyRgbMap.put(key + "::" + memberKey, labelMap.get(key).get(memberKey).getBackground().getRGB());
}
}
}
private void handleIndividualSelection() {
for (Button rdo: this.radioList) {
rdo.setSelection(false);
}
for (String key : this.compMap.keySet()) {
compMap.get(key).setEnabled(false);
}
}
private void handleGroupSelection(String group) {
individualRdo.setSelection(false);
for (Button rdo: this.radioList) {
if (!rdo.getText().equals(group)) {
rdo.setSelection(false);
}
}
for (String compMapKey: compMap.keySet()) {
if (compMapKey.equals(group)) {
compMap.get(compMapKey).setEnabled(true);
} else {
compMap.get(compMapKey).setEnabled(false);
}
}
}
/**
* Handle the color label that is being clicked.
*
* @param lbl
* Label that was clicked.
*/
private void handleLabelClickEvent(Label lbl) {
RGB rgb = lbl.getBackground().getRGB();
String key = (String) lbl.getData();
ColorDialog colorDlg = new ColorDialog(this.getShell());
colorDlg.setRGB(rgb);
colorDlg.setText("Select a Color");
RGB returnRGB = colorDlg.open();
if (returnRGB == null) {
return;
}
Color c = new Color(this.getDisplay(), returnRGB);
lbl.setBackground(c);
c.dispose();
if (keyRgbMap.containsKey(key) == true) {
keyRgbMap.put(key, returnRGB);
}
}
private void handleApply() {
// TODO Auto-generated method stub
// System.out.println("TODO: Implement me");
}
}

View file

@ -0,0 +1,408 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.stats.ui;
/**
* TODO Add Description
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Oct 16, 2012 mpduff Initial creation
*
* </pre>
*
* @author mpduff
* @version 1.0
*/
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.ColorDialog;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import com.raytheon.uf.common.stats.data.GraphData;
/**
* Composites that contains the controls to change colors and to determine what
* is displayed.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Oct 16, 2012 lvenable Initial creation
*
* </pre>
*
* @author lvenable
* @version 1.0
*/
public class GroupingComp extends Composite implements IGroupSelection {
/** Parse pattern */
private final Pattern colonPattern = Pattern.compile(":");
/** Selection Manager Dialog */
private SelectionManagerDlg selectionMangerDlg;
/** Scrolled composite containing the control widgets composite. */
private ScrolledComposite scrolledComp;
/** Composite containing the control widgets. */
private Composite controlComp;
/** A map of unique keys, Label controls. */
private Map<String, Label> labelMap;
/** A map of unique keys, Check box controls. */
private Map<String, Button> checkBtnMap;
/** A map of unique keys, RGB for the check boxes that are checked. */
private Map<String, RGB> keyRgbMap;
/** The graph data */
private final GraphData graphData;
/** Grouping callback */
private final IStatsGroup callback;
/**
* Constructor.
*
* @param parentComp
* Parent composite.
* @param swtStyle
* SWT style.
* @param statsData
* Statistical data.
*/
public GroupingComp(Composite parentComp, int swtStyle,
GraphData graphData, IStatsGroup callback) {
super(parentComp, swtStyle);
this.graphData = graphData;
this.callback = callback;
init();
}
/**
* Initialize the class.
*/
private void init() {
labelMap = new LinkedHashMap<String, Label>();
checkBtnMap = new LinkedHashMap<String, Button>();
keyRgbMap = new LinkedHashMap<String, RGB>();
GridLayout gl = new GridLayout(1, false);
GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
this.setLayout(gl);
this.setLayoutData(gd);
Label grpLbl = new Label(this, SWT.NONE);
grpLbl.setText("Groups:");
createScrolledComposite();
setupColorsAndKeyRgbMap();
addSelectionColorActionButtons();
fireCallback();
}
/**
* Create the scrolled composite and set the content.
*/
private void createScrolledComposite() {
scrolledComp = new ScrolledComposite(this, SWT.BORDER | SWT.H_SCROLL
| SWT.V_SCROLL);
GridLayout gl = new GridLayout(1, false);
gl.verticalSpacing = 1;
scrolledComp.setLayout(gl);
GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
gd.widthHint = 220;
gd.heightHint = 350;
scrolledComp.setLayoutData(gd);
controlComp = new Composite(scrolledComp, SWT.NONE);
controlComp.setLayout(new GridLayout(2, false));
controlComp.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
createControls();
controlComp.layout();
scrolledComp.setContent(controlComp);
scrolledComp.setExpandHorizontal(true);
scrolledComp.setExpandVertical(true);
scrolledComp.addControlListener(new ControlAdapter() {
@Override
public void controlResized(ControlEvent e) {
scrolledComp.setMinSize(controlComp.computeSize(SWT.DEFAULT,
SWT.DEFAULT));
}
});
scrolledComp.layout();
}
/**
* Create the color labels and check box controls.
*/
private void createControls() {
List<String> keyArray = graphData.getKeysWithData();
for (String key : keyArray) {
GridData gd = new GridData(20, 10);
Label lbl = new Label(controlComp, SWT.BORDER);
lbl.setLayoutData(gd);
lbl.setData(key);
lbl.addMouseListener(new MouseAdapter() {
@Override
public void mouseDown(MouseEvent e) {
Label lbl = (Label) e.getSource();
handleLabelClickEvent(lbl);
}
});
Button btn = new Button(controlComp, SWT.CHECK);
btn.setText(key);
btn.setSelection(true);
btn.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
Button btn = (Button) e.getSource();
handleCheckEvent(btn);
}
});
labelMap.put(key, lbl);
checkBtnMap.put(key, btn);
}
}
/**
* Add the Selection and Color Manager buttons.
*/
private void addSelectionColorActionButtons() {
if (checkBtnMap.isEmpty()) {
return;
}
Composite buttonComp = new Composite(this, SWT.NONE);
buttonComp.setLayout(new GridLayout(1, false));
buttonComp.setLayoutData(new GridData(SWT.CENTER, SWT.DEFAULT, true,
false));
int buttonWidth = 160;
GridData gd = new GridData(buttonWidth, SWT.DEFAULT);
Button selMgrBtn = new Button(buttonComp, SWT.PUSH);
selMgrBtn.setText("Selection Manager...");
selMgrBtn.setLayoutData(gd);
selMgrBtn.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
displaySelectionMgrDlg();
}
});
// Not including this functionality in the branch.
// gd = new GridData(buttonWidth, SWT.DEFAULT);
// Button colorMgrBtn = new Button(buttonComp, SWT.PUSH);
// colorMgrBtn.setText("Color Manager...");
// colorMgrBtn.setLayoutData(gd);
// colorMgrBtn.addSelectionListener(new SelectionAdapter() {
// @Override
// public void widgetSelected(SelectionEvent e) {
// displayColorMgrDlg();
// }
// });
}
/**
* Handle the check button event.
*
* @param btn
* Check box being checked/unchecked.
*/
private void handleCheckEvent(Button btn) {
String key = btn.getText();
if (btn.getSelection() == true) {
keyRgbMap.put(key, labelMap.get(key).getBackground().getRGB());
} else {
keyRgbMap.remove(key);
}
fireCallback();
}
/**
* Handle the color label that is being clicked.
*
* @param lbl
* Label that was clicked.
*/
private void handleLabelClickEvent(Label lbl) {
RGB rgb = lbl.getBackground().getRGB();
String key = (String) lbl.getData();
ColorDialog colorDlg = new ColorDialog(this.getShell());
colorDlg.setRGB(rgb);
colorDlg.setText("Select a Color");
RGB returnRGB = colorDlg.open();
if (returnRGB == null) {
return;
}
Color c = new Color(this.getDisplay(), returnRGB);
lbl.setBackground(c);
c.dispose();
if (keyRgbMap.containsKey(key) == true) {
keyRgbMap.put(key, returnRGB);
}
fireCallback();
}
/**
* Call the callback.
*/
private void fireCallback() {
callback.setGroupData(keyRgbMap);
}
/**
* Setup the colors for the labels and put the key, RGB in the selected map.
*/
private void setupColorsAndKeyRgbMap() {
ColorManager cm = new ColorManager();
int count = 0;
Color c;
for (String key : labelMap.keySet()) {
c = new Color(this.getDisplay(), cm.getColorAtIndex(count));
labelMap.get(key).setBackground(c);
++count;
c.dispose();
}
for (String key : checkBtnMap.keySet()) {
if (checkBtnMap.get(key).getSelection() == true) {
keyRgbMap.put(key, labelMap.get(key).getBackground().getRGB());
}
}
}
/**
* Display the Selection Manager dialog.
*/
private void displaySelectionMgrDlg() {
if (selectionMangerDlg == null || selectionMangerDlg.isDisposed()) {
selectionMangerDlg = new SelectionManagerDlg(getShell(), graphData,
this);
selectionMangerDlg.open();
} else {
selectionMangerDlg.bringToTop();
}
}
/**
* Display the Color Manager dialog.
*/
// Implementing in the next release.
// private void displayColorMgrDlg() {
// ColorManagerDlg dlg = new ColorManagerDlg(getShell(), graphData, this);
// dlg.open();
// }
/**
* {@inheritDoc}
*/
@Override
public void setSelections(Map<String, Map<String, Boolean>> selectionMap) {
List<String> keySequence = graphData.getKeySequence();
Map<String, List<String>> offMap = new HashMap<String, List<String>>();
for (String key : selectionMap.keySet()) {
for (String selection : selectionMap.get(key).keySet()) {
if (!selectionMap.get(key).get(selection)) {
if (!offMap.containsKey(key)) {
offMap.put(key, new ArrayList<String>());
}
offMap.get(key).add(selection);
}
}
}
if (offMap.size() == 0) {
for (String btnKey : checkBtnMap.keySet()) {
checkBtnMap.get(btnKey).setSelection(true);
keyRgbMap.put(btnKey, labelMap.get(btnKey).getBackground()
.getRGB());
}
} else {
for (String btnKey : checkBtnMap.keySet()) {
String[] parts = colonPattern.split(btnKey);
for (String group : offMap.keySet()) {
for (String part : parts) {
int idx = keySequence.indexOf(part);
if (idx >= 0 && offMap.get(group).contains(keySequence.get(idx))) {
checkBtnMap.get(btnKey).setSelection(false);
keyRgbMap.remove(btnKey);
} else {
checkBtnMap.get(btnKey).setSelection(true);
keyRgbMap.put(btnKey, labelMap.get(btnKey)
.getBackground().getRGB());
}
}
}
}
}
fireCallback();
}
}

View file

@ -0,0 +1,41 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.stats.ui;
/**
* TODO Add Description
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Oct 18, 2012 mpduff Initial creation
*
* </pre>
*
* @author mpduff
* @version 1.0
*/
public interface IColorSelection {
}

View file

@ -0,0 +1,48 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.stats.ui;
import java.util.Map;
/**
* Interface for Group Selections.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Oct 18, 2012 728 mpduff Initial creation
*
* </pre>
*
* @author mpduff
* @version 1.0
*/
public interface IGroupSelection {
/**
* Set the selections.
*
* @param selectionMap
*/
void setSelections(Map<String, Map<String, Boolean>> selectionMap);
}

View file

@ -0,0 +1,44 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.stats.ui;
/**
* Statistics dialog control interface.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Oct 9, 2012 728 mpduff Initial creation
*
* </pre>
*
* @author mpduff
* @version 1.0
*/
public interface IStatsControl {
/**
* Show the statistics control dialog.
*/
void showControl();
}

View file

@ -0,0 +1,74 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.stats.ui;
import java.util.Map;
import org.eclipse.swt.graphics.RGB;
import com.raytheon.uf.common.stats.data.GraphData;
/**
* Stats display interface.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Oct 3, 2012 728 mpduff Initial creation
*
* </pre>
*
* @author mpduff
* @version 1.0
*/
public interface IStatsDisplay {
/**
* Get the GraphData object
*
* @return GraphData
*/
GraphData getGraphData();
/**
* Draw grid lines flag
*
* @return true to draw the grid lines
*/
boolean drawGridLines();
/**
* Draw data lines flag
*
* @return true to draw the data lines
*/
boolean drawDataLines();
/**
* Get the group settings.
*
* @return The group settings map
*/
Map<String, RGB> getGroupSettings();
}

View file

@ -0,0 +1,51 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.stats.ui;
import java.util.Map;
import org.eclipse.swt.graphics.RGB;
/**
* Stats group interface.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Oct 17, 2012 728 mpduff Initial creation
*
* </pre>
*
* @author mpduff
* @version 1.0
*/
public interface IStatsGroup {
/**
* Set the group settings data.
*
* @param groupSettingsMap
*/
void setGroupData(Map<String, RGB> groupSettingsMap);
}

View file

@ -0,0 +1,319 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.stats.ui;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Layout;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import com.raytheon.uf.common.stats.data.GraphData;
import com.raytheon.viz.ui.dialogs.CaveSWTDialogBase;
/**
* Stats Selection Manager Dialog.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Oct 18, 2012 lvenable Initial creation
*
* </pre>
*
* @author lvenable
* @version 1.0
*/
public class SelectionManagerDlg extends CaveSWTDialogBase {
/** Main Composite */
private Composite mainComp;
/** Selection tree */
private Tree selectionTree;
/** GraphData object */
private final GraphData graphData;
/** Group selection callback */
private final IGroupSelection callback;
/**
* Constructor.
*
* @param parentShell
* @param graphData
* @param callback
*/
public SelectionManagerDlg(Shell parentShell, GraphData graphData,
IGroupSelection callback) {
super(parentShell, SWT.DIALOG_TRIM | SWT.MIN | SWT.RESIZE,
CAVE.DO_NOT_BLOCK | CAVE.MODE_INDEPENDENT
| CAVE.INDEPENDENT_SHELL);
setText("Selection Manager");
this.graphData = graphData;
this.callback = callback;
}
/**
* {@inheritDoc}
*/
@Override
protected Layout constructShellLayout() {
// Create the main layout for the shell.
GridLayout mainLayout = new GridLayout(1, false);
mainLayout.marginHeight = 2;
mainLayout.marginWidth = 2;
return mainLayout;
}
/**
* {@inheritDoc}
*/
@Override
protected void initializeComponents(Shell shell) {
shell.setMinimumSize(280, 400);
mainComp = new Composite(shell, SWT.NONE);
GridLayout gl = new GridLayout(1, false);
gl.marginHeight = 0;
gl.marginWidth = 0;
gl.horizontalSpacing = 0;
gl.verticalSpacing = 5;
GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
mainComp.setLayout(gl);
mainComp.setLayoutData(gd);
initControls();
populateTree();
}
/**
* Initialize controls
*/
private void initControls() {
createSelectionTree();
createActionControls();
}
/**
* Create selection tree
*/
private void createSelectionTree() {
GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
gd.widthHint = 250;
gd.heightHint = 350;
selectionTree = new Tree(mainComp, SWT.BORDER | SWT.CHECK);
selectionTree.setLayoutData(gd);
selectionTree.addListener(SWT.Selection, new Listener() {
@Override
public void handleEvent(Event event) {
if (event.detail == SWT.CHECK) {
TreeItem item = (TreeItem) event.item;
boolean checked = item.getChecked();
checkItems(item, checked);
checkPath(item.getParentItem(), checked, false);
}
}
});
}
/**
* Create the buttons
*/
private void createActionControls() {
Composite buttonComp = new Composite(shell, SWT.NONE);
buttonComp.setLayout(new GridLayout(3, false));
buttonComp.setLayoutData(new GridData(SWT.CENTER, SWT.DEFAULT, true,
false));
int buttonWidth = 80;
GridData gd = new GridData(buttonWidth, SWT.DEFAULT);
Button okBtn = new Button(buttonComp, SWT.PUSH);
okBtn.setText("OK");
okBtn.setLayoutData(gd);
okBtn.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
handleApply();
close();
}
});
gd = new GridData(buttonWidth, SWT.DEFAULT);
Button applyBtn = new Button(buttonComp, SWT.PUSH);
applyBtn.setText("Apply");
applyBtn.setLayoutData(gd);
applyBtn.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
handleApply();
}
});
gd = new GridData(buttonWidth, SWT.DEFAULT);
Button cancelBtn = new Button(buttonComp, SWT.PUSH);
cancelBtn.setText("Cancel");
cancelBtn.setLayoutData(gd);
cancelBtn.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
close();
}
});
}
/**
* Check the path of the item.
*
* @param item
* @param checked
* @param grayed
*/
private void checkPath(TreeItem item, boolean checked, boolean grayed) {
if (item == null) {
return;
}
if (grayed) {
checked = true;
} else {
int index = 0;
TreeItem[] items = item.getItems();
while (index < items.length) {
TreeItem child = items[index];
if (child.getGrayed() || checked != child.getChecked()) {
checked = grayed = true;
break;
}
index++;
}
}
item.setChecked(checked);
item.setGrayed(grayed);
checkPath(item.getParentItem(), checked, grayed);
}
/**
* Check or uncheck the items in the TreeItem
*
* @param item
* @param checked
*/
private void checkItems(TreeItem item, boolean checked) {
item.setGrayed(false);
item.setChecked(checked);
TreeItem[] items = item.getItems();
for (int i = 0; i < items.length; i++) {
checkItems(items[i], checked);
}
}
/**
* Populate the tree
*/
private void populateTree() {
Map<String, List<String>> grpMemberMap = graphData
.getGroupAndNamesMap();
for (String key : grpMemberMap.keySet()) {
TreeItem treeItem = new TreeItem(selectionTree, SWT.NONE);
treeItem.setText(key);
treeItem.setChecked(true);
List<String> array = grpMemberMap.get(key);
for (String subKey : array) {
TreeItem subTreeItem = new TreeItem(treeItem, SWT.NONE);
subTreeItem.setText(subKey);
subTreeItem.setChecked(true);
}
}
}
/**
* Apply button action handler.
*/
private void handleApply() {
Map<String, Map<String, Boolean>> selectionMap = new HashMap<String, Map<String, Boolean>>();
List<String> badList = new ArrayList<String>();
for (TreeItem item : selectionTree.getItems()) {
if (!item.getChecked()) {
badList.add(item.getText());
}
Map<String, Boolean> map = new HashMap<String, Boolean>();
for (TreeItem subItem : item.getItems()) {
map.put(subItem.getText(), subItem.getChecked());
}
selectionMap.put(item.getText(), map);
}
// Notify user of situation resulting in no data being graphed
if (badList.size() > 0) {
StringBuilder sb = new StringBuilder();
sb.append("The following ");
if (badList.size() > 1) {
sb.append("groups have");
} else {
sb.append("group has");
}
sb.append(" no selections made\n");
sb.append("and will result in an empty graph.\n\n");
for (int i = 0; i < badList.size(); i++) {
sb.append(badList.get(i)).append("\n");
}
sb.append("\nDo you wish to continue?");
MessageBox mb = new MessageBox(shell, SWT.ICON_QUESTION | SWT.YES
| SWT.NO);
mb.setText("Empty Graph");
mb.setMessage(sb.toString());
int choice = mb.open();
if (choice == SWT.YES) {
callback.setSelections(selectionMap);
}
} else {
callback.setSelections(selectionMap);
}
}
}

View file

@ -0,0 +1,680 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.stats.ui;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import com.raytheon.uf.common.stats.GraphDataRequest;
import com.raytheon.uf.common.stats.GraphDataResponse;
import com.raytheon.uf.common.stats.data.GraphData;
import com.raytheon.uf.common.stats.data.StatsEventData;
import com.raytheon.uf.common.stats.xml.StatisticsConfig;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.common.time.TimeRange;
import com.raytheon.uf.common.time.util.TimeUtil;
import com.raytheon.uf.viz.core.exception.VizException;
import com.raytheon.uf.viz.core.requests.ThriftClient;
import com.raytheon.uf.viz.stats.utils.StatsUiUtils;
import com.raytheon.viz.ui.dialogs.AwipsCalendar;
import com.raytheon.viz.ui.dialogs.CaveSWTDialog;
import com.raytheon.viz.ui.widgets.duallist.DualList;
import com.raytheon.viz.ui.widgets.duallist.DualListConfig;
import com.raytheon.viz.ui.widgets.duallist.IUpdate;
/**
* Stats graphing control dialog.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Sep 25, 2012 mpduff Initial creation
*
* </pre>
*
* @author mpduff
* @version 1.0
*/
public class StatsControlDlg extends CaveSWTDialog implements IStatsControl,
IUpdate {
/** Status handler. */
private final IUFStatusHandler statusHandler = UFStatus
.getHandler(StatsControlDlg.class);
/** Time Range combo box items */
private final String[] TIME_RANGE_ITEMS = new String[] { "1 hr", "3 hr",
"6 hr", "12 hr", "24 hr", "1 week", "2 weeks", "1 month" };
/** Ranges corresponding to the time range combo box */
private final long[] MILLI_RANGES = new long[] { TimeUtil.MILLIS_PER_HOUR,
TimeUtil.MILLIS_PER_HOUR * 3, TimeUtil.MILLIS_PER_HOUR * 6,
TimeUtil.MILLIS_PER_HOUR * 12, TimeUtil.MILLIS_PER_DAY,
TimeUtil.MILLIS_PER_WEEK, TimeUtil.MILLIS_PER_WEEK * 2,
TimeUtil.MILLIS_PER_MONTH };
/** Date Format object */
private final ThreadLocal<SimpleDateFormat> sdf = new ThreadLocal<SimpleDateFormat>() {
@Override
protected SimpleDateFormat initialValue() {
SimpleDateFormat sTemp = new SimpleDateFormat("MM/dd/yyyy HH");
sTemp.setTimeZone(TimeZone.getTimeZone("GMT"));
return sTemp;
}
};
/** Main composite */
private Composite mainComp;
/** Date time label */
private Label dateTimeSelectedLabel;
/** Date time button */
private Button dateTimeBtn;
/** Time range selection combo box */
private Combo timeRangeCombo;
/** Start radio button */
private Button startRdo;
/** Split radio button */
private Button splitRdo;
/** Display button */
private Button displayBtn;
/** Close Button */
private Button closeBtn;
/** Category combo box */
private Combo categoryCombo;
/** Event combo box */
private Combo eventTypeCombo;
/** Data type/attribute combo box */
private Combo dataTypeCombo;
/** Groups dual list config object */
private DualListConfig groupFilterListConfig;
/** Group dual list widget */
private DualList groupFilterDualList;
/** Data type label */
private Label dataTypeLabel;
/** Combo box size */
private int comboSize;
/** Selected Date */
private Date selectedDate;
/** List of configuration objects */
private List<StatisticsConfig> configList;
/** StatsUiUtils object */
private final StatsUiUtils utils = new StatsUiUtils();
/**
* Constructor.
*
* @param parent parent Shell
*/
public StatsControlDlg(Shell parent) {
super(parent, SWT.DIALOG_TRIM, CAVE.INDEPENDENT_SHELL
| CAVE.PERSPECTIVE_INDEPENDENT | CAVE.DO_NOT_BLOCK);
setText("Statistics Display Control");
Calendar cal = TimeUtil.newCalendar(TimeZone.getTimeZone("GMT"));
cal.set(Calendar.MILLISECOND, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MINUTE, 0);
cal.add(Calendar.DAY_OF_MONTH, -1);
this.selectedDate = cal.getTime();
}
/**
* {@inheritDoc}
*/
@Override
protected void initializeComponents(Shell shell) {
GridData gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false);
GridLayout gl = new GridLayout(1, false);
mainComp = new Composite(shell, SWT.NONE);
mainComp.setLayout(gl);
mainComp.setLayoutData(gd);
// calculateSize();
createDateTimeComp();
createTimeRangeComp();
createDataChoiceComp();
createButtons();
generateData();
populateCategoryCombo();
setDataTypesAndGroups();
}
/**
* Create the time composite.
*/
private void createDateTimeComp() {
GridData gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false);
GridLayout gl = new GridLayout(2, false);
Group timeDateGroup = new Group(mainComp, SWT.NONE);
timeDateGroup.setText(" Date/Time ");
timeDateGroup.setLayout(gl);
timeDateGroup.setLayoutData(gd);
GridData btnData = new GridData(135, SWT.DEFAULT);
dateTimeBtn = new Button(timeDateGroup, SWT.PUSH);
dateTimeBtn.setLayoutData(btnData);
dateTimeBtn.setText("Select Date/Time...");
dateTimeBtn
.setToolTipText("Click to select a date and time for display");
dateTimeBtn.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
handleDateTimeSelection();
}
});
gd = new GridData(SWT.FILL, SWT.CENTER, true, false);
dateTimeSelectedLabel = new Label(timeDateGroup, SWT.NONE | SWT.CENTER);
dateTimeSelectedLabel.setLayoutData(gd);
dateTimeSelectedLabel.setText(getFormattedDate(this.selectedDate));
}
/**
* Create the time range composite
*/
private void createTimeRangeComp() {
GridData gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false);
GridLayout gl = new GridLayout(2, false);
Group rangeGroup = new Group(mainComp, SWT.NONE);
rangeGroup.setText(" Graph Range ");
rangeGroup.setLayout(gl);
rangeGroup.setLayoutData(gd);
gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false);
gl = new GridLayout(2, false);
Composite comboComp = new Composite(rangeGroup, SWT.NONE);
comboComp.setLayout(gl);
comboComp.setLayoutData(gd);
gd = new GridData(SWT.FILL, SWT.CENTER, true, false);
timeRangeCombo = new Combo(comboComp, SWT.READ_ONLY);
timeRangeCombo.setLayoutData(gd);
timeRangeCombo.setToolTipText("Choose a Time Range");
timeRangeCombo.setItems(this.TIME_RANGE_ITEMS);
timeRangeCombo.select(0);
gd = new GridData(SWT.CENTER, SWT.DEFAULT, true, false);
gl = new GridLayout(2, false);
Composite rdoComp = new Composite(rangeGroup, SWT.NONE);
rdoComp.setLayout(gl);
rdoComp.setLayoutData(gd);
startRdo = new Button(rdoComp, SWT.RADIO);
startRdo.setSelection(true);
startRdo.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, false));
startRdo.setText("Start");
startRdo.setToolTipText("Start time range\nat selected time");
splitRdo = new Button(rdoComp, SWT.RADIO);
splitRdo.setSelection(false);
splitRdo.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, false));
splitRdo.setText("Split");
splitRdo.setToolTipText("Split time range\nat selected time");
}
/**
* Create the data choice comp
*/
private void createDataChoiceComp() {
GridData gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false);
GridLayout gl = new GridLayout(1, false);
Group choiceGroup = new Group(mainComp, SWT.NONE);
choiceGroup.setText(" Graph Data ");
choiceGroup.setLayout(gl);
choiceGroup.setLayoutData(gd);
gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false);
gl = new GridLayout(2, false);
Composite comboComp = new Composite(choiceGroup, SWT.NONE);
comboComp.setLayout(gl);
comboComp.setLayoutData(gd);
gd = new GridData(SWT.FILL, SWT.CENTER, true, false);
Label categoryLabel = new Label(comboComp, SWT.NONE);
categoryLabel.setLayoutData(gd);
categoryLabel.setText(" Category: ");
gd = new GridData(comboSize + 50, SWT.DEFAULT);
gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false);
categoryCombo = new Combo(comboComp, SWT.READ_ONLY);
categoryCombo.setLayoutData(gd);
categoryCombo.setSize(comboSize, SWT.DEFAULT);
categoryCombo.setToolTipText("The Statistics Category");
categoryCombo.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
updateOptions();
setDataTypesAndGroups();
}
});
gd = new GridData(SWT.FILL, SWT.CENTER, true, false);
Label eventTypeLabel = new Label(comboComp, SWT.NONE);
eventTypeLabel.setLayoutData(gd);
eventTypeLabel.setText(" Event Type: ");
gd = new GridData(comboSize + 50, SWT.DEFAULT);
gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false);
eventTypeCombo = new Combo(comboComp, SWT.READ_ONLY);
eventTypeCombo.setLayoutData(gd);
eventTypeCombo.setSize(comboSize, SWT.DEFAULT);
eventTypeCombo.setToolTipText("The Event Type to Display");
eventTypeCombo.select(0);
eventTypeCombo.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
setDataTypesAndGroups();
}
});
gd = new GridData(SWT.FILL, SWT.CENTER, true, false);
dataTypeLabel = new Label(comboComp, SWT.NONE);
dataTypeLabel.setLayoutData(gd);
dataTypeLabel.setText(" Event Attribute: ");
gd = new GridData(comboSize + 50, SWT.DEFAULT);
gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false);
dataTypeCombo = new Combo(comboComp, SWT.READ_ONLY);
dataTypeCombo.setLayoutData(gd);
dataTypeCombo.setSize(comboSize, SWT.DEFAULT);
dataTypeCombo.setToolTipText("The Event Attribute to Display");
gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false);
gl = new GridLayout(1, false);
Composite dualListComp = new Composite(choiceGroup, SWT.NONE);
dualListComp.setLayout(gl);
dualListComp.setLayoutData(gd);
groupFilterListConfig = new DualListConfig();
groupFilterListConfig.setAvailableListLabel("Available Groups:");
groupFilterListConfig.setSelectedListLabel("Selected Groups:");
groupFilterListConfig.setShowUpDownBtns(false);
groupFilterListConfig.setListWidth(150);
groupFilterListConfig.setListHeight(100);
this.groupFilterDualList = new DualList(dualListComp, SWT.NONE,
groupFilterListConfig, this);
}
/**
* Create the buttons
*/
private void createButtons() {
GridData gd = new GridData(SWT.CENTER, SWT.DEFAULT, true, false);
GridLayout gl = new GridLayout(2, false);
Composite comp = new Composite(mainComp, SWT.NONE);
comp.setLayout(gl);
comp.setLayoutData(gd);
GridData btnData = new GridData(85, SWT.DEFAULT);
displayBtn = new Button(comp, SWT.PUSH);
displayBtn.setLayoutData(btnData);
displayBtn.setText("Display");
displayBtn.setToolTipText("Display the Statistical Data");
displayBtn.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
handleDisplayAction();
}
});
btnData = new GridData(85, SWT.DEFAULT);
closeBtn = new Button(comp, SWT.PUSH);
closeBtn.setLayoutData(btnData);
closeBtn.setText("Close");
closeBtn.setToolTipText("Close this dialog");
closeBtn.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
close();
}
});
}
/**
* Display an informational popup message to the user.
*
* @param title The title
* @param message The message
* @param type Type of message
*/
public void displayPopup(String title, String message, int type) {
MessageBox messageDialog = new MessageBox(getShell(), type);
messageDialog.setText(title);
messageDialog.setMessage(message);
messageDialog.open();
}
/**
* Set the data types.
*
* @param dataTypes String[] of data types
*/
public void setDataTypes(String[] dataTypes) {
if (dataTypes != null) {
dataTypeCombo.setItems(dataTypes);
dataTypeCombo.select(0);
}
}
/**
* Date/Time selection handler
*/
protected void handleDateTimeSelection() {
AwipsCalendar ac = new AwipsCalendar(getShell(), selectedDate, true);
Object obj = ac.open();
if ((obj != null) && (obj instanceof Calendar)) {
selectedDate = ((Calendar) obj).getTime();
dateTimeSelectedLabel.setText(getFormattedDate(selectedDate));
}
}
/**
* Generate stats config data objects
*/
private void generateData() {
utils.generateData(this.configList);
}
/**
* Populate the categore combo box
*/
private void populateCategoryCombo() {
List<String> items = new ArrayList<String>();
for (StatisticsConfig config : this.configList) {
items.addAll(config.getCategories());
}
categoryCombo.setItems(items.toArray(new String[items.size()]));
categoryCombo.select(0);
String category = this.categoryCombo.getText();
Map<String, String> eventTypes = utils.getEventTypes(category);
this.eventTypeCombo.setItems(eventTypes.keySet().toArray(
new String[eventTypes.keySet().size()]));
eventTypeCombo.select(0);
this.eventTypeCombo.setData(eventTypes);
}
/**
* Set the data types based on category selection.
*/
public void setDataTypes() {
String category = this.categoryCombo.getItem(categoryCombo
.getSelectionIndex());
String type = this.eventTypeCombo.getItem(eventTypeCombo
.getSelectionIndex());
@SuppressWarnings("unchecked")
String typeID = ((Map<String, String>) eventTypeCombo.getData())
.get(type);
StatsEventData data = utils.getEventData(category, typeID);
this.dataTypeCombo.setItems(data.getAttributes());
dataTypeCombo.select(0);
Map<String, String> attMap = utils.getEventAttributes(category, type);
dataTypeCombo.setData(attMap);
}
/**
* Update the options based on combo box selections
*/
private void updateOptions() {
String category = this.categoryCombo.getItem(categoryCombo
.getSelectionIndex());
Map<String, String> eventTypes = utils.getEventTypes(category);
this.eventTypeCombo.setItems(eventTypes.keySet().toArray(
new String[eventTypes.keySet().size()]));
eventTypeCombo.select(0);
this.eventTypeCombo.setData(eventTypes);
String type = this.eventTypeCombo.getItem(eventTypeCombo
.getSelectionIndex());
@SuppressWarnings("unchecked")
String typeID = ((Map<String, String>) eventTypeCombo.getData())
.get(type);
StatsEventData data = utils.getEventData(category, typeID);
this.dataTypeCombo.setItems(data.getAttributes());
dataTypeCombo.select(0);
List<String> groupList = data.getGroupList();
Collections.sort(groupList);
groupFilterDualList.clearAvailableList(true);
groupFilterDualList.clearSelection();
groupFilterDualList.setAvailableItems(groupList);
groupFilterDualList.getConfig().setFullList(groupList);
}
/**
* Set the data type and groups
*/
public void setDataTypesAndGroups() {
String category = this.categoryCombo.getItem(categoryCombo
.getSelectionIndex());
String type = this.eventTypeCombo.getItem(eventTypeCombo
.getSelectionIndex());
@SuppressWarnings("unchecked")
String typeID = ((Map<String, String>) eventTypeCombo.getData())
.get(type);
StatsEventData data = utils.getEventData(category, typeID);
Map<String, String> attMap = utils.getEventAttributes(category, type);
dataTypeCombo.setData(attMap);
this.dataTypeCombo.setItems(data.getAttributes());
dataTypeCombo.select(0);
List<String> groupList = data.getGroupList();
Collections.sort(groupList);
groupFilterDualList.clearAvailableList(true);
groupFilterDualList.clearSelection();
groupFilterDualList.setAvailableItems(groupList);
groupFilterDualList.getConfig().setFullList(groupList);
}
/**
* {@inheritDoc}
*/
@Override
public void hasEntries(boolean entries) {
this.displayBtn.setEnabled(entries);
}
/**
* {@inheritDoc}
*/
@Override
public void selectionChanged() {
// not used
}
/**
* Display the graph!
*/
private void handleDisplayAction() {
GraphDataRequest request = new GraphDataRequest();
String type = eventTypeCombo.getText();
String category = categoryCombo.getText();
String dataType = this.dataTypeCombo.getText();
@SuppressWarnings("unchecked")
String typeID = ((Map<String, String>) eventTypeCombo.getData())
.get(type);
@SuppressWarnings("unchecked")
String dataTypeID = ((Map<String, String>) dataTypeCombo.getData())
.get(dataType);
String[] selectedGroups = groupFilterDualList.getSelectedListItems();
StatsEventData conf = utils.getEventData(category, typeID);
List<String> groupList = new ArrayList<String>();
for (String group : selectedGroups) {
String groupName = conf.getGroupNameFromDisplayName(group);
if (groupName != null) {
groupList.add(groupName);
}
}
request.setField(dataTypeID);
request.setCategory(category);
request.setEventType(typeID);
request.setDataType(dataTypeID);
request.setGrouping(groupList);
int idx = timeRangeCombo.getSelectionIndex();
long selectedMillis = MILLI_RANGES[idx];
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
cal.setTime(selectedDate);
Date start;
Date end;
if (splitRdo.getSelection()) {
// Go back half the time range
cal.add(Calendar.MILLISECOND, -1 * Math.round(selectedMillis / 2));
start = cal.getTime();
// move forward the whole time range
cal.add(Calendar.MILLISECOND, (int) selectedMillis);
end = cal.getTime();
} else {
start = cal.getTime();
// one month of millis is larger than an int
if (selectedMillis > Integer.MAX_VALUE) {
cal.add(Calendar.SECOND, (int) (selectedMillis / 1000));
} else {
cal.add(Calendar.MILLISECOND, (int) selectedMillis);
}
end = cal.getTime();
}
TimeRange tr = new TimeRange(start, end);
request.setTimeRange(tr);
request.setTimeStep(5);
try {
GraphDataResponse response = (GraphDataResponse) ThriftClient
.sendRequest(request);
GraphData graphData = response.getGraphData();
if (graphData != null) {
StatsGraphDlg graphDlg = new StatsGraphDlg(getShell(), this);
graphDlg.setGraphData(graphData);
graphDlg.setTitle(type);
graphDlg.setGraphTitle(dataType);
graphDlg.setGrouping(groupList);
graphDlg.setCategory(category);
graphDlg.setEventType(typeID);
graphDlg.setDataType(dataTypeID);
graphDlg.open();
} else {
displayPopup(
"No Data",
"No statistical data are available for the time period selected.",
SWT.ICON_INFORMATION);
}
} catch (VizException e) {
statusHandler.handle(Priority.ERROR, "Error Occured", e);
}
}
/**
* Format the date.
*
* @param date The date to format
* @return the formated string
*/
private String getFormattedDate(Date date) {
SimpleDateFormat format = sdf.get();
return format.format(date) + "Z";
}
/**
* {@inheritDoc}
*/
@Override
public void showControl() {
this.bringToTop();
}
/**
* @return the configList
*/
public List<StatisticsConfig> getConfigList() {
return configList;
}
/**
* @param configList
* the configList to set
*/
public void setConfigList(List<StatisticsConfig> configList) {
this.configList = configList;
}
}

View file

@ -0,0 +1,824 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.stats.ui;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseMoveListener;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.graphics.Transform;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import com.raytheon.uf.common.stats.data.DataPoint;
import com.raytheon.uf.common.stats.data.GraphData;
import com.raytheon.uf.common.stats.data.StatsData;
import com.raytheon.uf.common.time.TimeRange;
import com.raytheon.uf.common.time.util.TimeUtil;
import com.raytheon.uf.viz.core.RGBColors;
import com.raytheon.uf.viz.stats.display.ScaleManager;
/**
* Statistics graph canvas.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Oct 3, 2012 728 mpduff Initial creation
*
* </pre>
*
* @author mpduff
* @version 1.0
*/
public class StatsDisplayCanvas extends Canvas {
/** Date Format object for graph title */
private final ThreadLocal<SimpleDateFormat> titleDateFormat = new ThreadLocal<SimpleDateFormat>() {
@Override
protected SimpleDateFormat initialValue() {
SimpleDateFormat sTemp = new SimpleDateFormat("MM/dd/yyyy HH:mm");
sTemp.setTimeZone(TimeZone.getTimeZone("GMT"));
return sTemp;
}
};
/** Date Format object for x axis */
private final ThreadLocal<SimpleDateFormat> axisFormat = new ThreadLocal<SimpleDateFormat>() {
@Override
protected SimpleDateFormat initialValue() {
SimpleDateFormat sTemp = new SimpleDateFormat("MM/dd/yyyy");
sTemp.setTimeZone(TimeZone.getTimeZone("GMT"));
return sTemp;
}
};
/** Decimal Format object */
private final ThreadLocal<DecimalFormat> numFormat = new ThreadLocal<DecimalFormat>() {
@Override
protected DecimalFormat initialValue() {
DecimalFormat tmp = new DecimalFormat("####.##");
return tmp;
}
};
/** Constant */
private final String COLON = ":";
/** Constant */
private final String ZERO = "0";
/** Constant */
private final String COUNT = "count";
/** Canvas initialized flag */
private boolean initialized = false;
/** Constant */
private final String MINUTE_00 = "00";
private final int canvasWidth = 800;
private final int canvasHeight = 575;
private final int GRAPH_BORDER = 75;
private final int GRAPH_WIDTH = canvasWidth - GRAPH_BORDER * 2;
private final int GRAPH_HEIGHT = canvasHeight - GRAPH_BORDER * 2;
/** Y Axis dimensions */
private final int[] yAxis = new int[] { GRAPH_BORDER, GRAPH_BORDER,
GRAPH_BORDER, GRAPH_HEIGHT + GRAPH_BORDER };
/** X Axis dimensions */
private final int[] xAxis = new int[] { GRAPH_BORDER,
GRAPH_HEIGHT + GRAPH_BORDER, GRAPH_WIDTH + GRAPH_BORDER,
GRAPH_HEIGHT + GRAPH_BORDER };
/** Top border dimensions */
private final int[] borderTop = new int[] { GRAPH_BORDER, GRAPH_BORDER,
GRAPH_BORDER + GRAPH_WIDTH, GRAPH_BORDER };
/** Right border dimensions */
private final int[] borderRight = new int[] { GRAPH_BORDER + GRAPH_WIDTH,
GRAPH_BORDER, GRAPH_BORDER + GRAPH_WIDTH,
GRAPH_BORDER + GRAPH_HEIGHT };
/** Canvas center */
private final int center = canvasWidth / 2;
/** Canvas font */
private Font canvasFont;
/** Parent Composite */
private final Composite parentComp;
/** Font height in pixels */
private int fontHeight;
/** Font width in pixels */
private int fontAveWidth;
/** Scale value manager */
private ScaleManager scalingManager;
/** The graph title */
private String graphTitle;
/** The secondary graph title */
private final String graphTitle2;
/** Millis per pixel in the X direction */
private long millisPerPixelX;
/** Callback */
private final IStatsDisplay callback;
/** Map of Rectangle objects */
private final Map<String, List<Rectangle>> rectangleMap = new HashMap<String, List<Rectangle>>();
/** Tooltip shell */
private Shell tooltip;
/** Graph Data object */
private GraphData graphData;
/** Smallest value in the data set */
private double minValue;
/** Largest value in the data set */
private double maxValue;
/**
* Constructor
*
* @param parent
* Parent composite
* @param callback
* Callback to the parent
* @param graphTitle
* The graph title
*/
public StatsDisplayCanvas(Composite parent, IStatsDisplay callback,
String graphTitle) {
super(parent, SWT.DOUBLE_BUFFERED);
this.parentComp = parent;
this.callback = callback;
this.graphTitle = graphTitle;
this.graphData = callback.getGraphData();
TimeRange tr = graphData.getTimeRange();
String start = titleDateFormat.get().format(tr.getStart());
String end = titleDateFormat.get().format(tr.getEnd());
this.graphTitle = graphTitle;
this.graphTitle2 = start + "Z - " + end + "Z";
setupCanvas();
}
/**
* Initialize the canvas.
*/
private void setupCanvas() {
canvasFont = new Font(parentComp.getDisplay(), "Monospace", 9,
SWT.NORMAL);
GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
gd.heightHint = canvasHeight;
gd.widthHint = canvasWidth;
setLayoutData(gd);
addPaintListener(new PaintListener() {
@Override
public void paintControl(PaintEvent e) {
drawCanvas(e.gc);
}
});
addDisposeListener(new DisposeListener() {
@Override
public void widgetDisposed(DisposeEvent e) {
if ((canvasFont != null) && (!canvasFont.isDisposed())) {
canvasFont.dispose();
}
}
});
addMouseMoveListener(new MouseMoveListener() {
@Override
public void mouseMove(MouseEvent e) {
handleMouseMoveEvent(e);
}
});
}
/**
* Initialize drawing settings.
*
* @param gc
* The Graphics Context
*/
private void init(GC gc) {
if (!this.initialized) {
initialized = true;
gc.setAntialias(SWT.ON);
gc.setFont(canvasFont);
fontHeight = (gc.getFontMetrics().getHeight());
fontAveWidth = gc.getFontMetrics().getAverageCharWidth();
}
}
/**
* Draw on the canvas.
*
* @param gc
* The Graphics Context
*/
protected void drawCanvas(GC gc) {
init(gc);
gc.setBackground(parentComp.getDisplay()
.getSystemColor(SWT.COLOR_WHITE));
gc.fillRectangle(0, 0, canvasWidth, canvasHeight + 2);
RGB color = RGBColors.getRGBColor("gray85");
gc.setBackground(new Color(parentComp.getDisplay(), color.red,
color.green, color.blue));
Rectangle graphArea = new Rectangle(GRAPH_BORDER, GRAPH_BORDER,
GRAPH_WIDTH, GRAPH_HEIGHT);
gc.fillRectangle(graphArea);
gc.setBackground(parentComp.getDisplay()
.getSystemColor(SWT.COLOR_WHITE));
gc.setForeground(parentComp.getDisplay()
.getSystemColor(SWT.COLOR_BLACK));
gc.drawPolygon(borderTop);
gc.drawPolygon(borderRight);
// Draw the graph title
int titleLength = graphTitle.length() * fontAveWidth;
int title2Length = graphTitle2.length() * fontAveWidth;
int titleX = center - titleLength / 2;
int titleY = GRAPH_BORDER / 2 - fontHeight;
gc.drawText(graphTitle, titleX, titleY);
titleX = center - title2Length / 2;
titleY = GRAPH_BORDER / 2 + 5;
gc.drawText(graphTitle2, titleX, titleY);
drawXAxis(gc);
drawYAxis(gc);
drawData(gc);
drawYAxisLabel(gc);
}
/**
* Draw the X axis.
*
* @param gc
* The Graphics Context
*/
private void drawXAxis(GC gc) {
// Draw the xAxis line
gc.drawPolyline(xAxis);
// List of locations for the date labels
List<Integer> dateLocationList = new ArrayList<Integer>();
dateLocationList.add(GRAPH_BORDER); // first one
List<Date> dateList = new ArrayList<Date>();
SimpleDateFormat sdf = axisFormat.get();
TimeRange tr = graphData.getTimeRange();
dateList.add(tr.getStart()); // Add the first date
long milliRange = tr.getDuration();
long numHours = milliRange / TimeUtil.MILLIS_PER_HOUR;
millisPerPixelX = milliRange / GRAPH_WIDTH;
boolean showLine = true;
int height = 15;
long startMillis = tr.getStart().getTime();
StringBuilder buffer = new StringBuilder();
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
for (long i = tr.getStart().getTime(); i <= tr.getEnd().getTime(); i += TimeUtil.MILLIS_PER_HOUR) {
cal.setTimeInMillis(i);
int[] tickArray = {
(int) (GRAPH_BORDER + (i - startMillis) / millisPerPixelX),
GRAPH_BORDER + GRAPH_HEIGHT,
(int) (GRAPH_BORDER + (i - startMillis) / millisPerPixelX),
GRAPH_BORDER + GRAPH_HEIGHT + height };
if (cal.get(Calendar.HOUR_OF_DAY) == 0) {
gc.setLineWidth(3);
} else {
gc.setLineWidth(1);
}
int hour = cal.get(Calendar.HOUR_OF_DAY);
if ((numHours / 24 <= 7) || (hour % 6) == 0) {
gc.drawPolyline(tickArray);
if (callback.drawGridLines()) {
boolean draw = false;
if (numHours <= 6) {
draw = true;
} else if (numHours == 12) {
if (hour % 2 == 0) {
draw = true;
}
}
if (draw) {
int[] gridLine = new int[] {
(int) (GRAPH_BORDER + (i - startMillis)
/ millisPerPixelX),
GRAPH_BORDER + GRAPH_HEIGHT,
(int) (GRAPH_BORDER + (i - startMillis)
/ millisPerPixelX), GRAPH_BORDER };
gc.drawPolyline(gridLine);
}
}
}
if (hour == 0) {
dateLocationList.add((int) (GRAPH_BORDER + (i - startMillis)
/ millisPerPixelX));
if (!dateList.contains(cal.getTime())) {
dateList.add(cal.getTime());
}
}
buffer.setLength(0); // Clear the buffer
int y = GRAPH_BORDER + GRAPH_HEIGHT + 20;
int hr = cal.get(Calendar.HOUR_OF_DAY);
if ((numHours <= 24) || (hour % 6 == 0 && numHours <= 168)) {
if (numHours <= 3) {
for (int j = 0; j < 60; j += 15) {
buffer.setLength(0);
int x = (int) (GRAPH_BORDER + (i - startMillis + j
* TimeUtil.MILLIS_PER_MINUTE)
/ millisPerPixelX);
if (numHours == 1
|| (numHours == 3 && (j == 0 || j == 30))) {
String hrStr = (hr < 10) ? ZERO.concat(String
.valueOf(hr)) : String.valueOf(hr);
if (j == 0) {
buffer.append(hrStr).append(COLON)
.append(MINUTE_00);
} else {
buffer.append(hrStr).append(COLON).append(j);
}
int adjustment = buffer.length() * fontAveWidth / 2
- 1;
gc.drawText(buffer.toString(), x - adjustment, y);
if (callback.drawGridLines()) {
int[] gridLineArray = {
(int) (GRAPH_BORDER + (i - startMillis + TimeUtil.MILLIS_PER_MINUTE
* j)
/ millisPerPixelX),
GRAPH_BORDER + GRAPH_HEIGHT,
(int) (GRAPH_BORDER + (i - startMillis + TimeUtil.MILLIS_PER_MINUTE
* j)
/ millisPerPixelX),
GRAPH_BORDER };
gc.drawPolyline(gridLineArray);
}
}
int[] minorTickArray = {
(int) (GRAPH_BORDER + (i - startMillis + TimeUtil.MILLIS_PER_MINUTE
* j)
/ millisPerPixelX),
GRAPH_BORDER + GRAPH_HEIGHT,
(int) (GRAPH_BORDER + (i - startMillis + TimeUtil.MILLIS_PER_MINUTE
* j)
/ millisPerPixelX),
GRAPH_BORDER + GRAPH_HEIGHT + height - 5 };
gc.drawPolyline(minorTickArray);
}
} else {
int x = (int) (GRAPH_BORDER + (i - startMillis)
/ millisPerPixelX);
String hrStr = (hr < 10) ? ZERO.concat(String.valueOf(hr))
: String.valueOf(hr);
buffer.append(hrStr);
int adjustment = buffer.length() * fontAveWidth / 2 - 1;
gc.drawText(buffer.toString(), x - adjustment, y);
if (callback.drawGridLines()) {
if ((numHours == 24 && hr % 6 == 0)
|| (numHours == 168 && hr == 0)) {
int[] gridLineArray = {
(int) (GRAPH_BORDER + (i - startMillis)
/ millisPerPixelX),
GRAPH_BORDER + GRAPH_HEIGHT,
(int) (GRAPH_BORDER + (i - startMillis)
/ millisPerPixelX), GRAPH_BORDER };
gc.setLineWidth(1);
gc.drawPolyline(gridLineArray);
gc.setLineWidth(3);
}
}
}
} else if (numHours == 336 && hour == 0) {
int x = (int) (GRAPH_BORDER + (i - startMillis)
/ millisPerPixelX);
buffer.append(cal.get(Calendar.MONTH) + 1);
buffer.append("/");
buffer.append(cal.get(Calendar.DAY_OF_MONTH));
int adjustment = buffer.length() * fontAveWidth / 2 - 1;
gc.drawText(buffer.toString(), x - adjustment, y);
if (callback.drawGridLines()) {
// show every other line
if (showLine) {
int[] gridLineArray = {
(int) (GRAPH_BORDER + (i - startMillis)
/ millisPerPixelX),
GRAPH_BORDER + GRAPH_HEIGHT,
(int) (GRAPH_BORDER + (i - startMillis)
/ millisPerPixelX), GRAPH_BORDER };
gc.setLineWidth(1);
gc.drawPolyline(gridLineArray);
gc.setLineWidth(3);
}
showLine = !showLine;
}
} else if (numHours == 720) {
if (cal.get(Calendar.DAY_OF_MONTH) % 2 == 0 && hour == 0) {
int x = (int) (GRAPH_BORDER + (i - startMillis)
/ millisPerPixelX);
buffer.append(cal.get(Calendar.MONTH) + 1);
buffer.append("/");
buffer.append(cal.get(Calendar.DAY_OF_MONTH));
int adjustment = buffer.length() * fontAveWidth / 2 - 1;
gc.drawText(buffer.toString(), x - adjustment, y);
if (callback.drawGridLines()) {
if (showLine) {
int[] gridLineArray = {
(int) (GRAPH_BORDER + (i - startMillis)
/ millisPerPixelX),
GRAPH_BORDER + GRAPH_HEIGHT,
(int) (GRAPH_BORDER + (i - startMillis)
/ millisPerPixelX), GRAPH_BORDER };
gc.setLineWidth(1);
gc.drawPolyline(gridLineArray);
gc.setLineWidth(3);
}
showLine = !showLine;
}
}
}
}
dateLocationList.add(GRAPH_BORDER + GRAPH_WIDTH); // last one
int idx = 0;
if (dateLocationList.get(0) == dateLocationList.get(1)) {
dateLocationList.remove(0);
}
// Lower Date label
if (numHours < 336) {
for (Date date : dateList) {
// only one date
String dateStr = sdf.format(date);
int loc1 = dateLocationList.get(idx);
int loc2 = dateLocationList.get(++idx);
if (loc2 - loc1 > dateStr.length() * fontAveWidth) {
int loc = ((loc2 + loc1) / 2)
- (((dateStr.length() * fontAveWidth) / 2) + 1);
if (loc < GRAPH_BORDER + GRAPH_WIDTH) {
gc.drawText(dateStr, loc, GRAPH_BORDER + GRAPH_HEIGHT
+ 40);
}
}
}
}
}
/**
* Draw the Y axis.
*
* @param gc
* The Graphics Context
*/
private void drawYAxis(GC gc) {
DecimalFormat format = numFormat.get();
gc.setLineWidth(1);
gc.drawPolyline(yAxis);
double minVal = graphData.getMinValue();
double maxVal = graphData.getMaxValue();
int numberTicks = 4;
double inc = 5;
double minScaleVal = 0;
double maxScaleVal = 10;
if (minVal != minValue || maxVal != maxValue) {
scalingManager = new ScaleManager(minVal, maxVal);
numberTicks = scalingManager.getMajorTickCount();
inc = scalingManager.getMajorTickIncrement();
minScaleVal = scalingManager.getMinScaleValue();
maxScaleVal = scalingManager.getMaxScaleValue();
}
double yVal = minScaleVal;
// Draw the axis tick marks
for (int i = 0; i < numberTicks; i++) {
int yPix = y2pixel(minScaleVal, maxScaleVal, yVal);
int[] tick = { GRAPH_BORDER, yPix, GRAPH_BORDER - 10, yPix };
gc.drawPolyline(tick);
String label = format.format(yVal);
int labelX = GRAPH_BORDER - (label.length() * fontAveWidth) - 20;
int labelY = yPix - (fontHeight / 2);
gc.drawText(label, labelX, labelY);
yVal += inc;
// Draw gridline if needed
if (callback.drawGridLines()) {
int[] gridLine = new int[] { GRAPH_BORDER, yPix,
GRAPH_BORDER + GRAPH_WIDTH, yPix };
gc.drawPolyline(gridLine);
}
}
}
/**
* Draw the YAxis label.
*
* @param gc
* The Graphics Context
*/
private void drawYAxisLabel(GC gc) {
String unit = this.graphData.getDisplayUnit();
StringBuilder yAxisLabel = new StringBuilder(graphTitle);
if (unit != null && !unit.equalsIgnoreCase(COUNT) && unit.length() > 0) {
yAxisLabel.append(" (").append(unit).append(")");
}
gc.setForeground(getDisplay().getSystemColor(SWT.COLOR_BLACK));
// Rotate the Y header text.
int labelInPixels = gc.getFontMetrics().getAverageCharWidth()
* yAxisLabel.length();
int yCoord = (canvasHeight / 2) + (labelInPixels / 2);
Transform t = new Transform(gc.getDevice());
t.translate(2, yCoord); // new origin
t.rotate(-90f);
gc.setTransform(t);
gc.drawString(yAxisLabel.toString(), 0, 0, true);
t.dispose();
}
/**
* Draw the data on the canvas.
*
* @param gc
* The Graphics Context
*/
private void drawData(GC gc) {
double maxScaleVal = scalingManager.getMaxScaleValue();
double minScaleVal = scalingManager.getMinScaleValue();
Map<String, RGB> groupSettings = callback.getGroupSettings();
for (String key : graphData.getKeysWithData()) {
if (groupSettings.containsKey(key)) {
Color color = new Color(getDisplay(), groupSettings.get(key));
gc.setForeground(color);
gc.setBackground(color);
if (groupSettings.containsKey(key)) {
List<Integer> pointList = new ArrayList<Integer>();
if (!rectangleMap.containsKey(key)) {
rectangleMap.put(key, new ArrayList<Rectangle>());
}
rectangleMap.get(key).clear();
StatsData data = graphData.getStatsData(key);
if (data != null) {
// Loop over all group members
List<DataPoint> dataMap = data.getData(key);
long startMillis = graphData.getTimeRange().getStart()
.getTime();
int lastXpix = -999;
int lastYpix = -999;
for (DataPoint point : dataMap) {
long x = point.getX();
double y = point.getY();
int yPix = y2pixel(minScaleVal, maxScaleVal, y);
int xPix = (int) ((x - startMillis)
/ millisPerPixelX + GRAPH_BORDER);
if (xPix > GRAPH_BORDER + GRAPH_WIDTH) {
break;
}
pointList.add(xPix);
pointList.add(yPix);
Rectangle rect = new Rectangle(xPix - 3, yPix - 3,
6, 6);
rectangleMap.get(key).add(rect);
if (lastXpix != -999) {
if (callback.drawDataLines()) {
gc.drawLine(lastXpix, lastYpix, xPix, yPix);
}
}
lastXpix = xPix;
lastYpix = yPix;
}
for (int i = 0; i < rectangleMap.get(key).size(); i++) {
Rectangle rect = rectangleMap.get(key).get(i);
gc.setForeground(color);
gc.fillRectangle(rect);
gc.setForeground(getDisplay().getSystemColor(
SWT.COLOR_BLACK));
gc.drawRectangle(rect);
}
}
}
}
}
}
/**
* Y Value to pixel conversion.
*
* @param yMin
* The smallest y value
* @param yMax
* The largest y value
* @param y
* The y value
* @return the pixel corresponding to the y value
*/
private int y2pixel(double yMin, double yMax, double y) {
double yDiff = yMax - yMin;
double yValue = (GRAPH_HEIGHT / yDiff) * (y - yMin);
return (int) (GRAPH_HEIGHT - Math.round(yValue) + GRAPH_BORDER);
}
/**
* Mouse move event hanler.
*
* @param e
* MouseEvent object
*/
private void handleMouseMoveEvent(MouseEvent e) {
int x = e.x;
int y = e.y;
final String colon = ": ";
StringBuilder sb = new StringBuilder();
GraphData graphData = callback.getGraphData();
if (graphData == null) {
return;
}
for (String key : graphData.getKeys()) {
int idx = 0;
if (rectangleMap.containsKey(key)) {
for (Rectangle rect : rectangleMap.get(key)) {
if (callback.getGroupSettings().containsKey(key)) {
// if true then data are on the graph
if (rect.contains(x, y)) {
if (sb.length() > 0) {
sb.append("\n");
}
sb.append(key).append(colon);
DataPoint point = graphData.getStatsData(key)
.getData(key).get(idx);
sb.append(point.getSampleText());
}
}
idx++;
}
}
}
Rectangle bounds = this.getBounds();
Point pos = getShell().toDisplay(bounds.x + x + 15, bounds.y + y + 15);
if (sb.length() > 0) {
showTooltip(getShell(), pos.x, pos.y, sb.toString());
} else {
if (tooltip != null && !tooltip.isDisposed()) {
this.tooltip.dispose();
}
}
}
/**
* Show the "tooltip" mouseover.
*
* @param parent
* @param x
* @param y
* @return
*/
private Shell showTooltip(Shell parent, int x, int y, String text) {
if (tooltip != null && !tooltip.isDisposed()) {
tooltip.dispose();
}
tooltip = new Shell(parent, SWT.TOOL | SWT.ON_TOP);
tooltip.setLayout(new GridLayout());
tooltip.setBackground(tooltip.getDisplay().getSystemColor(
SWT.COLOR_INFO_BACKGROUND));
tooltip.setBackgroundMode(SWT.INHERIT_FORCE);
Label lbContent = new Label(tooltip, SWT.NONE);
lbContent.setText(text);
Point lbContentSize = lbContent.computeSize(SWT.DEFAULT, SWT.DEFAULT);
int width = lbContentSize.x + 10;
int height = lbContentSize.y + 10;
tooltip.setBounds(x, y, width, height);
tooltip.setVisible(true);
return tooltip;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.swt.widgets.Widget#dispose()
*/
@Override
public void dispose() {
if (this.canvasFont != null && !canvasFont.isDisposed()) {
this.canvasFont.dispose();
}
super.dispose();
}
/**
* Set the graph data.
*
* @param graphData
* The GraphData object
*/
public void setGraphData(GraphData graphData) {
this.graphData = graphData;
}
}

View file

@ -0,0 +1,583 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.stats.ui;
import java.util.List;
import java.util.Map;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.ImageLoader;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Layout;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import com.raytheon.uf.common.stats.GraphDataRequest;
import com.raytheon.uf.common.stats.GraphDataResponse;
import com.raytheon.uf.common.stats.data.GraphData;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.common.time.TimeRange;
import com.raytheon.uf.viz.core.exception.VizException;
import com.raytheon.uf.viz.core.requests.ThriftClient;
import com.raytheon.viz.ui.dialogs.CaveSWTDialog;
import com.raytheon.viz.ui.widgets.duallist.ButtonImages;
import com.raytheon.viz.ui.widgets.duallist.ButtonImages.ButtonImage;
/**
* The Graph Data Structure.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Oct 3, 2012 728 mpduff Initial creation
*
* </pre>
*
* @author mpduff
* @version 1.0
*/
public class StatsGraphDlg extends CaveSWTDialog implements IStatsDisplay,
IStatsGroup {
private final IUFStatusHandler statusHandler = UFStatus
.getHandler(StatsGraphDlg.class);
/** Data Request parameters */
public enum REQUEST_PARAMETER {
FullLeft, HalfLeft, HalfRight, FullRight
}
/** Callback */
private final IStatsControl callback;
/** The graph canvas */
private StatsDisplayCanvas displayCanvas;
/** The Graph data object */
private GraphData graphData;
/** The graph title */
private String graphTitle;
/** Menu bar */
private Menu menuBar;
/** Save Menu Item */
private MenuItem saveMI;
/** Exit Menu item */
private MenuItem exitMI;
/** Show control dialog menu item */
private MenuItem controlDisplayMI;
/** Show grid lines menu item */
private MenuItem gridLinesMI;
/** Draw grid lines flag */
private boolean drawGridLines = true;
/** Draw data lines flag */
private boolean drawDataLines = true;
/** Draw data items menu item */
private MenuItem dataLinesMI;
/** Grouping composite */
private GroupingComp groupComp;
/** Group Settings Map */
private Map<String, RGB> groupSettingsMap;
/** List of groups */
private List<String> groupList;
/** Category of stats data */
private String category;
/** Event type id of data */
private String typeID;
/** Data type (field) of the data */
private String dataTypeID;
/**
* Constructor.
*
* @param parent
* Parent Shell
* @param callback
* Callback
*/
public StatsGraphDlg(Shell parent, IStatsControl callback) {
super(parent, SWT.DIALOG_TRIM | SWT.MIN, CAVE.DO_NOT_BLOCK
| CAVE.INDEPENDENT_SHELL);
this.callback = callback;
}
/**
* {@inheritDoc}
*/
@Override
protected Layout constructShellLayout() {
GridLayout mainLayout = new GridLayout(1, true);
mainLayout.verticalSpacing = 0;
mainLayout.marginHeight = 0;
mainLayout.marginWidth = 0;
return mainLayout;
}
/**
* {@inheritDoc}
*/
@Override
protected Object constructShellLayoutData() {
return new GridData(SWT.FILL, SWT.FILL, true, true);
}
/**
* {@inheritDoc}
*/
@Override
protected void initializeComponents(Shell shell) {
createMenus();
GridData gd = new GridData(SWT.FILL, SWT.FILL, false, true);
GridLayout gl = new GridLayout(2, false);
Composite mainComp = new Composite(shell, SWT.NONE);
mainComp.setLayout(gl);
mainComp.setLayoutData(gd);
gd = new GridData(SWT.CENTER, SWT.DEFAULT, false, true);
gl = new GridLayout(1, false);
Composite leftComp = new Composite(mainComp, SWT.NONE);
leftComp.setLayout(gl);
leftComp.setLayoutData(gd);
createCanvas(leftComp);
gd = new GridData(SWT.FILL, SWT.FILL, false, true);
gl = new GridLayout(1, false);
groupComp = new GroupingComp(mainComp, SWT.BORDER, graphData, this);
groupComp.setLayout(gl);
groupComp.setLayoutData(gd);
gd = new GridData(SWT.CENTER, SWT.DEFAULT, false, true);
gl = new GridLayout(4, false);
Composite btnComp = new Composite(leftComp, SWT.NONE);
btnComp.setLayout(gl);
btnComp.setLayoutData(gd);
ButtonImages btnImg = new ButtonImages(leftComp);
final int buttonWidth = 45;
GridData btnData = new GridData(buttonWidth, SWT.DEFAULT);
Button fullLeftBtn = new Button(btnComp, SWT.PUSH);
fullLeftBtn.setImage(btnImg.getImage(ButtonImage.RemoveAll));
fullLeftBtn.setLayoutData(btnData);
fullLeftBtn
.setToolTipText("Moves the display a full time period to the left");
fullLeftBtn.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
requestRedraw(REQUEST_PARAMETER.FullLeft);
}
});
btnData = new GridData(buttonWidth, SWT.DEFAULT);
Button halfLeftBtn = new Button(btnComp, SWT.PUSH);
halfLeftBtn.setImage(btnImg.getImage(ButtonImage.Remove));
halfLeftBtn.setLayoutData(btnData);
halfLeftBtn
.setToolTipText("Moves the display half a time period to the left");
halfLeftBtn.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
requestRedraw(REQUEST_PARAMETER.HalfLeft);
}
});
btnData = new GridData(buttonWidth, SWT.DEFAULT);
Button halfRightBtn = new Button(btnComp, SWT.PUSH);
halfRightBtn.setImage(btnImg.getImage(ButtonImage.Add));
halfRightBtn.setLayoutData(btnData);
halfRightBtn
.setToolTipText("Moves the display half a time period to the right");
halfRightBtn.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
requestRedraw(REQUEST_PARAMETER.HalfRight);
}
});
btnData = new GridData(buttonWidth, SWT.DEFAULT);
Button fullRightBtn = new Button(btnComp, SWT.PUSH);
fullRightBtn.setImage(btnImg.getImage(ButtonImage.AddAll));
fullRightBtn.setLayoutData(btnData);
fullRightBtn
.setToolTipText("Moves the display a full time period to the right");
fullRightBtn.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
requestRedraw(REQUEST_PARAMETER.FullRight);
}
});
shell.setMenuBar(menuBar);
}
/**
* Create the menus
*/
private void createMenus() {
menuBar = new Menu(shell, SWT.BAR);
MenuItem fileMenuItem = new MenuItem(menuBar, SWT.CASCADE);
fileMenuItem.setText("File");
Menu fileMenu = new Menu(menuBar);
fileMenuItem.setMenu(fileMenu);
saveMI = new MenuItem(fileMenu, SWT.NONE);
saveMI.setText("&Save\tCtrl+S");
saveMI.setAccelerator(SWT.CTRL + 'S');
saveMI.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
saveGraph();
}
});
exitMI = new MenuItem(fileMenu, SWT.NONE);
exitMI.setText("&Quit\tCtrl+Q");
exitMI.setAccelerator(SWT.CTRL + 'Q');
exitMI.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
shell.dispose();
}
});
MenuItem graphMenuItem = new MenuItem(menuBar, SWT.CASCADE);
graphMenuItem.setText("Graph");
Menu graphMenu = new Menu(menuBar);
graphMenuItem.setMenu(graphMenu);
controlDisplayMI = new MenuItem(graphMenu, SWT.NONE);
controlDisplayMI.setText("Show &Display Control\tCtrl+D");
controlDisplayMI.setAccelerator(SWT.CTRL + 'D');
controlDisplayMI.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
callback.showControl();
}
});
gridLinesMI = new MenuItem(graphMenu, SWT.CHECK);
gridLinesMI.setText("Display Grid Lines");
gridLinesMI.setSelection(true);
gridLinesMI.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
drawGridLines = gridLinesMI.getSelection();
displayCanvas.redraw();
}
});
dataLinesMI = new MenuItem(graphMenu, SWT.CHECK);
dataLinesMI.setText("Display Data Lines");
dataLinesMI.setSelection(true);
dataLinesMI.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
drawDataLines = dataLinesMI.getSelection();
displayCanvas.redraw();
}
});
}
/**
* Create the canvas.
*
* @param comp
* Composite holding the canvas
*/
private void createCanvas(Composite comp) {
Composite canvasComp = new Composite(comp, SWT.BORDER);
GridLayout gl = new GridLayout(1, false);
gl.verticalSpacing = 0;
gl.horizontalSpacing = 0;
gl.marginHeight = 0;
gl.marginWidth = 0;
GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
canvasComp.setLayoutData(gd);
canvasComp.setLayout(gl);
displayCanvas = new StatsDisplayCanvas(canvasComp, this, graphTitle);
}
/**
* Set the GraphData object.
*
* @param graphData
*/
public void setGraphData(GraphData graphData) {
this.graphData = graphData;
}
/**
* {@inheritDoc}
*/
@Override
public GraphData getGraphData() {
return this.graphData;
}
/**
* Set the title.
*
* @param title
*/
public void setTitle(String title) {
setText(title);
}
/**
* Set the graph title.
*
* @param graphTitle
*/
public void setGraphTitle(String graphTitle) {
this.graphTitle = graphTitle;
}
/**
* Open a file dialog for saving the canvas.
*/
private void saveGraph() {
FileDialog dialog = new FileDialog(shell, SWT.SAVE);
String filename = dialog.open();
if (filename == null) {
return;
}
saveCanvas(filename);
}
/**
* Captures the canvas and saves the result into a file in a format
* determined by the filename extension .
*
* @param control
* The control to save
* @param fileName
* The name of the image to be saved
*/
public void saveCanvas(String filename) {
StringBuilder sb = new StringBuilder();
Display display = displayCanvas.getDisplay();
Image image = new Image(display, displayCanvas.getBounds().width,
displayCanvas.getBounds().height);
GC gc = new GC(image);
displayCanvas.drawCanvas(gc);
/* Default to PNG */
int style = SWT.IMAGE_PNG;
if ((filename.endsWith(".jpg") == true) || filename.endsWith("jpeg")) {
style = SWT.IMAGE_JPEG;
} else if (filename.endsWith(".bmp") == true) {
style = SWT.IMAGE_BMP;
} else {
filename += ".png";
}
ImageLoader loader = new ImageLoader();
loader.data = new ImageData[] { image.getImageData() };
loader.save(filename, style);
sb.setLength(0);
image.dispose();
gc.dispose();
}
/**
* Request the graph be redrawn with a new time range.
*
* @param parameter
* The amount of time to move
*/
private void requestRedraw(REQUEST_PARAMETER parameter) {
TimeRange tr = this.graphData.getTimeRange();
long dur = tr.getDuration();
long newStart;
long newEnd;
long start;
long end;
switch (parameter) {
case FullLeft:
start = tr.getStart().getTime();
newStart = start - dur;
newEnd = newStart + dur;
break;
case HalfLeft:
start = tr.getStart().getTime();
newStart = start - dur / 2;
newEnd = newStart + dur;
break;
case HalfRight:
start = tr.getStart().getTime();
newStart = start + dur / 2;
newEnd = newStart + dur;
break;
case FullRight:
end = tr.getEnd().getTime();
newStart = end;
newEnd = newStart + dur;
break;
default:
return;
}
GraphDataRequest request = new GraphDataRequest();
request.setGrouping(this.groupList);
request.setCategory(this.category);
request.setEventType(typeID);
request.setDataType(dataTypeID);
request.setField(dataTypeID);
TimeRange newTimeRange = new TimeRange(newStart, newEnd);
request.setTimeRange(newTimeRange);
request.setTimeStep(5);
try {
GraphDataResponse response = (GraphDataResponse) ThriftClient
.sendRequest(request);
GraphData localGraphData = response.getGraphData();
if (localGraphData == null
|| localGraphData.getStatsDataMap() == null
|| localGraphData.getStatsDataMap().size() == 0) {
MessageBox messageDialog = new MessageBox(getShell(),
SWT.ICON_INFORMATION);
messageDialog.setText("No Data Available");
messageDialog
.setMessage("No data available for the time range selected.");
messageDialog.open();
return;
}
this.graphData = localGraphData;
this.displayCanvas.setGraphData(graphData);
this.displayCanvas.redraw();
} catch (VizException e) {
this.statusHandler.handle(Priority.ERROR, "Error Requesting Data",
e);
}
}
/**
* {@inheritDoc}
*/
@Override
public boolean drawGridLines() {
return this.drawGridLines;
}
/**
* {@inheritDoc}
*/
@Override
public boolean drawDataLines() {
return this.drawDataLines;
}
/**
* {@inheritDoc}
*/
@Override
public void setGroupData(Map<String, RGB> groupSettingsMap) {
this.groupSettingsMap = groupSettingsMap;
displayCanvas.redraw();
}
/**
* {@inheritDoc}
*/
@Override
public Map<String, RGB> getGroupSettings() {
return this.groupSettingsMap;
}
/**
* Set the groups.
*
* @param groupList
* List of groups
*/
public void setGrouping(List<String> groupList) {
this.groupList = groupList;
}
/**
* Set the category.
*
* @param category
*/
public void setCategory(String category) {
this.category = category;
}
/**
* Set the event type.
*
* @param typeID
*/
public void setEventType(String typeID) {
this.typeID = typeID;
}
/**
* Set the data type id.
*
* @param dataTypeID
*/
public void setDataType(String dataTypeID) {
this.dataTypeID = dataTypeID;
}
}

View file

@ -0,0 +1,202 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.stats.utils;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import com.google.common.annotations.VisibleForTesting;
import com.raytheon.uf.common.stats.data.StatsEventData;
import com.raytheon.uf.common.stats.xml.StatisticsAggregate;
import com.raytheon.uf.common.stats.xml.StatisticsConfig;
import com.raytheon.uf.common.stats.xml.StatisticsEvent;
import com.raytheon.uf.common.stats.xml.StatisticsGroup;
/**
* Utility class for the Statistics UI.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Nov 8, 2012 728 mpduff Initial creation
*
* </pre>
*
* @author mpduff
* @version 1.0
*/
public class StatsUiUtils {
/** List of statistics configuration objects */
private List<StatisticsConfig> configList;
/**
* Map of category -> Map of event type -> event type object
*/
private final Map<String, Map<String, StatsEventData>> eventMap = new HashMap<String, Map<String, StatsEventData>>();
/**
* Constructor
*/
public StatsUiUtils() {
}
/**
* Generate the configuration objects.
*
* @param configList
*/
public void generateData(List<StatisticsConfig> configList) {
this.configList = configList;
for (StatisticsConfig config: configList) {
processConfig(config);
}
}
/**
* Process a configuration object.
*
* @param config configuration object
*/
@VisibleForTesting
void processConfig(StatisticsConfig config) {
for (StatisticsEvent event: config.getEvents()) {
processEvent(event);
}
}
/**
* Process a configuration event object
*
* @param event event config object
*/
@VisibleForTesting
void processEvent(StatisticsEvent event) {
if (!eventMap.containsKey(event.getCategory())) {
eventMap.put(event.getCategory(), new HashMap<String, StatsEventData>());
}
StatsEventData eventData = new StatsEventData();
eventData.setDisplayName(event.getDisplayName());
eventData.setType(event.getType());
List<StatisticsAggregate> attributeList = event.getAggregateList();
for (StatisticsAggregate attribute: attributeList) {
eventData.addAttribute(attribute.getDisplayName());
}
for (StatisticsGroup group: event.getGroupList()) {
eventData.addGroup(group.getDisplayName(), group.getName());
}
eventMap.get(event.getCategory()).put(eventData.getType(), eventData);
}
/**
* Get the event types for this category.
*
* @param category The category
* @return map of event display names -> event id
*/
@VisibleForTesting
public Map<String, String> getEventTypes(String category) {
Map<String, StatsEventData> eventsMap = eventMap.get(category);
Map<String, String> typeMap = new TreeMap<String, String>();
for (String key: eventsMap.keySet()) {
StatsEventData data = eventsMap.get(key);
typeMap.put(data.getDisplayName(), data.getType());
}
return typeMap;
}
/**
* Get the attributes/data types for the given category and event.
*
* @param category The category
* @param type The event type
* @return Map of attribute display name -> field
*/
@VisibleForTesting
public Map<String, String> getEventAttributes(String category, String type) {
Map<String, String> attMap = new TreeMap<String, String>();
for (StatisticsConfig config: configList) {
for (StatisticsEvent event: config.getEvents()) {
if (event.getCategory().equals(category) && event.getDisplayName().equals(type)) {
for (StatisticsAggregate agg: event.getAggregateList()) {
attMap.put(agg.getDisplayName(), agg.getField());
}
}
}
}
return attMap;
}
/**
* @return the eventMap
*/
@VisibleForTesting
public Map<String, Map<String, StatsEventData>> getEventMap() {
return eventMap;
}
/**
* Get the StatsEventData object for the given category and event type.
*
* @param category category
* @param type event type
* @return StatsEventData object
*/
@VisibleForTesting
public StatsEventData getEventData(String category, String type) {
return eventMap.get(category).get(type);
}
/**
* Get the aggregate config file for the given category, event type, and aggregate display name
*
* @param category category
* @param typeID event type id
* @param attributeDisplayName attribut display name
* @return StatisticsAggregate object
*/
public StatisticsAggregate getAggregateConfig(String category,
String typeID, String attributeDisplayName) {
for (StatisticsConfig config : configList) {
for (StatisticsEvent event: config.getEvents()) {
if (event.getCategory().equals(category) && event.getType().equals(typeID)) {
for (StatisticsAggregate agg: event.getAggregateList()) {
if (agg.getDisplayName().equals(attributeDisplayName)) {
return agg;
}
}
}
}
}
return null;
}
}

View file

@ -78,6 +78,30 @@
name="afterNewGroup"
visible="true">
</separator>
<separator
name="group1"
visible="true">
</separator>
<separator
name="group2"
visible="true">
</separator>
<separator
name="group3"
visible="true">
</separator>
<separator
name="group4"
visible="true">
</separator>
<separator
name="group5"
visible="true">
</separator>
<separator
name="importExportSeparator"
visible="true">
</separator>
<menu
id="import"
label="Import">

View file

@ -0,0 +1,226 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.viz.ui.dialogs;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.DateTime;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Spinner;
/**
* Awips Calendar Date Selection Dialog.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jan 9, 2012 mpduff Initial creation
*
* </pre>
*
* @author mpduff
* @version 1.0
*/
public class AwipsCalendar extends CaveSWTDialogBase {
/** The date selection calendar class */
private DateTime calendar;
/** The hour selection spinner class */
private Spinner hourSpinner;
/** The showHour flag */
private boolean showHour = true;
/** The showHour flag */
private Date date = null;
/**
* Constructor.
*
* @param parentShell
* @param showHour
*/
public AwipsCalendar(Shell parentShell, boolean showHour) {
super(parentShell, SWT.DIALOG_TRIM);
setText("Calendar");
this.showHour = showHour;
}
/**
* Constructor.
*
* @param parentShell
*/
public AwipsCalendar(Shell parentShell) {
super(parentShell, SWT.DIALOG_TRIM);
setText("Calendar");
}
/**
* Constructor.
*
* @param parentShell
* @param d Date to preset the calendar widget
* @param showHour true to display the hour spinner
*/
public AwipsCalendar(Shell parentShell, Date d, boolean showHour) {
super(parentShell, SWT.DIALOG_TRIM);
setText("Calendar");
this.date = d;
this.showHour = showHour;
}
/*
* (non-Javadoc)
*
* @see
* com.raytheon.viz.ui.dialogs.CaveSWTDialogBase#initializeComponents(org
* .eclipse.swt.widgets.Shell)
*/
@Override
protected void initializeComponents(Shell shell) {
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
if (date != null) {
cal.setTime(date);
}
if (showHour) {
createTopWidgets(cal.get(Calendar.HOUR_OF_DAY));
}
calendar = new DateTime(shell, SWT.CALENDAR | SWT.BORDER_SOLID);
calendar.setDate(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH));
createButtons();
}
/**
* Create the top widgets
*/
private void createTopWidgets(int hour) {
GridLayout gl = new GridLayout(2, false);
GridData gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false);
Composite top = new Composite(shell, SWT.NONE);
top.setLayout(gl);
top.setLayoutData(gd);
gd = new GridData(SWT.LEFT, SWT.DEFAULT, true, false);
Label lbl = new Label(top, SWT.NONE);
lbl.setLayoutData(gd);
lbl.setText("Select Hour (Z) and Date: ");
gd = new GridData(SWT.RIGHT, SWT.DEFAULT, true, false);
hourSpinner = new Spinner(top, SWT.BORDER | SWT.RIGHT);
hourSpinner.setLayoutData(gd);
hourSpinner.setMinimum(0);
hourSpinner.setMaximum(23);
hourSpinner.setSelection(hour);
hourSpinner.setIncrement(1);
hourSpinner.setPageIncrement(1);
}
/**
* Create the buttons
*/
private void createButtons() {
int buttonWidth = 75;
GridData btnData = new GridData(buttonWidth, SWT.DEFAULT);
GridData gd = new GridData(SWT.CENTER, SWT.DEFAULT, true, false);
GridLayout gl = new GridLayout(3, false);
Composite btnComp = new Composite(shell, SWT.NONE);
btnComp.setLayout(gl);
btnComp.setLayoutData(gd);
Button okBtn = new Button(btnComp, SWT.PUSH);
okBtn.setText("OK");
okBtn.setLayoutData(btnData);
okBtn.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
handleOk();
shell.dispose();
}
});
Button cancelBtn = new Button(btnComp, SWT.PUSH);
cancelBtn.setText("Cancel");
cancelBtn.setLayoutData(btnData);
cancelBtn.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
shell.dispose();
}
});
}
/**
* Event handler action for OK button
*/
private void handleOk() {
Calendar selectedDate = Calendar.getInstance(TimeZone
.getTimeZone("GMT"));
selectedDate.set(Calendar.YEAR, calendar.getYear());
selectedDate.set(Calendar.MONTH, calendar.getMonth());
selectedDate.set(Calendar.DAY_OF_MONTH, calendar.getDay());
if (showHour) {
selectedDate.set(Calendar.HOUR_OF_DAY,
Integer.parseInt(hourSpinner.getText()));
} else {
selectedDate.set(Calendar.HOUR_OF_DAY, 0);
}
selectedDate.set(Calendar.MINUTE, 0);
selectedDate.set(Calendar.SECOND, 0);
selectedDate.set(Calendar.MILLISECOND, 0);
this.setReturnValue(selectedDate);
}
/**
* Main
*
* @param args
*/
public static void main(String[] args) {
AwipsCalendar ac = new AwipsCalendar(new Shell());
ac.open();
}
}

View file

@ -6,10 +6,15 @@ Bundle-Version: 1.0.0.qualifier
Bundle-Vendor: RAYTHEON
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Export-Package: com.raytheon.uf.common.stats,
com.raytheon.uf.common.stats.data,
com.raytheon.uf.common.stats.util,
com.raytheon.uf.common.stats.xml
Require-Bundle: com.raytheon.uf.common.time;bundle-version="1.12.1174",
com.raytheon.uf.common.serialization;bundle-version="1.12.1174",
com.raytheon.uf.common.serialization.comm;bundle-version="1.12.1174",
javax.persistence;bundle-version="1.0.0",
com.raytheon.uf.common.dataplugin;bundle-version="1.12.1174",
com.raytheon.uf.common.event;bundle-version="1.0.0"
com.raytheon.uf.common.event;bundle-version="1.0.0",
com.google.guava;bundle-version="1.0.0",
com.raytheon.uf.common.util;bundle-version="1.12.1174",
com.raytheon.uf.common.status;bundle-version="1.12.1174"

View file

@ -57,7 +57,6 @@ import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement;
@XmlAccessorType(XmlAccessType.NONE)
@DynamicSerialize
public class AggregateRecord extends PersistableDataObject {
private static final long serialVersionUID = -4553588456131256014L;
@GeneratedValue(strategy = GenerationType.AUTO)
@ -189,4 +188,96 @@ public class AggregateRecord extends PersistableDataObject {
this.sum = sum;
}
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
long temp;
temp = Double.doubleToLongBits(count);
result = prime * result + (int) (temp ^ (temp >>> 32));
result = prime * result + ((endDate == null) ? 0 : endDate.hashCode());
result = prime * result
+ ((eventType == null) ? 0 : eventType.hashCode());
result = prime * result + ((field == null) ? 0 : field.hashCode());
result = prime * result
+ ((grouping == null) ? 0 : grouping.hashCode());
temp = Double.doubleToLongBits(max);
result = prime * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(min);
result = prime * result + (int) (temp ^ (temp >>> 32));
result = prime * result
+ ((startDate == null) ? 0 : startDate.hashCode());
temp = Double.doubleToLongBits(sum);
result = prime * result + (int) (temp ^ (temp >>> 32));
return result;
}
/* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!super.equals(obj)) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
AggregateRecord other = (AggregateRecord) obj;
if (Double.doubleToLongBits(count) != Double
.doubleToLongBits(other.count)) {
return false;
}
if (endDate == null) {
if (other.endDate != null) {
return false;
}
} else if (!endDate.equals(other.endDate)) {
return false;
}
if (eventType == null) {
if (other.eventType != null) {
return false;
}
} else if (!eventType.equals(other.eventType)) {
return false;
}
if (field == null) {
if (other.field != null) {
return false;
}
} else if (!field.equals(other.field)) {
return false;
}
if (grouping == null) {
if (other.grouping != null) {
return false;
}
} else if (!grouping.equals(other.grouping)) {
return false;
}
if (Double.doubleToLongBits(max) != Double.doubleToLongBits(other.max)) {
return false;
}
if (Double.doubleToLongBits(min) != Double.doubleToLongBits(other.min)) {
return false;
}
if (startDate == null) {
if (other.startDate != null) {
return false;
}
} else if (!startDate.equals(other.startDate)) {
return false;
}
if (Double.doubleToLongBits(sum) != Double.doubleToLongBits(other.sum)) {
return false;
}
return true;
}
}

View file

@ -0,0 +1,200 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.common.stats;
import java.util.List;
import com.raytheon.uf.common.serialization.annotations.DynamicSerialize;
import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement;
import com.raytheon.uf.common.serialization.comm.IServerRequest;
import com.raytheon.uf.common.time.TimeRange;
/**
* Request object to retrieve data for the Stats graphs
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Sep 11, 2012 728 mpduff Initial creation
*
* </pre>
*
* @author mpduff
* @version 1.0
*/
@DynamicSerialize
public class GraphDataRequest implements IServerRequest {
/** The time range */
@DynamicSerializeElement
private TimeRange timeRange;
/** Statistics Category */
@DynamicSerializeElement
private String category;
/** Statistics event type */
@DynamicSerializeElement
private String eventType;
/** Statistics field */
@DynamicSerializeElement
private String field;
/** List of groups */
@DynamicSerializeElement
private List<String> grouping;
/** Event data type/Attribute */
@DynamicSerializeElement
private String dataType;
/** Metadata request flag */
@DynamicSerializeElement
private boolean metaDataRequest = false;
/**
* Data timestep (frequency) in minutes.
*/
@DynamicSerializeElement
private int timeStep;
/**
* @return the timeRange
*/
public TimeRange getTimeRange() {
return timeRange;
}
/**
* @param timeRange
* the timeRange to set
*/
public void setTimeRange(TimeRange timeRange) {
this.timeRange = timeRange;
}
/**
* @return the eventType
*/
public String getEventType() {
return eventType;
}
/**
* @param eventType
* the eventType to set
*/
public void setEventType(String eventType) {
this.eventType = eventType;
}
/**
* @return the field
*/
public String getField() {
return field;
}
/**
* @param field
* the field to set
*/
public void setField(String field) {
this.field = field;
}
/**
* @return the grouping
*/
public List<String> getGrouping() {
return grouping;
}
/**
* @param grouping
* the grouping to set
*/
public void setGrouping(List<String> grouping) {
this.grouping = grouping;
}
/**
* @param timeStep
* the timeStep to set
*/
public void setTimeStep(int timeStep) {
this.timeStep = timeStep;
}
/**
* @return the timeStep
*/
public int getTimeStep() {
return timeStep;
}
/**
* @return the dataType
*/
public String getDataType() {
return dataType;
}
/**
* @param dataType
* the dataType to set
*/
public void setDataType(String dataType) {
this.dataType = dataType;
}
/**
* @param metaDataRequest
* the metaDataRequest to set
*/
public void setMetaDataRequest(boolean metaDataRequest) {
this.metaDataRequest = metaDataRequest;
}
/**
* @return the category
*/
public String getCategory() {
return category;
}
/**
* @param category
* the category to set
*/
public void setCategory(String category) {
this.category = category;
}
/**
* @return the metaDataRequest
*/
public boolean isMetaDataRequest() {
return metaDataRequest;
}
}

View file

@ -0,0 +1,90 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.common.stats;
import java.util.List;
import com.raytheon.uf.common.serialization.ISerializableObject;
import com.raytheon.uf.common.serialization.annotations.DynamicSerialize;
import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement;
import com.raytheon.uf.common.stats.data.GraphData;
import com.raytheon.uf.common.stats.xml.StatisticsConfig;
/**
* Response object for the GraphDataRequest.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Sep 11, 2012 728 mpduff Initial creation
*
* </pre>
*
* @author mpduff
* @version 1.0
*/
@DynamicSerialize
public class GraphDataResponse implements ISerializableObject {
@DynamicSerializeElement
private GraphData graphData;
@DynamicSerializeElement
private List<StatisticsConfig> configList;
public GraphDataResponse() {
}
/**
* @return the configList
*/
public List<StatisticsConfig> getConfigList() {
return configList;
}
/**
* @param configList
* the configList to set
*/
public void setConfigList(List<StatisticsConfig> configList) {
this.configList = configList;
}
/**
* Set the GraphData object
*
* @param graphData
*/
public void setGraphData(GraphData graphData) {
this.graphData = graphData;
}
/**
* Get the GraphData object
*
* @return
*/
public GraphData getGraphData() {
return this.graphData;
}
}

View file

@ -0,0 +1,268 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.common.stats.data;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import com.raytheon.uf.common.serialization.annotations.DynamicSerialize;
import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement;
/**
* Class holding an x,y data point and other associated information for the
* point.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Sep 7, 2012 mpduff Initial creation
*
* </pre>
*
* @author mpduff
* @version 1.0
*/
@XmlRootElement
@XmlAccessorType(XmlAccessType.NONE)
@DynamicSerialize
public class DataPoint implements Comparable<DataPoint> {
/** Date Format object */
private final ThreadLocal<SimpleDateFormat> sdf = new ThreadLocal<SimpleDateFormat>() {
@Override
protected SimpleDateFormat initialValue() {
SimpleDateFormat sTemp = new SimpleDateFormat("MM/dd/yyyy HH:mm");
sTemp.setTimeZone(TimeZone.getTimeZone("GMT"));
return sTemp;
}
};
/** Decimal Format object */
private final ThreadLocal<DecimalFormat> decFormat = new ThreadLocal<DecimalFormat>() {
@Override
protected DecimalFormat initialValue() {
DecimalFormat format = new DecimalFormat("########.#");
return format;
}
};
/**
* X value - millis
*/
@DynamicSerializeElement
private long x;
/**
* Y value
*/
@DynamicSerializeElement
protected double y = 0.0;
/**
* Text display for the sampling of this point
*/
@DynamicSerializeElement
protected String sampleText;
/** Min value */
@DynamicSerializeElement
private double min = Integer.MAX_VALUE;
/** Max value */
@DynamicSerializeElement
private double max = Integer.MIN_VALUE;
/** Count */
@DynamicSerializeElement
private double count = 0;
/** Sum */
@DynamicSerializeElement
private double sum;
/** Constructor */
public DataPoint() {
}
/**
* @return the y
*/
public double getY() {
return this.getAvg();
}
/**
* @param y
* the y to set
*/
public void setY(double y) {
this.y += y;
}
/**
* @param sampleText
* the sampleText to set
*/
public void setSampleText(String sampleText) {
this.sampleText = sampleText;
}
/**
* Get the sample text for this point object
*
* @return the sample text string
*/
public String getSampleText() {
SimpleDateFormat dateFormat = sdf.get();
DecimalFormat decimalFormat = decFormat.get();
return dateFormat.format(new Date(x)) + "Z, "
+ decimalFormat.format(getAvg());
}
/**
* @param x
* the x to set
*/
public void setX(long x) {
this.x = x;
}
/**
* @return the x
*/
public long getX() {
return x;
}
/**
* {@inheritDoc}
*/
@Override
public int compareTo(DataPoint dp) {
if (this.x == dp.x) {
return 0;
} else if (this.x < dp.x) {
return -1;
} else if (this.x > dp.x) {
return 1;
}
return 0;
}
/**
* @return the min
*/
public double getMin() {
return min;
}
/**
* Set the min value if it is less than the current min.
*
* @param min
* the min to set
*/
public void setMin(double min) {
if (this.min > min) {
this.min = min;
}
}
/**
* @return the max
*/
public double getMax() {
return max;
}
/**
* Set the max value if it is greater than the current max.
*
* @param max
* the max to set
*/
public void setMax(double max) {
if (this.max < max) {
this.max = max;
}
}
/**
* @return the count
*/
public double getCount() {
return count;
}
/**
* @param count
* the count to set
*/
public void setCount(double count) {
this.count = count;
}
/**
*
* @param count
* the count to add
*/
public void addToCount(double count) {
this.count += count;
}
/**
* @return the sum
*/
public double getSum() {
return sum;
}
/**
* @param sum
* the sum to set
*/
public void setSum(double sum) {
this.sum += sum;
}
/**
* @return the avg
*/
public double getAvg() {
if (count > 0) {
return this.sum / count;
}
return 0;
}
}

View file

@ -0,0 +1,376 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.common.stats.data;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import com.google.common.annotations.VisibleForTesting;
import com.raytheon.uf.common.serialization.annotations.DynamicSerialize;
import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement;
import com.raytheon.uf.common.stats.AggregateRecord;
import com.raytheon.uf.common.stats.StatisticsEvent;
import com.raytheon.uf.common.stats.util.UnitUtils;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.common.time.TimeRange;
import com.raytheon.uf.common.util.ReflectionException;
import com.raytheon.uf.common.util.ReflectionUtil;
/**
* Data object for the statistics graph.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Oct 3, 2012 728 mpduff Initial creation
*
* </pre>
*
* @author mpduff
* @version 1.0
*/
@DynamicSerialize
public class GraphData {
private static final IUFStatusHandler statusHandler = UFStatus
.getHandler(GraphData.class);
/** Map of milliseconds -> StatsBin object */
@DynamicSerializeElement
private final Map<Long, StatsBin> bins = new TreeMap<Long, StatsBin>();
/** List of member keys */
@DynamicSerializeElement
private List<String> keys;
/** AggregateRecord list */
@DynamicSerializeElement
private List<AggregateRecord> recordList = new ArrayList<AggregateRecord>();
/**
* key -> stats data object
*/
@DynamicSerializeElement
private Map<String, StatsData> statsDataMap = new HashMap<String, StatsData>();
/** Time range */
@DynamicSerializeElement
private TimeRange timeRange;
/** Map of group -> key */
@DynamicSerializeElement
private final Map<String, String> keySequenceMap = new LinkedHashMap<String, String>();
/** StatsLabelData object */
@DynamicSerializeElement
private StatsLabelData statsLabelData;
/** Display unit */
@DynamicSerializeElement
private String displayUnit;
/** UnitUtils object */
private UnitUtils unitUtils;
/**
* Constructor.
*/
public GraphData() {
}
/**
* @return the bins
*/
public Map<Long, StatsBin> getStatsBins() {
return bins;
}
/**
* @param recordList
* the recordList to set
*/
public void setRecordList(List<AggregateRecord> recordList) {
this.recordList = recordList;
}
/**
* @return the recordList
*/
public List<AggregateRecord> getRecordList() {
return recordList;
}
/**
* Add an AggregateRecord.
*
* @param record
*/
public void addRecord(AggregateRecord record) {
if (!recordList.contains(record)) {
recordList.add(record);
}
}
/**
* @return the statsData
*/
public StatsData getStatsData(String groupMemberName) {
return this.statsDataMap.get(groupMemberName);
}
/**
* Get a list of group memebers.
*
* @return
*/
public List<String> getGroupMembers() {
List<String> memberList = new ArrayList<String>(statsDataMap.keySet());
Collections.sort(memberList);
return memberList;
}
/**
* Get the smallest value in the data set.
*
* @return
*/
public double getMinValue() {
double min = Double.MAX_VALUE;
for (String key : statsDataMap.keySet()) {
double minVal = statsDataMap.get(key).getMinValue();
if (minVal < min) {
min = minVal;
}
}
return min;
}
/**
* Get the largest value in the data set.
*
* @return
*/
public double getMaxValue() {
double max = Double.MIN_VALUE;
for (String key : statsDataMap.keySet()) {
double maxVal = statsDataMap.get(key).getMaxValue();
if (maxVal > max) {
max = maxVal;
}
}
return max;
}
/**
* Get the time range for this object.
*
* @return
*/
public TimeRange getTimeRange() {
return this.timeRange;
}
/**
* Set the TimeRange
*
* @param timeRange
*/
public void setTimeRange(TimeRange timeRange) {
this.timeRange = timeRange;
}
/**
* Set the key sequence
*
* @param keySequence
*/
public void setKeySequence(List<String> keySequence) {
for (String key : keySequence) {
keySequenceMap.put(key, "");
}
keys = keySequence;
}
/**
* Get the key sequence.
*
* @return
*/
public List<String> getKeySequence() {
return keys;
}
/**
* Get a list of all keys.
*
* @return the keys
*/
public List<String> getKeys() {
return keys;
}
/**
* Get a list of keys that contain data.
*
* @return the keys with data
*/
public List<String> getKeysWithData() {
List<String> keysWithData = new ArrayList<String>();
for (String key : keys) {
StatsData sd = this.getStatsData(key);
if (sd != null) {
keysWithData.add(key);
}
}
return keysWithData;
}
/**
* Set the StatsLabelData object
*
* @param statsLabelData
*/
public void setStatsLabelData(StatsLabelData statsLabelData) {
this.statsLabelData = statsLabelData;
this.keys = statsLabelData.makeKeys();
}
/**
* Get the StatsLabelData
*
* @return
*/
public StatsLabelData getStatsLabelData() {
return this.statsLabelData;
}
/**
* Get the group and names map.
*
* @return
*/
public Map<String, List<String>> getGroupAndNamesMap() {
return statsLabelData.getGroupAndNamesMap();
}
/**
* Get the units from the event object
*
* @param eventId
* Event id
* @param field
* data field
*
* @return The units
*/
@VisibleForTesting
static String getUnitsFromEventObject(String eventId, String field) {
// Get the units from the event class
String units = "Count";
try {
StatisticsEvent obj = ReflectionUtil.newInstanceOfAssignableType(
StatisticsEvent.class, eventId);
units = obj.getStorageUnit(field);
} catch (ReflectionException e) {
statusHandler.handle(Priority.ERROR, "Error Instantiating "
+ eventId, e);
}
return units;
}
/**
* @return the statsDataMap
*/
public Map<String, StatsData> getStatsDataMap() {
return statsDataMap;
}
/**
* @return the keySequenceMap
*/
public Map<String, String> getKeySequenceMap() {
return keySequenceMap;
}
/**
* @return the displayUnit
*/
public String getDisplayUnit() {
return displayUnit;
}
/**
* @param displayUnit
* the displayUnit to set
*/
public void setDisplayUnit(String displayUnit) {
this.displayUnit = displayUnit;
}
/**
* @param keys
* the keys to set
*/
public void setKeys(List<String> keys) {
this.keys = keys;
}
/**
* Set the StatsData map.
*
* @param statsDataMap
*/
public void setStatsDataMap(Map<String, StatsData> statsDataMap) {
this.statsDataMap = statsDataMap;
}
/**
* @return the unitUtils
*/
public UnitUtils getUnitUtils() {
return unitUtils;
}
/**
* @param unitUtils
* the unitUtils to set
*/
public void setUnitUtils(UnitUtils unitUtils) {
this.unitUtils = unitUtils;
this.unitUtils.setConversion(this.getMaxValue());
}
}

View file

@ -0,0 +1,91 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.common.stats.data;
import java.util.ArrayList;
import java.util.List;
import com.raytheon.uf.common.serialization.annotations.DynamicSerialize;
import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement;
import com.raytheon.uf.common.stats.AggregateRecord;
/**
* A bin of Statistical data.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Sep 11, 2012 723 mpduff Initial creation
*
* </pre>
*
* @author mpduff
* @version 1.0
*/
@DynamicSerialize
public class StatsBin {
/** Millisecond value for this bin */
private long binMillis;
/** List of AggregateRecords */
@DynamicSerializeElement
private final List<AggregateRecord> data = new ArrayList<AggregateRecord>();
/** Constructor */
public StatsBin() {
}
/**
* @return the binMillis
*/
public long getBinMillis() {
return binMillis;
}
/**
* @param binMillis
* the binMillis to set
*/
public void setBinMillis(long binMillis) {
this.binMillis = binMillis;
}
/**
* Add an AggregateRecord object.
*
* @param record
*/
public void setData(AggregateRecord record) {
this.data.add(record);
}
/**
* Get the AggregateRecord objects
*
* @return
*/
public List<AggregateRecord> getData() {
return data;
}
}

View file

@ -0,0 +1,317 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.common.stats.data;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import com.raytheon.uf.common.serialization.annotations.DynamicSerialize;
import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement;
import com.raytheon.uf.common.stats.AggregateRecord;
import com.raytheon.uf.common.stats.util.UnitUtils;
import com.raytheon.uf.common.time.TimeRange;
/**
* Statistical data object holding data to be graphed.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Sep 07, 2012 728 mpduff Initial creation
*
* </pre>
*
* @author mpduff
* @version 1.0
*/
@XmlRootElement
@XmlAccessorType(XmlAccessType.NONE)
@DynamicSerialize
public class StatsData {
/** Key to this object */
@DynamicSerializeElement
private String key;
/** List of AggregateRecords */
@DynamicSerializeElement
private final List<AggregateRecord> recordList = new ArrayList<AggregateRecord>();
/**
* Frequency (timestep) of the data 5 min, hourly, daily
*/
@DynamicSerializeElement
private int dataFrequency;
/**
* Time Range of the data in this object
*/
@DynamicSerializeElement
private TimeRange timeRange = new TimeRange();
/** List of DataPoint objects */
@DynamicSerializeElement
private List<DataPoint> pointList = new ArrayList<DataPoint>();
/** Map of millis -> StatsBin objects */
@DynamicSerializeElement
private Map<Long, StatsBin> bins;
/** UnitUtils object */
private UnitUtils unitUtils;
/** Constructor */
public StatsData() {
}
/**
* Constructor
*
* @param key
* Key to the object
* @param tsMillis
* timestep in ms
* @param timeRange
* TimeRange object
* @param unitUtils
* UnitUtils object
*/
public StatsData(String key, long tsMillis, TimeRange timeRange,
UnitUtils unitUtils) {
this.key = key;
this.dataFrequency = (int) tsMillis;
this.timeRange = timeRange;
this.unitUtils = unitUtils;
}
/**
* @return the minValue
*/
public Double getMinValue() {
double minValue = Integer.MAX_VALUE;
for (DataPoint point : pointList) {
if (point.getMin() < minValue) {
minValue = point.getMin();
}
}
return minValue;
}
/**
* @return the maxValue
*/
public Double getMaxValue() {
double maxValue = Integer.MIN_VALUE;
for (DataPoint point : pointList) {
if (point.getAvg() > maxValue) {
maxValue = point.getAvg();
}
}
return maxValue;
}
/**
* @return the dataFrequency
*/
public int getDataFrequency() {
return dataFrequency;
}
/**
* @param dataFrequency
* the dataFrequency to set
*/
public void setDataFrequency(int dataFrequency) {
this.dataFrequency = dataFrequency;
}
/**
* Get the list of DataPoint objects for the key.
*
* @param key
* The key
* @return List of DataPoint objects
*/
public List<DataPoint> getData(String key) {
Collections.sort(pointList);
return pointList;
}
/**
* @return the timeRange
*/
public TimeRange getTimeRange() {
return timeRange;
}
/**
* @param pointList
* the pointList to set
*/
public void setPointList(List<DataPoint> pointList) {
this.pointList = pointList;
}
/**
* Add an AggregateRecord.
*
* @param rec
* the record to add
*/
public void addRecord(AggregateRecord rec) {
this.recordList.add(rec);
}
/**
* Get the key
*
* @return
*/
public String getKey() {
return key;
}
/**
* Set the key
*
* @param key
* the key to set
*/
public void setKey(String key) {
this.key = key;
}
/**
* Set the StatsBin object map.
*
* @param bins
*/
public void setBins(Map<Long, StatsBin> bins) {
this.bins = bins;
}
/**
* Accumulates the AggregateRecord objects into the correct bins.
*/
public void accumulate(String key) {
pointList.clear();
for (AggregateRecord record : recordList) {
Date startDate = record.getStartDate().getTime();
long start = startDate.getTime();
long bin = getBinKey(start);
if (bins.get(bin) != null) {
bins.get(bin).setData(record);
}
}
createPoints(key);
}
/**
* Create the points for this key.
*
* @param dataKey
*/
private void createPoints(String dataKey) {
// Bins are created, now make the graph group member and point objects
// convert the data values before storing in the data object
double conversion = unitUtils.getConversion();
for (long key : bins.keySet()) {
StatsBin sb = bins.get(key);
List<AggregateRecord> dataList = sb.getData();
if (!dataList.isEmpty()) {
DataPoint point = new DataPoint();
point.setX(sb.getBinMillis());
for (AggregateRecord rec : dataList) {
// Check for an existing point object
point.setMax(rec.getMax() / conversion);
point.setMin(rec.getMin() / conversion);
point.setSum(rec.getSum() / conversion);
point.addToCount(rec.getCount());
}
pointList.add(point);
}
}
}
/**
* Get the bin key for the given millisecond value.
*
* @param millis
* The millisecond value
* @return The bin that should hold this millisecond value
*/
private long getBinKey(long millis) {
for (long bin : this.bins.keySet()) {
if (millis <= bins.get(bin).getBinMillis()) {
return bin;
}
}
return 0;
}
/**
* @return the recordList
*/
public List<AggregateRecord> getRecordList() {
return recordList;
}
/**
* @return the pointList
*/
public List<DataPoint> getPointList() {
return pointList;
}
/**
* @return the bins
*/
public Map<Long, StatsBin> getBins() {
return bins;
}
/**
* @param timeRange
* the timeRange to set
*/
public void setTimeRange(TimeRange timeRange) {
this.timeRange = timeRange;
}
}

View file

@ -0,0 +1,164 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.common.stats.data;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Stats Event helper object.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Nov 8, 2012 728 mpduff Initial creation
*
* </pre>
*
* @author mpduff
* @version 1.0
*/
public class StatsEventData {
/** Event Type */
private String type;
/** Event display name */
private String displayName;
/** List of groups */
private List<String> groupList = new ArrayList<String>();
/** List of Attributes */
private List<String> attributeList = new ArrayList<String>();
/** Map of Display Name -> Name */
private final Map<String, String> groupMap = new HashMap<String, String>();
/**
* @return the type
*/
public String getType() {
return type;
}
/**
* @param type
* the type to set
*/
public void setType(String type) {
this.type = type;
}
/**
* @return the displayName
*/
public String getDisplayName() {
return displayName;
}
/**
* @param displayName
* the displayName to set
*/
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
/**
* @return the groupList
*/
public List<String> getGroupList() {
return groupList;
}
/**
* @param groupList
* the groupList to set
*/
public void setGroupList(List<String> groupList) {
this.groupList = groupList;
}
/**
* @return the attributeList
*/
public List<String> getAttributeList() {
return attributeList;
}
/**
* @param attributeList
* the attributeList to set
*/
public void setAttributeList(List<String> attributeList) {
this.attributeList = attributeList;
}
/**
* @param group
* displayName of the group to add
*/
public void addGroup(String displayName, String name) {
this.groupList.add(displayName);
this.groupMap.put(displayName, name);
}
/**
* @param attribute
* the attribute to add
*/
public void addAttribute(String attribute) {
this.attributeList.add(attribute);
}
/**
* Get the group list
*
* @return
*/
public String[] getGroups() {
return groupList.toArray(new String[groupList.size()]);
}
/**
* Get the attribute list
*
* @return
*/
public String[] getAttributes() {
return attributeList.toArray(new String[groupList.size()]);
}
/**
* Get the group name from the display name.
*
* @param displayName
* @return
*/
public String getGroupNameFromDisplayName(String displayName) {
return groupMap.get(displayName);
}
}

View file

@ -0,0 +1,183 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.common.stats.data;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import com.raytheon.uf.common.serialization.annotations.DynamicSerialize;
import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement;
/**
* Statistics Label Object.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Oct 16, 2012 728 mpduff Initial creation
*
* </pre>
*
* @author mpduff
* @version 1.0
*/
@DynamicSerialize
public class StatsLabelData {
/** Group string */
@DynamicSerializeElement
private String group = "";
/** List of group names */
@DynamicSerializeElement
private List<String> groupNames = new ArrayList<String>();
/** Recursive reference */
@DynamicSerializeElement
private StatsLabelData statsLabelData = null;
/**
* Constructor.
*/
public StatsLabelData() {
}
/**
* Constructor.
*
* @param group
* @param groupNames
*/
public StatsLabelData(String group, List<String> groupNames) {
this.groupNames = groupNames;
this.group = group;
}
/**
* Get the group.
*
* @return
*/
public String getGroup() {
return group;
}
/**
* Set the group
*
* @param group
*/
public void setGroup(String group) {
this.group = group;
}
/**
* Get the group names
*
* @return
*/
public List<String> getGroupNames() {
return groupNames;
}
/**
* Set the group name list
*
* @param groupNames
*/
public void setGroupNames(List<String> groupNames) {
this.groupNames = groupNames;
}
/**
* Get the StatsLabelData object.
*
* @return
*/
public StatsLabelData getStatsLabelData() {
return statsLabelData;
}
/**
* Set the StatsLabelData object
*
* @param statsLabelData
*/
public void setStatsLabelData(StatsLabelData statsLabelData) {
this.statsLabelData = statsLabelData;
}
/**
* Add a group name.
*
* @param name
*/
public void addGroupName(String name) {
groupNames.add(name);
}
/**
* Make the data keys
*
* @return List of the data keys
*/
public List<String> makeKeys() {
ArrayList<String> keysArray = new ArrayList<String>();
if (statsLabelData == null) {
return groupNames;
}
List<String> subKeys = statsLabelData.makeKeys();
for (String grpName : groupNames) {
for (String subKey : subKeys) {
keysArray.add(grpName + ":" + subKey);
}
}
return keysArray;
}
/**
* Get the group and group names map.
*
* @return
*/
public LinkedHashMap<String, List<String>> getGroupAndNamesMap() {
LinkedHashMap<String, List<String>> groupMap = new LinkedHashMap<String, List<String>>();
groupMap.put(group, groupNames);
if (statsLabelData != null) {
LinkedHashMap<String, List<String>> tmpMap = statsLabelData
.getGroupAndNamesMap();
for (String s : tmpMap.keySet()) {
groupMap.put(s, tmpMap.get(s));
}
}
return groupMap;
}
}

View file

@ -0,0 +1,287 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.common.stats.util;
import java.util.HashSet;
import java.util.Set;
import com.raytheon.uf.common.serialization.ISerializableObject;
import com.raytheon.uf.common.serialization.annotations.DynamicSerialize;
import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement;
import com.raytheon.uf.common.time.util.TimeUtil;
/**
* Utility class for data size conversions. KB vs MB vs GB
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Nov 14, 2012 728 mpduff Initial creation.
*
* </pre>
*
* @author mpduff
* @version 1.0
*/
@DynamicSerialize
public class UnitUtils implements ISerializableObject {
/** Bytes per Kilobyte */
private static final double BYTES_PER_KILOBYTE = 1024.0;
/** Different unit types for statistics */
public static enum UnitTypes {
DATA_SIZE, TIME, COUNT
}
/**
* Data Size Conversions
*/
public static enum DataSize {
KB("KB", BYTES_PER_KILOBYTE), MB("MB", BYTES_PER_KILOBYTE
* BYTES_PER_KILOBYTE), GB("GB", BYTES_PER_KILOBYTE
* BYTES_PER_KILOBYTE * BYTES_PER_KILOBYTE);
private final String unit;
private final double conversion;
private static Set<String> dataUnits;
private DataSize(String unit, double conversion) {
this.unit = unit;
this.conversion = conversion;
populateSet();
}
private static void populateSet() {
dataUnits = new HashSet<String>();
dataUnits.add("KB");
dataUnits.add("MB");
dataUnits.add("GB");
}
public String getDataUnit() {
return unit;
}
public double getConversion() {
return conversion;
}
public static Set<String> getDataUnits() {
return dataUnits;
}
}
/**
* Time Conversions.
*/
public static enum TimeConversion {
MS("ms", 1), Second("seconds", TimeUtil.MILLIS_PER_SECOND), Minute(
"minutes", TimeUtil.MILLIS_PER_MINUTE), Hour("hours",
TimeUtil.MILLIS_PER_HOUR);
private static Set<String> dataUnits;
private final String unit;
private final double conversion;
private TimeConversion(String unit, double conversion) {
this.unit = unit;
this.conversion = conversion;
populateSet();
}
private static void populateSet() {
dataUnits = new HashSet<String>();
dataUnits.add("seconds");
dataUnits.add("ms");
dataUnits.add("minutes");
dataUnits.add("hours");
}
public String getDataUnit() {
return unit;
}
public double getConversion() {
return conversion;
}
public static Set<String> getDataUnits() {
return dataUnits;
}
}
/** The event type */
private String eventType;
/** The data type */
private String dataType;
/** The display unit */
@DynamicSerializeElement
private String displayUnit;
/** The unit type */
@DynamicSerializeElement
private UnitTypes unitType;
/** Copnversion factor */
@DynamicSerializeElement
private double conversion = 1;
/**
* Constructor
*/
public UnitUtils() {
}
/**
* Constructor
*
* @param eventType
* event type
* @param dataType
* event attribute/data type
*/
public UnitUtils(String eventType, String dataType) {
this.eventType = eventType;
this.dataType = dataType;
// Default to count
this.unitType = UnitTypes.COUNT;
}
/**
* The largest value of the data set. This is used to determine which
* conversion to use if one is not specified.
*
* @param value
* Largest value of the data set
*
* @return The conversion factor
*/
public void setConversion(double value) {
// Which unit type is it?
if (unitType == UnitTypes.COUNT) {
conversion = 1;
} else if (unitType == UnitTypes.DATA_SIZE) {
if (value < DataSize.MB.getConversion()) {
conversion = DataSize.KB.getConversion();
} else if (value < DataSize.GB.getConversion()) {
conversion = DataSize.MB.getConversion();
} else if (value >= DataSize.GB.getConversion()) {
conversion = DataSize.GB.getConversion();
}
} else if (unitType == UnitTypes.TIME) {
if (value < TimeUtil.MILLIS_PER_MINUTE) {
conversion = TimeUtil.MILLIS_PER_SECOND;
} else if (value < TimeUtil.MILLIS_PER_HOUR) {
conversion = TimeUtil.MILLIS_PER_MINUTE;
} else {
conversion = TimeUtil.MILLIS_PER_SECOND;
}
}
}
/**
* @return the eventType
*/
public String getEventType() {
return eventType;
}
/**
* @return the dataType
*/
public String getDataType() {
return dataType;
}
/**
* Get the conversion
*
* @return
*/
public double getConversion() {
return conversion;
}
/**
* @return the unitType
*/
public UnitTypes getUnitType() {
return unitType;
}
/**
* @param unitType
* the unitType to set
*/
public void setUnitType(UnitTypes unitType) {
this.unitType = unitType;
}
/**
* @return the displayUnit
*/
public String getDisplayUnit() {
return displayUnit;
}
/**
* Set the display unit.
*
* @param displayUnit
*/
public void setDisplayUnit(String displayUnit) {
this.displayUnit = displayUnit;
// Determine the unitType
if (DataSize.getDataUnits().contains(displayUnit)) {
unitType = UnitTypes.DATA_SIZE;
} else if (TimeConversion.getDataUnits().contains(displayUnit)) {
unitType = UnitTypes.TIME;
}
if (unitType == UnitTypes.DATA_SIZE) {
if (displayUnit.equals(DataSize.KB.getDataUnit())) {
conversion = DataSize.KB.getConversion();
} else if (displayUnit.equals(DataSize.MB.getDataUnit())) {
conversion = DataSize.MB.getConversion();
} else if (displayUnit.equals(DataSize.GB.getDataUnit())) {
conversion = DataSize.GB.getConversion();
}
} else if (unitType == UnitTypes.TIME) {
if (displayUnit.equals(TimeConversion.MS.getDataUnit())) {
conversion = 1;
} else if (displayUnit.equals(TimeConversion.Second.getDataUnit())) {
conversion = TimeUtil.MILLIS_PER_SECOND;
} else if (displayUnit.equals(TimeConversion.Minute.getDataUnit())) {
conversion = TimeUtil.MILLIS_PER_MINUTE;
}
}
}
}

View file

@ -56,6 +56,10 @@ public class StatisticsAggregate {
@DynamicSerializeElement
private String displayName;
@XmlAttribute
@DynamicSerializeElement
private String displayUnit;
/**
* @return the field
*/
@ -85,4 +89,18 @@ public class StatisticsAggregate {
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
/**
* @return the displayUnit
*/
public String getDisplayUnit() {
return displayUnit;
}
/**
* @param displayUnit the displayUnit to set
*/
public void setDisplayUnit(String displayUnit) {
this.displayUnit = displayUnit;
}
}

View file

@ -20,7 +20,9 @@
package com.raytheon.uf.common.stats.xml;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
@ -77,13 +79,13 @@ public class StatisticsConfig implements ISerializableObject {
* @return List<String> of categories
*/
public List<String> getCategories() {
List<String> categories = new ArrayList<String>();
Set<String> categories = new HashSet<String>();
if (events != null && events.size() > 0) {
for (StatisticsEvent event : events) {
categories.add(event.getCategory());
}
}
return categories;
return new ArrayList<String>(categories);
}
}

View file

@ -40,6 +40,7 @@ import com.raytheon.uf.common.time.SimulatedTime;
* Feb 02, 2009 njensen Initial creation
* Sep 11, 2012 1154 djohnson Add MILLIS constants and isNewerDay().
* Nov 09, 2012 1322 djohnson Add SECONDS_PER_MINUTE.
* Nov 21, 2012 728 mpduff Added MILLIS_PER_MONTH.
*
* </pre>
*
@ -95,6 +96,8 @@ public class TimeUtil {
public static final long MILLIS_PER_WEEK = MILLIS_PER_DAY * 7;
public static final long MILLIS_PER_MONTH = MILLIS_PER_DAY * 30;
public static final long MILLIS_PER_YEAR = 3600 * 24 * 1000 * 365;
public static final int SECONDS_PER_MINUTE = 60;

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>com.raytheon.uf.edex.registry.feature</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.pde.FeatureBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.pde.FeatureNature</nature>
</natures>
</projectDescription>

View file

@ -0,0 +1,13 @@
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:amq="http://activemq.apache.org/schema/core"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
<bean id="statsHandler" class="com.raytheon.uf.edex.stats.handler.GraphDataHandler"/>
<bean factory-bean="handlerRegistry" factory-method="register">
<constructor-arg value="com.raytheon.uf.common.stats.GraphDataRequest"/>
<constructor-arg ref="statsHandler"/>
</bean>
</beans>

View file

@ -0,0 +1,322 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.edex.stats.data;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.regex.Pattern;
import com.google.common.annotations.VisibleForTesting;
import com.raytheon.uf.common.stats.AggregateRecord;
import com.raytheon.uf.common.stats.data.GraphData;
import com.raytheon.uf.common.stats.data.StatsBin;
import com.raytheon.uf.common.stats.data.StatsData;
import com.raytheon.uf.common.stats.data.StatsLabelData;
import com.raytheon.uf.common.stats.util.UnitUtils;
import com.raytheon.uf.common.time.TimeRange;
import com.raytheon.uf.common.time.util.TimeUtil;
/**
* Accumulates the statistics data.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Nov 15, 2012 728 mpduff Initial creation
*
* </pre>
*
* @author mpduff
* @version 1.0
*/
public class StatsDataAccumulator {
private final Pattern COLON_PATTERN = Pattern.compile(":");
private final Pattern DASH_PATTERN = Pattern.compile("-");
private final String COLON = ":";
/** List of records */
private AggregateRecord[] records;
/** List of groups */
@VisibleForTesting
List<String> groups;
/** TimeRange oject */
private TimeRange timeRange;
/** Event type */
private String eventType;
/** Event data type/attribute */
private String dataType;
/** Display unit */
private String displayUnit;
/** Data's timestep */
private long timeStep;
/** Stats data map */
@VisibleForTesting
final Map<String, StatsData> statsDataMap = new HashMap<String, StatsData>();
/** Map of time in ms -> StatsBin objects */
@VisibleForTesting
final Map<Long, StatsBin> bins = new TreeMap<Long, StatsBin>();
/** Map of group name -> group members */
@VisibleForTesting
Map<String, Set<String>> groupMemberMap = new HashMap<String, Set<String>>();
/**
* Set the AggregateRecord[]
*
* @param records
* array of AggregateRecord objects
*/
public void setRecords(AggregateRecord[] records) {
this.records = records;
}
/**
* Set up the grouping objects.
*/
@VisibleForTesting
public void setupGroupings() {
for (AggregateRecord aggRec : records) {
String grouping = aggRec.getGrouping();
String[] groupString = DASH_PATTERN.split(grouping);
String group;
String member;
for (String grp : groupString) {
String[] parts = COLON_PATTERN.split(grp);
group = parts[0];
member = parts[1];
if (!groupMemberMap.containsKey(group)) {
groupMemberMap.put(group, new TreeSet<String>());
}
groupMemberMap.get(group).add(member);
}
}
groups = new ArrayList<String>(groupMemberMap.keySet());
}
/**
* Get the GraphData object
*
* @param groups
* List of groups
* @return The GraphData object
*/
public GraphData getGraphData(List<String> groups) {
// Create the StatsLableData object
// Create the keys (owner:plugin:provider)
// Loop backwards over the data
StatsLabelData prevLabelData = null;
StatsLabelData statsLabelData = null;
UnitUtils unitUtils = new UnitUtils(eventType, dataType);
unitUtils.setDisplayUnit(displayUnit);
for (int i = groups.size() - 1; i >= 0; i--) {
String group = groups.get(i);
statsLabelData = new StatsLabelData(group, new ArrayList<String>(
groupMemberMap.get(group)));
if (prevLabelData != null) {
statsLabelData.setStatsLabelData(prevLabelData);
}
prevLabelData = statsLabelData;
}
gather(unitUtils, groups);
// StatsLabelData is created and holds all the keys
GraphData graphData = new GraphData();
graphData.setStatsLabelData(statsLabelData);
graphData.setDisplayUnit(displayUnit);
graphData.setStatsDataMap(statsDataMap);
graphData.setTimeRange(timeRange);
graphData.setKeys(new ArrayList<String>(this.statsDataMap.keySet()));
graphData.setUnitUtils(unitUtils);
graphData.setKeySequence(groups);
return graphData;
}
/**
* Create the StatsDataMap keys
*
* @param unitUtils
* UnitUtils object
* @param groups
* List of groups
*/
@VisibleForTesting
void createStatsDataMap(UnitUtils unitUtils, List<String> groups) {
Map<String, String> keySequenceMap = new LinkedHashMap<String, String>();
for (String key : groups) {
keySequenceMap.put(key, "");
}
String builtKey = "";
for (AggregateRecord record : records) {
if (record.getEventType().equals(eventType)
&& record.getField().equals(dataType)) {
// Have a matching record
for (String key : keySequenceMap.keySet()) {
keySequenceMap.put(key, "");
}
String[] groupings = DASH_PATTERN.split(record.getGrouping());
for (String grouping : groupings) {
String[] parts = COLON_PATTERN.split(grouping);
String group = parts[0];
String groupMember = parts[1];
for (String key : keySequenceMap.keySet()) {
if (group.equals(key)) {
keySequenceMap.put(key, keySequenceMap.get(key)
.concat(groupMember + COLON));
break;
}
}
}
for (String key : keySequenceMap.keySet()) {
builtKey = builtKey.concat(keySequenceMap.get(key));
}
if (builtKey.length() != 0) {
// Drop the last ":"
builtKey = builtKey.substring(0, builtKey.length() - 1);
}
if (!statsDataMap.containsKey(builtKey)) {
statsDataMap.put(builtKey, new StatsData(builtKey,
timeStep, this.timeRange, unitUtils));
}
statsDataMap.get(builtKey).addRecord(record);
builtKey = "";
}
}
}
/**
* Gather the data together in each bin.
*
* @param unitUtils
* UnitUtils object
* @param groups
* List of groups
*/
private void gather(UnitUtils unitUtils, List<String> groups) {
createStatsDataMap(unitUtils, groups);
calculateBins();
for (String key : statsDataMap.keySet()) {
StatsData data = statsDataMap.get(key);
data.setBins(bins);
data.accumulate(key);
statsDataMap.put(key, data);
}
}
/**
* Calculate the bins for the graph.
*/
@VisibleForTesting
void calculateBins() {
bins.clear();
long duration = timeRange.getDuration();
long startMillis = timeRange.getStart().getTime();
long numBins = duration / (timeStep * TimeUtil.MILLIS_PER_MINUTE);
for (long i = 0; i < numBins; i++) {
StatsBin sb = new StatsBin();
sb.setBinMillis(startMillis
+ (i * timeStep * TimeUtil.MILLIS_PER_MINUTE));
bins.put(i, sb);
}
}
/**
* @param timeRange
* the timeRange to set
*/
public void setTimeRange(TimeRange timeRange) {
this.timeRange = timeRange;
}
/**
* @return the timeRange
*/
public TimeRange getTimeRange() {
return timeRange;
}
/**
* @param eventType
* the eventType to set
*/
public void setEventType(String eventType) {
this.eventType = eventType;
}
/**
* @param dataType
* the dataType to set
*/
public void setDataType(String dataType) {
this.dataType = dataType;
}
/**
* Set the display units.
*
* @param displayUnit
* the displayUnit to set
*/
public void setDisplayUnits(String displayUnit) {
this.displayUnit = displayUnit;
}
/**
* TimeStep in minutes
*
* @param timeStep
*/
public void setTimeStep(int timeStep) {
this.timeStep = timeStep;
}
}

View file

@ -0,0 +1,220 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.edex.stats.handler;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
import com.raytheon.uf.common.dataquery.db.QueryParam.QueryOperand;
import com.raytheon.uf.common.serialization.comm.IRequestHandler;
import com.raytheon.uf.common.stats.AggregateRecord;
import com.raytheon.uf.common.stats.GraphDataRequest;
import com.raytheon.uf.common.stats.GraphDataResponse;
import com.raytheon.uf.common.stats.data.GraphData;
import com.raytheon.uf.common.stats.xml.StatisticsAggregate;
import com.raytheon.uf.common.stats.xml.StatisticsConfig;
import com.raytheon.uf.common.stats.xml.StatisticsEvent;
import com.raytheon.uf.common.time.util.TimeUtil;
import com.raytheon.uf.edex.database.dao.CoreDao;
import com.raytheon.uf.edex.database.dao.DaoConfig;
import com.raytheon.uf.edex.database.query.DatabaseQuery;
import com.raytheon.uf.edex.stats.data.StatsDataAccumulator;
import com.raytheon.uf.edex.stats.util.ConfigLoader;
/**
* Graph Data Request Handler.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Sep 11, 2012 728 mpduff Initial creation
*
* </pre>
*
* @author mpduff
* @version 1.0
*/
public class GraphDataHandler implements IRequestHandler<GraphDataRequest> {
/** Aggregate Record DAO */
private final CoreDao dao = new CoreDao(DaoConfig.forClass("metadata",
AggregateRecord.class));
private static final String START_DATE = "startDate";
private static final String END_DATE = "endDate";
private static final String EVENT_TYPE = "eventType";
private static final String FIELD = "field";
private static final String COUNT = "COUNT";
/**
* Constructor.
*/
public GraphDataHandler() {
}
/**
* {@inheritDoc}
*/
@Override
public GraphDataResponse handleRequest(GraphDataRequest request)
throws Exception {
GraphDataResponse response;
if (request.isMetaDataRequest()) {
response = getMetaData();
} else {
response = getGraphData(request);
}
return response;
}
/**
* Get the statistical configuration objects and add them to the response.
*
* @return GraphDataResponse
*
* @throws Exception
*/
private GraphDataResponse getMetaData() throws Exception {
ConfigLoader loader = new ConfigLoader();
loader.load();
List<StatisticsConfig> configList = loader.getConfigurations();
GraphDataResponse response = new GraphDataResponse();
response.setConfigList(configList);
return response;
}
/**
* Get the Graph Data object and add it to the response.
*
* @param request
* The request object
* @return GraphDataResponse
* @throws Exception
*/
private GraphDataResponse getGraphData(GraphDataRequest request)
throws Exception {
GraphDataResponse response = new GraphDataResponse();
DatabaseQuery query = new DatabaseQuery(AggregateRecord.class.getName());
Calendar start = convertToCalendar(request.getTimeRange().getStart());
Calendar end = convertToCalendar(request.getTimeRange().getEnd());
query.addQueryParam(START_DATE, start, QueryOperand.GREATERTHANEQUALS);
query.addQueryParam(END_DATE, end, QueryOperand.LESSTHANEQUALS);
if (request.getEventType() != null) {
query.addQueryParam(EVENT_TYPE, request.getEventType(),
QueryOperand.EQUALS);
}
if (request.getField() != null) {
query.addQueryParam(FIELD, request.getField(),
QueryOperand.EQUALS);
}
List<?> results = dao.queryByCriteria(query);
if (!results.isEmpty()) {
List<AggregateRecord> arList = new ArrayList<AggregateRecord>();
for (int i = 0; i < results.size(); i++) {
if (results.get(i) instanceof AggregateRecord) {
arList.add((AggregateRecord) results.get(i));
}
}
String displayUnit = getDisplayUnit(request.getCategory(),
request.getEventType(), request.getDataType());
StatsDataAccumulator accum = new StatsDataAccumulator();
accum.setRecords(arList.toArray(new AggregateRecord[arList.size()]));
accum.setDisplayUnits(displayUnit);
accum.setEventType(request.getEventType());
accum.setDataType(request.getField());
accum.setTimeRange(request.getTimeRange());
accum.setTimeStep(request.getTimeStep());
accum.setupGroupings();
GraphData graphData = accum.getGraphData(request.getGrouping());
response.setGraphData(graphData);
}
return response;
}
/**
* Convert a Date object to Calendar object.
*
* @param date
* @return Calendar object
*/
private Calendar convertToCalendar(Date date) {
Calendar cal = TimeUtil.newCalendar(TimeZone.getTimeZone("GMT"));
cal.setTimeInMillis(date.getTime());
return cal;
}
/**
* Get the display unit.
*
* @param dataType
* @param type
* @param category
* @return The display unit, NONE if no units
*/
private String getDisplayUnit(String category, String type, String dataType)
throws Exception {
ConfigLoader loader = new ConfigLoader();
loader.load();
List<StatisticsConfig> configList = loader.getConfigurations();
String unit = COUNT;
for (StatisticsConfig config : configList) {
for (String cat : config.getCategories()) {
if (cat.equals(category)) {
for (StatisticsEvent event : config.getEvents()) {
if (event.getType().equals(type)) {
for (StatisticsAggregate agg : event
.getAggregateList()) {
if (agg.getField().equals(dataType)) {
return agg.getDisplayUnit();
}
}
}
}
}
}
}
return unit;
}
}

View file

@ -36,7 +36,6 @@ import com.raytheon.uf.common.stats.xml.StatisticsConfig;
import com.raytheon.uf.common.stats.xml.StatisticsEvent;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.edex.stats.xml.Statistics;
/**
* Loads StatisticsConfig files from localization.
@ -62,8 +61,7 @@ public class ConfigLoader {
private static final JAXBManager jaxbManager;
static {
try {
jaxbManager = new JAXBManager(StatisticsConfig.class,
Statistics.class);
jaxbManager = new JAXBManager(StatisticsConfig.class);
} catch (JAXBException e) {
throw new ExceptionInInitializerError(e);
}

View file

@ -58,6 +58,10 @@ public class Aggregate {
@DynamicSerializeElement
private Unit<?> unit = Unit.ONE;
@XmlAttribute
@DynamicSerializeElement
private String displayName;
/** the name of the statistic function */
@XmlElement(name = "function")
@DynamicSerializeElement
@ -94,4 +98,19 @@ public class Aggregate {
this.functions = functions;
}
/**
* @param displayName
* the displayName to set
*/
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
/**
* @return the displayName
*/
public String getDisplayName() {
return displayName;
}
}

View file

@ -52,6 +52,10 @@ public class Item {
@DynamicSerializeElement
private String result;
@XmlAttribute
@DynamicSerializeElement
private String displayName;
public String getName() {
return name;
}
@ -68,4 +72,18 @@ public class Item {
this.result = result;
}
/**
* @param displayName the displayName to set
*/
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
/**
* @return the displayName
*/
public String getDisplayName() {
return displayName;
}
}

View file

@ -4,8 +4,8 @@
displayName="Processing Events" category="Data Ingest Events">
<statisticsGroup name="pluginName" displayName="Data Type" />
<statisticsAggregate field="processingTime"
displayName="Processing Time" unit="ms" />
displayName="Processing Time" displayUnit="ms" />
<statisticsAggregate field="processingLatency"
displayName="Processing Latency" unit="ms" />
displayName="Processing Latency" displayUnit="ms" />
</statisticsEvent>
</statisticsConfig>