Blame view

src/ihm/TablooProto.java 10.1 KB
ebf0bdb2   mandjemb   interface ok: man...
1
2
3
4
5
6
  package ihm;
  
  /*
   * TablooProto.java requires no other files.
   * 
   */
23982881   [mandjemb]   update ihm
7
8
9
10
11
  import java.awt.Color;
  import java.awt.Component;
  import javax.swing.JFrame;
  import javax.swing.JScrollPane;
  import javax.swing.JTable;
ebf0bdb2   mandjemb   interface ok: man...
12
  import javax.swing.table.AbstractTableModel;
23982881   [mandjemb]   update ihm
13
14
  import java.awt.Dimension;
  import java.awt.GridLayout;
ebf0bdb2   mandjemb   interface ok: man...
15
16
  import java.io.File;
  import java.io.FileInputStream;
23982881   [mandjemb]   update ihm
17
  import java.io.FileNotFoundException;
ebf0bdb2   mandjemb   interface ok: man...
18
19
  import java.io.IOException;
  import java.io.ObjectInputStream;
23982881   [mandjemb]   update ihm
20
21
22
23
24
25
26
  
  import javax.swing.JLabel;
  import javax.swing.JPanel;
  import javax.swing.table.DefaultTableCellRenderer;
  import javax.swing.table.TableColumn;
  
  import kernel.Grid;
02c44758   Remi   finish ihm
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
  import kernel.exception.*;
  import kernel.function.Average;
  import kernel.function.Sum;
  import kernel.operation.Addition;
  import kernel.operation.Division;
  import kernel.operation.Multiplication;
  import kernel.operation.Subtraction;
  
  import javax.swing.*;
  import javax.swing.table.AbstractTableModel;
  import javax.swing.table.DefaultTableCellRenderer;
  import javax.swing.table.TableColumn;
  import java.awt.*;
  import java.awt.event.WindowAdapter;
  import java.awt.event.WindowEvent;
  import java.io.IOException;
  import java.util.Arrays;
  import java.util.List;
  import java.util.Objects;
  import java.util.regex.Matcher;
  import java.util.regex.Pattern;
  import java.util.stream.Collectors;
ebf0bdb2   mandjemb   interface ok: man...
49
  
ebf0bdb2   mandjemb   interface ok: man...
50
  public class TablooProto extends JPanel {
02c44758   Remi   finish ihm
51
52
53
  	
  	static Grid grid;
  	
ebf0bdb2   mandjemb   interface ok: man...
54
  	// Fourni: ne rien changer.
02c44758   Remi   finish ihm
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
  	public TablooProto(Grid grid) throws ClassNotFoundException, IOException {
  		super(new GridLayout(1, 0));
  		
  		// modele de donnees
  		// cf. plus loin la inner classe MyTableModel a modifier...
  		MyTableModel tableModel = new MyTableModel(grid);
  		
  		// la JTable et ses parametres
  		JTable table = new JTable(tableModel);
  		table.setPreferredScrollableViewportSize(new Dimension(1000, 500));
  		table.setGridColor(Color.BLACK);
  		table.setShowGrid(true);
  		
  		// on ajoute un scroll
  		JScrollPane scrollPane = new JScrollPane(table, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
  		add(scrollPane);
  		table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
  		
  		// parametrage de la 1ere ligne = noms des colonnes
  		((DefaultTableCellRenderer) table.getTableHeader().getDefaultRenderer()).setHorizontalAlignment(JLabel.CENTER);
  		
  		// parametrage de la 1ere colonne consacree a la numerotation des lignes
  		TableColumn tm = table.getColumnModel().getColumn(0);
  		tm.setPreferredWidth(tm.getPreferredWidth() * 2 / 3);
  		tm.setCellRenderer(new PremiereColonneSpecificRenderer(Color.LIGHT_GRAY));
  		
  	}
  	
  	// Inner class pour changer l'aspect de la premiere colonne consacree a la numerotation des lignes
  	// Fourni: ne rien changer.
  	class PremiereColonneSpecificRenderer extends DefaultTableCellRenderer {
  		
  		/**
  		 *
ebf0bdb2   mandjemb   interface ok: man...
89
  		 */
ebf0bdb2   mandjemb   interface ok: man...
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
  		Color couleur;
  
          public PremiereColonneSpecificRenderer(Color couleur) {
              super();
              this.couleur = couleur;
              this.setHorizontalAlignment(JLabel.CENTER);
          }
  
          @Override
          public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
              Component cell = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
              cell.setBackground(couleur);
              return cell;
          }
      }
  
      // Inner class pour etablir la connexion entre la JTable graphique et un modele de donnees.
      // Pour nous le modele de donnees sera une grille du noyau de representation et de calcul
      // construite et sauvegardee par serialisation comme precedemmment.
      // Dans ce prototype exemple, le modele de donnees est une simple matrice de String "en dur".
      // Il faudra le remplacer par une connexion a une telle grille.
      class MyTableModel extends AbstractTableModel {
  
          /**
  		 * 
  		 */
  		private static final long serialVersionUID = 1L;
02c44758   Remi   finish ihm
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
  		private Grid grid;
  		
  		MyTableModel(Grid grid) {
  			this.grid = grid;
  		}
  		
  		@Override
  		// Standard: doit retourner le nbre de colonnes de la JTable
  		public int getColumnCount() {
  			return grid.getTotalColumn() + 1;
  		}
  		
  		@Override
  		// Standard: doit retourner le nbre de lignes de la JTable
  		public int getRowCount() {
  			return grid.getTotalRow();
  		}
  		
  		// Standard: doit renvoyer le nom de la colonne a afficher en tete
  		// Fourni: ne rien changer.
  		@Override
  		public String getColumnName(int col) {
  			if (col == 0) {
  				return ""; // colonne consacrée aux numeros de ligne
  			} else {
  				return "" + (char) ((int) ('A') + col - 1);
  			}
  		}
  		
  		// Utilitaire interne fourni (ne rien changer)
  		// Retourne le nom d'une case a partir de ses coordonnees dans la JTable.
  		private String getNomCase(int row, int col) {
  			return this.getColumnName(col) + (row + 1); // row commence a 0
  		}
  		
  		@Override
  		// Standard: doit renvoyer le contenu a afficher de la case correspondante
  		public Object getValueAt(int row, int col) {
  			if (col == 0) {
  				// Fourni: ne rien changer.
  				// en colonne 0 : numeros de lignes
  				return "" + (row + 1);
  			} else {
  				try {
  					return grid.getDevelopedFormula(this.getColumnName(col), row + 1) + "=" + grid.getValue(this.getColumnName(col), row + 1);
ebf0bdb2   mandjemb   interface ok: man...
162
  				} catch (CellNotFoundException e) {
23982881   [mandjemb]   update ihm
163
  					// TODO Auto-generated catch block
ebf0bdb2   mandjemb   interface ok: man...
164
165
166
  					
  				}
              }
23982881   [mandjemb]   update ihm
167
  			return "";
02c44758   Remi   finish ihm
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
  		}
  		
  		// Standard.
  		// Fourni: ne rien changer.
  		@Override
  		public Class getColumnClass(int c) {
  			return getValueAt(0, c).getClass();
  		}
  		
  		// Standard: determine si une case est editable ou non.
  		// Fourni: ne rien changer.
  		// Seules les cases de la 1er colonne ne le sont pas
  		// (consacrees a la numerotation des lignes)
  		@Override
  		public boolean isCellEditable(int row, int col) {
  			return col > 0;
  		}
  		
  		// Standard: l'utilisateur a entré une valeur dans une case,
  		// mettre a jour le modèle de donnees connecte.
  		// L'utilisateur a modifie une case.
  		// Si c'est une valeur numerique
  		// - modifier la case correspondante dans la grille si cette case existe
  		// - ajouter la case correspondante dans la grille
  		@Override
  		public void setValueAt(Object input, int row, int col) {
  			Formula formula = new Addition(null, null);
  			double value = 0;
  			int cellType;
  			
  			if (input instanceof String && !((String) input).isEmpty()) {
  				String text = (String) input;
  				try {
ebf0bdb2   mandjemb   interface ok: man...
201
  					try {
02c44758   Remi   finish ihm
202
203
204
205
206
207
208
  						// Récupération de la valeur
  						value = Double.parseDouble(text);
  						cellType = 0;
  					} catch (NumberFormatException exception) {
  						// Récupération de la formule
  						formula = this.generateFormulaWithString(text);
  						cellType = 1;
ebf0bdb2   mandjemb   interface ok: man...
209
  					}
02c44758   Remi   finish ihm
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
  					
  					String cellName = this.getNomCase(row, col);
  					switch (cellType) {
  						case 0:
  							if (this.grid.cellExist(cellName))
  								this.grid.setValue(this.getColumnName(col), row + 1, value);
  							else
  								this.grid.createCell(this.getColumnName(col), row + 1, value);
  							break;
  						case 1:
  							if (this.grid.cellExist(cellName))
  								this.grid.setFormula(this.getColumnName(col), row + 1, formula);
  							else
  								this.grid.createCell(this.getColumnName(col), row + 1, formula);
  							break;
ebf0bdb2   mandjemb   interface ok: man...
225
  					}
02c44758   Remi   finish ihm
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
  				} catch (CellNotFoundException | BadSyntaxException | CreateCycleException | InvalidIntervalException e) {
  					JOptionPane.showMessageDialog(null, e.getMessage(), "Attention", JOptionPane.INFORMATION_MESSAGE);
  				}
  			} else {
  				try {
  					this.grid.deleteCell(this.getColumnName(col), row + 1);
  				} catch (CannotDeleteCellException e) {
  					JOptionPane.showMessageDialog(null, e.getMessage(), "Attention", JOptionPane.INFORMATION_MESSAGE);
  				}
  			}
  			
  			// mise a jour automatique de l'affichage de toute la table suite a la modification
  			fireTableDataChanged();
  		}
  		
  		private Formula generateFormulaWithString(String input) throws CellNotFoundException, BadSyntaxException {
  			Pattern functionPattern = Pattern.compile("=([A-Z]+)\\(([A-Z0-9,]+)\\)");
  			Matcher functionMatcher = functionPattern.matcher(input);
  			
  			if (functionMatcher.matches()) {
  				List<Cell> cells = Arrays.stream(functionMatcher.group(2).split(","))
  						.map(c -> grid.getCell(c))
  						.collect(Collectors.toList());
  				
  				if (cells.contains(null))
  					throw new CellNotFoundException();
  				
  				cells = cells.stream().filter(Objects::nonNull).collect(Collectors.toList());
  				
  				switch (functionMatcher.group(1)) {
  					case "SUM":
  					case "SOMME":
  						return new Sum(cells);
  					case "AVERAGE":
  					case "MOYENNE":
  						return new Average(cells);
  				}
  			} else {
  				Pattern binaryOperationPattern = Pattern.compile("=([A-Z]+[0-9]+)([+\\-*/])([A-Z]+[0-9]+)");
  				Matcher binaryOperationMatcher = binaryOperationPattern.matcher(input);
  				
  				if (!binaryOperationMatcher.matches())
  					throw new BadSyntaxException();
  				
  				Cell leftCell = grid.getCell(binaryOperationMatcher.group(1));
  				Cell rightCell = grid.getCell(binaryOperationMatcher.group(3));
  				
  				if (leftCell == null || rightCell == null)
  					throw new CellNotFoundException();
  				
  				switch (binaryOperationMatcher.group(2)) {
  					case "+":
  						return new Addition(leftCell, rightCell);
  					case "-":
  						return new Subtraction(leftCell, rightCell);
  					case "*":
  						return new Multiplication(leftCell, rightCell);
  					case "/":
  						return new Division(leftCell, rightCell);
  				}
  			}
  			
  			return null;
  		}
  	}
  	// Fin de la inner class MyTableModel
  	
  	// Exécution de l'interface graphique a partir d'un terminal.
  	public static void main(String[] args) throws ClassNotFoundException, IOException {
  		try {
  			grid = Grid.load();
  		} catch (IOException | ClassNotFoundException e) {
  			grid = new Grid();
  		}
  		// a charger comme modele de donnees.
  		TablooProto tableur = new TablooProto(grid);
  		
  		// Creation de l'application et lancement
  		// Fourni: ne rien changer.
  		JFrame frame = new JFrame("TABLO");
  		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  		tableur.setOpaque(true);
  		frame.setContentPane(tableur);
  		frame.pack();
  		frame.setVisible(true);
  		
  		// Sauvegarde de la grille lors de la fermeture de l'application
  		frame.addWindowListener(new WindowAdapter() {
  			@Override
  			public void windowClosing(WindowEvent we) {
  				try {
  					grid.save();
  				} catch (IOException e) {
  					System.out.println(e.getMessage());
  				}
  				System.exit(0);
  			}
  		});
  	}
ebf0bdb2   mandjemb   interface ok: man...
325
  }