Subversion Repositories eFlore/Applications.cel

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
155 aurelien 1
package org.tela_botanica.client.vues;
2
import org.tela_botanica.client.image.ImageMediateur;
3
import org.tela_botanica.client.interfaces.Rafraichissable;
4
import org.tela_botanica.client.observation.ObservationMediateur;
5
 
6
import com.google.gwt.core.client.GWT;
7
import com.google.gwt.json.client.JSONArray;
8
import com.google.gwt.json.client.JSONObject;
9
import com.google.gwt.user.client.Window;
10
import com.gwtext.client.core.EventObject;
11
import com.gwtext.client.data.Node;
12
import com.gwtext.client.data.NodeTraversalCallback;
13
import com.gwtext.client.data.Tree;
14
import com.gwtext.client.data.event.NodeListener;
15
import com.gwtext.client.widgets.Button;
16
import com.gwtext.client.widgets.Container;
17
import com.gwtext.client.widgets.Panel;
18
import com.gwtext.client.widgets.event.ButtonListenerAdapter;
19
import com.gwtext.client.widgets.event.PanelListenerAdapter;
20
import com.gwtext.client.widgets.form.TextField;
21
import com.gwtext.client.widgets.layout.VerticalLayout;
22
import com.gwtext.client.widgets.tree.TreeEditor;
23
import com.gwtext.client.widgets.tree.TreeNode;
24
import com.gwtext.client.widgets.tree.TreePanel;
25
import com.gwtext.client.widgets.tree.event.TreeNodeListener;
26
import com.gwtext.client.widgets.tree.event.TreeNodeListenerAdapter;
27
import com.gwtext.client.widgets.tree.event.TreePanelListenerAdapter;
28
 
29
public class ArbreMotsClesObsVue extends Panel implements Rafraichissable {
30
 
31
		/**
32
		 * Le médiateur associé à la vue
33
		 */
34
		private ObservationMediateur oMediateur = null;
35
 
36
		/**
37
		 * Le treepanel qui affiche l'arbre
38
		 */
39
		private static TreePanel arbreMotsCles = null;
40
		/**
41
		 * L'éditeur qui permet de modifier les mots clés dans l'arbre
42
		 */
43
		private TreeEditor te = null;
44
		/**
45
		 * Le textfield associé à l'éditeur
46
		 */
47
		private TextField tfEdit = null;
48
		/**
49
		 * Bouton de validation
50
		 */
51
		private Button valider = null;
52
		/**
53
		 * Une string permettant connaitre les mots clés cochés en cours séparés par
54
		 * des virgules
55
		 */
56
		private String motsClesEnCours = "";
57
		/**
58
		 * Tableau contenant les mots clés qui n'ont pas encore été jaouté à l'arbre
59
		 * (sert au lazy rendering quand on reçoit des mots clés avant que le rendu
60
		 * du conteneur n'ai été effectué)
61
		 */
62
		private String[] motsClesEnAttente = new String[0];
63
		/**
64
		 * Booléen d'évènement qui sert à savoir si on est en train d'ajouter un
65
		 * noeud
66
		 */
67
		private boolean ajoutNoeud = false;
68
		/**
69
		 * Booléen d'évènement qui sert à savoir si on est en train de modifier un
70
		 * noeud
71
		 */
72
		private boolean modifNoeud = false;
73
		/**
74
		 * Booléen d'instanciation du conteneur
75
		 */
76
		private boolean arbreCharge = false;
77
		/**
78
		 * Booléen d'évènement qui sert à savoir si les mots clés ont bien été reçu
79
		 */
80
		private boolean motsCleInitialises;
81
 
82
		/**
83
		 * Constructeur sans paramètre (privé car interdit d'utilisation)
84
		 */
85
		@SuppressWarnings("unused")
86
		private ArbreMotsClesObsVue() {
87
			super();
88
		}
89
 
90
		/**
91
		 * Constructeur avec paramètre
92
		 *
93
		 * @param im
94
		 *            le médiateur à associer
95
		 */
96
		public ArbreMotsClesObsVue(ObservationMediateur om) {
97
			// on crée le panel
98
			super("Mots clés");
99
			this.setLayout(new VerticalLayout());
100
			oMediateur = om;
101
 
102
			// on crée le conteneur de l'arbre
103
			arbreMotsCles = new TreePanel();
104
			// on permet le drag and drop dans l'arbre
105
			arbreMotsCles.setEnableDD(true);
106
			arbreMotsCles.setId("x-view-tree-keyword-obs");
107
 
108
			// on crée une racine pour l'arbre
109
			TreeNode root = new TreeNode("Tags");
110
			root.setId("racine_obs");
111
			String[] usObject = { "Mots clés", "racine" };
112
			root.setUserObject(usObject);
113
			root.setExpandable(true);
114
			arbreMotsCles.setRootNode(root);
115
			arbreMotsCles.setRootVisible(true);
116
			arbreMotsCles.setBorder(false);
117
			arbreMotsCles.setWidth(500);
118
 
119
			arbreMotsCles.getRootNode().addListener(new TreeNodeListenerAdapter() {
120
				public void onClick(Node node, EventObject e) {
121
					if(!arbreCharge) {
122
						expand();
123
					}
124
				}
125
 
126
				public void onExpand(Node node) {
127
					if(!arbreCharge) {
128
						obtenirArbreMotsCles();
129
						arbreCharge = true;
130
					}
131
				}
132
			});
133
 
134
			// on crée l'éditeur pour l'arbre
135
			tfEdit = new TextField();
136
			tfEdit.setAutoWidth(true);
137
			te = new TreeEditor(arbreMotsCles, tfEdit);
138
			valider = new Button("Appliquer");
139
			arbreMotsCles.add(te);
140
 
141
			// on met en forme le layout
142
			this.add(arbreMotsCles);
143
			this.add(valider);
144
 
145
			this.setBorder(false);
146
			this.setCollapsible(true);
147
			this.setTitleCollapse(true);
148
 
149
			// on ajoute les listeners
150
			ajouterListeners();
151
 
152
		}
153
 
154
		/**
155
		 * Acesseur pour le médiateur
156
		 *
157
		 * @return le médiateur associé à la vue
158
		 */
159
		private ObservationMediateur getOMediateur() {
160
 
161
			return oMediateur;
162
 
163
		}
164
 
165
		/**
166
		 * Acesseur pour l'arbre des mots clés
167
		 *
168
		 * @return le panel contenant l'arbre
169
		 */
170
		public TreePanel getArbreMotsCles() {
171
			return arbreMotsCles;
172
		}
173
 
174
		/**
175
		 * Accesseur pour l'éditeur
176
		 *
177
		 * @return l'éditeur associé à l'arbre
178
		 */
179
		public TreeEditor getTe() {
180
			return te;
181
		}
182
 
183
		/**
184
		 * Acesseur pour le TextField associé à l'éditeur
185
		 *
186
		 * @return le champ texte associé à l'éditeur
187
		 */
188
		public TextField getTfEdit() {
189
			return tfEdit;
190
		}
191
 
192
		/**
193
		 * Ajoute les listeners nécessaires pour la gestion des évènements
194
		 */
195
		private void ajouterListeners() {
196
			arbreMotsCles.addListener(new TreePanelListenerAdapter() {
197
 
198
				// gestion du clic sur un noeud
199
				public void onClick(TreeNode node, EventObject e) {
200
 
201
					e.stopEvent();
202
					gererClicNoeud(node);
203
				}
204
 
205
				// gestion du clic droit sur un noeud
206
				public void onContextMenu(TreeNode node, EventObject e) {
207
 
208
					e.stopEvent();
209
					getOMediateur().montrerContextMenuArbre(node, e, getTe());
210
 
211
				}
212
 
213
				// gestion du double clic sur un noeud
214
				public void onDblClick(TreeNode node, EventObject e) {
215
 
216
					modifNoeud = true;
217
					if (!node.getId().equals("racine_obs")) {
218
						te.startEdit(node);
219
					}
220
				}
221
 
222
				// gestion de la modification du texte d'un noeud
223
				public void onTextChange(TreeNode node, String text, String oldText) {
224
 
225
					// on récupère les informations associées au noeud
226
					TreeNode nd = node;
227
					String[] usObject = new String[2];
228
					usObject[0] = text;
229
					usObject[1] = ((String[]) nd.getUserObject())[1];
230
					nd.setUserObject(usObject);
231
 
232
					// si c'est un nouveau noeud
233
					if (ajoutNoeud) {
234
						// on notifie le médiateur de l'ajout et on lui passe
235
						// l'arbre
236
						getOMediateur().ajouterMotCleDansArbre(nd,
237
								getArbreMotsCles().getTree());
238
						// et considère l'ajout achevé
239
						ajoutNoeud = false;
240
					}
241
					// si c'est noeud déjà existant
242
					else {
243
						if (modifNoeud) {
244
							// on notifie le médiateur de la modification et on lui
245
							// passe l'arbre
246
							getOMediateur().modifierMotCleDansArbre(nd,
247
									getArbreMotsCles().getTree());
248
							// et on considère la modification achevée
249
							modifNoeud = false;
250
						}
251
					}
252
 
253
				}
254
 
255
				// gestion du déplacement d'un noeud
256
				public void onMoveNode(Tree tree, TreeNode node,
257
						TreeNode oldParent, TreeNode newParent, int index) {
258
					// on notifie le médiateur et on lui passe l'arbre
259
					getOMediateur().deplacerMotCleDansArbre(node,
260
							getArbreMotsCles().getTree());
261
				}
262
 
263
			});
264
 
265
			// gestion de la validation
266
			valider.addListener(new ButtonListenerAdapter() {
267
 
268
				// lors du clic
269
				public void onClick(Button button, EventObject e) {
270
 
271
					// on vide les mots clés en cours
272
					motsClesEnCours = "";
273
					// pour chaque noeud à partir de la racine
274
					getArbreMotsCles().getRootNode().cascade(
275
							new NodeTraversalCallback() {
276
 
277
								// on éxécute une fonction
278
								public boolean execute(Node node) {
279
 
280
									// on récupère le mot clé associé au noeud et
281
									// ses infos
282
									TreeNode tn = getArbreMotsCles().getNodeById(
283
											node.getId());
284
 
285
									String[] usObject = (String[]) tn
286
											.getUserObject();
287
									getOMediateur().mettreAjourMotsClesId(
288
											usObject[0], usObject[1]);
289
 
290
									if (tn.getUI().isChecked()) {
291
										// et les concatène à la string des mots
292
										// clés en cours
293
										motsClesEnCours += usObject[1] + ",";
294
									}
295
 
296
									return true;
297
								}
298
 
299
							});
300
 
301
					// enfin on notifie le médiateur et on lui passe l'arbre et la
302
					// liste des mots clés ainsi obtenue
303
					getOMediateur().mettreAjourMotsCles(motsClesEnCours,
304
							arbreMotsCles.getTree());
305
				}
306
			});
307
 
308
		}
309
 
310
		/**
311
		 * Envoie une demande au médiateur pour obtenir l'arbre des mots clés
312
		 */
313
		public void obtenirArbreMotsCles() {
314
 
315
			getOMediateur().obtenirArbreMotsCles(this);
316
 
317
		}
318
 
319
		/**
320
		 * Supprime un noeud de l'arbre
321
		 *
322
		 * @param n
323
		 *            le noeud à supprimer
324
		 */
325
		public void supprimerNoeud(TreeNode n) {
326
			// si ça n'est pas la racine (qu'on ne peut pas supprimer)
327
			if (!n.getId().equals(getArbreMotsCles().getRootNode().getId())) {
328
				// on détache le noeud et on le détruit
329
				n.getParentNode().removeChild(n);
330
				n.destroy();
331
				// puis on en notifie le médiateur en lui passant le noeud supprimé
332
				// et l'arbre
333
				getOMediateur()
334
						.supprimerMotCleDansArbre(n, arbreMotsCles.getTree());
335
			} else {
336
				// si l'utilisateur tente de supprimer la racine, on l'avertit de
337
				// son erreur
338
				Window.alert("Impossible de supprimer la racine de l'arbre");
339
			}
340
		}
341
 
342
		/**
343
		 * Ajoute un noeud dans l'arbre au parent donné
344
		 *
345
		 * @param parent
346
		 *            le futur parent du noeud à ajouter
347
		 */
348
		public void ajouterNoeud(TreeNode parent) {
349
 
350
			// on met l'ajout du noeud à vrai
351
			ajoutNoeud = true;
352
			// on crée un nouveau noeud vide
353
			TreeNode nd = new TreeNode("");
354
			nd.setCls("x-view-treenode-keyword");
355
			nd.setChecked(true);
356
			// on associe un objet au noeud qui contient des infos
357
			String[] usObject = new String[2];
358
			// l'objet contient le nom du noeud
359
			usObject[0] = "";
360
			usObject[1] = genererIdMotCle(nd);
361
			nd.setId(usObject[1]);
362
			nd.setUserObject(usObject);
363
			// l'identifiant d'un noeud c'est son hashcode
364
			// l'objet associé au noeud contient aussi son identifiant
365
 
366
			// on le concatène au parent et on étend ses enfants
367
			parent.appendChild(nd);
368
			parent.expand();
369
			// enfin on place le curseur et on fait apparaitre le champ d'édition
370
			// pour que l'utilisateur nomme son mot clé
371
			te.startEdit(nd);
372
 
373
		}
374
 
375
		/**
376
		 * Coche le noeud s'il est décoché, le décoche sinon
377
		 *
378
		 * @param node
379
		 */
380
		public void gererClicNoeud(TreeNode node) {
381
			if (node.getUI().isChecked()) {
382
				node.getUI().toggleCheck(false);
383
			} else {
384
				node.getUI().toggleCheck(true);
385
			}
386
		}
387
 
388
		/**
389
		 * Parcourt l'arbre et coche les noeud qui font partie de la liste des mots
390
		 * clés à cocher
391
		 *
392
		 * @param motsClesIds
393
		 *            un tableau contenant les identifiants des mots clés à cocher
394
		 */
395
		public void cocherMotsCles(final String[] motsClesIds) {
396
			if (getArbreMotsCles() != null
397
					&& getArbreMotsCles().getRootNode() != null) {
398
				// à partir de la racine
399
				getArbreMotsCles().getRootNode().cascade(
400
						new NodeTraversalCallback() {
401
 
402
							// pour chaque noeud
403
							public boolean execute(Node node) {
404
 
405
								getArbreMotsCles().getNodeById(node.getId())
406
								.getUI().toggleCheck(false);
407
 
408
								// on parcourt le tableau des mots clés
409
								for (int i = 0; i < motsClesIds.length; i++) {
410
									// si le mot clé fait partie des id à cocher on
411
									// le coche
412
									String usObject[] = (String[]) node
413
											.getUserObject();
414
									String nodeId = usObject[1];
415
 
416
									if (nodeId.equals(motsClesIds[i])) {
417
											getArbreMotsCles().getNodeById(nodeId+"_obs")
418
													.getUI().toggleCheck(true);
419
 
420
											return true;
421
									}
422
								}
423
								// et on passe au suivant
424
								return true;
425
							}
426
 
427
						});
428
			}
429
			else {
430
				motsClesEnAttente = motsClesIds ;
431
			}
432
		}
433
 
434
		/**
435
		 * Méthode héritée de l'interface rafraichissable
436
		 *
437
		 * @param nouvelleDonnees
438
		 *            les nouvelles données pour l'objet
439
		 * @param repandreRafraichissement
440
		 *            booleen qui dit si on doit répandre l'évenement
441
		 */
442
		public void rafraichir(Object nouvelleDonnees,
443
				boolean repandreRafraichissement) {
444
 
445
			if(nouvelleDonnees instanceof Tree) {
446
 
447
				Tree nouvelArbre = (Tree)nouvelleDonnees ;
448
 
449
				// on prend sa racine et on l'attache à l'arbre des mots clés
450
				Node[] rootChild = getArbreMotsCles().getRootNode().getChildNodes();
451
				for (int i = 0; i < rootChild.length; i++) {
452
 
453
					rootChild[i].remove();
454
				}
455
 
456
				copierFilsNoeud(nouvelArbre.getRootNode(),getArbreMotsCles().getRootNode());
457
 
458
				// si l'arbre n'était pas encore considéré comme instancié
459
				if (!arbreCharge) {
460
					// on signale que oui
461
					arbreCharge = true;
462
				}
463
 
464
				// s'il y a des mots clés en attente (lors du premier rendering)
465
				if (motsCleInitialises == false && motsClesEnAttente != null) {
466
					// on les coche
467
					// cocherMotsCles(motsClesEnAttente) ;
468
					motsCleInitialises = true;
469
				}
470
 
471
				if(motsClesEnAttente.length > 0) {
472
							cocherMotsCles(motsClesEnAttente);
473
				}
474
			}
475
 
476
			// Si on reçoit un tableau de String (cas ou l'on séléectionne une
477
			// nouvelle image)
478
			if (nouvelleDonnees instanceof String[]) {
479
				// et que l'arbre est instancié
480
				if (arbreCharge) {
481
					// le tableau de String contient les id des mots clés associés à
482
					// l'image
483
					// on coche les mots clés contenu dans le tableau
484
					String[] motsClesIds = (String[]) nouvelleDonnees;
485
					cocherMotsCles(motsClesIds);
486
 
487
				}
488
				// si l'arbre n'est pas encore instancié on met les mots clés en
489
				// attente
490
				else {
491
					motsClesEnAttente = (String[]) nouvelleDonnees;
492
				}
493
			}
494
		}
495
 
496
		private String genererIdMotCle(TreeNode nd) {
497
			return "" + (nd.hashCode() + (Math.random() * 10000));
498
		}
499
 
500
		/**
501
		 * Fonction récursive qui prend deux noeuds d'arbre en paramètre et crée un
502
		 * copie du sous arbre du premier noeud, qu'elle concatène au deuxième
503
		 *
504
		 * @param ndPereOriginal
505
		 *            le père des noeuds de l'arbre original
506
		 * @param ndPereCopie
507
		 *            le père qui va recevoir les copies
508
		 */
509
		private void copierFilsNoeud(Node ndPereOriginal, TreeNode ndPereCopie) {
510
			if (ndPereCopie != null && ndPereOriginal != null) {
511
				Node[] ndNodeFils = ndPereOriginal.getChildNodes();
512
 
513
				for (int i = 0; i < ndNodeFils.length; i++) {
514
 
515
					String[] usObj = (String[]) ndNodeFils[i].getUserObject();
516
					TreeNode child = new TreeNode(usObj[0]);
517
					child.setId(usObj[1] +"_obs");
518
					child.setChecked(false);
519
					child.setUserObject(usObj);
520
					ndPereCopie.appendChild(child);
521
 
522
					if (!ndNodeFils[i].isLeaf()) {
523
						copierFilsNoeud(ndNodeFils[i], child);
524
					}
525
 
526
				}
527
			}
528
		}
529
}