/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Copyright (C) 2011-2012 Marchand Eric <ricoh51@free.fr>
This file is part of Freegressi.
Freegressi is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Freegressi is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Freegressi. If not, see <http://www.gnu.org/licenses/>.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
package freegressi.fit;
import beans.JLabelRouge;
import beans.JTextFieldSouligne;
import freegressi.fit.Fit.TendanceType;
import freegressi.fit.FitModel.TendanceChangedEvent;
import freegressi.fit.FitModel.TendanceCreatedEvent;
import freegressi.fit.FitModel.TendanceDeletedEvent;
import freegressi.parser.Verificateur;
import freegressi.tableur.Noeud;
import freegressi.tableur.Sym;
import freegressi.tableur.Tableur;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
/**
* Classe qui doit disparaitre
* @author marchand
*/
public class JPanelTend extends JPanel implements ActionListener, FitListener,
ChangeListener {
/** le combo qui reçoit la liste des tendances possibles */
private JComboBox jcType = new JComboBox();
/** Le combo qui choisit la variable Y */
private JComboBox jcY = new JComboBox();
/** Le combo qui choisit la variable X */
private JComboBox jcX = new JComboBox();
/** le JTextField qui reçoit le résultat de la régression */
private JTextField jtfResultat = new JTextField();
/** Le JTextField qui reçoit le résultat de l'écart expérience-modèle */
private JTextField jtfEcartRelatif = new JTextField();
/** Un flag qui demande de ne pas répondre aux actions pendant l'initialisation */
private boolean nePasRepondre;
/** Action de supprimer une courbe de tendance */
private SupprimeAction supprimeAction = new SupprimeAction("Supprimer",
new javax.swing.ImageIcon(getClass().getResource("/freegressi/img/Gnome-edit-delete-24.png")),
"Supprimer cette courbe de tendance", 0);
/** Le bouton supprimer */
private JButton jbSupp = new JButton(supprimeAction);
/** Un handle pour numéroter les tendances et les reconnaitre */
private int numero;
/** La tendance en cours dans ce JPanelTend */
//private Fit tendanceEnCours/* = new Fit()*/;
/** le textfield qui reçoit l'expression manuelle */
private JTextFieldSouligne jtfsExpression = new JTextFieldSouligne(Color.RED);
/** le label indiquant une erreur dans l'expression manuelle */
private JLabelRouge jlErreur = new JLabelRouge();
/** le label qui contient le nom de la série Y */
private JLabel jlNomY = new JLabel();
/** */
private JCheckBox jcDroite = new JCheckBox("Prolonger la droite sur le graphique");
/** la ligne du layout contenant l'expression manuelle */
// private ISpannableGridRow ligneManuelle;
// /** la ligne du layout contenant l'erreur de frappe éventuelle */
// private ISpannableGridRow ligneErreur;
// /** la ligne du layout contenant le degré du polynome */
// private ISpannableGridRow ligneDegre;
// /** la ligne du layout contenant le choix de prolonger les droites */
// private ISpannableGridRow ligneDroite;
/** Le spinner qui contient les degres possibles de polynome */
private JSpinner jsDegres = new JSpinner(new SpinnerNumberModel(2, 0, 9, 1));
private Tableur tableur;
private FitModel tendanceModel;
private Fit oldTendance;
public JPanelTend(Fit tendance) {
oldTendance = tendance;
this.numero = tendance.getNumero();
this.tendanceModel = FitModel.getInstance();
this.tableur = tendance.getTableur();
nePasRepondre = true;
creerUI();
initFields(tendance);
//@TODO Attention le graphe n'est pas créé quand on rajoute une deuxième variable!!
// String nomY = evaluateur.getJpg().getGraphe().getListeDonnees().get(0).getNom();
// String nomX = evaluateur.getJpg().getGraphe().getDonneesX().getNom();
//@TODO à changer
// String nomY = tendance.getNomY();
// String nomX = tendance.getNomX();
//
//
// List<String> ls = tableur.donneListeNoms();
// int indexY = ls.lastIndexOf(nomY);
// jcY.setSelectedIndex(indexY);
// jlNomY.setText(nomY + " =");
// int indexX = ls.lastIndexOf(nomX);
// jcX.setSelectedIndex(indexX);
nePasRepondre = false;
//tendanceEnCours = tendance;
// tendanceEnCours.setMinX(tableur.donneColonne(nomX).getMin());
// tendanceEnCours.setMaxX(tableur.donneColonne(nomX).getMax());
// remplitTendanceEnCours();
//tendanceModel.addTendanceListener(this);
//tendanceModel.notifyAjouteTendance(tendanceEnCours);
//jcType.actionPerformed(null);
// jcType.setSelectedIndex(0);
modifyJCType();
//tendanceModel.notifyModifieTendance(tendanceEnCours);
}
/** Créé l'interface graphique en utilisant le designgridlayout */
private void creerUI() {
Border blackline = BorderFactory.createLineBorder(Color.black);
setBorder(blackline);
// Les combos
remplirComboType();
jcType.addActionListener(this);
remplirCombosXY();
jcY.addActionListener(this);
jcX.addActionListener(this);
// Le spinner de degres du polynome
jsDegres.addChangeListener(this);
//jsDegres.getEditor().
// le JTextFieldSouligne qui reçoit la formule
jtfsExpression.addActionListener(this);
jtfsExpression.addKeyListener(new java.awt.event.KeyAdapter() {
@Override
public void keyReleased(java.awt.event.KeyEvent evt) {
jtfsKeyReleased(evt);
}
});
jtfResultat.setEditable(false);
jtfEcartRelatif.setEditable(false);
// Le layout
// DesignGridLayout layout = new DesignGridLayout(this);
// layout.labelAlignment(LabelAlignment.RIGHT);
//
// layout.row().grid(new JLabel("Régression " + numero + " :")).add(jcY);
// layout.row().grid(new JLabel("fonction de :")).add(jcX);
// layout.row().grid(new JLabel("Type :")).add(jcType);
// ligneManuelle = layout.row().grid(jlNomY).add(jtfsExpression);
// ligneErreur = layout.row().grid().add(jlErreur);
// ligneDegre = layout.row().grid(new JLabel("De degré : ")).add(jsDegres).empty().empty();
// ligneDroite = layout.row().grid().add(jcDroite);
// layout.row().grid(new JLabel("Résultat :")).add(jtfResultat);
// layout.row().grid(new JLabel("Écart :")).add(jtfEcartRelatif);
// layout.row().grid().add(jbSupp);
}
private void initFields(Fit tendance){
nePasRepondre = true;
jcY.setSelectedItem(tendance.getNomY());
jcX.setSelectedItem(tendance.getNomX());
jcType.setSelectedIndex(tendance.getType().getNumero());
jcDroite.setSelected(tendance.isProlongLine());
jsDegres.setValue(tendance.getDegrePolynome());
jtfsExpression.setText(tendance.getExpression());
jlErreur.setText("");
jlNomY.setText(tendance.getNomY() + " =");
jtfResultat.setText(tendance.getResultat());
jtfEcartRelatif.setText(tendance.getEcart());
nePasRepondre = false;
}
public void setTableur(Tableur tableur) {
this.tableur = tableur;
}
public int getNumero() {
return numero;
}
/**
* Remplit je combo jcType avec tous les types de tendances possibles
*/
private void remplirComboType() {
jcType.removeAllItems();
for (TendanceType tendanceType : TendanceType.values()) {
jcType.addItem(tendanceType.getLabel());
}
}
private void remplirCombosXY() {
List<String> ls = tableur.donneListeNoms();
jcY.removeAllItems();
for (int i = 0; i < ls.size(); i++) {
jcY.addItem(ls.get(i));
}
jcX.removeAllItems();
for (int i = 0; i < ls.size(); i++) {
jcX.addItem(ls.get(i));
}
}
/**
* Appelée à chaque frappe dans le textfieldExpression
* @param evt
*/
private void jtfsKeyReleased(java.awt.event.KeyEvent evt) {
Noeud noeud;
noeud = Verificateur.parseExpressionTendance(jtfsExpression.getText(), jcX.getSelectedItem().toString());
if (noeud == null) {
jlErreur.setText("Vous devez entrer une expression!");
jtfsExpression.effaceTout();
} else {
if (noeud.getType() == Sym.ERROR || noeud.getType() == Sym.PARSER_ERROR || noeud.getType() == Sym.PARSER_COHERENCE_ERROR) {
jlErreur.setText(noeud.getTexteErreur());
jtfsExpression.souligne(noeud.getColonne(), noeud.getColonne() + 1);
} else {
jlErreur.setText(" ");
jtfsExpression.effaceTout();
//remplitTendanceEnCours();
if (nePasRepondre) {
return;
}
tendanceModel.notifyModifieTendance(oldTendance, getTendance());
}
}
}
/**
* Cache les lignes qui étaient précédemment visibles, attention les lignes
* du designgridlayout empilent les appels à hide ou show
*/
private void hideLines(){
// if (jsDegres.isVisible())
// ligneDegre.hide();
// if (jcDroite.isVisible())
// ligneDroite.hide();
// if (jtfsExpression.isVisible()){
// ligneErreur.hide();
// ligneManuelle.hide();
// }
}
private void modifyJCType(){
// hideLines();
// int n = jcType.getSelectedIndex();
// TendanceType tt = TendanceType.numeroToTendanceType(n);
// switch (tt){
// case LINEAR:
// case AFFINE:
// ligneDroite.show();
// break;
// case POLYNOMIAL:
// ligneDegre.show();
// break;
// case HAND:
// ligneManuelle.show();
// ligneErreur.show();
// jtfsKeyReleased(null);
// break;
// }
}
/**
* Répond à une action de l'utilisateur
* @param e
*/
@Override
public void actionPerformed(ActionEvent e) {
// ne pas répondre pendant l'initialisation
if (nePasRepondre) {
return;
}
// Afficher ou cacher le jtfsExpression
if (e.getSource().equals(jcType)) {
modifyJCType();
} else if (e.getSource().equals(jcY)) {
jlNomY.setText(jcY.getSelectedItem().toString() + " =");
}
//remplitTendanceEnCours();
tendanceModel.notifyModifieTendance(oldTendance, getTendance());
}
/**
* Répond à l'évenement "une tendance a changé"
* @param event
*/
@Override
public void tendanceChanged(TendanceChangedEvent event) {
Fit tendance = event.getNewTendance();
if (tendance.getNumero() == numero) {
oldTendance = tendance;
initFields(tendance);
modifyJCType();
//updateTendance(event.getNewTendance());
}
}
/**
* Répond à l'évènement "une tendance a été créée""
* @param event
*/
@Override
public void tendanceCreated(TendanceCreatedEvent event) {
Fit tendance = event.getNewTendance();
if (tendance.getNumero() == numero) {
oldTendance = tendance;
initFields(tendance);
//updateTendance(event.getNewTendance());
}
}
/**
* Répond à l'évenement "suppression d'une tendance"
* @param event
*/
@Override
public void tendanceDeleted(TendanceDeletedEvent event) {
// ne rien faire, c'est le JPanelTendances qui s'occupe de la destruction
}
/**
* Répond à l'évenement "un état a changé" (spinner)
* @param e
*/
@Override
public void stateChanged(ChangeEvent e) {
if (nePasRepondre) {
return;
}
tendanceModel.notifyModifieTendance(oldTendance, getTendance());
}
public Fit getTendance(){
String nomY = jcY.getSelectedItem().toString();
String nomX = jcX.getSelectedItem().toString();
int type = jcType.getSelectedIndex();
TendanceType tt = TendanceType.numeroToTendanceType(type);
boolean prolongLine = jcDroite.isSelected();
SpinnerNumberModel model = (SpinnerNumberModel) jsDegres.getModel();
int degre = model.getNumber().intValue();
String expression = jtfsExpression.getText();
boolean manuelle = jcType.getSelectedIndex() == jcType.getItemCount() - 1;
double minX = oldTendance.getMinX();
double maxX = oldTendance.getMaxX();
double minY = oldTendance.getMinY();
double maxY = oldTendance.getMaxY();
Fit tendance = new Fit(tableur, numero, manuelle, tt, nomY, nomX,
expression, "", "", null, null, null, minX, maxX, minY, maxY, 0, degre, prolongLine,
this, true);
return tendance;
}
/**
* Action "supprimer une courbe de tendance"
*/
class SupprimeAction extends AbstractAction {
public SupprimeAction(String text, ImageIcon icon, String desc, Integer mnemonic) {
super(text, icon);
putValue(SHORT_DESCRIPTION, desc);
putValue(MNEMONIC_KEY, mnemonic);
}
@Override
public void actionPerformed(ActionEvent e) {
tendanceModel.notifySupprimeTendance(oldTendance);
}
}
}