Skip to content

Instantly share code, notes, and snippets.

@sickel
Created October 30, 2019 07:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sickel/6a0e041e2502fc37cf043243f9fc605d to your computer and use it in GitHub Desktop.
Save sickel/6a0e041e2502fc37cf043243f9fc605d to your computer and use it in GitHub Desktop.
Waterfall - java Keep it here, use some ideas for qgis plugin
import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.*;
/*
(c) Morten Sickel 2010 - 2011
Licenced under GNU GPL v3 or later
*/
/*
TODO: The routines for data display and fetching of data are presently too
closely coupled. The routines for fetching data from the server should maybe be
extracted into an own object
TODO: Define integration time by dragging rather than by left and right click
TODO: display existing hits OK 31052011
*/
// $Id: Waterfall.java 762 2011-05-31 07:50:58Z radioecology $
class WaterfallException extends Exception{
}
class Waterfall extends JComponent {
/*
This class draws and updates the waterfall plot
*/
public static final int HISPEED=80; // update delay in ms for hi speed updates
/* TODO: Hispeed fetches more lines in one batch same delay as for LOWSPEED -
thereby lower load on the database server
*/
public static final int LOWSPEED=800;
private BufferedImage bi;
private URL ajaxserver;
private static Boolean active=false;
private Boolean plotkeV=true,hispeed=false;
// PlotkeV: X scale in keV or channels
// active: the updates are running
private int marked=-1, datasetid=0,index=0, xaxheight=15, total=1,follower=1;
// Total: Total number of spectra in the data set
// Follower: Current last id of shown spectra
int w=300, h=400, intchcol, endrepeats, nchan,inttime=0,intto=-1;
private float chcol;
public static Timer readtimer;
private int[] indexes;
private float[][] values; // backingstore for the values in the spectrum
private double a=0.1644,b=6.1225;
// default calibration values
// May be set do different values for
// other instruments or new calibrations
public int getTotal(){
return total;
}
public int getFollower(){
return follower;
}
public boolean hispeed(){
return hispeed;
}
public boolean hispeed(boolean set){
hispeed=set;
return hispeed;
}
public void calibrate(String calibdata){
// The calibration data may come in as two space separated floating point numbers
String [] temp = null;
System.out.println(calibdata);
temp=calibdata.split(" ");
a=Float.valueOf(temp[1].trim()).floatValue();
b=Float.valueOf(temp[0].trim()).floatValue();
}
public void calibrate(float newa, float newb){
// sets the calibration values directly
a=newa;
b=newb;
}
public void setPlotkeV(boolean keV){
plotkeV=keV;
}
public void toggleActive(){
active=!active;
}
public boolean isActive(){
return active;
}
public int getH(){
return h-xaxheight;
}
public int getDatasetid(){
return datasetid;
}
public int getMarked(){
return marked;
}
public void removeMarked(){
marked=-1;
}
public int getInttime(){
return inttime;
}
public int getIndex(){
return index;
}
public Waterfall(int dataset, int setnchan) {
nchan=setnchan;
datasetid=dataset;
bi = new BufferedImage(w,h,BufferedImage.TYPE_INT_RGB);
this.addMouseListener(new wfMouseadapter());
/* The number of rows in the plot may be (well now is) less than
the number of channels in the spectrum. intchcol is the number of
channels that is to be downsampled to one row. chcol (a floating point
value) is used to find which channel to use as the startingpoint for
a given row.
*/
chcol=(float)nchan/w; // must cast nchan to get out a float
intchcol=Math.round(chcol);
readtimer = new Timer(LOWSPEED, new TimerListener(this));
readtimer.start();
indexes=new int[h];
values=new float[h][nchan];
repaint();
drawGrid();
}
public void setDatasetid(int dataset){
datasetid=dataset;
}
private float[] transposechannels(float[] chs){
return chs;
}
public void drawnew(int startidx,boolean abs){
/*
Fetches a new dataset and plots it
*/
fetchnew(startidx,abs);
Graphics2D wf=bi.createGraphics();
wf.setColor(Color.BLACK);
wf.fillRect(0,0,w,h);
for(int i=0;i<getH();i++){
newline(i,values[i]);
}
if (marked>=0){
markSelected();
}
drawGrid();
repaint();
}
public void fetchnew(int startidx,boolean abs){
/*
This is really a special case of fetchrows
Fetches data for a new plot up to a given index
*/
int oldindex=index;
String oldtimestamp=WaterfallApplet.timestamp.getText();
try {
String fetchid;
fetchid=abs?"id=":"nth=";
// abs is set to true if an absolute id is used, false if it is an index within the dataset
if(!(abs) && (total-startidx < h-50)){
startidx=startidx-(h-50);
// Else an empty plot will be shown with all the data "above" the plot.
}
fetchid=fetchid+Integer.toString(startidx);
//ajaxserver = new URL(WaterfallApplet.codebase+"/ajaxserver.php?a=fetchset&cosmic=no&"+fetchid+"&datasetid="+Integer.toString(datasetid)+"&total="+Integer.toString(total) );
ajaxserver = new URL(WaterfallApplet.codebase+"/ajaxserver.php?a=fetchset&cosmic=no&"+fetchid+"&datasetid="+Integer.toString(datasetid) );
URLConnection conn=ajaxserver.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
/** The returned data should be on the format
* Timestamp on the first line
* last id on the second line
* each following line is a complete spectrum with comma separated values
*/
// TODO: Dekoble fra wfa
WaterfallApplet.timestamp.setText(in.readLine()); // reads timestamp
index=Integer.valueOf(in.readLine().trim()).intValue(); // reads Id
total=Integer.valueOf(in.readLine().trim()).intValue();
follower=Integer.valueOf(in.readLine().trim()).intValue();
// TODO: Rett opp her - dekoble fra wfa, se til at det funker ved scrolling
System.out.println("tot:"+total+"foll:"+follower+"<");
WaterfallApplet.infolabel.setText(total==follower?"End of data set":"");
int row =0;
String decodedString;
while (((decodedString = in.readLine()) != null) && (row<h)) {
try
{
float[] chs=decodeline(decodedString);
indexes[row]=Math.round(chs[0]); // id for the row
System.arraycopy(chs, 1, chs, 0, chs.length-1); // Shifts out the ids
values[row]=chs;
row++;
}
catch (NumberFormatException e){e.printStackTrace();}
}
in.close();
for(int i=row;i<h-1;i++){
// Clear out the rest of values if not totally filled
for(int j=0;j<nchan;j++){
values[i][j]=0;
}
}
}
catch (NumberFormatException e){
// TODO dekoble fra wfa
WaterfallApplet.infolabel.setText("End of data set");
WaterfallApplet.timestamp.setText(oldtimestamp);
index=oldindex;
System.out.println("Invalid index read, index set to :"+index);
}
catch(MalformedURLException e) {e.printStackTrace();}
catch(IOException e){e.printStackTrace();}
}
public float[] getRow(int rowid){
try{
// fetching data from backingstore
rowid=lookupMark(rowid);
}
catch(WaterfallException wfe) {System.out.println("Finner ikke aktuelt spekter ("+rowid+")");}
return values[rowid];
}
private float[] decodeline(String line){
String [] temp = null;
temp=line.split(",");
float[] chs = new float[nchan];
for(int j=0;j<temp.length;j++){
chs[j] = Float.valueOf(temp[j].trim()).floatValue();
}
return chs;
}
public void fetchRows(int n){
/*
Fetches data for a plot up to a given index
TODO: Combine with fetchnew!
*/
int oldindex=index;
// System.out.println("oldindex:"+index);
// TODO dekoble fra wfa:
String oldtimestamp=WaterfallApplet.timestamp.getText();
try {
ajaxserver = new URL(WaterfallApplet.codebase+"/ajaxserver.php?a=fetchset&cosmic=no&id=" +Integer.toString(index)+"&datasetid="+Integer.toString(datasetid)+"&limit="+Integer.toString(n)+"&sort=asc" );
URLConnection conn=ajaxserver.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
/** The returned data should be on the format
* Timestamp on the first line
* last id on the second line
* each following line is a complete spectrum with comma separated values
*/
WaterfallApplet.timestamp.setText(in.readLine()); // reads timestamp
index=Integer.valueOf(in.readLine().trim()).intValue(); // reads Id
System.out.println("Id:"+index);
total=Integer.valueOf(in.readLine().trim()).intValue();
follower=Integer.valueOf(in.readLine().trim()).intValue();
WaterfallApplet.infolabel.setText("");
if (oldindex == index){ // no new data
WaterfallApplet.infolabel.setText("End of data set");
endrepeats++;
if(endrepeats>10){ // Pauses data updates if nothing new for 10 updates
active=false; // Stops the calls for new data
WaterfallApplet.BtRunwf.setSelected(false); // "pops out" the run button
}
return ; // nothing more to do here
}
endrepeats=0;
// System.out.println("index:"+index);
String decodedString;
while (((decodedString = in.readLine()) != null)) {
try
{
float[] chs=decodeline(decodedString);
int idx=Math.round(chs[0]); // id for the row
System.arraycopy(chs, 1, chs, 0, chs.length-1); // Shifts out the id
drawshift(idx, chs); // shifts the new data sets into the backing store and draws the plot.
}
catch (NumberFormatException e){e.printStackTrace();}
}
in.close();
}
catch (NumberFormatException e){
WaterfallApplet.infolabel.setText("End of data set");
WaterfallApplet.timestamp.setText(oldtimestamp);
index=oldindex;
System.out.println("Invalid index read, index set to :"+index);
endrepeats++;
if(endrepeats>10){ // Pauses data updates if nothing new for 10 updates
active=false; // Stops the calls for new data
WaterfallApplet.BtRunwf.setSelected(false); // "pops out" the run button
}
}
catch(MalformedURLException e) {e.printStackTrace();}
catch(IOException e){e.printStackTrace();}
}
public void drawshift(int idx, float[] chs){
System.arraycopy(indexes, 0, indexes, 1, indexes.length-1);
System.arraycopy(values, 0, values, 1, values.length-1);
indexes[0]=idx;
values[0]=chs;
newline(-1,chs); // put in a new line at the top, shift the rest down
}
public void drawshift(float[] chs){
System.arraycopy(indexes, 0, indexes, 1, indexes.length-1);
System.arraycopy(values, 0, values, 1, values.length-1);
indexes[0]=index;
values[0]=chs;
newline(-1,chs); // put in a new line at the top, shift the rest down
}
private void newline(Integer row, float[] chs){
/*
TODO: The first number in the array is now indicating a hit. 1 = hit, 0 = no hit
*/
/* Draws a new line in the waterfall plot at row# row. If the new row is to be
inserted at the top so that the rest of the plot is shifted one line down, row is to be set to a negative value
*/
if (row<0){ // To flag that a new row is put in on the top to put the rest of the dataset one row down
for (Integer i=0;i<w;i++) { // Moves the entire picture one row down. may be an easier way?
for (int j=getH()-2;j>=0;j--){ // Goes from the bottom and up since the bottom row is the one to be discarded
bi.setRGB(i,j+1,bi.getRGB(i,j));
}
}
row=0; // New row to come in at the (now empty) top row
}
float max=Legend.getMax();
boolean marked=chs[0]==1; // A hit exists at the active row
System.arraycopy(chs, 1, chs, 0, chs.length-1); // Shifts out the mark
for(Integer i=0;i<w;i++){ // Draws the new line, either in the spectrum or at the top
float value=chs[Math.round(i*chcol)];
if(Legend.getLog() && value>0){
value=(float)Math.log(value);
}
if (value>=max){
bi.setRGB(i,row, Legend.makeARGB(0, 255, 255, 255));}
else{
try{
bi.setRGB(i,row,Legend.colors[Math.round(value/max*Legend.NCOLORS)+1]);
}
catch(ArrayIndexOutOfBoundsException e){
System.out.println("Exception Newline() : Value:"+value+"|max:"+max+"|ncol:"+Legend.NCOLORS+"|");
}
}
}
if(marked){
// A marker exists here. Draws a gray line at the end of the spectre.
Graphics2D wf=bi.createGraphics();
wf.setColor(Color.GRAY); // Possible to make a color with alpha channel here?
wf.drawLine(w-20,row,w,row);
}
}
public void markSelected(){ // marks (if any) selected line
try{
int y=lookupMark(marked);
Graphics2D wf=bi.createGraphics();
wf.setColor(Color.GRAY); // custom color with alpha ch?
if(marked >= 0 && marked < index && marked>indexes[getH()]){ // if there is a mark somewhere on the plot
wf.drawLine(0,y,w,y);
}
if(inttime>0 && intto < index && intto>indexes[getH()]){
y=lookupMark(intto);
wf.drawLine(0,y,w,y);
repaint();
}
}
catch(WaterfallException wfe) {System.out.println("Kan ikke justere posisjon");}
}
public void drawGrid(){
// marks some channels 100, 200 ... 500
Graphics2D wf=bi.createGraphics();
wf.setColor(Color.LIGHT_GRAY);
int max=plotkeV?7:6;
wf.fillRect(0,h-xaxheight,w,h);
int mult=plotkeV?500:100;
for(int i=1;i<max;i++){
int ch=plotkeV?(int)((i*500-b)/a):i*100;
int ptx = Math.round(ch/chcol); //
wf.setColor(Color.GRAY);
wf.drawLine(ptx,0,ptx,h-xaxheight);
wf.setColor(Color.BLACK);
wf.drawString(Integer.toString(i*mult),ptx-15,h-2);
}
String unit=plotkeV?"keV":"Ch";
wf.drawString(unit,0,h-2);
}
public Dimension getPreferredSize() {
return new Dimension(w, h);
}
public void paintComponent(Graphics g) {
g.drawImage(bi,10,10,null);
drawGrid();
}
class wfMouseadapter extends MouseAdapter{
public void mouseClicked(MouseEvent e) {
try{
if (datasetid >0){
if((e.getButton()==MouseEvent.BUTTON3) && (marked>0)){
// Right click. Defines an integral relative to last left click
// if(marked>0){
// Defines an integral relative to last left click
if (inttime > 0 && lookupMark(intto)>0){
// Removes old mark
newline(lookupMark(marked+inttime),getRow(marked+inttime)); // Puts the data back where the old line was
}
intto=indexes[e.getY()-10];
if(intto>marked){
// The integration time is always calculated from the first mark
inttime=intto-marked;
}else{
inttime=marked-intto;
marked=intto;
}
markSelected(); // Draws the mark
}else{
if(e.getButton()==MouseEvent.BUTTON1){
// System.out.print("Left:");
// Left click, sets a new mark
if(e.getY()>=10){
setMouseMark(e.getY()-10); // stores the new mark
}
}}
}
}
catch(WaterfallException wfe) {System.out.println("Kan ikke justere posisjon");}
}
} // class wfMouseAdapter
public int lookupMark(int markidx) throws WaterfallException {
// Returns the location of a given specter Throws an exception if not found
int retvalue = -1;
for (int i=0;i<indexes.length && retvalue <0;i++){
retvalue=indexes[i]==markidx?i:retvalue;
}
if (retvalue==-1){ throw new WaterfallException();}
System.out.println("idx:"+indexes[retvalue]);
//System.out.println("lookupmark->"+retvalue);
return retvalue;
}
public int nextMark(int mark, boolean up) throws WaterfallException{
// Moves to the next mark in a series. The ids may not be continious
int i=lookupMark(mark);
i=up?i+1:i-1;
return indexes[i];
}
void setMouseMark(int markline){
try{
setmarked(indexes[markline]); // Translates the image coordinate to a specterid
}
catch (ArrayIndexOutOfBoundsException e){System.out.println("line: "+markline);}
}
public void setmarked(int newmark){
int oldmark=marked;
int oldinttime=inttime;
// System.out.println("index:"+index+"|indexes[0]:"+indexes[0]+"|");
marked=newmark;
try{
// System.out.println("oldmark:"+oldmark);
newline(lookupMark(oldmark),getRow(oldmark)); // Puts the data back where the old line was
}
catch(WaterfallException wfe) {System.out.println("Ikke gammelt merke");}
try{
// Removes any old integration time marker
newline(lookupMark(oldmark+inttime),getRow(oldmark+inttime)); // Puts the data back where the old line was
}
catch(WaterfallException wfe) {System.out.println("Ikke gammelt integrasjonstid");}
// Enables the buttons
WaterfallApplet.BtSaveHit.setEnabled(true);
WaterfallApplet.BtLink.setEnabled(true);
WaterfallApplet.BtUp.setEnabled(true);
WaterfallApplet.BtDn.setEnabled(true);
// System.out.println("enabled buttons");
inttime=0;
markSelected();
repaint();
}
}
class TimerListener implements ActionListener{
/*
Helper class for timed updates
*/
Waterfall wf;
public TimerListener(Waterfall initwf){
wf=initwf;
}
public void actionPerformed(ActionEvent e){
if (wf.isActive()){
if(wf.hispeed()){
wf.fetchRows(10);
}else{
wf.fetchRows(1);
}
wf.repaint();
}
}
}
import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.*;
/*
(c) Morten Sickel 2010
Licenced under GNU GPL v3 or later
*/
// $Id: Legend.java 547 2010-01-26 11:35:19Z radioecology $
class Legend extends JComponent {
/*
This class makes a legend. It also defines the color array used in the waterfall
*/
private BufferedImage legend;
public static float max;
static final float DEFAULTMAX=200; // Default value for max
static int[] colors; // set of colors to use
static final int NCOLORS=1536; // Numbers of steps in the colorscale
private static boolean log;
int w=70;
int h=410;
public static float getMax(){
return log?(float)Math.log(max):max;
}
public static void setLog(boolean setlog){
log=setlog;
}
public static boolean getLog(){
return log;
}
public static int makeARGB(int a, int r, int g, int b) {
// Creates an integer color value from an argb quartet. (0-255)
// (a=alpha cannel, transparency, set to 0 for non transparent colors
return a << 24 | r << 16 | g << 8 | b;
}
public Legend(float setmax){
colors=new int[NCOLORS+1];
for(int i = 0; i <= 256; i++) {
// Setting up a color scale
// Goes along the egdes of the RGB color cube
// cf http://www.poirrier.be/~jean-etienne/info/clibs/gd-rainbow.php
// Red (255,0,0) to yellow (255,255,0)
colors[NCOLORS-i] = makeARGB(0,255,i,0);
// Yellow to green (0,255,0)
colors[NCOLORS-(i + 256)] = makeARGB(0,255-i,255,0);
// Green to cyan (0,255,255)
colors[NCOLORS-(i + 512)] = makeARGB(0,0,255,i);
// cyan to blue (0,0,255)
colors[NCOLORS-(i + 768)] = makeARGB(0,0,255-i,255);
// blue to mangenta( 255,0,255)
colors[NCOLORS-(i + 1024)] = makeARGB(0,i,0,255);
// Should go back to red, but
// add the first -i to go down into black (0,0,0)
// rather than back to red (255,0,0) to make an unique color scale
colors[NCOLORS-(i + 1280)] = makeARGB(0,255-i,0,255-i); // Fades down into black
}
max=setmax;
}
public void paintComponent(Graphics g) {
legend= new BufferedImage(w,h,BufferedImage.TYPE_INT_ARGB);
Graphics2D leg=legend.createGraphics();
Font font = new Font("Dialog", Font.PLAIN, 12);
int tenth=Math.round(h/10); // Makes ten marks along the scale. Makes perfect sense for linear, may rethink for log
int next=0; // Next value to mark
int n=0; // Number of marks
float drawmax=getMax();
for (int i=0;i<=h-10;i++){
int row=i+5;
if (i==next || i == h-10){ // draw a marker
float num=drawmax*(10-n++)/10; // Which number to mark. The numbers go the opposite direction of the y-axis numbers
if(log){
num=(float)Math.exp(num);
}
leg.setColor(Color.BLACK);
leg.drawString(Float.toString(Math.round(num)),25,row+5);
leg.drawLine(5,row,20,row);
next+=tenth;
}else{ // Draw a normal colored line
leg.setColor(new Color(colors[(h-10-i)*NCOLORS/(h-10)]));
leg.drawLine(5,row,15,row);
}
}
g.drawImage(legend,-5,5,null);
}
public Dimension getPreferredSize() {
return new Dimension(w, h);
}
}
/*
(c) Morten Sickel 2010 - 2011
Licenced under GNU GPL v3 or later
*/
// $Id: WaterfallApplet.java 762 2011-05-31 07:50:58Z radioecology $
// TODO : Initiering av scrollbar - må hindre at plottet hopper til slutten etter å ha blitt lest inn OK
// TODO : End of data set vises når det ikke skulle ha vært vist ifm scrolling. OK
// TODO: BUG: Vil ikke scrolle helt til slutten med scrollbar - hopper tilbake til posisjonen den hadde før scroll.
import java.applet.AppletContext;
import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.*;
//import java.util.Date;
public class WaterfallApplet extends JApplet {
private Waterfall waterfall;
private JScrollBar scroller;
public static JLabel timestamp;
public static JLabel infolabel;
static JFrame f;
AppletContext appletContext;
public static String codebase;
public static JButton BtMeta, BtLink, BtSaveHit, BtPrev, BtNext, BtUp, BtDn;
public static JToggleButton BtRunwf,BtSpeed;
private static final String NEXT_PAGE = "Next";
private static final String PREVIOUS_PAGE = "Prev";
private static final String NEXT_PAGE_AC = "SHOW NEXT PAGE";
private static final String PREV_PAGE_AC = "SHOW PREV PAGE";
private Timer updateScroller;
private static final String DOWN_ARROW="D";
private static final String DOWN_ARROW_AC="MOVE_MARKER_DOWN";
private static final String UP_ARROW="U";
private static final String UP_ARROW_AC="MOVE_MARKER_UP";
private long lastscroll=0; // Time of last scroller movement
JComboBox CBDataSet;
JTextField TFMax;
private String unit,selectedsystem="",selectedproject="";
JCheckBox CbLog;
Waterfall wf;
Legend legend;
private boolean fetchall=false;
public long getlastscroll(){
return lastscroll;
}
public void resetlastscroll(){
// for use when a scroll event has been finished
lastscroll=0;
}
public void setScrollmax(int max){
scroller.setMaximum(max);
scroller.setVisibleAmount(wf.getH());
}
public void setScrollvalue(int val){
scroller.setValue(val);
}
public void getScrollvalue(){
scroller.getValue();
}
public int wftotal(){
if(!(wf==null)){
return wf.getTotal();
}else{
return 1;
}
}
public int wffollower(){
if(!(wf==null)){
return wf.getFollower();
}else{
return 1;
}
}
public void scrollto(){
//System.out.println("-->"+scroller.getValue());
if(scroller.getValue()>0){
wf.drawnew(scroller.getValue(),false);
}
}
public WaterfallApplet () {
updateScroller = new Timer(200, new UpdateScroller(this));
updateScroller.start();
}
/* Reads parameters from the html file;
unit . if set to ch, the waterfallplot is shown with channels as
units along the x-axis. In other cases the unit is keV
dataset: Name of a dataset to be opened at startup
id; id of a spectrum that is to be marked at startup. Id must be within
the selected dataset,
*/
public void init() {
System.out.println("WaterfallApplet svn $Revision: 762 $ loaded");
codebase=this.getCodeBase().toString();
unit= getParameter("unit");
unit=unit==null?"keV":unit;
buildUI();
String parameter=getParameter("dataset");
if(!(parameter==null)){
selectedproject="";
selectedsystem="";
fetchall=true; // Must load all sets
loadCBDataSet(fetchsetlist());
fetchall=false; // Do not want all sets
CBDataSet.setSelectedItem(parameter);
String selected=(String)CBDataSet.getSelectedItem();
if(selected.equals(parameter)){
startwaterfall();
}
}
parameter=getParameter("id");
if(!(parameter==null || parameter.equals(""))){
try{
int marked=Integer.valueOf(parameter.trim()).intValue();
wf.setmarked(marked);
wf.drawnew(marked+200,true);
}
catch (NumberFormatException e){e.printStackTrace();}
}
}
public String[] fetchsetlist(){
String [] datasets=new String[500]; // TODO - use a more sensible data type
try {
String ajaxstring="/ajaxserver.php?a=listsets";
if(fetchall){
ajaxstring+="&fetchall=fetchall";
}
if(!(selectedsystem.equals(""))){
ajaxstring+="&system="+URLEncoder.encode(selectedsystem,"utf8");
}
if(!(selectedproject.equals(""))){
ajaxstring+="&project="+URLEncoder.encode(selectedproject,"utf8");
}
//System.out.println(ajaxstring);
URL ajaxserver = new URL(WaterfallApplet.codebase+ajaxstring );
URLConnection conn=ajaxserver.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
int i =0;
String decodedString;
while ((decodedString = in.readLine()) != null) {
datasets[i++] = decodedString;
//System.out.println(decodedString);
}
in.close();
}
catch (MalformedURLException e) {e.printStackTrace();}
catch(IOException e){e.printStackTrace();}
return datasets;
}
private void loadCBDataSet(String[] list){
CBDataSet.removeAllItems();
for (int i=0;i<list.length;i++){
// System.out.println(list[i]);
if (!(list[i]==(null))){
CBDataSet.addItem(list[i]);
}else {i=list.length;}
}
}
public void buildUI() {
wf=new Waterfall(0,512);
wf.setPlotkeV(!unit.equals("ch"));
legend=new Legend(Legend.DEFAULTMAX);
scroller=new JScrollBar();
scroller.setVisibleAmount(wf.getH());
add(legend,BorderLayout.EAST);
add(scroller,BorderLayout.WEST);
scroller.addAdjustmentListener(new AdjustmentListener() {
public void adjustmentValueChanged(AdjustmentEvent e){
lastscroll=System.currentTimeMillis();
}
}
);
Font font = new Font("Dialog", Font.PLAIN, 11);
setFont(font);
CBDataSet=new JComboBox();
loadCBDataSet(fetchsetlist());
CBDataSet.setFont(font);
JButton BtLoad=new JButton("Load data");
DataLoader dataLoader=new DataLoader();
BtLoad.addActionListener(dataLoader);
timestamp=new JLabel("");
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.HORIZONTAL;
//gbc.weightx = 0.5;
gbc.insets=new Insets(2,2,0,2);
timestamp.setPreferredSize(new Dimension(200,20));
JPanel Pnorth=new JPanel(new GridBagLayout());
TFMax=new JTextField(""+Legend.max,4);
BtLink=new JButton("Specter");
BtLink.setEnabled(false);
BtLink.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
try{
appletContext=getAppletContext();
String url="/specter.php?id="+Integer.toString(wf.getMarked());
url+=wf.getInttime()>0?"&inttime="+Integer.toString(wf.getInttime()):"";
appletContext.showDocument(new URL(WaterfallApplet.codebase+url),"specter");
}catch (IOException IOe) {IOe.printStackTrace();}
}
});
BtMeta=new JButton("Data info");
FileInfoViewer fileInfoViewer= new FileInfoViewer();
BtMeta.addActionListener(fileInfoViewer);
BtMeta.setEnabled(false);
JButton BtSetMax=new JButton("Set");
LegendSetter setLegend=new LegendSetter();
BtSetMax.addActionListener(setLegend);
BtSaveHit=new JButton("Save hit");
BtSaveHit.setEnabled(false);
BtSaveHit.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
try{
URL ajaxserver = new URL(WaterfallApplet.codebase+"/ajaxserver.php?a=savehit&rawdataid=" +Integer.toString(wf.getMarked())+"&fileid="+Integer.toString(wf.getDatasetid()) );
URLConnection conn=ajaxserver.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
in.close();
}
catch (MalformedURLException SaveHitMUe) { SaveHitMUe.printStackTrace();}
catch(IOException SaveHitIOe){SaveHitIOe.printStackTrace();}
};
});
CbLog= new JCheckBox("Log");
MarkAdjuster markAdjuster=new MarkAdjuster();
java.net.URL upurl=this.getClass().getResource("up_arrow.png");
BtUp = new JButton(new ImageIcon(upurl));
BtUp.setEnabled(false);
BtUp.setActionCommand(UP_ARROW_AC);
BtUp.addActionListener(markAdjuster);
java.net.URL dnurl=this.getClass().getResource("dn_arrow.png");
BtDn = new JButton(new ImageIcon(dnurl));
BtDn.setEnabled(false);
BtDn.setActionCommand(DOWN_ARROW_AC);
BtDn.addActionListener(markAdjuster);
gbc.gridx=0;gbc.gridy=0;gbc.gridwidth=2;gbc.weightx=0.5;
Pnorth.add(BtSaveHit,gbc);
gbc.gridx=2;gbc.gridy=0;gbc.gridwidth=2;gbc.weightx=0.5;
Pnorth.add(BtLink,gbc);
gbc.gridx=4;gbc.gridy=0;gbc.gridwidth=1;gbc.weightx=0.5;
Pnorth.add(BtUp,gbc);
gbc.gridx=5;gbc.gridy=0;gbc.gridwidth=1;gbc.weightx=0.5;
Pnorth.add(BtDn,gbc);
gbc.gridx=6;gbc.gridy=0;gbc.gridwidth=2;gbc.weightx=0.5;
Pnorth.add(new JLabel(" Max value :"),gbc);
gbc.gridx=10;gbc.gridy=0;gbc.gridwidth=1;gbc.weightx=0.5;
Pnorth.add(BtSetMax,gbc);
gbc.gridx=0;gbc.gridy=1;gbc.gridwidth=4;
Pnorth.add(timestamp,gbc);
gbc.gridx=4;gbc.gridy=1;gbc.gridwidth=3;
Pnorth.add(infolabel=new JLabel(" "),gbc);
gbc.gridx=7;gbc.gridy=1;gbc.gridwidth=3;
Pnorth.add(TFMax,gbc);
gbc.gridx=10;gbc.gridy=1;
Pnorth.add(CbLog,gbc);
Pnorth.doLayout();
add("North", Pnorth);
BtRunwf = new JToggleButton("Run");
BtRunwf.setEnabled(false);
BtRunwf.setPreferredSize(new Dimension(70, 25));
BtRunwf.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
wf.toggleActive();
wf.endrepeats=0;
};
});
BtSpeed = new JToggleButton("Fast");
BtSpeed.setPreferredSize(new Dimension(70, 25));
BtSpeed.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
//wf.readtimer.setDelay(BtSpeed.isSelected()?Waterfall.HISPEED:Waterfall.LOWSPEED);
wf.hispeed(BtSpeed.isSelected());
};
});
add("Center", wf);
DataPager dataPager=new DataPager();
BtNext = new JButton(NEXT_PAGE);
BtNext.setEnabled(false);
BtNext.setActionCommand(NEXT_PAGE_AC);
BtNext.addActionListener(dataPager);
BtPrev = new JButton(PREVIOUS_PAGE);
BtPrev.setEnabled(false);
BtPrev.setActionCommand(PREV_PAGE_AC);
BtPrev.addActionListener(dataPager);
JPanel Psouth=new JPanel(new GridBagLayout());
DataSetDialog DSD=new DataSetDialog();
JButton BtReload = new JButton("Reload datasets");
BtReload.addActionListener(DSD);
int x=0,y=0;
gbc.gridx=x++;gbc.gridy=y;gbc.gridwidth=1;
Psouth.add(CBDataSet,gbc);
gbc.gridx=x++;gbc.gridy=y;gbc.gridwidth=1;
Psouth.add(BtLoad,gbc);
gbc.gridx=x++;gbc.gridy=y;gbc.gridwidth=1;
Psouth.add(BtRunwf,gbc);
gbc.gridx=x++;gbc.gridy=y;gbc.gridwidth=1;
Psouth.add(BtSpeed,gbc);
x=0;
gbc.gridx=x++;gbc.gridy=++y;gbc.gridwidth=1;
Psouth.add(BtReload,gbc);
gbc.gridx=x++;gbc.gridy=y;gbc.gridwidth=1;
Psouth.add(BtMeta,gbc);
gbc.gridx=x++;gbc.gridy=y;gbc.gridwidth=1;
Psouth.add(BtPrev,gbc);
gbc.gridx=x++;gbc.gridy=y;gbc.gridwidth=1;
Psouth.add(BtNext,gbc);
Psouth.setPreferredSize(new Dimension(300, 70));
Pnorth.setPreferredSize(new Dimension(300, 60));
Psouth.doLayout();
add("South",Psouth);
invalidate();
}
// This class shows a dialog box for reloading of datasets
private class DataSetDialog implements ActionListener{
private JFrame fr;
private void initDialog(){
fr=new JFrame();
JPanel pan = new JPanel(new GridBagLayout()); //
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.insets=new Insets(2,2,0,2);
gbc.gridx=0;gbc.gridy=0;gbc.gridwidth=1;
String[] nullstring={""};
final JComboBox CbProject=new JComboBox(nullstring);
pan.add(new JLabel("Projects :"),gbc);
gbc.gridx=1;gbc.gridy=0;gbc.gridwidth=2;
pan.add(CbProject,gbc);
final JComboBox CbSystem=new JComboBox(nullstring);
gbc.gridx=0;gbc.gridy=1;gbc.gridwidth=1;
pan.add(new JLabel("Systems :"),gbc);
gbc.gridx=1;gbc.gridy=1;gbc.gridwidth=2;
pan.add(CbSystem,gbc);
gbc.gridx=0;gbc.gridy=2;gbc.gridwidth=1;
final JCheckBox CbAll=new JCheckBox("Show all");
pan.add(CbAll,gbc);
JButton BtOK=new JButton("OK");
BtOK.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
selectedsystem=""+CbSystem.getSelectedItem();
selectedproject=""+CbProject.getSelectedItem();
fetchall=CbAll.isSelected();
loadCBDataSet(fetchsetlist());
fr.setVisible(false);
};
});
JButton BtCancel=new JButton("Cancel");
BtCancel.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
fr.setVisible(false);
};
});
gbc.gridx=1;gbc.gridy=2;gbc.gridwidth=1;
pan.add(BtOK,gbc);
gbc.gridx=2;gbc.gridy=2;gbc.gridwidth=1;
pan.add(BtCancel,gbc);
pan.doLayout();
fr.add(pan);
fr.pack();
fr.setLocationRelativeTo(null);
try{
URL ajaxserver = new URL(WaterfallApplet.codebase+"ajaxserver.php?a=listsystems&listtype=text");
URLConnection conn=ajaxserver.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String item,title="";
int i=0;
while ((item = in.readLine()) != null) {
if(item.equals(":===:")){
title = in.readLine();
item = in.readLine(); // the next item
}
if(title.equals("system")){CbSystem.addItem(item);}
if(title.equals("project")){CbProject.addItem(item);}
}
in.close();
}
catch (MalformedURLException e) {e.printStackTrace();}
catch(IOException e){e.printStackTrace();}
}
public void actionPerformed(ActionEvent e){
if (fr==null){initDialog();}
fr.setVisible(true);
};
}
private void startwaterfall(){
try {
URL ajaxserver = new URL(WaterfallApplet.codebase+"/ajaxserver.php?a=getstart&dataset="+CBDataSet.getSelectedItem()+"&offset="+Integer.toString(wf.getH()) );
URLConnection conn=ajaxserver.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
wf.setDatasetid(Integer.valueOf(in.readLine().trim()).intValue());
int startid=Integer.valueOf(in.readLine().trim()).intValue();
String calibdata=in.readLine();
calibdata=calibdata.isEmpty()?in.readLine():calibdata;
wf.calibrate(calibdata);
wf.drawnew(startid,true); // The end of the first screenfull of data
wf.removeMarked();
in.close();
infolabel.setText("");
BtRunwf.setEnabled(wf.getDatasetid()>0);
BtPrev.setEnabled(wf.getDatasetid()>0);
BtNext.setEnabled(wf.getDatasetid()>0);
BtMeta.setEnabled(wf.getDatasetid()>0);
}
catch (MalformedURLException rde) {rde.printStackTrace();}
catch(IOException rde){rde.printStackTrace();}
}
private class DataLoader implements ActionListener{
public void actionPerformed(ActionEvent e){
startwaterfall();
};
}
private class MarkAdjuster implements ActionListener{
// Moves the mark one spectre up or down
// Thanks to http://www.java-forums.org/java-applets/18142-closing-popup-jframe-applet.html
// where I was looking for something else but came across how to write a common event handler
public void actionPerformed(ActionEvent e){
try {
String command=e.getActionCommand();
int mark=wf.getMarked();
mark=wf.nextMark(mark,command==DOWN_ARROW_AC);
wf.setmarked(mark);
}
catch(WaterfallException wfe) {System.out.println("Kan ikke justere posisjon");}
};
}
private class DataPager implements ActionListener{
// Tells the waterfall to go one page up or down
public void actionPerformed(ActionEvent e){
String command=e.getActionCommand();
System.out.println('<'+command+'>');
int delta=300; // a bit less than the height, makes it easier to keep the overview
delta=command==NEXT_PAGE_AC?delta:-1*delta;
int index=wf.getIndex();
wf.drawnew(index+delta,true);
};
}
private class FileInfoViewer implements ActionListener {
// Fetches info on the current dataset, displays it verbatim in a dialogbox.
public void actionPerformed(ActionEvent e) {
String info="";
try{
URL ajaxserver = new URL(WaterfallApplet.codebase+"/ajaxserver.php?a=fileinfo&fileid="+Integer.toString(wf.getDatasetid()) );
URLConnection conn=ajaxserver.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
info=in.readLine();
in.close();
}
catch (MalformedURLException SaveHitMUe) { SaveHitMUe.printStackTrace();}
catch(IOException SaveHitIOe){SaveHitIOe.printStackTrace();}
int n = JOptionPane.showConfirmDialog(
f,info,"Current dataset",
JOptionPane.YES_NO_OPTION);
if(n == JOptionPane.YES_OPTION){ // Opens up a web page for details /editing of the information
try{
appletContext=getAppletContext();
appletContext.showDocument(new URL(WaterfallApplet.codebase+"data.php?table=datafile&id="+Integer.toString(wf.getDatasetid())),"datawindow");
}catch (IOException IOe) {IOe.printStackTrace();}
}
}
}
private class LegendSetter implements ActionListener
// Sets the scale and log/lin status of the legend
{
public void actionPerformed(ActionEvent e){
float oldmax=legend.max;
try{
legend.max=Float.valueOf(TFMax.getText().trim()).floatValue();
if (legend.max<0){
legend.max=legend.DEFAULTMAX;
TFMax.setText(Float.toString(legend.max));
}
}catch (NumberFormatException numexp)
{
TFMax.setText(Float.toString(legend.max));
}
if (legend.max != oldmax || legend.getLog()!=CbLog.isSelected()){
// Will not redraw the plot if nothing is changed
legend.setLog(CbLog.isSelected());
legend.repaint();
if(wf.getDatasetid()>0){ // No reason to redraw if scale is changed before any data are loaded
wf.drawnew(wf.getIndex(),true);
}
} /*
This reloads the dataset from the server.
May have backup store in an array. More mem use
on the client, less network traffic and less load
on the data base server.
*/
};
}
public static void main(String s[]) {
f = new JFrame("Waterfall plot");
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {System.exit(0);}
});
WaterfallApplet wfa = new WaterfallApplet();
wfa.buildUI();
f.add("Center", wfa);
f.pack();
f.setVisible(true);
}
public void paintComponent(Graphics g){
g.fillRect(0,0,500,300);
}
}
class UpdateScroller implements ActionListener{
/*
Helper class for timed updates
*/
private WaterfallApplet wfa;
public UpdateScroller(WaterfallApplet initwf){
wfa=initwf;
}
public void actionPerformed(ActionEvent e){
wfa.setScrollmax(wfa.wftotal());
long diff=System.currentTimeMillis()-wfa.getlastscroll();
if(diff>700){
// the scroller has been left alone for 0.7 secs - time for action
if(diff>1000){
// adjusts the scroller to whereever the plot is
wfa.setScrollvalue(wfa.wftotal()-wfa.wffollower());
wfa.resetlastscroll();
}else{
wfa.scrollto(); // fetches the new data set
wfa.resetlastscroll();
// System.out.println(System.currentTimeMillis()-wfa.getlastscroll());
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment