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