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