Subversion Repositories eFlore/Applications.cel

Rev

Rev 1083 | Go to most recent revision | Details | Last modification | View Log | RSS feed

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