Subversion Repositories eFlore/Applications.cel

Rev

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