package moduls.frm.children;
import inicial.Parametres_Inicials;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.Rectangle2D;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import genomeObjects.CSDisplayData;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import definicions.BoxContainer;
import definicions.Cluster;
import definicions.Config;
import definicions.Dimensions;
import parser.EscalaFigures;
import parser.EscaladoBox;
import parser.Fig_Pizarra;
import parser.figures.Cercle;
import parser.figures.Escala;
import parser.figures.Linia;
import parser.figures.Marge;
import parser.figures.NomsDendo;
import parser.figures.NomsLabelsEscala;
import tipus.Orientation;
import tipus.rotacioNoms;
import utils.BoxFont;
import newickTreeParsing.Tree;
import newickTreeParsing.TreeNode;
import moduls.frm.ContextLeaf;
import moduls.frm.FrmPrincipalDesk;
import moduls.frm.XYBox;
public class FrmPhylo extends JPanel implements MouseListener{
//fields
//baseline
private FrmPrincipalDesk fr;
private CSDisplayData CSD;
// =========== Borrowed from FrmPiz ===================/
// ---- Drawing -----
// Conversion of tree -> figures
private LinkedList<?>[] figures = { new LinkedList<Cercle>(),
new LinkedList<Linia>(), new LinkedList<Marge>() };
private static final int CERCLE = 0;
private static final int LINIA = 1;
private static final int MARGE = 2;
//Drawing / painting related
private Graphics2D g;
private int LastSelectedNode = -1;
private Rectangle2D[] RectanglesSurroundingLabels;
// ----- Configurataion + Parameters ---------//
//Configuration related
private Config cfg = null;
private double radi;
private int numClusters;
private Orientation orientacioClusters = Orientation.EAST;
private rotacioNoms orientacioNoms = rotacioNoms.HORITZ;
//Component Sizes
private double val_Max_show; //size to show
private double val_Min_show;
double width_dendograma = 0.0; //dendrogram sizes
double height_dendograma = 0.0;
double width_escala = 0.0; //scale sizes
double height_escala = 0.0;
double height_butlles = 0.0; //circle sizes
double width_butlles = 0.0;
double width_lbl_escala = 0.0; //scale label
double height_lbl_escala = 0.0;
double width_nom_nodes = 0.0; //Node names
double height_nom_nodes = 0.0;
private String max_s = "";
private double VerticalRenderScaleFactor = 1.0; //JPanel stretching parameters
private double HorizontalRenderScaleFactor = 1.0;
//Scale boxes (for graphical rendering)
private EscaladoBox parserDendograma = null;
private EscaladoBox parserBulles = null;
private EscaladoBox parserEscala = null;
private EscaladoBox parserNoms = null;
private EscaladoBox parserLbl = null;
//constructor
public FrmPhylo(FrmPrincipalDesk f, CSDisplayData CSD){
this.fr = f;
this.CSD = CSD;
this.addMouseListener(this);
}
// ------------- Methods from FrmPiz -------------- //
//====== Configuration/Setting - type methods =====//
//Figure import and parsing + configuration related
public void setFigures(final LinkedList[] lst) {
this.setFigura(lst);
}
public void setFigura(LinkedList figura[]) {
this.figures = figura;
}
public LinkedList[] getFigura() {
return figures;
}
public void setConfig(Config cfg) {
this.cfg = cfg;
radi = cfg.getRadi();
numClusters = fr.getPanBtn().getPhyloTreeLeaves();
orientacioClusters = cfg.getOrientacioDendo();
orientacioNoms = cfg.getOrientacioNoms();
//old way
val_Max_show = cfg.getValorMaxim();
val_Min_show = cfg.getValorMinim();
// //new way!
// val_Max_show = fr.getPanBtn().val_Max_show_Phylo;
// val_Min_show = 0;
}
//====== Drawing Methods =========================//
//Set all size parameters for all dendrogram objects.
private void setAmplades(Graphics2D g) {
final Orientation or = cfg.getOrientacioDendo();
/* dendrogram */
if (Orientation.NORTH.equals(or) || Orientation.SOUTH.equals(or)) {
width_dendograma = this.AmpladaBoxClusters();
height_dendograma = val_Max_show - val_Min_show;
} else {
width_dendograma = val_Max_show - val_Min_show;
//width_dendograma = 400; //no effect
height_dendograma = this.AmpladaBoxClusters();
}
/* show the scale */
if (cfg.getConfigMenu().isEscalaVisible()) {
/* size of the scale */
if (Orientation.NORTH.equals(or) || Orientation.SOUTH.equals(or)) {
width_escala = 2 * radi; // east and west
height_escala = val_Max_show - val_Min_show;
} else {
height_escala = 2 * radi; // north and south
width_escala = val_Max_show - val_Min_show;
//Reading width = 1.0, height = 10.0
//System.out.println("Width: " + width_escala + " Height: " + height_escala);
}
} else {
width_escala = 0;
height_escala = 0;
}
/*
* Comments:
* commenting out this whole section removes bullets, but changing the size
* of rr or the quantities of rr doesn't chage anything.
*/
/* show the bullets */ //rr = node size
double rr = cfg.getConfigMenu().getRadiBullets();
//System.out.println("rr is " + rr);
if ((rr = cfg.getConfigMenu().getRadiBullets()) > 0) {
if (Orientation.NORTH.equals(or) || Orientation.SOUTH.equals(or)) {
width_butlles = this.AmpladaBoxClusters();
height_butlles = 2 * rr;
} else {
width_butlles = 2 * rr;
height_butlles = 2*this.AmpladaBoxClusters();
}
} else {
width_butlles = 0;
height_butlles = 0;
}
/* show the labels of the scale */
if (cfg.getConfigMenu().isEtiquetaEscalaVisible()) {
final BoxFont bf = new BoxFont(cfg.getConfigMenu().getFontLabels());
String txt;
int ent;
Dimensions<Double> dim;
ent = (int) Math.round(val_Max_show);
txt = Integer.toString(ent);
if (Orientation.EAST.equals(or) || Orientation.WEST.equals(or)) {
if (cfg.isTipusDistancia()) {
dim = bf.getBoxNumberNatural(90, (txt.trim()).length(),
cfg.getAxisDecimals());
} else {
dim = bf.getBoxNumberEnters(90, (txt.trim()).length(),
cfg.getAxisDecimals());
}
} else {
if (cfg.isTipusDistancia()) {
dim = bf.getBoxNumberNatural(0, (txt.trim()).length(),
cfg.getAxisDecimals());
} else {
dim = bf.getBoxNumberEnters(0, (txt.trim()).length(),
cfg.getAxisDecimals());
}
}
width_lbl_escala = dim.getWidth();
height_lbl_escala = dim.getHeight();
} else {
width_lbl_escala = 0;
height_lbl_escala = 0;
}
/* names of the bullets */
if (cfg.getConfigMenu().isNomsVisibles()) {
int alf;
final BoxFont bf = new BoxFont(cfg.getConfigMenu().getFontNoms());
String tmp;
Dimensions<Double> dim;
/* width of names of the bullets */
if (cfg.getOrientacioNoms().equals(rotacioNoms.HORITZ))
alf = 0;
else if (cfg.getOrientacioNoms().equals(rotacioNoms.INCLINAT))
alf = 45;
else
alf = -90;
if (max_s.equals("")) {
final Enumeration<String> el = cfg.getHtNoms().elements();
while (el.hasMoreElements()) {
tmp = el.nextElement();
if (tmp.length() > max_s.length())
max_s = tmp;
}
}
dim = bf.getBox(alf, max_s);
width_nom_nodes = dim.getWidth();
height_nom_nodes = dim.getHeight();
} else {
width_nom_nodes = 0;
height_nom_nodes = 0;
}
}
//determine a box of coordinates to contain all objects.
private void DesplacaPantalla(final BoxContainer b, final double h_mon) {
double h;
h = h_mon - b.getCorner_y();
b.setCorner_y(-h);
}
private double AmpladaBoxClusters() {
return ((2 * radi * numClusters) + ((numClusters - 1) * radi));
}
private void draftDendo(Graphics2D g2d) {
// LinkedList<Marge> Marges = getFigura()[2];
// for (Marge m : Marges){
// System.out.println("m, Early_Draftdendo: " + m.getPhyloWeight());
// }
//boxes (on the screen) defining coordinates for rendering
BoxContainer boxDendograma, boxBulles, boxEscala, boxEscalalbl, boxNoms;
//Set a preference for the rendering algorithms.
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
/* Symmetric frame where it won't be able to paint anything */
final double inset_Mon = Parametres_Inicials.getMarco();// 15
/* World size */
final double width_Mon = this.getSize().getWidth();
final double height_Mon = this.getSize().getHeight();
// set widths ---?
this.setAmplades(g2d);
// size of the box
Dimensions<Double> m_d, m_b, m_n, m_e, m_l;
m_d = new Dimensions<Double>(width_dendograma, height_dendograma);
// bullets?
m_b = new Dimensions<Double>(width_butlles, height_butlles);
m_n = new Dimensions<Double>(width_nom_nodes, height_nom_nodes);
m_e = new Dimensions<Double>(width_escala, height_escala);
m_l = new Dimensions<Double>(width_lbl_escala, height_lbl_escala);
/* Calculates the free space and places the box on the screen */
// final XYBox posbox = new XYBox(cfg, inset_Mon, width_Mon, height_Mon,
// m_d, m_b, m_n, m_e, m_l);
/*
* messing with these parameters affects how the dendogram info is displayed.
*
* width_Mon = width of the dendogram figure + labels within the frame
* height_Mon = height ''
* inset_Mon = size of border around figure
* m_* describe the dimensions (width and height) of different quantities
*
*/
//m_n = new Dimensions<Double>(width_nom_nodes, 10*height_nom_nodes);
//Added render scale factors render the vertical spacing between objects accurately.
final XYBox posbox = new XYBox(cfg, inset_Mon, HorizontalRenderScaleFactor*width_Mon,
VerticalRenderScaleFactor*height_Mon,
m_d, m_b, m_n, m_e, m_l);
//System.out.println("FrmPhylo() scale height,width: " + m_e.getHeight() + "," + m_e.getWidth());
// define the box
boxDendograma = posbox.getBoxDendo();
boxBulles = posbox.getBoxBulles();
boxEscala = posbox.getBoxEscala();
boxEscalalbl = posbox.getBoxLabelsEscala();
boxNoms = posbox.getBoxNames();
//System.out.println("boxNoms at" + boxNoms.getVal_min_X() + " by " + boxNoms.getVal_min_Y());
// locate on screen
// 'DesplacaPantalla' = scroll screen
// move box
this.DesplacaPantalla(boxDendograma, height_Mon);
this.DesplacaPantalla(boxBulles, height_Mon);
this.DesplacaPantalla(boxEscala, height_Mon);
this.DesplacaPantalla(boxEscalalbl, height_Mon);
this.DesplacaPantalla(boxNoms, height_Mon);
// reverse the axis of growth
g2d.scale(1, -1);
g2d.setBackground(Color.GREEN);
/*
* calculates the factor that allows coordinates to world coordinates screen
*/
parserDendograma = new EscaladoBox(boxDendograma);
if (cfg.getConfigMenu().getRadiBullets() > 0)
parserBulles = new EscaladoBox(boxBulles);
if (cfg.getConfigMenu().isNomsVisibles())
parserNoms = new EscaladoBox(boxNoms);
if (cfg.getConfigMenu().isEscalaVisible())
parserEscala = new EscaladoBox(boxEscala);
if (cfg.getConfigMenu().isEtiquetaEscalaVisible())
parserLbl = new EscaladoBox(boxEscalalbl);
// System.out.println("FrmPhylo.parserLbl: " + parserLbl);
// System.out.println("FrmPhylo.parserEscala: " + parserEscala);
//
// range and data type to represent
//EDIT!!!!!!!!!
// --- show things ------------------------------------------------//
final EscalaFigures ef = new EscalaFigures(val_Max_show,
val_Min_show,
cfg.getTipusMatriu(), cfg.getPrecision());
// Marge m; //margin
// final Iterator<Marge> itm = ef.ParserMarge(getFigura()[MARGE])
// .iterator();
// while (itm.hasNext()) {
// m = itm.next();
// m.setEscala(parserDendograma);
// m.setColor(cfg.getConfigMenu().getColorMarge());
// m.setFilled(true);
// m.dibuixa(g2d, orientacioClusters); //draw
// }
//horizontal lines
Linia lin;
final Iterator<Linia> it = ef.ParserLinies(getFigura()[LINIA])
.iterator();
while (it.hasNext()) {
lin = it.next();
lin.setEscala(parserDendograma);
//adjustlines with appropriate information
lin.setFromPhyloTree(true);
lin.setFr(fr);
//draw lines
lin.dibuixa(g2d, orientacioClusters);
//draw lines!
//System.out.println("line: " + lin.getAlcada());
}
//vertical lines / boxes
Marge m;
final Iterator<Marge> itm2 = ef.ParserMarge(getFigura()[MARGE])
.iterator();
while (itm2.hasNext()) {
m = itm2.next();
m.setEscala(parserDendograma);
m.setColor(cfg.getConfigMenu().getColorMarge());
m.setFilled(false);
m.setFont(cfg.getConfigMenu().getFontNoms());
m.setFromPhyloTree(true);
m.setFr(fr);
m.dibuixa(g2d, orientacioClusters);
}
//show nodes (bullets)
if (cfg.getConfigMenu().getRadiBullets() > 0) {
final Iterator<Cercle> itc = getFigura()[CERCLE].iterator();
while (itc.hasNext()) {
final Cercle cer = itc.next();
cer.setEscala(parserBulles);
cer.dibuixa(g2d, orientacioClusters);
}
}
//show names of nodes
if (cfg.getConfigMenu().isNomsVisibles()) {
NomsDendo nomsD;
nomsD = new NomsDendo(getFigura()[CERCLE], cfg.getTipusMatriu());
nomsD.setEscala(parserNoms);
nomsD.setColor(cfg.getConfigMenu().getColorNoms());
nomsD.setFont(cfg.getConfigMenu().getFontNoms());
nomsD.dibuixa(g2d, orientacioClusters, orientacioNoms);
//retrieve rectangles from names
this.setRectanglesSurroundingLabels(nomsD.getRectangles());
//Map info to contexts
CSD.setPhyloCoordinates(nomsD.getRectangles());
CSD.setPhyloNodeNames(nomsD.getNodeNames());
//map each graphical context to the appropriate source species, in the phylogenetic tree.
for (ContextLeaf CL : CSD.getGraphicalContexts()){
for (int i = 0; i < CSD.getPhyloNodeNames().length; i++){
if (CL.getSourceSpecies().equals(CSD.getPhyloNodeNames()[i])){
CL.setPhyloTreeCoordinates(CSD.getPhyloCoordinates()[i]);
CL.setPhyloTreeNodeNameNumber(i);
break;
}
}
}
//
// //initialize all nodes as unselected
// boolean[] InitialNodeNumbers = new boolean[RectanglesSurroundingLabels.length];
// Arrays.fill(InitialNodeNumbers, Boolean.FALSE);
// this.setSelectedNodeNumbers(InitialNodeNumbers);
}
// show scale
if (cfg.getConfigMenu().isEscalaVisible()) {
Escala esc;
if (orientacioClusters.equals(Orientation.WEST)
|| orientacioClusters.equals(Orientation.EAST))
esc = new Escala(boxEscala.getVal_min_X(),
boxEscala.getVal_max_X(), cfg.getIncrement(),
cfg.getTics());
else
esc = new Escala(boxEscala.getVal_min_Y(),
boxEscala.getVal_max_Y(), cfg.getIncrement(),
cfg.getTics());
esc.setEscala(parserEscala);
esc.setColor(cfg.getConfigMenu().getColorEix());
esc.dibuixa(g2d, orientacioClusters, cfg.getTipusMatriu(),
cfg.getTics());
}
//System.out.println("FrmPhylo.draftdendo():" + boxEscala.getVal_max_X());
//show numerical scale labels
if (cfg.getConfigMenu().isEtiquetaEscalaVisible() && cfg.getTics() > 0) {
NomsLabelsEscala nomsEsc;
if (orientacioClusters.equals(Orientation.WEST)
|| orientacioClusters.equals(Orientation.EAST)) {
nomsEsc = new NomsLabelsEscala(boxEscalalbl.getVal_min_X(),
boxEscalalbl.getVal_max_X(),
boxEscalalbl.getVal_max_Y(), cfg.getIncrement(),
cfg.getTics(), cfg.getAxisDecimals());
} else {
nomsEsc = new NomsLabelsEscala(boxEscalalbl.getVal_min_Y(),
boxEscalalbl.getVal_max_Y(),
boxEscalalbl.getVal_max_X(), cfg.getIncrement(),
cfg.getTics(), cfg.getAxisDecimals());
}
nomsEsc.setEscala(parserLbl);
nomsEsc.setColor(cfg.getConfigMenu().getColorLabels());
nomsEsc.setFont(cfg.getConfigMenu().getFontLabels());
nomsEsc.dibuixa(g2d, orientacioClusters, cfg.getTipusMatriu());
}
}
public void setRectanglesSurroundingLabels(
Rectangle2D[] rectanglesSurroundingLabels) {
RectanglesSurroundingLabels = rectanglesSurroundingLabels;
}
public void paint(Graphics arg0) {
//update configuration information
//val_Max_show = fr.getPanBtn().val_Max_show_Phylo;
//System.out.println("FrmPhylo.paint(): valmax = " + val_Max_show);
//this does not seem to change much.
//this.setConfig(fr.getCurrentFrame().getInternalFrameData().getCfgp());
//basic painting parameters
super.paint(arg0);
Graphics2D g2d = (Graphics2D) arg0;
this.g = g2d;
this.draftDendo(g);
//change color for drawing
g.setPaint(Color.RED);
//boxes around nodes
for (ContextLeaf CL : CSD.getGraphicalContexts()){
if (CL.isSelected()){
if (CL.getPhyloTreeCoordinates() != null){
g.draw(CL.getPhyloTreeCoordinates());
}
}
}
//reset color
g.setPaint(Color.BLACK);
}
//-------------- Getters and Setters -------------- //
public FrmPrincipalDesk getFr() {
return fr;
}
public void setFr(FrmPrincipalDesk fr) {
this.fr = fr;
}
public CSDisplayData getCSD() {
return CSD;
}
public void setCSD(CSDisplayData cSD) {
CSD = cSD;
}
@Override
public void mouseClicked(MouseEvent e) {
//left click
if (SwingUtilities.isLeftMouseButton(e)){
//update CSD
this.CSD = fr.getCurrentFrame().getInternalFrameData().getQD().getCSD();
int x ,y;
x = e.getX();
y = e.getY();
//initialize
boolean[] SelectedAfterClick = new boolean[RectanglesSurroundingLabels.length];
Arrays.fill(SelectedAfterClick, Boolean.FALSE);
//update with current existing set (if appropriate)
if (e.isShiftDown() == true || e.isControlDown() == true){
for (ContextLeaf CL : CSD.getGraphicalContexts()){
for (int i = 0; i < CSD.getPhyloNodeNames().length; i++){
//Species Tree
if (fr.getPanPhyTreeMenu().getRadSpecies().isSelected()){
if (CL.getSourceSpecies().equals(CSD.getPhyloNodeNames()[i])){
SelectedAfterClick[i] = CL.isSelected();
break;
}
//Gene Tree
} else {
}
}
}
}
//draw a box around the correct coordinate
for (int i = 0; i < RectanglesSurroundingLabels.length; i++){
Point p = new Point(x,-y);
if (RectanglesSurroundingLabels[i].contains(p)){
if (e.isShiftDown() == false && e.isControlDown() == false){
SelectedAfterClick[i] = true; //no button
} else if (e.isShiftDown() == false && e.isControlDown() == true){
if (SelectedAfterClick[i] == true){
SelectedAfterClick[i] = false;
} else {
SelectedAfterClick[i] = true;
}
} else {
if (LastSelectedNode != -1){
//determine relative location of selected node to current shift+clicked node
if (LastSelectedNode <= i){
for (int j = LastSelectedNode; j<= i; j++){
SelectedAfterClick[j] = true;
}
} else {
for (int j = LastSelectedNode; j >= i; j--){
SelectedAfterClick[j] = true;
}
}
} else {
SelectedAfterClick[i] = true; //no previous selected node
}
}
//update last selected node
LastSelectedNode = i;
}
}
//update status of currently selected nodes
for (ContextLeaf CL : CSD.getGraphicalContexts()){
//initially, de-select.
CL.setSelected(false);
//option to re-select?
for (int i = 0; i < CSD.getPhyloNodeNames().length; i++){
//Species Tree
if (fr.getPanPhyTreeMenu().getRadSpecies().isSelected()){
if (CL.getSourceSpecies().equals(CSD.getPhyloNodeNames()[i])){
CL.setSelected(SelectedAfterClick[i]);
}
//Gene Tree
} else {
}
}
}
//update master CSD
fr.getCurrentFrame().getInternalFrameData().getQD().setCSD(CSD);
//call main frame to update this and all other panels
this.fr.UpdateSelectedNodes();
}
}
@Override
public void mouseEntered(MouseEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void mouseExited(MouseEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void mousePressed(MouseEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void mouseReleased(MouseEvent arg0) {
// TODO Auto-generated method stub
}
//update display
public void UpdateNodes(){
//retrieve most current set of selected nodes
this.CSD = fr.getCurrentFrame().getInternalFrameData().getQD().getCSD();
//repaint nodes
this.repaint();
}
}