Subversion Repositories eFlore/Applications.cel

Rev

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