Commit 239828810c452aadc8a26f7d4abccd3d44acd34c

Authored by [mandjemb]
1 parent a7f554a1

update ihm

.Rhistory 0 → 100644
essai.ser
No preview for this file type
rapport_finale.md 0 → 100644
... ... @@ -0,0 +1,394 @@
  1 +# RAPPORT FINALE
  2 +
  3 +> ANDJEMBE Maksoudath, TANIEL Rémi
  4 +
  5 +Le but du projet est de réaliser un tableur "basique" mais facilement
  6 +extensible, l'application sera divisée en 2 parties :
  7 +* le kernel
  8 +* la partie graphique
  9 +
  10 +Le kernel s'occupera de toutes les opérations de notre grid, les cases
  11 +ne pourront contenir que des réels ou des formules(opération binaire ou
  12 +des fonctions acceptant des plages de cases).
  13 +
  14 +## 1. Analyse et conception
  15 +
  16 +
  17 +### SCHEMA UML
  18 +
  19 +Voici le schéma UML de notre application, les classes et méthodes
  20 +abstraites sont en italique :
  21 +
  22 +![UML](uml.png)
  23 +
  24 +
  25 +### PSEUDO-JAVA CREATION GRILLE,CASES
  26 +
  27 +Voici un exemple de création d'une grid et de l'ajout / modification /
  28 +affichage de plusieurs types de case :
  29 +
  30 +```java
  31 +class Application {
  32 +
  33 + public static void main(String[] args) {
  34 + Grille g = new Grille();
  35 +
  36 + g.createCase("b",1); //Ajout case vide
  37 + g.createCase("a",1,100.0); //Ajout case avec valeur
  38 + g.createCase("a",2,50.0); //Ajout case avec valeur
  39 + g.createCase("a",3,new Addition(g.getCase("a",2),g.getCase("a",1))); //Ajout case avec operation binaire
  40 +
  41 + List<Case> plageCase1 = new ArrayList<Case>(); // Crée une liste de case
  42 + plageCase1.add(g.getCase("a",1));
  43 + plageCase1.add(g.getCase("a",2));
  44 + plageCase1.add(g.getCase("a",3));
  45 +
  46 + g.createCase("a",4,new Somme(plageCase1)); //Ajout case avec fonctions
  47 +
  48 + g.setValeur("b",1,100); //Met la valeur de b1 à 100
  49 +
  50 + List<Case> plageCase2 = new ArrayList<Case>(); // Crée une liste de case
  51 + plageCase1.add(g.getCase("a",4));
  52 + plageCase1.add(g.getCase("a",2));
  53 + plageCase1.add(g.getCase("a",3));
  54 +
  55 + g.setFormule("b",2,new Moyenne(plageCase2)); //Met la formule dans b2
  56 +
  57 + g.getValeur("a",1); //Affichera 100.0
  58 + g.getValeur("a",4); //Affichera (100+50+150)=100
  59 + g.getFormuleAsString("b",2); //Affichera MOYENNE(a4,a2,a3)
  60 + g.getFormuleDeveloppe("b",2);
  61 + }
  62 +}
  63 +```
  64 +
  65 +### CHOIX STRUCTURE DE DONNÉES
  66 +
  67 +Nous devons choisir une structure de donnée pour stocker les cases dans
  68 +notre grid, nous savons déjà que nous allons utiliser ne collection
  69 +pour les stocker,voici celles que nous connaissons:
  70 +- des tableaux
  71 +- des listes
  72 +- des maps
  73 +- des sets
  74 +
  75 +D'après le schéma UML ci-dessus, nous allons donc utiliser une `HashMap`
  76 +pour stocker les cases de notre grid :
  77 +* Pour rechercher une case et, effectuer des opérations dessus ce sera
  78 +plus facile, la clé de la Map sera une chaine de caractère (String) qui
  79 +représente la coordonnée de cette case (c'est-à-dire la concaténation
  80 +du nom de ligne et de l'indice de la colonne, exemple "A1", "B9", etc...)
  81 +
  82 +Une case peut etre utilisée dans plusieurs autres cases, on ne sait
  83 +pas le nombre d'autres cases où elle sera utilisée, on stockera donc
  84 +cette donée dans une `ArrayList` de `Case`.
  85 +
  86 +Certaines fonctions (`Moyenne`, `Somme`) utilise également une plage de case, pour stocker ces cases,
  87 +nous allons également une `ArrayList` de `Case`.
  88 +
  89 +### METHODES ESSENTIELLES EN PSEUDO-JAVA
  90 +
  91 +#### 1. Methode getValeur
  92 +
  93 +```java
  94 +
  95 +class Grille {
  96 + Map<String, Case> cases = new HashMap<>();
  97 +
  98 + double getValeur(String colonne, int ligne){
  99 + String code=colonne+ligne;
  100 + return cases.get(code).getValeur();
  101 + }
  102 +}
  103 +
  104 +
  105 +class Case {
  106 + String colonne;
  107 + int ligne;
  108 + double valeur;
  109 +
  110 + double getValeur() {
  111 + return valeur;
  112 + }
  113 +}
  114 +
  115 +```
  116 +
  117 +
  118 +#### 2. Methode getFormuleAsString
  119 +
  120 +```java
  121 +
  122 +class Grille {
  123 + Map<String, Case> cases = new HashMap<>();
  124 +
  125 + String getFormule(String colonne, int ligne) {
  126 + String code=colonne+ligne;
  127 + return cases.get(code).getFormuleAsString();
  128 + }
  129 +}
  130 +
  131 +
  132 +class Case {
  133 + String colonne;
  134 + int ligne;
  135 + double valeur;
  136 + Formule formule;
  137 +
  138 + String getFormuleAsString() {
  139 + if (formule != null)
  140 + return formule.toString();
  141 + else
  142 + return toString();
  143 + }
  144 +}
  145 +
  146 +// Exemple pour Addition
  147 +class Addition {
  148 + Case gauche;
  149 + Case droite;
  150 +
  151 + String toString() {
  152 + return gauche.toString() + "+" + droite.toString();
  153 + }
  154 +}
  155 +
  156 +```
  157 +
  158 +
  159 +#### 3. Methode getFormuleDeveloppe
  160 +
  161 +```java
  162 +class Grille{
  163 + Map<String, Case> cases = new HashMap<>();
  164 +
  165 + String getFormuleDeveloppe(String colonne, int ligne) {
  166 + String code=colonne+ligne;
  167 + return cases.get(code).getFormuleDeveloppe();
  168 + }
  169 +}
  170 +
  171 +class Case{
  172 + String colonne;
  173 + int ligne;
  174 + double valeur;
  175 + Formule formule;
  176 + ArrayList<Case> utiliseDans = new ArrayList<Case>();
  177 +
  178 + String getFormuleDeveloppe() {
  179 + if (formule != null)
  180 + return formule.getFormuleDeveoppe();
  181 + else
  182 + return toString();
  183 + }
  184 +}
  185 +
  186 +Average
  187 +class Moyenne {
  188 + List<Case> listCases = new ArrayList<Case>();
  189 +
  190 + String getFormuleDeveloppe() {
  191 + return Average + listCases.stream().map(c -> c.getFormuleDeveloppe()).collect((Collectors).joining(", ")) + ")";
  192 + }
  193 +}
  194 +
  195 +```
  196 +
  197 +
  198 +#### 4. Methode eval()
  199 +
  200 +- Dans Addition :
  201 +
  202 +```java
  203 +class Addition {
  204 + Case gauche;
  205 + Case droite;
  206 +
  207 + double eval() {
  208 + return gauche.getValeur() + droite.getValeur();
  209 + }
  210 +}
  211 +
  212 +```
  213 +
  214 +- Dans Multiplication :
  215 +
  216 +```java
  217 +class Multiplication {
  218 + Case gauche;
  219 + Case droite;
  220 +
  221 + double eval() {
  222 + return gauche.getValeur() * droite.getValeur();
  223 + }
  224 +}
  225 +```
  226 +
  227 +
  228 +- Dans Soustraction :
  229 +
  230 +```java
  231 +class Soustraction {
  232 + Case gauche;
  233 + Case droite;
  234 +
  235 + double eval() {
  236 + return gauche.getValeur() - droite.getValeur();
  237 + }
  238 +}
  239 +
  240 +```
  241 +
  242 +- Dans Division :
  243 +
  244 +```java
  245 +class Division {
  246 + Case gauche;
  247 + Case droite;
  248 +
  249 + double eval() {
  250 + if (droite.getValeur() != 0)
  251 + return gauche.getValeur() / droite.getValeur();
  252 + else
  253 + lève une exception
  254 + }
  255 +}
  256 +
  257 +```
  258 +
  259 +- Dans Moyenne :
  260 +
  261 +```java
  262 +class Moyenne {
  263 + List<Case> listCases = new ArrayList<Case>();
  264 +
  265 + double eval() {
  266 + double val=0;
  267 +
  268 + if (listCases.size() != 0)
  269 + for(int i=0; i<listCases.size(); i++)
  270 + val += listCases.get(i).getValeur();
  271 + return val / listCases.size();
  272 + else
  273 + lève une exception
  274 + }
  275 +}
  276 +
  277 +```
  278 +- Dans Somme :
  279 +
  280 +```java
  281 +class Somme {
  282 + List<Case> listCases = new ArrayList<Case>();
  283 +
  284 + double eval() {
  285 + double val=0;
  286 + if (listCases.size() != 0)
  287 + for(int i=0; i<listCases.size(); i++)
  288 + val += listCases.get(i).getValeur();
  289 + return val;
  290 + else
  291 + lève une exception
  292 + }
  293 +}
  294 +
  295 +```
  296 +
  297 +#### 5. Methode setValeur
  298 +
  299 +```java
  300 +class Grille {
  301 + Map<String, Case> cases = new HashMap<>();
  302 +
  303 + void setValeur(String colonne, int ligne, double value) {
  304 + String code = colonne + ligne;
  305 + return cases.get(code).setValeur(value);
  306 + }
  307 +}
  308 +
  309 +class Case {
  310 + String colonne;
  311 + int ligne;
  312 + double valeur;
  313 + Formule formule;
  314 + List<Case> utiliseDans = new ArrayList<Case>();
  315 +
  316 + void setValeur(double value) {
  317 + valeur = value;
  318 + for(int i=0; i<utiliseDans.size(); i++)
  319 + utiliseDans.get(i).updateValeur();
  320 + }
  321 +}
  322 +
  323 +```
  324 +
  325 +#### 5. Methode setFormule
  326 +
  327 +```java
  328 +class Grille {
  329 + Map<String, Case> cases = new HashMap<>();
  330 +
  331 + void setFormule(String colonne, int ligne, Formule formule) {
  332 + String code = colonne + ligne;
  333 + return cases.get(code).setFormule(formula);
  334 + }
  335 +}
  336 +
  337 +
  338 +class Case {
  339 + String colonne;
  340 + int ligne;
  341 + double valeur;
  342 + Formule formule;
  343 + List<Case> utiliseDans = new ArrayList<Case>();
  344 +
  345 + void updateValeur() {
  346 + valeur = formule.eval();
  347 + }
  348 +
  349 + void setFormule(Formule formula) {
  350 + if (!formula.creerCycle(this))
  351 + formule = formula;
  352 + updateValeur();
  353 + for(int i=0; i<utiliseDans.size(); i++)
  354 + utiliseDans.get(i).updateValeur();
  355 + else
  356 + lève une exception
  357 + }
  358 +}
  359 +
  360 +BinaryOperation
  361 +class OperationBinaire {
  362 + Case gauche;
  363 + Case droite;
  364 +
  365 + boolean creerCycle(Case case) {
  366 + if (gauche != case && droite != case) {
  367 + if (gauche.isFormula() && droite.isFormula())
  368 + return gauche.getFormule().creerCycle(case) && droite.getFormule().creerCycle(case);
  369 + else
  370 + return false;
  371 + }
  372 +
  373 + return true;
  374 + }
  375 +}
  376 +
  377 +```
  378 +
  379 +### LISTE DE TESTS
  380 +
  381 +Afin de s'assurer de la maintenabilité de notre code et de la qualité de
  382 +celui-ci, nous allons réaliser plusieurs tests sur les différentes méthodes
  383 +que nous allons programmé dans notre application, voici quelques
  384 +exemples :
  385 +
  386 +- Création d'une case avec une valeur fixe
  387 +- Création d'une case avec une formule d' `Opération binaire` et une
  388 +fonction comme `Moyenne`
  389 +- Modification d'une case avec une valeur sans qu'elle soit utilisée dans
  390 +une autre case
  391 +- Modification d'une case avec une valeur utilisée dans une autre case
  392 +- Vérification qu'une erreur se lève lors de la création des 2 types
  393 +de cycles (direct et indirect)
  394 +- Renvoie de la formule dévéloppée d'une case avec une formule assez compliqué
... ...
src/app/Application.java
... ... @@ -19,7 +19,7 @@ import java.util.List;
19 19 public class Application {
20 20  
21 21 public static void main(String[] args) throws IOException {
22   - File fichier = new File("essai.ser");
  22 + File fichier = new File("grille.ser");
23 23  
24 24 // ouverture d'un flux sur un fichier
25 25 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(fichier));
... ... @@ -31,8 +31,11 @@ public class Application {
31 31  
32 32 try {
33 33 grid.createCell("A", 1, 60.);
  34 + grid.createCell("B", 1, 50.);
34 35 grid.createCell("B", 1, 0.);
  36 +
35 37 grid.createCell("A", 2, 5.);
  38 + grid.createCell("C", 8, 5.);
36 39 grid.createCell("A", 6, new Addition(grid.getCell("A", 1), grid.getCell("A", 2)));
37 40  
38 41 List<Cell> sumList = new ArrayList<>();
... ...
src/ihm/TablooProto.java
... ... @@ -4,28 +4,38 @@ package ihm;
4 4 * TablooProto.java requires no other files.
5 5 *
6 6 */
7   -
8   -import kernel.Grid;
9   -import kernel.exception.CellNotFoundException;
10   -import kernel.exception.InvalidIntervalException;
11   -
12   -import javax.swing.*;
  7 +import java.awt.Color;
  8 +import java.awt.Component;
  9 +import javax.swing.JFrame;
  10 +import javax.swing.JScrollPane;
  11 +import javax.swing.JTable;
13 12 import javax.swing.table.AbstractTableModel;
14   -import javax.swing.table.DefaultTableCellRenderer;
15   -import javax.swing.table.TableColumn;
16   -import java.awt.*;
  13 +import java.awt.Dimension;
  14 +import java.awt.GridLayout;
17 15 import java.io.File;
18 16 import java.io.FileInputStream;
  17 +import java.io.FileNotFoundException;
19 18 import java.io.IOException;
20 19 import java.io.ObjectInputStream;
21   -import java.util.Collections;
  20 +
  21 +import javax.swing.JLabel;
  22 +import javax.swing.JPanel;
  23 +import javax.swing.table.DefaultTableCellRenderer;
  24 +import javax.swing.table.TableColumn;
  25 +
  26 +import kernel.Grid;
  27 +import kernel.exception.CellNotFoundException;
  28 +import kernel.exception.InvalidIntervalException;
22 29  
23 30 public class TablooProto extends JPanel {
24 31  
  32 + /**
  33 + *
  34 + */
25 35 private static final long serialVersionUID = 1L;
26 36  
27 37 // Fourni: ne rien changer.
28   - public TablooProto() throws ClassNotFoundException, IOException {
  38 + public TablooProto() throws FileNotFoundException, ClassNotFoundException, IOException {
29 39 super(new GridLayout(1, 0));
30 40  
31 41 // modele de donnees
... ... @@ -90,15 +100,19 @@ public class TablooProto extends JPanel {
90 100 private static final long serialVersionUID = 1L;
91 101 // TODO
92 102 // remplacer ce tableau en dur du prototype par la grille serialisee:
93   - // noyau.Grille calc;
94   - Grid calc;
  103 + kernel.Grid calc;
  104 + //String[][] calc;
95 105  
96   - MyTableModel() throws ClassNotFoundException, IOException {
  106 + MyTableModel() throws FileNotFoundException, IOException, ClassNotFoundException {
97 107 // TODO: remplacer cette initialisation par le chargement de la grille serialisee
98   - File fichier = new File("essai.ser") ;
  108 + File fichier = new File("grille.ser") ;
99 109 ObjectInputStream ois = new ObjectInputStream(new FileInputStream(fichier)) ;
100 110 calc = (Grid)ois.readObject() ;
101 111 ois.close();
  112 + //calc = new String[this.getRowCount()][this.getColumnCount()];
  113 + //for (int ligne =0; ligne < calc.length; ligne++)
  114 + //for (int colonne=0; colonne < calc[ligne].length; colonne++)
  115 + //calc[ligne][colonne] = "";
102 116 }
103 117  
104 118 @Override
... ... @@ -106,17 +120,14 @@ public class TablooProto extends JPanel {
106 120 public int getColumnCount() {
107 121 // TODO: remplacer par le nbre de colonnes de la grille
108 122 // + 1 pour la colonne 0 consacrée aux numeros de ligne)
109   - //return Collections.max(calc.getTotalColumn())+1;
110   - return 10;
  123 + return calc.getTotalColumn()+1;
111 124 }
112 125  
113 126 @Override
114 127 // Standard: doit retourner le nbre de lignes de la JTable
115 128 public int getRowCount() {
116 129 // TODO: remplacer par le nbre de lignes de la grille
117   - return Collections.max(calc.getTotalLine())+1;
118   - //return 10;
119   -
  130 + return calc.getTotalLine();
120 131 }
121 132  
122 133 // Standard: doit renvoyer le nom de la colonne a afficher en tete
... ... @@ -150,12 +161,11 @@ public class TablooProto extends JPanel {
150 161 try {
151 162 return "" + calc.getDevelopedFormula(this.getColumnName(col), row+1)+"="+calc.getValue(this.getColumnName(col), row+1);
152 163 } catch (CellNotFoundException e) {
153   -
  164 + // TODO Auto-generated catch block
154 165  
155 166 }
156 167 }
157   - return 0;
158   -
  168 + return "";
159 169 }
160 170  
161 171 // Standard.
... ... @@ -202,7 +212,7 @@ public class TablooProto extends JPanel {
202 212 calc.createCell(this.getColumnName(col), row+1, Double.parseDouble((String)value));
203 213 } catch (InvalidIntervalException e) {
204 214 // TODO Auto-generated catch block
205   - e.printStackTrace();
  215 +
206 216 }
207 217 }
208 218 // Ne pas modifier :
... ... @@ -214,7 +224,7 @@ public class TablooProto extends JPanel {
214 224  
215 225 // Exécution de l'interface graphique a partir d'un terminal.
216 226 // TODO: parametrer le tout par un fichier de grille serialisee.
217   - public static void main(String[] args) throws ClassNotFoundException, IOException {
  227 + public static void main(String[] args) throws FileNotFoundException, ClassNotFoundException, IOException {
218 228 // TODO: parametrer le tableur par un fichier de grille serialisee
219 229 // a charger comme modele de donnees.
220 230 TablooProto tableur = new TablooProto();
... ...
src/kernel/Cell.java
... ... @@ -10,7 +10,7 @@ import java.util.List;
10 10 public class Cell implements Serializable {
11 11  
12 12 private static final long serialVersionUID = 1L;
13   - private static final int MAX_LIGNES = 20;
  13 +
14 14  
15 15 private String column;
16 16 private int line;
... ... @@ -18,10 +18,9 @@ public class Cell implements Serializable {
18 18 private Formula formula;
19 19 private List<Cell> usedIn = new ArrayList<>();
20 20  
21   - public Cell(String column, int line, double value) throws InvalidIntervalException {
22   - column = column.toUpperCase();
23   - if (!validateInterval(column, line))
24   - throw new InvalidIntervalException();
  21 + public Cell(String column, int line, double value) {
  22 +
  23 +
25 24  
26 25 this.column = column;
27 26 this.line = line;
... ... @@ -29,10 +28,8 @@ public class Cell implements Serializable {
29 28 }
30 29  
31 30 public Cell(String column, int line, Formula formula)
32   - throws CreateCycleException, InvalidIntervalException {
33   - column = column.toUpperCase();
34   - if (!validateInterval(column, line))
35   - throw new InvalidIntervalException();
  31 + throws CreateCycleException {
  32 +
36 33  
37 34 this.column = column;
38 35 this.line = line;
... ... @@ -96,7 +93,5 @@ public class Cell implements Serializable {
96 93 }
97 94 }
98 95  
99   - private boolean validateInterval(String column, int line) {
100   - return line >= 1 && line <= MAX_LIGNES && column.compareTo("A") >= 0 && column.compareTo("Z") <= 0;
101   - }
  96 +
102 97 }
... ...
src/kernel/Grid.java
... ... @@ -13,26 +13,32 @@ import java.util.Map;
13 13 public class Grid implements Serializable {
14 14  
15 15 private static final long serialVersionUID = 1L;
16   -
  16 + private static final int MAX_LIGNES = 20;
  17 + private static final String MAX_COLONNES = "Z";
17 18 private Map<String, Cell> cells = new HashMap<>();
18 19 public static LanguageEnum language = LanguageEnum.FR;
19   - private List<Integer> listLine = new ArrayList<>();
20   - private List<Integer> listColumn = new ArrayList<>();
  20 +
21 21  
22 22 public void createCell(String column, int line, double value) throws InvalidIntervalException {
  23 + column = column.toUpperCase();
  24 +
  25 + if (!validateInterval(column, line))
  26 + throw new InvalidIntervalException();
23 27 String id = this.getCellId(column, line);
24 28 Cell cell = new Cell(column, line, value);
25   -
26 29 this.cells.put(id, cell);
27   - this.saveDifferentLineColumn(column, line);
  30 +
28 31 }
29 32  
30 33 public void createCell(String column, int line, Formula formula) throws CreateCycleException, InvalidIntervalException {
  34 + column = column.toUpperCase();
  35 +
  36 + if (!validateInterval(column, line))
  37 + throw new InvalidIntervalException();
31 38 String id = this.getCellId(column, line);
32 39 Cell cell = new Cell(column, line, formula);
33   -
34 40 this.cells.put(id, cell);
35   - this.saveDifferentLineColumn(column, line);
  41 +
36 42 }
37 43  
38 44 public void setValue(String column, int line, double value) throws CellNotFoundException {
... ... @@ -77,18 +83,28 @@ public class Grid implements Serializable {
77 83 return column + line;
78 84 }
79 85  
80   - private void saveDifferentLineColumn(String column, int line) {
81   - if (!this.listLine.contains(line))
82   - this.listLine.add(line);
83   - if (!this.listColumn.contains((int) column.charAt(0)))
84   - this.listColumn.add((int) column.charAt(0) - (int) 'A' + 1);
  86 +
  87 + public int getTotalColumn() {
  88 + return MAX_COLONNES.charAt(0) - (int) 'A' + 1;
  89 + //return convertStringToInt(MAX_COLONNES);
  90 + }
  91 +
  92 + public int getTotalLine() {
  93 + return MAX_LIGNES;
85 94 }
86 95  
87   - public List<Integer> getTotalColumn() {
88   - return listColumn;
  96 + private boolean validateInterval(String column, int line) {
  97 + return line >= 1 && line <= MAX_LIGNES && convertStringToInt(column)>=convertStringToInt("A") && convertStringToInt(column)<=convertStringToInt(MAX_COLONNES);
89 98 }
90 99  
91   - public List<Integer> getTotalLine() {
92   - return listLine;
  100 + private int convertStringToInt(String str){
  101 + int ascii=0;
  102 + for(int i = 0; i < str.length(); i++){ // while counting characters if less than the length add one
  103 + char character = str.charAt(i); // start on the first character
  104 + ascii = ascii+(int) character;
  105 +
  106 + }
  107 + return ascii;
93 108 }
  109 +
94 110 }
... ...