Subversion Repositories eFlore/Archives.cel-v2

Rev

Rev 38 | Rev 47 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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