/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Copyright (C) 2011-2013 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.graphics;
import freegressi.fit.Fit;
import freegressi.fit.FitListener;
import freegressi.fit.FitModel;
import freegressi.fit.FitModel.TendanceChangedEvent;
import freegressi.fit.FitModel.TendanceCreatedEvent;
import freegressi.fit.FitModel.TendanceDeletedEvent;
import freegressi.main.FreegressiEvent;
import freegressi.tableur.Colonne;
import freegressi.tableur.SpreadSheets;
import freegressi.tableur.SpreadSheets.ActiveSheetChangedEvent;
import freegressi.tableur.SpreadSheets.SheetAddedEvent;
import freegressi.tableur.SpreadSheets.SheetDeletedEvent;
import freegressi.tableur.SpreadSheets.SheetDescriptionChangedEvent;
import freegressi.tableur.SpreadSheets.SheetsAngleChangedEvent;
import freegressi.tableur.SpreadSheets.SheetsCSChangedEvent;
import freegressi.tableur.SpreadSheets.SheetsColumnAddedEvent;
import freegressi.tableur.SpreadSheets.SheetsColumnDeletedEvent;
import freegressi.tableur.SpreadSheets.SheetsColumnModifiedEvent;
import freegressi.tableur.SpreadSheets.SheetsColumnMovedEvent;
import freegressi.tableur.SpreadSheets.SheetsColumnSortedEvent;
import freegressi.tableur.SpreadSheets.SheetsColumnsEditedEvent;
import freegressi.tableur.SpreadSheets.SheetsListener;
import freegressi.tableur.SpreadSheets.SheetsRenamedEvent;
import freegressi.tableur.Tableur;
import freegressi.tableur.Tableur.SheetCellChangedEvent;
import freegressi.tableur.Tableur.SheetLinesAddedEvent;
import freegressi.tableur.Tableur.SheetLinesDeletedEvent;
import freegressi.tableur.Tableur.TableurChangeListener;
import java.awt.*;
import java.util.ArrayList;
import java.util.EventListener;
import java.util.EventObject;
import java.util.List;
import javax.swing.event.EventListenerList;
/**
* Le modèle des graphiques, cette classe est un singleton qui s'occupe
* de tous les calculs de la zone de dessin.
*
* @author marchand
*/
public class GraphicModel implements SheetsListener, TableurChangeListener
,FitListener{
/** La liste des objets à dessiner */
private List<GraphicObject> objects = new ArrayList<>();
/** La liste des écouteurs */
private EventListenerList listeners;
/** La seule instance de GraphicModel */
private static GraphicModel graphicModel = null;
/** La feuille courante */
private Tableur sheet = null;
/** L'axe du bas */
private Axis axisX1;
/** L'axe du haut */
private Axis axisX2;
/** L'axe de gauche */
private Axis axisY1;
/** L'axe de droite */
private Axis axisY2;
/** La largeur de la zone de dessin */
private int width = -1;
/** La hauteur de la zone de dessin */
private int height = -1;
/** La police de caractères des axes */
private Font axisFont = new Font("Courier", Font.BOLD, 20);
/** */
private Font gradFont = new Font("hj", Font.PLAIN, 15);
/** */
private Graphics2D g2 = null;
/** Le Shape en surbrillance sous la souris */
private Shape hilight = null;
/** La couleur de surbrillance */
private Color hilightColor = new Color(255, 125, 0);
/** Le style du graphique qui contient tous les réglages */
private GraphicStyle graphicStyle;
/** La largeur (ou hauteur) minimum d'un axe */
private int AXIS_MINWIDTH = 10;
/** Flag qui dit si l'initialisation du chargement d'un fichier est terminée */
private boolean initializing = true;
/**
* Constructeur privé pour singleton
*/
private GraphicModel() {
listeners = new EventListenerList();
}
/**
*
* @return La seule instance de GraphicModel
*/
public static GraphicModel getInstance() {
if (graphicModel == null) {
graphicModel = new GraphicModel();
}
return graphicModel;
}
public void setInitializing(boolean initializing) {
this.initializing = initializing;
if (!initializing){
updateAxisAndCurves();
fireGraphicChanged();
}
}
public Tableur getSheet() {
return sheet;
}
/**
* Méthode spéciale pour pouvoir exécuter des tests
*/
public void initForTests(){
createDefaultGraphicStyle();
}
/**
*
* @return la zone de dessin des courbes, hors zones d'axes
*/
public Rectangle getRectangle(){
if (graphicStyle == null){
return null;
}
return new Rectangle(axisY1.getAxisWidth() - 1, axisX2.getAxisHeight() - 1,
width - axisY2.getAxisWidth() - axisY1.getAxisWidth() + 1,
height - axisX1.getAxisHeight() - axisX2.getAxisHeight() + 1);
}
/**
*
* @return Le GraphicStyle cad tous les réglages du graphique
*/
public GraphicStyle getGraphicStyle() {
return graphicStyle;
}
/**
*
* @param graphic
*/
public void setGraphicStyle(GraphicStyle graphic) {
//sheet = SpreadSheets.getInstance().getActiveSheet();
System.out.println("----------- setGraphicStyle " + graphic + " ------- sheet " + sheet);
if (graphic == null){
createDefaultGraphicStyle();
} else {
this.graphicStyle = graphic;
axisX1 = graphicStyle.getaX1();
axisY1 = graphicStyle.getaY1();
axisX2 = graphicStyle.getaX2();
axisY2 = graphicStyle.getaY2();
}
}
/**
*
* @return la liste des objets graphiques à dessiner
*/
public List<GraphicObject> getObjects() {
return objects;
}
/**
*
* @return le Shape correspondant à l'objet en surbrillance
*/
public Shape getHilight() {
return hilight;
}
/**
*
* @return la couleur de l'objet en surbrillance
*/
public Color getHilightColor(){
return hilightColor;
}
/**
*
* @return le contexte graphique de la zone de dessin
*/
public Graphics2D getG2() {
return g2;
}
/**
* Définit le contexte graphique de la zone de dessin.
* Utile pour calculer les dimensions des textes
* @param g2
*/
public void setG2(Graphics2D g2) {
this.g2 = g2;
updateAxisAndCurves();
}
/**
*
* @param font
* @param str
* @return la largeur d'un texte dans la zone de dessin
*/
public int textWidth(Font font, String str) {
if (g2 == null){
return 0;
}
Font save = g2.getFont();
g2.setFont(font);
FontMetrics fm = g2.getFontMetrics();
int result = fm.stringWidth(str);
g2.setFont(save);
return result;
}
/**
*
* @param font
* @param str
* @return la hauteur d'un texte dans la zone de dessin
*/
public int textHeight(Font font, String str) {
if (g2 == null){
return 0;
}
Font save = g2.getFont();
g2.setFont(font);
int result = g2.getFontMetrics().getHeight();
g2.setFont(save);
return result;
}
/**
*
* @param font
* @param str
* @return
*/
public int textDescent(Font font, String str) {
if (g2 == null){
return 0;
}
Font save = g2.getFont();
g2.setFont(font);
int result = g2.getFontMetrics().getDescent();
g2.setFont(save);
return result;
}
/**
*
* @param font
* @param str
* @return
*/
public int textAscent(Font font, String str) {
if (g2 == null){
return 0;
}
Font save = g2.getFont();
g2.setFont(font);
int result = g2.getFontMetrics().getAscent();
g2.setFont(save);
return result;
}
/**
* Renvoit un tableau d'entiers correspondant aux valeurs en pixel
* des points d'une courbe
* @param x les valeurs réelles
* @param x1 le min de l'axe (en pixel)
* @param x2 le max de l'axe (en pixel)
* @param min le min de x
* @param max le max de x
* @return le tableau d'entiers
*/
private int[] getIntArray(double[] x, int x1, int x2, double min, double max){
int[] result = new int[x.length];
double a = (x2 - x1) / (max - min);
double b = (x1 * max - x2 * min) / (max - min);
for (int i = 0; i < x.length; i++){
if (Double.isNaN(x[i])){
result[i] = Integer.MAX_VALUE;
}else{
result[i] = (int)Math.round(a * x[i] + b);
}
}
return result;
}
/**
* Répond à l'évenement "La feuille active a changée"
* @param event
*/
@Override
public void activeSheetChanged(ActiveSheetChangedEvent event) {
System.out.println("GraphicModel : activeSheetChanged");
sheet = event.getNewActiveSheet();
if (graphicStyle == null){
//createDefaultGraphicStyle();
System.out.println("GraphicModel ActiveSheetChanged graphicStyle == null");
return;
}
if (sheet == null){
System.out.println("GraphicModel ActiveSheetChanged sheet == null");
createDefaultGraphicStyle();
//return;
}
setMinMax(sheet);
notifyGraphicStyleChanged(graphicStyle, false);
}
@Override
public void sheetAdded(SheetAddedEvent event) {
// rien à faire, le graphique changera avec activeSheetChanged()
}
@Override
public void sheetDeleted(SheetDeletedEvent event) {
// rien à faire, le graphique changera avec activeSheetChanged()
//System.out.println("GraphicModel : Sheet deleted");
}
@Override
public void sheetRenamed(SheetsRenamedEvent event) {
// rien à faire, le graphique ne change pas
}
@Override
public void columnAdded(SheetsColumnAddedEvent event) {
// rien à faire, le graphique ne change pas
}
/**
* Répond à l'évenement "Une ou plusieurs colonnes ont été
* supprimées"
* @param event
*/
@Override
public void columnDeleted(SheetsColumnDeletedEvent event) {
List<Colonne> list = event.getColonnes().get(0);
String name;
boolean flag = false;
for (Colonne col : list){
name = col.getColonneDescription().getNom();
for (int i = graphicStyle.getCurves().size() - 1; i > -1; i--){
Curve curve = graphicStyle.getCurves().get(i);
if (curve.getxName().equals(name) || curve.getyName().equals(name)){
flag = true;
break;
//graphicStyle.getCurves().remove(i);
}
}
}
if (flag){
GraphicStyle gs = createDefaultGraphicStyle2();
//createDefaultGraphicStyle();
notifyGraphicStyleChanged(gs, true);
}
}
@Override
public void angleChanged(SheetsAngleChangedEvent event) {
if (sheet == null || graphicStyle == null){
return;
}
setMinMax(sheet);
notifyGraphicStyleChanged(graphicStyle, false);
}
/**
* Répond à l'évenement "une colonne a été modifiée"
* @param event
*/
@Override
public void columnModified(SheetsColumnModifiedEvent event) {
String oldName = event.getAncienNom();
for (Curve curve : graphicStyle.getCurves()){
if (curve.useName(oldName)){
GraphicStyle gs = createDefaultGraphicStyle2();
notifyGraphicStyleChanged(gs, true);
return;
}
}
}
@Override
public void columnMoved(SheetsColumnMovedEvent event) {
}
@Override
public void columnSorted(SheetsColumnSortedEvent event) {
notifyGraphicStyleChanged(graphicStyle, false); // @TODO à vérifier
}
@Override
public void columnsEdited(SheetsColumnsEditedEvent event) {
System.out.println("GraphicModel : SheetsColumnEdited *******************");
GraphicStyle gs = createDefaultGraphicStyle2();
notifyGraphicStyleChanged(gs, true);
}
@Override
public void sheetDescriptionChanged(SheetDescriptionChangedEvent event) {
}
@Override
public void sheetsCSChanged(SheetsCSChangedEvent event) {
}
/**
* Répond à l'évenement "une cellule a changé"
* @param event
*/
@Override
public void sheetCellChanged(SheetCellChangedEvent event) {
Colonne col = sheet.donneColonne(event.getColonne() - 1);
setMinMax(col);
notifyGraphicStyleChanged(graphicStyle, false);
}
/**
* Recalcule les min et max de toutes les colonnes de la feuille en cours
* pour les axes en échelle automatique
* @param sheet
*/
private void setMinMax(Tableur sheet){
if (sheet == null){
return;
}
for (Colonne col : sheet.getListeColonnes()){
setMinMax(col);
}
}
/**
* Trouve la liste de noms de variables associées à un axe
* @param axis
* @return
*/
private List<String> namesOnAxis(Axis axis){
List<String> names = new ArrayList<>();
for (Curve curve : graphicStyle.getCurves()){
if (curve.getAxisX().equals(axis)){
names.add(curve.getxName());
}
if (curve.getAxisY().equals(axis)){
names.add(curve.getyName());
}
}
return names;
}
/**
* Recalcule les min et max de la colonne col
* pour les axes en échelle automatique
* @param col
*/
private void setMinMax(Colonne col){
String name = col.getColonneDescription().getNom();
// Trouver les axes
boolean b = false, t = false, l = false, r = false;
for (Curve curve : graphicStyle.getCurves()){
if (curve.getxName().equals(name)){
switch (curve.getAxisX().getAxisStyle().getPosition()){
case BOTTOM : b = true; break;
case TOP : t = true; break;
case LEFT : l = true; break;
case RIGHT : r = true; break;
}
switch (curve.getAxisY().getAxisStyle().getPosition()){
case BOTTOM : b = true; break;
case TOP : t = true; break;
case LEFT : l = true; break;
case RIGHT : r = true; break;
}
} else if (curve.getyName().equals(name)){
switch (curve.getAxisX().getAxisStyle().getPosition()){
case BOTTOM : b = true; break;
case TOP : t = true; break;
case LEFT : l = true; break;
case RIGHT : r = true; break;
}
switch (curve.getAxisY().getAxisStyle().getPosition()){
case BOTTOM : b = true; break;
case TOP : t = true; break;
case LEFT : l = true; break;
case RIGHT : r = true; break;
}
}
}
List<String> names;
if (b){
names = namesOnAxis(axisX1);
minmaxAxis(axisX1, names);
}
if (l){
names = namesOnAxis(axisY1);
minmaxAxis(axisY1, names);
}
if (r){
names = namesOnAxis(axisY2);
minmaxAxis(axisY2, names);
}
if (t){
names = namesOnAxis(axisX2);
minmaxAxis(axisX2, names);
}
}
/**
* Utilisée dans setMinMax
* @param axis
* @param names
*/
private void minmaxAxis(Axis axis, List<String> names){
Colonne c;
double min = Double.MAX_VALUE, max = Double.MIN_VALUE;
for (String n : names){
c = sheet.donneColonne(n);
if (c.getMin() < min) { min = c.getMin();}
if (c.getMax() > max) { max = c.getMax();}
}
axis.getAxisStyle().reInitMinMax(min, max);
}
/**
* Répond à l'évenement "des lignes ont été ajoutées"
* @param event
*/
@Override
public void sheetLinesAdded(SheetLinesAddedEvent event) {
setMinMax(sheet);
notifyGraphicStyleChanged(graphicStyle, false);
}
/**
* Répond à l'évenement "des lignes ont été supprimées"
* @param event
*/
@Override
public void sheetLinesDeleted(SheetLinesDeletedEvent event) {
setMinMax(sheet);
notifyGraphicStyleChanged(graphicStyle, false);
}
/**
* Réinitialisation des objets graphiques
*/
private void initGraphic(){
objects.clear();
hilight = null;
objects.add(axisX1);
objects.add(axisY1);
objects.add(axisX2);
objects.add(axisY2);
}
/**
* Fabrique un GraphicStyle par défaut avec les deux premières
* colonnes du tableur
* @return
*/
private GraphicStyle createDefaultGraphicStyle2(){
GraphicStyle gs = new GraphicStyle();
Tableur sh = SpreadSheets.getInstance().getActiveSheet();
if (sh != null && sh.donneNombreColonne() > 0){
Colonne col1, col2;
col1 = sh.donneColonne(0);
String xName = col1.getColonneDescription().getNom();
gs.setAbscissa(xName);
gs.getaX1().setAll(xName, xName, true, col1.getMin(), col1.getMax(), Position.RIGHT);
if (sh.donneNombreColonne() > 1){
col2 = sh.donneColonne(1);
} else {
col2 = col1;
}
String yName = col2.getColonneDescription().getNom();
gs.getaY1().setAll(yName, yName, true, col2.getMin(), col2.getMax(), Position.TOP);
PointLineStyle pls = new PointLineStyle(Color.BLACK, PointStyle.CIRCLE, 5, LineStyle.NONE, 2);
Curve curve = new Curve(xName, yName, gs.getaX1(), gs.getaY1(), pls);
gs.getCurves().add(curve);
}
return gs;
}
/**
* Il n'y a pas encore de graphique, on en crée un par défault avec
* les deux premières colonnes des tableurs
*/
private void createDefaultGraphicStyle(){
graphicStyle = createDefaultGraphicStyle2();
axisX1 = graphicStyle.getaX1();
axisY1 = graphicStyle.getaY1();
axisX2 = graphicStyle.getaX2();
axisY2 = graphicStyle.getaY2();
}
private double[] listToArray(List<Double> doubles){
double[] d = new double[doubles.size()];
for (int i = 0; i < doubles.size(); i++){
d[i] = doubles.get(i);
}
return d;
}
/**
* Met à jour la liste des courbes de tendance.
*/
private void updateFitCurves(){
System.out.println("********** updateFitCurves");
if (graphicStyle == null){
return;
}
List<Fit> fits = FitModel.getInstance().getListTendances();
List<Curve> curves = graphicStyle.getCurves();
List<Curve> fitCurves = graphicStyle.getFitCurves();
for (Curve fitCurve : fitCurves){
objects.remove(fitCurve);
}
fitCurves.clear();
Curve fitCurve;
int xmin = axisX1.getAxisX();
int xmax = axisX1.getAxisX() + axisX1.getAxisWidth() - 1;
int ymax = axisY1.getAxisY();
int ymin = axisY1.getAxisY() + axisY1.getAxisHeight() - 1;
for (Fit fit : fits){
for (Curve curve : curves){
if (fit.getNomX().equals(curve.getxName()) && fit.getNomY().equals(curve.getyName())){
PointLineStyle pls = new PointLineStyle(curve.getForeGround(), null, 0, LineStyle.CONTINUE, curve.getLineWidth());
fitCurve = new Curve(fit.getNomX(), fit.getNomY(), null, null, pls);
double[] xd = listToArray(fit.getListeX());
double[] yd = listToArray(fit.getListeY());
int[] x = getIntArray(xd, xmin, xmax, fit.getMinX(), fit.getMaxX());
int[] y = getIntArray(yd, ymin, ymax, fit.getMinY(), fit.getMaxY());
fitCurve.update(x, y);
fitCurves.add(fitCurve);
objects.add(fitCurve);
break;
}
}
}
}
@Override
public void tendanceChanged(TendanceChangedEvent event) {
updateFitCurves();
notifyGraphicStyleChanged(graphicStyle, false);
}
@Override
public void tendanceCreated(TendanceCreatedEvent event) {
updateFitCurves();
notifyGraphicStyleChanged(graphicStyle, false);
}
@Override
public void tendanceDeleted(TendanceDeletedEvent event) {
updateFitCurves();
notifyGraphicStyleChanged(graphicStyle, false);
}
/**
* Classe qui définit l'évenement "la taille du graphique a changé"
*/
public class GraphicSizeChangedEvent extends EventObject {
private final int newWidth;
private final int newHeight;
public GraphicSizeChangedEvent(Object source, int newWidth, int newHeight) {
super(source);
this.newWidth = newWidth;
this.newHeight = newHeight;
}
public int getNewHeight() {
return newHeight;
}
public int getNewWidth() {
return newWidth;
}
}
/**
* Recalcule tous les axes et les courbes
*/
private void updateAxisAndCurves(){
if (initializing){
return;
}
initGraphic();
if (graphicStyle == null){
System.out.println("updateAxisAndCurves graphicStyle == null");
return;
}
if (width < 5 || height < 5){
System.out.println("updateAxisAndCurves taille trop petite");
return;
}
if (g2 == null){
System.out.println("updateAxisAndCurves pas de g2");
return;
}
System.out.println("GraphicModel updateAxisAndCurves " + width + " " + height);
int numberHeight = textHeight(gradFont, "1E1");
String largerY1, largerY2;
int heightTitleX1, heightTitleX2, heightTitleY1, heightTitleY2;
int axisY1Width = AXIS_MINWIDTH, axisY2Width = AXIS_MINWIDTH,
axisX1Height, axisX2Height;
if ( !axisY1.getTitle().equals("")){
largerY1 = Axis.getLargerGrad(height, axisY1.getMin(), axisY1.getMax());
heightTitleY1 = textHeight(axisFont, axisY1.getTitle());
axisY1Width = heightTitleY1 + textWidth(gradFont, largerY1) + Axis.getGradSize();
}
axisY1.setAxisWidth(axisY1Width);
if (!axisY2.getTitle().equals("")){
largerY2 = Axis.getLargerGrad(height, axisY2.getMin(), axisY2.getMax());
heightTitleY2 = textHeight(axisFont, axisY2.getTitle());
axisY2Width = heightTitleY2 + textWidth(gradFont, largerY2) + Axis.getGradSize();
}else{
//axisY2Width = 1;
}
axisY2.setAxisWidth(axisY2Width);
if (!axisX1.getTitle().equals("")){
heightTitleX1 = textHeight(axisFont, axisX1.getTitle());
axisX1Height = heightTitleX1 + numberHeight + Axis.getGradSize();
}else{
heightTitleX1 = AXIS_MINWIDTH;
axisX1Height = heightTitleX1;
}
axisX1.setAxisHeight(axisX1Height);
axisX1.setAxisWidth(width - axisY1Width - axisY2Width);
axisX1.setAxisX(axisY1Width - 1);
axisX1.setAxisY(height - 1 - axisX1Height);
axisX1.update(width, height/*, min, max*/);
if (!axisX2.getTitle().equals("")){
heightTitleX2 = textHeight(axisFont, axisX2.getTitle());
axisX2Height = heightTitleX2 + numberHeight + Axis.getGradSize();
}else{
heightTitleX2 = AXIS_MINWIDTH;
axisX2Height = heightTitleX2;
}
axisX2.setAxisHeight(axisX2Height);
axisX2.setAxisWidth(width - axisY1Width - axisY2Width);
axisX2.setAxisX(axisY1Width - 1);
axisX2.setAxisY(0);
axisX2.update(width, height);
axisY1.setAxisHeight(height - axisX1Height - axisX2Height);
axisY1.setAxisX(0);
axisY1.setAxisY(axisX2Height - 1);
axisY1.update(width, height);
axisY2.setAxisHeight(height - axisX1Height - axisX2Height);
axisY2.setAxisX(width - axisY2Width - 1);
axisY2.setAxisY(axisX2Height - 1);
axisY2.update(width, height);
for (Curve curve : graphicStyle.getCurves()){
//Colonne colX = SpreadSheets.getInstance().getActiveSheet().donneColonne(curve.getAxisX().getAxisStyle().getName());
Colonne colX = sheet.donneColonne(curve.getxName());
double minX = curve.getAxisX().getMin();
double maxX = curve.getAxisX().getMax();
int x1 = axisX1.getAxisX();
int x2 = axisX1.getAxisX() + axisX1.getAxisWidth() - 1;
int[] x = getIntArray(colX.getTableauDouble(), x1, x2, minX, maxX);
//Colonne colY = SpreadSheets.getInstance().getActiveSheet().donneColonne(curve.getAxisY().getAxisStyle().getName());
//Colonne colY = sheet.donneColonne(curve.getAxisY().getAxisStyle().getName());
Colonne colY = sheet.donneColonne(curve.getyName());
// if (colY == null){
// System.out.println("colY == null");
// }
double minY = curve.getAxisY().getMin();
double maxY = curve.getAxisY().getMax();
int y1 = axisY1.getAxisY() + axisY1.getAxisHeight() - 1;
int y2 = axisY1.getAxisY();
int[] y = getIntArray(colY.getTableauDouble(), y1, y2, minY, maxY);
curve.update(x, y);
objects.add(curve);
}
for (Curve curve : graphicStyle.getFitCurves()){
objects.add(curve);
}
}
/**
* La taille de la zone de dessin a changé, il faut redessiner le graphique
* @param newWidth la nouvelle largeur
* @param newHeight la nouvelle hauteur
*/
public void notifySizeChanged(int newWidth, int newHeight){
if (width == newWidth && height == newHeight){
return;
}
System.out.println("GraphicModel notifySizeChanged " + newWidth + " " + newHeight);
width = newWidth;
height = newHeight;
updateAxisAndCurves();
updateFitCurves();
fireSizeChanged(width, height);
}
/**
* Informe tous les écouteurs que la taille de la zone de dessin a changé
* @param newWidth
* @param newHeight
*/
private void fireSizeChanged(int newWidth, int newHeight) {
GraphicListener[] listenerList = (GraphicListener[]) listeners.getListeners(GraphicListener.class);
for (GraphicListener listener : listenerList) {
listener.graphicSizeChanged(new GraphicSizeChangedEvent(this, newWidth, newHeight));
}
}
/**
* Classe qui définit l'évenement "le graphique a changé"
*/
public class GraphicChangedEvent extends EventObject {
public GraphicChangedEvent(Object source) {
super(source);
}
}
/**
* La souris a été déplacée, il faut redessiner le graphique
*/
public void notifyGraphicChanged(){
fireGraphicChanged();
}
/**
* Informe tous les écouteurs que la souris a été déplacée
*/
private void fireGraphicChanged() {
GraphicListener[] listenerList = (GraphicListener[]) listeners.getListeners(GraphicListener.class);
for (GraphicListener listener : listenerList) {
listener.graphicChanged(new GraphicChangedEvent(this));
}
}
/**
* Ajoute un écouteur à la liste
* @param listener l'écouteur à ajouter
*/
public void addGraphicListener(GraphicListener listener) {
listeners.add(GraphicListener.class, listener);
}
/**
* Retire un écouteur de la liste
* @param listener l'écouteur à retirer
*/
public void removeGraphicListener(GraphicListener listener) {
listeners.remove(GraphicListener.class, listener);
}
public interface GraphicListener extends EventListener {
public void graphicSizeChanged(GraphicSizeChangedEvent event);
public void graphicChanged(GraphicChangedEvent event);
public void graphicStyleChanged(GraphicStyleChangedEvent event);
}
/**
* La souris a bougé
* @param newX
* @param newY
*/
public void notifyMouseMoved(int newX, int newY){
// retirer le dernier ob
boolean found = false;
Shape shape;
for (GraphicObject object : objects){
if (object != null && object.contains(newX, newY)){
shape = object.getHilight();
found = true;
if (shape.equals(hilight)){
// ne rien faire
}else{
// changer l'objet hilighted
hilight = shape;
notifyGraphicChanged();
}
break;
}
}
if (!found && hilight != null){
hilight = null;
notifyGraphicChanged();
}
}
/**
* La souris a quitté la zone de dessin
*/
public void notifyMouseExited(){
if (hilight != null){
hilight = null;
notifyGraphicChanged();
}
}
/**
* Crée un texte XML correspondant au graphique en vue de l'enregistrement
* sur le disque.
* @param tab le nombre de tabulations devant chaque ligne
* @return le XML du graphique
*/
public String toXML(String tab){
String tab2 = tab + "\t";
String str = tab + "<graphic>\n";
str += graphicStyle.toXML(tab2);
str += tab + "</graphic>\n";
return str;
}
/**
*
* @param color
* @return
*/
public static String encodeColor(Color color){
return "#" + Integer.toHexString((color.getRGB() & 0xffffff) | 0x1000000).substring(1) ;
}
/**
* La classe qui définit l'évenement "le style du graphique a changé"
*/
public class GraphicStyleChangedEvent extends FreegressiEvent {
private final GraphicStyle oldGS;
private final GraphicStyle newGS;
public GraphicStyleChangedEvent(Object source, GraphicStyle oldGS, GraphicStyle newGS, boolean undoable) {
super(source);
this.newGS = newGS;
this.undoable = undoable;
this.oldGS = oldGS;
}
@Override
public boolean isUndoable() {
return undoable;
}
public GraphicStyle getNewGS() {
return newGS;
}
public GraphicStyle getOldGS() {
return oldGS;
}
@Override
public String getText() {
return "Changer le graphique";
}
@Override
public void undo() {
notifyGraphicStyleChanged(oldGS, false);
}
@Override
public void redo() {
notifyGraphicStyleChanged(newGS, false);
}
}
/**
* Le style du graphique a changé
* @param graphicStyle le nouveau style
* @param undoable
*/
public void notifyGraphicStyleChanged(GraphicStyle graphicStyle, boolean undoable){
System.out.println("GraphicModel notifyGraphicStyleChanged");
//sheet = SpreadSheets.getInstance().getActiveSheet();
GraphicStyle oldGS = this.graphicStyle;
setGraphicStyle(graphicStyle);
updateAxisAndCurves();
fireGraphicStyleChanged(oldGS, graphicStyle, undoable);
}
/**
* Informer les écouteurs que le style du graphique a changé
* @param oldGS
* @param newGS
* @param undoable
*/
private void fireGraphicStyleChanged(GraphicStyle oldGS, GraphicStyle newGS, boolean undoable) {
GraphicStyleChangedEvent event = new GraphicStyleChangedEvent(this, oldGS, newGS,undoable);
GraphicListener[] listenerList = (GraphicListener[]) listeners.getListeners(GraphicListener.class);
for (GraphicListener listener : listenerList) {
listener.graphicStyleChanged(event);
}
}
}