/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
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.tableur;
import freegressi.main.MainModel.ApplicationSeFermeEvent;
import freegressi.main.MainModel.FichierOuvertEvent;
import freegressi.main.MainModel.MainListener;
import freegressi.main.MainModel.NouveauExperienceEvent;
import freegressi.main.MainModel.SaveEvent;
import freegressi.parser.Lexer;
import freegressi.parser.Parser;
import freegressi.parser.Verificateur;
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.SheetsRenamedEvent;
import java.awt.Color;
import java.util.ArrayList;
import java.util.EventListener;
import java.util.List;
import java.util.StringTokenizer;
import javax.swing.event.EventListenerList;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;
/**
*
* @author marchand
*/
public class EditColumnsModel implements SpreadSheets.SheetsListener, MainListener{
private static EditColumnsModel model;
private static String EOL = System.getProperty("line.separator");
private EventListenerList listeners = new EventListenerList();
private final static StyleContext sc = new StyleContext();
private static Style normalStyle = sc.addStyle("normal", null);
private static Style errorStyle = sc.addStyle("error", null);
private static Style idStyle = sc.addStyle("id", null);
private static Style functionStyle = sc.addStyle("function", null);
private static Style commentStyle = sc.addStyle("comment", null);
private static Style unitStyle = sc.addStyle("unit", null);
private static Style commentTextStyle = sc.addStyle("commentText", null);
private static Style unitTextStyle = sc.addStyle("unitText", null);
private String editorString = "";
private String saveEditor = "";
private ArrayList<EditState> editStates = new ArrayList<EditState>();
private int maxUndo = 50;
private int index = -1;
/**
* Constructeur privé pour singleton
*/
private EditColumnsModel() {
}
public static EditColumnsModel getInstance() {
if (model == null) {
StyleConstants.setForeground(normalStyle, Color.BLACK);
StyleConstants.setForeground(errorStyle, Color.red);
StyleConstants.setBold(errorStyle, true);
//StyleConstants.setFontSize(errorStyle, StyleConstants.getFontSize(normalStyle) + 10);
//StyleConstants.setForeground(idStyle, new Color(18, 143, 239));
StyleConstants.setForeground(idStyle, new Color(53, 102, 140));
//StyleConstants.setBold(idStyle, true);
//StyleConstants.setForeground(functionStyle, Color.darkGray);
StyleConstants.setForeground(functionStyle, new Color(109, 115, 119));
StyleConstants.setForeground(commentStyle, Color.lightGray);
//StyleConstants.setForeground(unitStyle, Color.blue);
StyleConstants.setForeground(unitStyle, Color.gray);
StyleConstants.setForeground(commentTextStyle, Color.lightGray);
StyleConstants.setForeground(unitTextStyle, Color.gray);
model = new EditColumnsModel();
}
return model;
}
public String getEditorString() {
if (editorString.equals("")){
editorString = SpreadSheets.getInstance().getActiveSheet().toEditColumns();
}
return editorString;
}
public void setEditorString(String newEditorString){
saveEditor = getEditorString();
editorString = newEditorString;
}
/**
* Début d'édition des colonnes
*/
public void startEditing() {
saveEditor = getEditorString();
// Indiquer au JDialogEditColumns que l'édition a démarré
ColumnsChangedEvent cce = new ColumnsChangedEvent(saveEditor);
EditColumnsListener[] listenerList = (EditColumnsListener[]) listeners.getListeners(EditColumnsListener.class);
for (EditColumnsListener listener : listenerList) {
listener.columnsChanged(cce);
}
}
/**
* L'utilisateur valide les changements
*/
public void okToChange(boolean ok, String ed) {
if (ok){
ArrayList<String> newNames = new ArrayList<String>();
ArrayList<String> newEpressions = new ArrayList<String>();
ArrayList<String> newUnits = new ArrayList<String>();
splitEditor(ed, newNames, newEpressions, newUnits);
editorString = ed;
SpreadSheets.getInstance().notifySheetsColumnsEdited(newNames,
newEpressions, newUnits, saveEditor, editorString);
}else{
// Restaurer l'editeur
editorString = saveEditor;
}
}
/**
* Créée pour faire des tests
* @param ed
*/
public void changeEditor(String ed){
saveEditor = editorString;
editorString = ed;
ArrayList<String> newNames = new ArrayList<String>();
ArrayList<String> newEpressions = new ArrayList<String>();
ArrayList<String> newUnits = new ArrayList<String>();
splitEditor(ed, newNames, newEpressions, newUnits);
SpreadSheets.getInstance().notifySheetsColumnsEdited(newNames,
newEpressions, newUnits, saveEditor, editorString);
}
/**
* Renvoit la liste des noms, expressions et unités des variables calculées
*/
public boolean splitEditor(String ed, ArrayList<String> names,
ArrayList<String> expressions, ArrayList<String> units){
//StringTokenizer st = new StringTokenizer(ed, "\n", false);
StringTokenizer st = new StringTokenizer(ed, EOL, false);
StringTokenizer stEgal;
String line;
while (st.hasMoreTokens()) { // Pour chaque ligne
line = st.nextToken();
// retirer les espaces avant et après
line = line.trim();
// Est-ce une ligne de commentaire? dans ce cas on l'ignore
if (line.startsWith("#")){
continue;
}
// Y'a-t-il un signe égal?
int egalPos = line.indexOf("=");
if (egalPos > 0){ // il y a au moins un signe = et pas en première position
stEgal = new StringTokenizer(line, "=", false);
if (stEgal.hasMoreTokens()){
names.add(stEgal.nextToken().trim());
if (stEgal.hasMoreTokens()){
String str1 = stEgal.nextToken();
splitExprUnitComment(str1, expressions, units);
}else{
return false;
}
}else{
return false;
}
}else{ // pas de signe = ou un signe = en première position
return false;
}
}
if (names.size() != expressions.size() || names.size() != units.size()
|| expressions.size() != units.size()){
return false;
}
return true;
}
/**
* Découpe la string str en expression et unité.
* Les résultats sont ajoutés en fin des 2 listes fournies
* @param str
* @param expressions
* @param units
*/
public void splitExprUnitComment(String str,
ArrayList<String> expressions, ArrayList<String> units){
String exprUnit;
String[] result = str.split("#");
if (result.length > 0){
exprUnit = result[0];
result = exprUnit.split("@");
if (result.length > 0){
expressions.add(result[0]);
if (result.length > 1){
//units.add(result[1]);
units.add(concatUnits(result));
}else{
units.add("");
}
}else{
expressions.add("");
units.add("");
}
}else{
expressions.add("");
units.add("");
}
}
private String concatUnits(String[] units){
String result = "";
if (units.length < 2){
return result;
}
for (int i = 1; i < units.length; i++){
result += units[i];
}
return result;
}
private String lastName = "";
/**
* Crée une liste de StyledToken pour la coloration
* syntaxique de text dans le JColorPane.
* Envoit la première des erreurs rencontrées aux écouteurs (essentiellement
* le JDialogEditColumns)
* @param text
* @return la liste des StyledToken ou null si il y a un problème avec
* le lexer
*/
public EditState createStyledTokens(String text, int caretPosition){
ArrayList<StyledToken> tokens = new ArrayList<StyledToken>();
List<String> errors = new ArrayList<String>();
text = text.replace(EOL, "\n");
String[] lines = text.split("\n");
int offset = 0;
Style style;
List<String> names = SpreadSheets.getInstance().getActiveSheet()
.getListExperimentalNames();
String line;
for(int i = 0; i < lines.length; i++){
line = lines[i] + "\n";
ArrayList<Noeud> nodes = Verificateur.lexe(line);
if (nodes == null){
System.err.println("Erreur interne du lexer!");
return null;
}
Parser parser = new Parser(nodes);
Noeud racine = parser.parser();
checkRoot(racine, errors);
if (nodes != null && nodes.get(0).getType() == Sym.UNIT){
nodes.get(0).setType(Sym.PARSER_COHERENCE_ERROR);
nodes.get(0).setTexteErreur(Sym.ERREUR_NOM_EXPRESSION);
errors.add(Sym.ERREUR_NOM_EXPRESSION);
}
//boolean inComment = false;
for(Noeud node : nodes){
checkUnit(node, errors);
checkId(node, errors, names);
if (node.getType() == Sym.PARSER_COHERENCE_ERROR){
errors.add(node.getRacine().getTexteErreur());
}
style = getStyle(node);
// int n1 = offset + node.getColonne();
// int n2 = node.getTexteLexer().length();
// System.out.println(node.getType() + " " + n1 + " " + n2 + " ;" + node.getTexteLexer());
StyledToken st = new StyledToken(offset + node.getColonne(),
node.getTexteLexer().length(), style);
tokens.add(st);
}
offset += line.length();
}
String error = errors.isEmpty()?"":errors.get(0);
EditState es = new EditState(text, tokens, error, error.equals(""),
false, false, caretPosition);
addEditState(es);
return es;
}
/* Utilisée dans createStyledTokens*/
private void checkRoot(Noeud root, List<String> errors){
if (root != null){
if (root.getType() == Sym.ERROR ||
root.getType() == Sym.PARSER_COHERENCE_ERROR){
errors.add(root.getTexteErreur());
}else if (root.getType() != Sym.EGAL){
root.setType(Sym.PARSER_COHERENCE_ERROR);
root.setTexteErreur(Sym.ERREUR_NOM_EXPRESSION);
errors.add(Sym.ERREUR_NOM_EXPRESSION);
}else if (root.getFilsG() == null){
root.setType(Sym.PARSER_COHERENCE_ERROR);
root.setTexteErreur(Sym.ERREUR_NOM_EXPRESSION);
errors.add(Sym.ERREUR_NOM_EXPRESSION);
}else if(root.getFilsG().getType() != Sym.ID){
root.getFilsG().setType(Sym.PARSER_COHERENCE_ERROR);
root.getFilsG().setTexteErreur(Sym.ERREUR_NOM_EXPRESSION);
errors.add(Sym.ERREUR_NOM_EXPRESSION);
}else{
}
}else{
}
}
private void checkUnit(Noeud node, List<String> errors){
if (node.getType() == Sym.UNIT_TEXT){
if (Verificateur.parseUnite(node.getTexteLexer()) != -1){
node.setType(Sym.PARSER_COHERENCE_ERROR);
node.setTexteErreur(Sym.ERREUR_UNITE);
errors.add(Sym.ERREUR_UNITE);
}
}
}
/* Utilisée dans createStyledTokens*/
private void checkId(Noeud node, List<String> errors, List<String> names){
if (node.getType() == Sym.ID){
if (node.getPere() != null
&& node.getPere().getType() == Sym.EGAL
&& node.getPere().getFilsG() == node){
if (!names.contains(node.getNom())){
names.add(node.getNom());
lastName = node.getNom();
// newNames.add(lastName);
}else{
node.setType(Sym.PARSER_COHERENCE_ERROR);
node.setTexteErreur(Sym.ERREUR_NOM_UTILISE);
errors.add(Sym.ERREUR_NOM_UTILISE);
}
}else{
if (!names.contains(node.getNom())){
node.setType(Sym.PARSER_COHERENCE_ERROR);
node.setTexteErreur(Sym.ERREUR_NOM_INCONNU);
errors.add(Sym.ERREUR_NOM_INCONNU);
}else{
if (node.getNom().equals(lastName)){
node.setType(Sym.PARSER_COHERENCE_ERROR);
node.setTexteErreur(Sym.ERREUR_AUTOREFERENCE);
errors.add(Sym.ERREUR_AUTOREFERENCE);
}
}
}
}
}
/* Utilisée dans createStyledTokens*/
private Style getStyle(Noeud node){
Style style;
if(node.getType() == Sym.ERROR){
style = errorStyle;
}else if (node.getType() == Sym.PARSER_COHERENCE_ERROR){
style = errorStyle;
}else if(node.getType() == Sym.ID){
style = idStyle;
}else if(node.getCategorie() == Sym.CATEGORIE_FONCTION){
style = functionStyle;
}else if(node.getType() == Sym.COMMENT){
style = commentStyle;
}else if(node.getType() == Sym.UNIT){
style = unitStyle;
}else if(node.getType() == Sym.COMMENT_TEXT){
style = commentTextStyle;
}else if(node.getType() == Sym.UNIT_TEXT){
style = unitTextStyle;
}
else{
style = normalStyle;
}
return style;
}
@Override
public void activeSheetChanged(ActiveSheetChangedEvent event) {
if (event.getNewActiveSheet() == null)
return;
if (editorString.equals("")){
editorString = SpreadSheets.getInstance().getActiveSheet().toEditColumns();
}
}
@Override
public void sheetAdded(SheetAddedEvent event) {
//System.out.println(editorString);
}
@Override
public void sheetDeleted(SheetDeletedEvent event) {
//System.out.println(editorString);
}
@Override
public void sheetRenamed(SheetsRenamedEvent event) {
}
/**
* Une colonne a été ajoutée "à la main", il faut reconstruire editorString
* Cette colonne
* @param event
*/
@Override
public void columnAdded(SheetsColumnAddedEvent event) {
int position = event.getPosition();
Tableur sheet = SpreadSheets.getInstance().getActiveSheet();
String name = event.getColonnes().get(0).getColonneDescription().getNom();
if (sheet.donneColonne(name).getColonneDescription().getType() == Sym.TypeVariable.VARIABLE_EXPERIMENTALE){
return;
}
String expr = event.getColonnes().get(0).getColonneDescription().getExpression();
String unit = event.getColonnes().get(0).getColonneDescription().getUnite();
String newLine = name + "=" + expr;
if (!unit.equals("")){
newLine += "@" + unit;
}
newLine += "\n";
String oldEditorString = getEditorString();
// Si c'est un ajout à la fin, on s'en occupe tout de suite
//int n1 = sheet.getColumnCount();
int n2 = sheet.donneNombreColonne();
if (position == n2){
editorString += newLine;
return;
}
// Sinon on reconstruit tout
editorString = "";
String[] lines = oldEditorString.split("\n");
String line;
int n = sheet.getNumberOfExperimentalColumns();
//int n = sheet.getNumberOfCalculatedColumns();
boolean ok = false;
for(int i = 0; i < lines.length; i++){
line = lines[i] + "\n";
ArrayList<Noeud> nodes = new ArrayList<Noeud>();
try {
Lexer lex = new Lexer(new java.io.StringReader(line), nodes);
lex.yylex();
} catch (Exception ex) {
System.err.println("Erreur interne du lexer!");
return;
}
// //
// if (nodes == null || nodes.get(0) == null){
// System.out.println("Erreur interne EditColumnsModel.modifyColumn!");
// return;
// }
// la ligne est vide ou est un commentaire on la recopie
if (nodes.isEmpty() || nodes.get(0).getType() == Sym.COMMENT){
editorString += line;
continue;
}
// la ligne ne commence pas par un id
if (nodes.get(0).getType() != Sym.ID){
System.out.println("Erreur interne EditColumnsModel.modifyColumn!");
return;
}
// on insere la nouvelle ligne si c'est la bonne position
if (position == n + 1){
editorString += newLine;
ok = true;
}
// la ligne est celle correspondant à un id, on la recopie
editorString += line;
n++;
}
// Si on arrive ici, c'est qu'il faut ajouter newLine en bout
if (!ok){
editorString += newLine;
}
}
private boolean isNameIn(String name,ArrayList<Colonne> cols){
for (Colonne col : cols){
if (col.getColonneDescription().getNom().equals(name)){
return true;
}
}
return false;
}
/**
* Une colonne a été détruite "à la main", il faut reconstruire editorString
* @param event
*/
@Override
public void columnDeleted(SheetsColumnDeletedEvent event) {
String oldEditorString = getEditorString();
editorString = "";
String[] lines = oldEditorString.split("\n");
String line;
for(int i = 0; i < lines.length; i++){
line = lines[i] + "\n";
ArrayList<Noeud> nodes = new ArrayList<Noeud>();
try {
Lexer lex = new Lexer(new java.io.StringReader(line), nodes);
lex.yylex();
} catch (Exception ex) {
System.err.println("Erreur interne du lexer!");
return;
}
// //
// if (nodes == null || nodes.get(0) == null){
// System.out.println("Erreur interne EditColumnsModel.modifyColumn!");
// return;
// }
// la ligne est vide ou est un commentaire on la recopie
if (nodes.isEmpty() || nodes.get(0).getType() == Sym.COMMENT){
editorString += line;
continue;
}
// la ligne ne commence pas par un id
if (nodes.get(0).getType() != Sym.ID){
System.out.println("Erreur interne EditColumnsModel.modifyColumn!");
return;
}
// la ligne est celle correspondant à un id, on la recopie si elle
// ne doit pas être supprimée
String name = nodes.get(0).getNom();
ArrayList<Colonne> cols = (ArrayList<Colonne>)event.getColonnes().get(0);
if (!isNameIn(name, cols)){
editorString += line;
}
}
}
@Override
public void angleChanged(SheetsAngleChangedEvent event) {
}
/**
* Une colonne a été modifiée "à la main", il faut reconstruire editorString
* @param event
*/
@Override
public void columnModified(SheetsColumnModifiedEvent event) {
// String oldEditorString = event.getOldEditorString();
// if (!oldEditorString.equals(editorString)){
// System.out.println("Les deux editors sont différents");
// }
String oldEditorString = getEditorString();
String newName = event.getNewNom();
editorString = "";
Tableur sheet = SpreadSheets.getInstance().getActiveSheet();
String[] lines = oldEditorString.split("\n");
String line;
for(int i = 0; i < lines.length; i++){
line = lines[i] + "\n";
ArrayList<Noeud> nodes = new ArrayList<Noeud>();
try {
Lexer lex = new Lexer(new java.io.StringReader(line), nodes);
lex.yylex();
} catch (Exception ex) {
System.err.println("Erreur interne du lexer!");
return;
}
//
// if (nodes == null || nodes.get(0) == null){
// System.out.println("Erreur interne EditColumnsModel.modifyColumn!");
// return;
// }
// la ligne est vide ou est un commentaire on la recopie
if (nodes.isEmpty() || nodes.get(0).getType() == Sym.COMMENT){
editorString += line;
continue;
}
// la ligne ne commence pas par un id
if (nodes.get(0).getType() != Sym.ID){
System.out.println("Erreur interne EditColumnsModel.modifyColumn!");
return;
}
// la ligne est celle correspondant à un id, on la reconstruit entierement
// System.out.println("----------");
// for (Colonne col : sheet.getListeColonnes()){
// System.out.println(col.getColonneDescription().getNom());
// }
// System.out.println("----------");
String name = nodes.get(0).getNom();
Colonne col = sheet.donneColonne(name);
if (col == null){
col = sheet.donneColonne(newName);
name = newName;
}
// ColonneDescription cd = col.getColonneDescription();
// String s = cd.getExpression();
if (col == null){
System.out.println("**********************col == null, " + newName);
}
String expression = col.getColonneDescription().getExpression().trim();
String unit = col.getColonneDescription().getUnite().trim();
String comment = "";
boolean addComment = false;
// Récupérer les commentaires éventuels
for (int k = 0; k < nodes.size(); k++){
if (nodes.get(k).getType() == Sym.COMMENT){
if (k < nodes.size() - 1){
comment = nodes.get(k+1).getTexteLexer();
if (comment.length() > 0){
addComment = true;
}
break;
}
}
}
editorString += name + "=" + expression;
if (unit.length() > 0){
editorString += "@" + unit;
}
if (addComment){
editorString += "#" + comment;
}
editorString += "\n";
}
}
@Override
public void columnMoved(SheetsColumnMovedEvent event) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void columnSorted(SheetsColumnSortedEvent event) {
}
/**
*
* @param event
*/
@Override
public void columnsEdited(SheetsColumnsEditedEvent event) {
if (!event.isUndoable()){ // l'appel provient d'un undo ou redo
//System.out.println("EditColumnsModel : columnsEdited");
setEditorString(event.getNewEditor());
}
}
@Override
public void fichierOuvert(FichierOuvertEvent event) {
//editorString = "";
}
@Override
public void applicationFermee(ApplicationSeFermeEvent event) {
}
@Override
public void nouveauExperience(NouveauExperienceEvent event) {
editorString = "";
}
@Override
public void mainSave(SaveEvent event) {
}
@Override
public void sheetDescriptionChanged(SheetDescriptionChangedEvent event) {
}
@Override
public void sheetsCSChanged(SheetsCSChangedEvent event) {
// throw new UnsupportedOperationException("Not supported yet.");
}
public interface EditColumnsListener extends EventListener {
public void columnsChanged(ColumnsChangedEvent event);
}
public class ColumnsChangedEvent {
private String editString;
public ColumnsChangedEvent(String editString) {
this.editString = editString;
}
public String getEditString() {
return editString;
}
}
public class ErrorChangedEvent{
private String error;
public ErrorChangedEvent(String error){
this.error = error;
}
public String getError() {
return error;
}
}
/**
* Ajoute un écouteur à la liste
* @param listener l'écouteur à ajouter
*/
public final void addListener(EditColumnsListener listener) {
listeners.add(EditColumnsListener.class, listener);
}
/**
* Retire un écouteur de la liste
* @param listener l'écouteur à retirer
*/
public void removeListener(EditColumnsListener listener) {
listeners.remove(EditColumnsListener.class, listener);
}
public class EditState {
private String text;
private ArrayList<StyledToken> tokens;
private String errorText;
private boolean okState, undoState, redoState;
private int caretPosition;
public EditState(String text, ArrayList<StyledToken> tokens,
String errorText, boolean okState, boolean undoState,
boolean redoState, int caretPosition){
this.text = text;
this.tokens = tokens;
this.errorText = errorText;
this.okState = okState;
this.undoState = undoState;
this.redoState = redoState;
this.caretPosition = caretPosition;
}
public void setRedoState(boolean redoState) {
this.redoState = redoState;
}
public void setUndoState(boolean undoState) {
this.undoState = undoState;
}
public int getCaretPosition() {
return caretPosition;
}
public String getText() {
return text;
}
public String getErrorText() {
return errorText;
}
public boolean isOkState() {
return okState;
}
public boolean isRedoState() {
return redoState;
}
public ArrayList<StyledToken> getTokens() {
return tokens;
}
public boolean isUndoState() {
return undoState;
}
}
/*
* ************* Undo et Redo dans l'éditeur *********************
*/
public EditState undo(){
if (!isUndoPossible()) {
return null;
}
index--;
EditState es = editStates.get(index);
es.setUndoState(isUndoPossible());
es.setRedoState(isRedoPossible());
return es;
}
public EditState redo(){
if (!isRedoPossible()) {
return null;
}
index++;
EditState es = editStates.get(index);
es.setUndoState(isUndoPossible());
es.setRedoState(isRedoPossible());
return es;
}
/** Règle le nombre max de undo possible
*
* @param maxUndo
*/
public void setMaxUndo(int maxUndo){
this.maxUndo = maxUndo;
}
private void addEditState(EditState es){
// supprimer les éléments suivants index
if (index != editStates.size() - 1) {
for (int i = editStates.size() - 1; i > index; i--) {
editStates.remove(i);
}
}
// Ajouter le nouveau es à la liste
editStates.add(es);
index++;
// Supprimer le premier élément s'il y en a trop
if (editStates.size() > maxUndo){
editStates.remove(0);
index--;
}
es.setUndoState(isUndoPossible());
es.setRedoState(isRedoPossible());
}
private boolean isUndoPossible(){
return index > 0;
}
private boolean isRedoPossible(){
return index < editStates.size() - 1;
}
}