Subversion Repositories eFlore/Applications.cel

Rev

Details | Last modification | View Log | RSS feed

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