Subversion Repositories eFlore/Applications.cel

Rev

Rev 1291 | 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;
2042 aurelien 5
import org.tela_botanica.client.util.MotsClesUtilitaire;
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;
13
import com.gwtext.client.widgets.Panel;
14
import com.gwtext.client.widgets.event.ButtonListenerAdapter;
15
import com.gwtext.client.widgets.form.TextField;
16
import com.gwtext.client.widgets.layout.VerticalLayout;
17
import com.gwtext.client.widgets.tree.TreeEditor;
18
import com.gwtext.client.widgets.tree.TreeNode;
19
import com.gwtext.client.widgets.tree.TreePanel;
20
import com.gwtext.client.widgets.tree.event.TreePanelListenerAdapter;
21
 
22
/**
5 aperonnet 23
 * Arbre des mots clés, qui est une vue rafraichissable, qui contient des mots
24
 * clés cochables et réorganisables à volonté
25
 *
2 aperonnet 26
 * @author aurelien
5 aperonnet 27
 *
2 aperonnet 28
 */
29
public class ArbreMotsClesVue extends Panel implements Rafraichissable {
30
 
31
	/**
32
	 * Le médiateur associé à la vue
33
	 */
5 aperonnet 34
	private ImageMediateur iMediateur = null;
35
 
2 aperonnet 36
	/**
37
	 * Le treepanel qui affiche l'arbre
38
	 */
5 aperonnet 39
	private TreePanel arbreMotsCles = null;
2 aperonnet 40
	/**
41
	 * L'éditeur qui permet de modifier les mots clés dans l'arbre
42
	 */
5 aperonnet 43
	private TreeEditor te = null;
2 aperonnet 44
	/**
45
	 * Le textfield associé à l'éditeur
46
	 */
5 aperonnet 47
	private TextField tfEdit = null;
2 aperonnet 48
	/**
49
	 * Bouton de validation
50
	 */
5 aperonnet 51
	private Button valider = null;
2 aperonnet 52
	/**
5 aperonnet 53
	 * Une string permettant connaitre les mots clés cochés en cours séparés par
54
	 * des virgules
2 aperonnet 55
	 */
5 aperonnet 56
	private String motsClesEnCours = "";
1009 aurelien 57
 
58
	private String[] tableauMotsClesEnCours = new String[0];
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
	 */
155 aurelien 64
	private String[] motsClesEnAttente = new String[0];
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
 
2042 aurelien 84
	private String cheminTemporaireAjout;
85
 
2 aperonnet 86
	/**
87
	 * Constructeur sans paramètre (privé car interdit d'utilisation)
88
	 */
89
	@SuppressWarnings("unused")
5 aperonnet 90
	private ArbreMotsClesVue() {
91
		super();
2 aperonnet 92
	}
5 aperonnet 93
 
2 aperonnet 94
	/**
95
	 * Constructeur avec paramètre
5 aperonnet 96
	 *
97
	 * @param im
98
	 *            le médiateur à associer
2 aperonnet 99
	 */
5 aperonnet 100
	public ArbreMotsClesVue(ImageMediateur im) {
2 aperonnet 101
		// on crée le panel
5 aperonnet 102
		super("Mots clés");
2 aperonnet 103
		this.setLayout(new VerticalLayout());
5 aperonnet 104
		iMediateur = im;
105
 
2 aperonnet 106
		// on crée le conteneur de l'arbre
5 aperonnet 107
		arbreMotsCles = new TreePanel();
2 aperonnet 108
		// on permet le drag and drop dans l'arbre
5 aperonnet 109
		arbreMotsCles.setEnableDD(true);
110
		arbreMotsCles.setId("x-view-tree-keyword");
111
 
2 aperonnet 112
		// on crée une racine pour l'arbre
5 aperonnet 113
		TreeNode root = new TreeNode("Tags");
114
		root.setId("racine");
115
		String[] usObject = { "Mots clés", "racine" };
116
		root.setUserObject(usObject);
117
		arbreMotsCles.setRootNode(root);
155 aurelien 118
		arbreMotsCles.setRootVisible(true);
5 aperonnet 119
		arbreMotsCles.setBorder(false);
120
		arbreMotsCles.setWidth(500);
121
 
2 aperonnet 122
		// on crée l'éditeur pour l'arbre
5 aperonnet 123
		tfEdit = new TextField();
124
		tfEdit.setAutoWidth(true);
125
		te = new TreeEditor(arbreMotsCles, tfEdit);
126
		valider = new Button("Appliquer");
127
		arbreMotsCles.add(te);
128
 
2 aperonnet 129
		// on met en forme le layout
5 aperonnet 130
		this.add(arbreMotsCles);
131
		this.add(valider);
132
 
133
		this.setBorder(false);
134
		this.setCollapsible(true);
135
		this.setTitleCollapse(true);
135 aurelien 136
 
2 aperonnet 137
		// on ajoute les listeners
5 aperonnet 138
		ajouterListeners();
139
 
2 aperonnet 140
	}
5 aperonnet 141
 
2 aperonnet 142
	/**
143
	 * Acesseur pour le médiateur
5 aperonnet 144
	 *
2 aperonnet 145
	 * @return le médiateur associé à la vue
146
	 */
135 aurelien 147
	private ImageMediateur getIMediateur() {
5 aperonnet 148
 
149
		return iMediateur;
150
 
2 aperonnet 151
	}
5 aperonnet 152
 
2 aperonnet 153
	/**
154
	 * Acesseur pour l'arbre des mots clés
5 aperonnet 155
	 *
2 aperonnet 156
	 * @return le panel contenant l'arbre
157
	 */
158
	public TreePanel getArbreMotsCles() {
159
		return arbreMotsCles;
160
	}
161
 
162
	/**
163
	 * Accesseur pour l'éditeur
5 aperonnet 164
	 *
2 aperonnet 165
	 * @return l'éditeur associé à l'arbre
166
	 */
167
	public TreeEditor getTe() {
168
		return te;
169
	}
170
 
171
	/**
172
	 * Acesseur pour le TextField associé à l'éditeur
5 aperonnet 173
	 *
2 aperonnet 174
	 * @return le champ texte associé à l'éditeur
175
	 */
176
	public TextField getTfEdit() {
177
		return tfEdit;
178
	}
5 aperonnet 179
 
2 aperonnet 180
	/**
181
	 * Ajoute les listeners nécessaires pour la gestion des évènements
182
	 */
5 aperonnet 183
	private void ajouterListeners() {
2042 aurelien 184
 
185
		final Rafraichissable r = this;
2 aperonnet 186
		arbreMotsCles.addListener(new TreePanelListenerAdapter() {
5 aperonnet 187
 
1291 aurelien 188
			@Override
1009 aurelien 189
			public void onExpandNode(TreeNode node) {
190
				cocherMotsCles(tableauMotsClesEnCours);
191
			}
192
 
2 aperonnet 193
			// gestion du clic sur un noeud
1291 aurelien 194
			@Override
2 aperonnet 195
			public void onClick(TreeNode node, EventObject e) {
5 aperonnet 196
				e.stopEvent();
2 aperonnet 197
				gererClicNoeud(node);
198
			}
199
 
200
			// gestion du clic droit sur un noeud
1291 aurelien 201
			@Override
2 aperonnet 202
			public void onContextMenu(TreeNode node, EventObject e) {
5 aperonnet 203
				e.stopEvent();
135 aurelien 204
				getIMediateur().montrerContextMenuArbre(node, e, getTe());
2 aperonnet 205
			}
5 aperonnet 206
 
2 aperonnet 207
			// gestion du double clic sur un noeud
1291 aurelien 208
			@Override
2 aperonnet 209
			public void onDblClick(TreeNode node, EventObject e) {
1009 aurelien 210
				modifNoeud = true;
5 aperonnet 211
				if (!node.getId().equals("racine")) {
2 aperonnet 212
					te.startEdit(node);
213
				}
214
			}
5 aperonnet 215
 
216
			// gestion de la modification du texte d'un noeud
1291 aurelien 217
			@Override
2 aperonnet 218
			public void onTextChange(TreeNode node, String text, String oldText) {
219
 
220
				// on récupère les informations associées au noeud
5 aperonnet 221
				TreeNode nd = node;
222
				String[] usObject = new String[2];
223
				usObject[0] = text;
224
				usObject[1] = ((String[]) nd.getUserObject())[1];
225
				nd.setUserObject(usObject);
226
 
2 aperonnet 227
				// si c'est un nouveau noeud
5 aperonnet 228
				if (ajoutNoeud) {
1009 aurelien 229
					// on considère l'ajout achevé
1007 aurelien 230
					ajoutNoeud = false;
1009 aurelien 231
					// et on notifie le médiateur de l'ajout et on lui passe
5 aperonnet 232
					// l'arbre
135 aurelien 233
					getIMediateur().ajouterMotCleDansArbre(nd,
2042 aurelien 234
							getArbreMotsCles().getTree(), r);
2 aperonnet 235
				}
236
				// si c'est noeud déjà existant
5 aperonnet 237
				else {
1007 aurelien 238
					// et on considère la modification achevée
239
					modifNoeud = false;
240
					// on notifie le médiateur de la modification et on lui
241
					// passe l'arbre
242
					getIMediateur().modifierMotCleDansArbre(nd,
243
							getArbreMotsCles().getTree());
2 aperonnet 244
				}
5 aperonnet 245
 
2 aperonnet 246
			}
5 aperonnet 247
 
2 aperonnet 248
			// gestion du déplacement d'un noeud
1291 aurelien 249
			@Override
5 aperonnet 250
			public void onMoveNode(Tree tree, TreeNode node,
251
					TreeNode oldParent, TreeNode newParent, int index) {
2 aperonnet 252
				// on notifie le médiateur et on lui passe l'arbre
135 aurelien 253
				getIMediateur().deplacerMotCleDansArbre(node,
5 aperonnet 254
						getArbreMotsCles().getTree());
255
			}
256
 
257
		});
258
 
2 aperonnet 259
		// gestion de la validation
260
		valider.addListener(new ButtonListenerAdapter() {
5 aperonnet 261
 
2 aperonnet 262
			// lors du clic
1291 aurelien 263
			@Override
2 aperonnet 264
			public void onClick(Button button, EventObject e) {
5 aperonnet 265
 
2 aperonnet 266
				// on vide les mots clés en cours
5 aperonnet 267
				motsClesEnCours = "";
2 aperonnet 268
				// pour chaque noeud à partir de la racine
5 aperonnet 269
				getArbreMotsCles().getRootNode().cascade(
270
						new NodeTraversalCallback() {
2 aperonnet 271
 
5 aperonnet 272
							// on éxécute une fonction
1291 aurelien 273
							@Override
5 aperonnet 274
							public boolean execute(Node node) {
275
 
276
								// on récupère le mot clé associé au noeud et
277
								// ses infos
278
								TreeNode tn = getArbreMotsCles().getNodeById(
279
										node.getId());
280
 
281
								String[] usObject = (String[]) tn
282
										.getUserObject();
135 aurelien 283
								getIMediateur().mettreAjourMotsClesId(
5 aperonnet 284
										usObject[0], usObject[1]);
285
 
286
								if (tn.getUI().isChecked()) {
287
									// et les concatène à la string des mots
288
									// clés en cours
289
									motsClesEnCours += usObject[1] + ",";
290
								}
291
 
292
								return true;
293
							}
294
 
295
						});
296
 
297
				// enfin on notifie le médiateur et on lui passe l'arbre et la
298
				// liste des mots clés ainsi obtenue
135 aurelien 299
				getIMediateur().mettreAjourMotsCles(motsClesEnCours,
5 aperonnet 300
						arbreMotsCles.getTree());
2 aperonnet 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] = "";
2042 aurelien 355
		cheminTemporaireAjout = MotsClesUtilitaire.construireChemin(nd);
356
		usObject[1] = cheminTemporaireAjout;
357
		nd.setId(cheminTemporaireAjout);
5 aperonnet 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
1291 aurelien 399
						@Override
5 aperonnet 400
						public boolean execute(Node node) {
401
 
88 jpm 402
							getArbreMotsCles().getNodeById(node.getId())
403
							.getUI().toggleCheck(false);
404
 
5 aperonnet 405
							// on parcourt le tableau des mots clés
406
							for (int i = 0; i < motsClesIds.length; i++) {
407
								// si le mot clé fait partie des id à cocher on
408
								// le coche
409
								String usObject[] = (String[]) node
410
										.getUserObject();
411
								String nodeId = usObject[1];
412
 
413
								if (nodeId.equals(motsClesIds[i])) {
414
									getArbreMotsCles().getNodeById(nodeId)
415
											.getUI().toggleCheck(true);
416
									return true;
417
								}
2 aperonnet 418
							}
5 aperonnet 419
							// et on passe au suivant
420
							return true;
2 aperonnet 421
						}
5 aperonnet 422
 
423
					});
2 aperonnet 424
		}
425
	}
5 aperonnet 426
 
2 aperonnet 427
	/**
428
	 * Méthode héritée de l'interface rafraichissable
5 aperonnet 429
	 *
430
	 * @param nouvelleDonnees
431
	 *            les nouvelles données pour l'objet
432
	 * @param repandreRafraichissement
433
	 *            booleen qui dit si on doit répandre l'évenement
2 aperonnet 434
	 */
1291 aurelien 435
	@Override
2 aperonnet 436
	public void rafraichir(Object nouvelleDonnees,
437
			boolean repandreRafraichissement) {
101 jpm 438
 
155 aurelien 439
		if(nouvelleDonnees instanceof Tree) {
5 aperonnet 440
 
155 aurelien 441
			Tree nouvelArbre = (Tree)nouvelleDonnees ;
5 aperonnet 442
 
443
			// on prend sa racine et on l'attache à l'arbre des mots clés
444
			Node[] rootChild = getArbreMotsCles().getRootNode().getChildNodes();
445
			for (int i = 0; i < rootChild.length; i++) {
135 aurelien 446
 
5 aperonnet 447
				rootChild[i].remove();
448
			}
101 jpm 449
 
2042 aurelien 450
			MotsClesUtilitaire.copierFilsNoeud(nouvelArbre.getRootNode(),getArbreMotsCles().getRootNode());
5 aperonnet 451
 
452
			// si l'arbre n'était pas encore considéré comme instancié
135 aurelien 453
			if (!arbreCharge) {
5 aperonnet 454
				// on signale que oui
135 aurelien 455
				arbreCharge = true;
5 aperonnet 456
			}
2 aperonnet 457
		}
5 aperonnet 458
 
459
		// Si on reçoit un tableau de String (cas ou l'on séléectionne une
460
		// nouvelle image)
461
		if (nouvelleDonnees instanceof String[]) {
1009 aurelien 462
 
5 aperonnet 463
				// le tableau de String contient les id des mots clés associés à
464
				// l'image
2 aperonnet 465
				// on coche les mots clés contenu dans le tableau
1009 aurelien 466
				tableauMotsClesEnCours = (String[]) nouvelleDonnees;
467
				cocherMotsCles(tableauMotsClesEnCours);
2 aperonnet 468
		}
2042 aurelien 469
 
470
		// reception d'un nouvel identifiant de mot clé
471
		if(nouvelleDonnees instanceof Integer) {
472
			if(cheminTemporaireAjout != null) {
473
				String id = ((Integer)(nouvelleDonnees)).toString();
474
				TreeNode noeudEnAjout = arbreMotsCles.getNodeById(cheminTemporaireAjout);
475
				String[] userObj = {noeudEnAjout.getText(), id};
476
				noeudEnAjout.setUserObject(userObj);
477
				noeudEnAjout.setId(id);
478
				cheminTemporaireAjout = null;
155 aurelien 479
			}
480
		}
2042 aurelien 481
 
482
		arbreMotsCles.enable();
155 aurelien 483
	}
2 aperonnet 484
}