package IBA_J.resources.lib;
import ij.IJ;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.ArrayList;
import java.util.Random;
import java.util.Vector;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.ValueMarker;
import org.jfree.chart.plot.XYPlot;
/**
* CheckBoxListener is the class responsible for the events related
* with the checked / unchecked state of the checkboxes indicating the Min and MlastCheckBoxActivatedax spectra values.
* It will draw lines on the Spectra where the user has choosed energies
*/
public class CheckBoxListenerSp implements ItemListener,DocumentListener{
private XYPlotSp sourceXYPlotSp;
private ArrayList<JCheckBox> checkBoxList = new ArrayList<JCheckBox>();
private ArrayList<int[]> colorList = new ArrayList<int[]>(); //color corresponding to the checkboxes
private ArrayList<Float> lineDrewPositions = new ArrayList<Float>();
private ArrayList<ValueMarker> lineDrewMarkers = new ArrayList<ValueMarker>();
private ArrayList<int[]> lineDrewColors = new ArrayList<int[]>();
private JCheckBox lastCheckBoxActivated;
public CheckBoxListenerSp(XYPlotSp sourceXYPlotSp) {
this.sourceXYPlotSp= sourceXYPlotSp;
}
public JCheckBox getLastCheckBoxActivated(){
return lastCheckBoxActivated;
}
public boolean isNotTaken(int r, int g,int b, int numberOfCall){
//checks if the generated color is available to be used as marker
if ( g+b>(70*r/100) ) { //to avoid the red color (similar to graph color)
if(colorList.isEmpty())
return true;
//checks if the color is not already taken (or close to it)
//chooses a low treshold if numberOfCall is high
int treshold;
if(numberOfCall>40){
treshold=1;
}
else if(numberOfCall>25){
treshold=5;
}
else if(numberOfCall>10){
treshold=10;
}
else {
treshold=20;
}
for(int i=0;i<colorList.size();i++){
int[] colorRGB = colorList.get(i);
int r2=colorRGB[0], g2=colorRGB[1], b2=colorRGB[2];
if ( (r>r2+treshold || r<r2-treshold) && (g>g2+treshold || g<g2-treshold) ){
return true;
}
if ( (g>g2+treshold || g<g2-treshold) && (b>b2+treshold || b<b2-treshold) ){
return true;
}
}
}
return false;
}
/**
* this method uses a marker to draw a bouding line on the dispayed spectra's front layer.
* @param position
* @param checkBoxCurrent
*/
public void drawVerticalLine(float position, JCheckBox checkBoxCurrent){
// position is the value on the axis
ValueMarker marker = new ValueMarker(position);
Color colorToDraw;
int r=0,g=0,b=0;
if(!checkBoxList.contains(checkBoxCurrent)){
int numberOfCall=0;
while(!isNotTaken(r,g,b,numberOfCall)){
r=randInt(100,200);
g=randInt(120,220);
b=randInt(120,220);
numberOfCall++;
}
}
else {
int index=checkBoxList.indexOf(checkBoxCurrent);
int[] colorRGB = colorList.get(index);
r = colorRGB[0];
g = colorRGB[1];
b = colorRGB[2];
}
colorToDraw = new Color(0,0,0);
//colorToDraw = new Color(r,g,b);
marker.setPaint(colorToDraw);
marker.setOutlinePaint(colorToDraw);
// change line style (dashboard)
BasicStroke dashedStroke = new BasicStroke(
1.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND,
1.0f, new float[] {6.0f, 6.0f}, 0.0f);
marker.setStroke(dashedStroke);
JFreeChart chart=sourceXYPlotSp.getChart();
XYPlot XYPlotOfChart = (XYPlot) chart.getPlot();
//draw vertical line
XYPlotOfChart.addDomainMarker(marker);
int[] colorToAdd = new int[3];
colorToAdd[0]=r;
colorToAdd[1]=g;
colorToAdd[2]=b;
lineDrewPositions.add(position);
lineDrewMarkers.add(marker);
lineDrewColors.add(colorToAdd);
if (!checkBoxList.contains(checkBoxCurrent)){
checkBoxList.add(checkBoxCurrent);
colorList.add(colorToAdd);
}
}
/**
* this method removes the marker used as bouding line on the dispayed spectra's front layer.
* @param position
* @param checkBoxCurrent
*/
public void removeVerticalLine(float position,JCheckBox checkBoxCurrent){
JFreeChart chart=sourceXYPlotSp.getChart();
XYPlot XYPlotOfChart = (XYPlot) chart.getPlot();
//before remove : check if the vertical line is not the same for an other checkbox
//in this case the position is also taken in another checkbox selected
ArrayList<JCheckBox> checkBoxsSelected = sourceXYPlotSp.getSelectedCheckBox();
boolean isPresent = false;
int indexIsPresent=-1;
if (checkBoxsSelected.size()>0){//so other box are selected
Vector vectValues = sourceXYPlotSp.getValuesMinMaxNames(true,false,false);
ArrayList<float[]> minMaxSpectra = (ArrayList<float[]>) vectValues.get(1);
for(int i=0;i<minMaxSpectra.size();i++){
boolean isEqual1 = Float.compare(position,minMaxSpectra.get(i)[0])==0;
boolean isEqual2 = Float.compare(position,minMaxSpectra.get(i)[1])==0;
if (isEqual1||isEqual2) {//so no suppression
//no suppression but color may not correspond
//--> suppression then readd
isPresent=true;
indexIsPresent=i;
}
}
}
//remove vertical line
int index = lineDrewPositions.indexOf(position);
ValueMarker marker = lineDrewMarkers.get(index);
XYPlotOfChart.removeDomainMarker(marker);
lineDrewPositions.remove(position);
lineDrewMarkers.remove(marker);
lineDrewColors.remove(index);
//commented code below : if you want to NOT keep the same color after checking/unchecking one checkbox
//if (numberOfCall==2){
// int index2 = checkBoxList.indexOf(checkBoxCurrent);
// colorList.remove(index2);
// checkBoxList.remove(index2);
//}
if(isPresent){ //so need to found the right color/box and draw
//find only checkboxselected
JCheckBox checkBoxSimilarValue = checkBoxsSelected.get(indexIsPresent);
drawVerticalLine(position, checkBoxSimilarValue);
}
}
/**
* This method is called each time that a checkbox is selected/unselected
* @param e
*/
@Override
public void itemStateChanged(ItemEvent e) {
update(e.getSource());
}
public void update(Object objectActivated){
Vector vectButtons = sourceXYPlotSp.getVectButtonsSupp();
for (Object vectButton : vectButtons) {
JComponent[] tabJCompToCheck = (JComponent[]) vectButton;
JCheckBox checkBoxCurrent = (JCheckBox) tabJCompToCheck[0];
if(objectActivated==checkBoxCurrent){
if(checkBoxCurrent.isSelected())
lastCheckBoxActivated=checkBoxCurrent;
//first reset : check up; if min/max has been changed, markers' colors need to be rechecked.
// this checkbox = one color so it checks if markers of this color remain, they have to be removed.
int indexOfCheckBox = checkBoxList.indexOf(checkBoxCurrent);
if (indexOfCheckBox!=-1){
int[] colorRGBOfCheckBox=colorList.get(indexOfCheckBox);
int r=colorRGBOfCheckBox[0];
int g=colorRGBOfCheckBox[1];
int b=colorRGBOfCheckBox[2];
ArrayList<Integer> valToRemove= new ArrayList<>();
for(int j=0;j<lineDrewColors.size();j++){
int[] colorToCheck = lineDrewColors.get(j);
if (r==colorToCheck[0] && g==colorToCheck[1] && b==colorToCheck[2]){
valToRemove.add(j);
}
}
for(int j=0;j<valToRemove.size();j++){
float positionToRemove= lineDrewPositions.get(valToRemove.get(j));
removeVerticalLine(positionToRemove,checkBoxCurrent);
for(int k=0;k<valToRemove.size();k++){
valToRemove.set(k,valToRemove.get(k)-1);
}
}
}
//get the min and max values to draw
for (int j=0;j<2;j++){
JTextField textFieldMinMax = (JTextField) tabJCompToCheck[j+2];
if ( !(textFieldMinMax.getText().equals("Min") || textFieldMinMax.getText().equals("Max")) ) {
float minMax = -1;
try {
minMax = Float.valueOf(textFieldMinMax.getText());
}
catch(NumberFormatException e2){}
if (minMax>-1){
if(checkBoxCurrent.isSelected()) {
if(! lineDrewPositions.contains(minMax)){
drawVerticalLine(minMax,checkBoxCurrent);
}
}
}
}
}
}
}
}
/**
* @param min
* @param max
* @return a randomly generated number between min and max (max included)
*/
public static int randInt(int min, int max) {
// Usually this can be a field rather than a method variable
Random rand = new Random();
// nextInt is normally exclusive of the top value,
// so add 1 to make it inclusive
int randomNum = rand.nextInt((max - min) + 1) + min;
return randomNum;
}
public void handlesDocumentEvt(DocumentEvent dEvt){
int lengthText = dEvt.getDocument().getLength();
try{
String text = dEvt.getDocument().getText(0,lengthText);
JCheckBox checkBoxToUpdate = sourceXYPlotSp.getCheckBoxRelatedToField(text);
if(checkBoxToUpdate!=null && checkBoxToUpdate.isSelected()){
update(checkBoxToUpdate);
}
}
catch(BadLocationException e){}
}
@Override
public void insertUpdate(DocumentEvent dEvt) {
handlesDocumentEvt(dEvt);
}
@Override
public void removeUpdate(DocumentEvent dEvt) {
handlesDocumentEvt(dEvt);
}
@Override
public void changedUpdate(DocumentEvent e) {
//not used
}
}