/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
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.main;
import freegressi.graphics.GraphicModel;
import freegressi.graphics.GraphicStyle;
import freegressi.tableur.SpreadSheets;
import freegressi.tableur.Tableur;
import freegressi.fit.FitModel;
import freegressi.utils.Utils;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.text.DateFormat;
import java.util.*;
import javax.swing.JOptionPane;
import javax.swing.event.EventListenerList;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.SAXException;
/**
* Le modèle des données de fichier : ouverture sauvegarde...
* Singleton
* @author marchand
*/
public class MainModel {
/** Le numéro de version de freegressi */
private String version = "0.1alpha";
/** Le nom de l'application */
private String applicationName = "Freegressi " + version;
/** Le nom de base d'une nouvelle feuille */
private String baseSheetName = "Feuille";
/** Le nom de base d'un nouveau fichier */
private String noName = "Sans Nom";
/** Le numéro d'une nouvelle feuille */
private int sheetNumber;
/** Le fichier correspondant au document */
private File file = null;
/** La liste des écouteurs */
private EventListenerList listeners;
/** MainModel est un singleton */
private static MainModel mainModel = null;
/**
* Constructeur privé pour singleton
*/
private MainModel() {
listeners = new EventListenerList();
initSheetNumber(0);
}
/**
*
* @return La seule instance du singleton
*/
public static MainModel getInstance(){
if (mainModel == null){
mainModel = new MainModel();
}
return mainModel;
}
/**
*
* @return le nom de l'application + version
*/
public String getApplicationName() {
return applicationName;
}
/**
*
* @return la version de l'application
*/
public String getVersion() {
return version;
}
/**
*
* @return le File du document ouvert
*/
public File getFile(){
return file;
}
/**
*
* @return Le nom court du fichier
*/
public String getShortFileName(){
if (file != null){
return file.getName();
}else{
return noName;
}
}
/**
*
* @return le prochain numéro de feuille
*/
private int getNextSheetNumber(){
sheetNumber++;
return sheetNumber;
}
/**
* Initialise le numéro de nouvelle feuille
* @param n
*/
private void initSheetNumber(int n){
sheetNumber = n;
}
/**
* L'interface permet de communiquer avec la JMainFrame
*/
public interface MainListener extends EventListener {
public void fichierOuvert(FichierOuvertEvent event);
public void applicationFermee(ApplicationSeFermeEvent event);
public void nouveauExperience(NouveauExperienceEvent event);
public void mainSave(SaveEvent event);
}
/**
* Ajoute un écouteur à la liste
* @param listener l'écouteur à ajouter
*/
public void addMainListener(MainListener listener) {
listeners.add(MainListener.class, listener);
}
/**
* Retire un écouteur de la liste
* @param listener l'écouteur à retirer
*/
public void removeMainListener(MainListener listener) {
listeners.remove(MainListener.class, listener);
}
/** ************************************************************************
* Création d'un nouveau fichier à partir de données expérimentales
*
************************************************************************* */
/**
* Classe qui définit l'évenement :
* - nouveau fichier à partir de données expérimentales
*/
public class NouveauExperienceEvent extends EventObject {
private Tableur tableur;
public NouveauExperienceEvent(Object source, Tableur tableur) {
super(source);
this.tableur = tableur;
}
public Tableur getTableur() {
return tableur;
}
}
/**
* Un nouveau fichier est créé, à partir de variables expérimentales
* @param listeNoms la liste des noms de variables expérimentales
* @param listeUnites la liste des unités de variables
*/
public void notifyNouveauExperience(ArrayList<String> listeNoms, ArrayList<String> listeUnites) {
GraphicModel.getInstance().setInitializing(true);
Tableur tableur = new Tableur(listeNoms, listeUnites);
// créer une ligne vierge pour commencer
tableur.ajouteNLignesVierges(1, 0);
file = null;
initSheetNumber(0);
tableur.setName(baseSheetName + getNextSheetNumber());
fireNouveauExperience(tableur);
List<Tableur> sheetList = new ArrayList<>();
sheetList.add(tableur);
SpreadSheets.getInstance().notifyNewDocument(sheetList, "", 3);
GraphicModel.getInstance().notifyGraphicStyleChanged(null, false);
GraphicModel.getInstance().setInitializing(false);
}
/**
* Informe les écouteurs qu'un nouveau fichier est créé à partir
* de variables expérimentales
* @param tableur la feuille correspondante
*/
private void fireNouveauExperience(Tableur tableur) {
MainListener[] listenerList = (MainListener[]) listeners.getListeners(MainListener.class);
for (MainListener listener : listenerList) {
listener.nouveauExperience(new NouveauExperienceEvent(this, tableur/*, listeTendances, listeGraphiques, fileName*/));
}
}
/** ************************************************************************
* Nouvelle feuille
*
************************************************************************* */
/**
* Création d'une nouvelle feuille vierge
*/
public void notifyNewSheet(){
Tableur sheet = SpreadSheets.getInstance().getActiveSheet();
Tableur newSheet = sheet.getEmptyCopy();
newSheet.ajouteNLignesVierges(1, 0);
int n = getNextSheetNumber();
newSheet.setName(baseSheetName + n);
SpreadSheets.getInstance().notifySheetAdded(newSheet, true);
}
/** ************************************************************************
* Ouverture d'un fichier FRG
*
************************************************************************* */
/**
* Un fichier vient d'être ouvert
* @param file
* @return true si tout s'est bien passé
*/
public boolean notifyOuvrirFichier(File file) {
String ext = getFileExtensionName(file);
if (ext.equals("rw3")){
RW3Handler rw3 = new RW3Handler();
String str = Utils.fileToString(file.getAbsolutePath());
try{
rw3.parse(str);
} catch (Exception e){
JOptionPane.showMessageDialog(null,
"Erreur pendant la lecture du document!\n" + file.getName() +
"\n" + e.getMessage(),
"Oups une erreur...", JOptionPane.ERROR_MESSAGE);
return false;
}
List<Tableur> sheets = rw3.getSheets();
GraphicModel.getInstance().setInitializing(true);
String editor = "";
int CS = 3;
SpreadSheets.getInstance().notifyNewDocument(sheets, editor, CS);
//GraphicStyle graphicStyle = gestionnaire.getGraphicStyle();
GraphicModel.getInstance().notifyGraphicStyleChanged(null, false);
fireFichierOuvert( getShortFileName());
GraphicModel.getInstance().setInitializing(false);
return true;
}
SAXParserFactory fabrique = SAXParserFactory.newInstance();
FRGHandler gestionnaire = new FRGHandler();
try {
SAXParser parseur = fabrique.newSAXParser();
parseur.parse(file, gestionnaire);
} catch (ParserConfigurationException | SAXException | IOException exc) {
System.err.println("Erreur pendant la lecture du document! : "
+ exc.getMessage());
JOptionPane.showMessageDialog(null,
"Erreur pendant la lecture du document!\n" + file.getName() +
"\n" + exc.getMessage(),
"Oups une erreur...", JOptionPane.ERROR_MESSAGE);
return false;
}
if (!gestionnaire.isFichierOk()) {
JOptionPane.showMessageDialog(null,
"Il n'y a pas de données dans ce document!\n" + file.getName(),
"Oups une erreur...", JOptionPane.ERROR_MESSAGE);
return false;
}
this.file = file;
List<Tableur> sheetList = gestionnaire.getSheetList();
int n;
for (Tableur sheet : sheetList){
n = getNextSheetNumber();
if (sheet.getName().equals("")){
sheet.setName(baseSheetName + n);
}
}
GraphicModel.getInstance().setInitializing(true);
String editor = gestionnaire.getEditor();
int CS = gestionnaire.getCS();
SpreadSheets.getInstance().notifyNewDocument(sheetList, editor, CS);
GraphicStyle graphicStyle = gestionnaire.getGraphicStyle();
GraphicModel.getInstance().notifyGraphicStyleChanged(graphicStyle, false);
fireFichierOuvert( getShortFileName());
GraphicModel.getInstance().setInitializing(false);
//initSheetNumber(sheetList.size());
return true;
}
/**
* Informe les écouteurs qu'un fichier vient d'être ouvert
* @param nomFichier
*/
private void fireFichierOuvert(String nomFichier) {
MainListener[] listenerList = (MainListener[]) listeners.getListeners(MainListener.class);
for (MainListener listener : listenerList) {
listener.fichierOuvert(new FichierOuvertEvent(this, nomFichier));
}
}
/**
* Classe qui définit l'évenement :
* - ouverture d'un fichier
*/
public class FichierOuvertEvent extends EventObject {
private String nomFichier;
public FichierOuvertEvent(Object source, String nomFichier) {
super(source);
this.nomFichier = nomFichier;
}
public String getNomFichier() {
return nomFichier;
}
}
/** ************************************************************************
* Fermer l'application
*
************************************************************************* */
/**
* L'application va se fermer
*/
public void notifyFermerApplication() {
fireFermerApplication();
}
/**
* Informe les écouteurs que l'application va se fermer
*/
private void fireFermerApplication() {
//System.out.println("ferme");
MainListener[] listenerList = (MainListener[]) listeners.getListeners(MainListener.class);
for (MainListener listener : listenerList) {
listener.applicationFermee(new ApplicationSeFermeEvent(this));
}
}
/**
* Classe qui définit l'évenement :
* - l'application se ferme
*/
public class ApplicationSeFermeEvent extends EventObject {
public ApplicationSeFermeEvent(Object source) {
super(source);
}
}
/** ************************************************************************
* Enregistrer le fichier
*
************************************************************************* */
/**
* Classe qui définit l'évenement :
* - On enregistre le document
*/
public class SaveEvent extends EventObject {
public SaveEvent(Object source) {
super(source);
}
}
/**
* Enregistre un fichier sur le disque
* @param text le texte à enregistrer
* @param nomDuFichier le nom du fichier sur le disque
*/
private void save(String text, String fileName) {
try {
String xml = "";
xml += text;
FileWriter lu = new FileWriter(fileName);
try (BufferedWriter out = new BufferedWriter(lu)) {
out.write(xml);
}
} catch (IOException er) {
System.err.println("Erreur durant l'écriture du fichier! " + er.getMessage());
}
}
/**
* Enregistre le document courant
* @param newFile le nom du document à sauver
*/
public void notifySaveAsDocument(File newFile) {
Locale locale = Locale.getDefault();
DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.FULL, locale);
Date now = new Date();
String strDate = dateFormat.format(now);
String str = "<?xml version='1.0' encoding='utf-8'?>\n";
str += "<document>\n";
str += "\t<infos>\n";
str += "\t\t<application-name>"+applicationName+"</application-name>\n";
str += "\t\t<creator>"+System.getProperty("user.name")+"</creator>\n";
str += "\t\t<date>"+strDate+"</date>\n";
str += "\t</infos>\n";
str += SpreadSheets.getInstance().toXML("\t");
str += "\t<fits>\n";
str += FitModel.getInstance().toXML("\t");
str += "\t</fits>\n";
str += GraphicModel.getInstance().toXML("\t");
str += "</document>\n";
file = changeFileExtension(newFile, "frg");
save(str, file.getAbsolutePath());
fireSaveDocument();
}
/**
* A tester, non utilisé, récupéré à :
* http://www.java2s.com/Tutorial/Java/0180__File/Getfileextensionname.htm
* @param f
* @return
*/
public static String getFileExtensionName(File f) {
if (f.getName().indexOf(".") == -1) {
return "";
} else {
return f.getName().substring(f.getName().length() - 3, f.getName().length());
}
}
/**
* Change l'extension d'un nom de fichier
* @param old l'ancien fichier
* @param ext la nouvelle extension
* @return le nouveau fichier
*/
private File changeFileExtension(File old, String ext){
String oldName = old.getAbsolutePath();
int dotPos = oldName.lastIndexOf(".");
//String strExtension = oldName.substring(dotPos + 1);
String strFilename;
if (dotPos > -1){
strFilename = oldName.substring(0, dotPos);
}else{
strFilename = oldName;
}
String strNewFileName = strFilename + "." + ext;
File newFile = new File(strNewFileName);
return newFile;
}
/**
*
* @return Le dernier répertoire utilisé
*/
public String getLastDir(){
if (file != null){
return file.getParent();
}else{
return "";
}
}
/**
* Le document doit être enregistré
*/
public void notifySaveDocument() {
notifySaveAsDocument(file);
}
/**
* Informe les écouteurs que le document vient d'être sauvé
*/
private void fireSaveDocument() {
MainListener[] listenerList = (MainListener[]) listeners.getListeners(MainListener.class);
for (MainListener listener : listenerList) {
listener.mainSave(new SaveEvent(this));
}
}
/** ************************************************************************
* Ouvrir un document à partir du presse-papier
*
************************************************************************* */
/**
* Crée un nouveau document à partir des données contenues dans
* le presse papier
* @param str le presse papier
*/
public void notifyDocumentFromClipboard(String str) {
// Pas de données dans le presse papier
if (str == null) {
JOptionPane.showMessageDialog(null, "Il n'y a pas de données dans le presse-papier!",
"Freegressi, Erreur du presse-papier", JOptionPane.ERROR_MESSAGE);
return;
}
// Il y a des données
CSVHandler csv = new CSVHandler();
Tableur tableur;
// Transformer ces données en liste de colonnes
try {
tableur = csv.stringToSheet(str);
} catch (Exception e){
JOptionPane.showMessageDialog(null, "Les données du presse-papier ne sont pas reconnues!",
"Freegressi, Erreur du presse-papier", JOptionPane.ERROR_MESSAGE);
return;
}
GraphicModel.getInstance().setInitializing(true);
initSheetNumber(0);
tableur.setName(baseSheetName + getNextSheetNumber());
List<Tableur> sheetList = new ArrayList<>();
sheetList.add(tableur);
String editor = tableur.toEditColumns();
SpreadSheets.getInstance().notifyNewDocument(sheetList, editor, 3);
file = null;
fireFichierOuvert(/*null,*/ getShortFileName());
GraphicModel.getInstance().notifyGraphicStyleChanged(null, false);
GraphicModel.getInstance().setInitializing(false);
}
}