1,72 → 1,104 |
package org.tela_botanica.client.vues; |
|
import java.util.HashMap; |
|
import org.tela_botanica.client.image.ImageMediateur; |
import org.tela_botanica.client.interfaces.Rafraichissable; |
import org.tela_botanica.client.modeles.MotsClesAsynchroneDAO; |
|
import com.google.gwt.core.client.JavaScriptObject; |
import com.google.gwt.user.client.Window; |
import com.gwtext.client.core.EventObject; |
import com.gwtext.client.core.ExtElement; |
import com.gwtext.client.data.Node; |
import com.gwtext.client.data.NodeTraversalCallback; |
import com.gwtext.client.data.Tree; |
import com.gwtext.client.dd.DD; |
import com.gwtext.client.dd.DragData; |
import com.gwtext.client.dd.DragDrop; |
import com.gwtext.client.widgets.BoxComponent; |
import com.gwtext.client.widgets.Button; |
import com.gwtext.client.widgets.Component; |
import com.gwtext.client.widgets.Container; |
import com.gwtext.client.widgets.Editor; |
import com.gwtext.client.widgets.Panel; |
import com.gwtext.client.widgets.event.ButtonListener; |
import com.gwtext.client.widgets.event.ButtonListenerAdapter; |
import com.gwtext.client.widgets.event.ComponentListener; |
import com.gwtext.client.widgets.event.ComponentListenerAdapter; |
import com.gwtext.client.widgets.event.ContainerListener; |
import com.gwtext.client.widgets.event.ContainerListenerAdapter; |
import com.gwtext.client.widgets.event.EditorListener; |
import com.gwtext.client.widgets.event.EditorListenerAdapter; |
import com.gwtext.client.widgets.event.PanelListenerAdapter; |
import com.gwtext.client.widgets.form.Field; |
import com.gwtext.client.widgets.form.TextField; |
import com.gwtext.client.widgets.layout.RowLayout; |
import com.gwtext.client.widgets.layout.RowLayoutData; |
import com.gwtext.client.widgets.menu.Menu; |
import com.gwtext.client.widgets.tree.DropNodeCallback; |
import com.gwtext.client.widgets.tree.TreeEditor; |
import com.gwtext.client.widgets.tree.TreeNode; |
import com.gwtext.client.widgets.tree.TreePanel; |
import com.gwtext.client.widgets.tree.event.TreePanelListener; |
import com.gwtext.client.widgets.tree.event.TreePanelListenerAdapter; |
|
/** |
* Arbre des mots clés, qui est une vue rafraichissable, |
* qui contient des mots clés cochables et réorganisables à volonté |
* @author aurelien |
* |
*/ |
public class ArbreMotsClesVue extends Panel implements Rafraichissable { |
|
/** |
* Le médiateur associé à la vue |
*/ |
private ImageMediateur iMediateur = null ; |
|
/** |
* Le treepanel qui affiche l'arbre |
*/ |
private TreePanel arbreMotsCles = null ; |
/** |
* L'éditeur qui permet de modifier les mots clés dans l'arbre |
*/ |
private TreeEditor te = null ; |
/** |
* Le textfield associé à l'éditeur |
*/ |
private TextField tfEdit = null ; |
/** |
* Bouton de validation |
*/ |
private Button valider = null ; |
/** |
* Une string permettant connaitre les mots clés cochés en cours séparés par des virgules |
*/ |
private String motsClesEnCours = "" ; |
/** |
* Tableau contenant les mots clés qui n'ont pas encore été jaouté à l'arbre |
* (sert au lazy rendering quand on reçoit des mots clés avant que le rendu du conteneur n'ai été effectué) |
*/ |
private String[] motsClesEnAttente ; |
/** |
* Booléen d'évènement qui sert à savoir si on est en train d'ajouter un noeud |
*/ |
private boolean ajoutNoeud = false ; |
/** |
* Booléen d'évènement qui sert à savoir si on est en train de modifier un noeud |
*/ |
private boolean modifNoeud = false ; |
/** |
* Booléen d'instanciation du conteneur |
*/ |
private boolean estInstancie = false ; |
/** |
* Booléen d'évènement qui sert à savoir si les mots clés ont bien été reçu |
*/ |
private boolean motsCleInitialises ; |
|
/** |
* Constructeur sans paramètre (privé car interdit d'utilisation) |
*/ |
private ArbreMotsClesVue() |
{ |
super() ; |
} |
|
/** |
* Constructeur avec paramètre |
* @param im le médiateur à associer |
*/ |
public ArbreMotsClesVue(ImageMediateur im) |
{ |
// on crée le panel |
super("Mots clés") ; |
this.setLayout(new RowLayout()); |
iMediateur = im ; |
|
// on crée le conteneur de l'arbre |
arbreMotsCles = new TreePanel() ; |
// on permet le drag and drop dans l'arbre |
arbreMotsCles.setEnableDD(true) ; |
|
// on crée une racine pour l'arbre |
TreeNode root = new TreeNode("Tags") ; |
root.setId("racine") ; |
String[] usObject = {"Mots clés" , "racine" } ; |
76,17 → 108,25 |
arbreMotsCles.setRootVisible(false) ; |
arbreMotsCles.getRootNode().setIcon("tela.png") ; |
|
// on crée l'éditeur pour l'arbre |
tfEdit = new TextField() ; |
te = new TreeEditor(arbreMotsCles,tfEdit) ; |
valider = new Button("Appliquer") ; |
arbreMotsCles.add(te) ; |
|
// on met en forme le layout |
this.add(arbreMotsCles,new RowLayoutData("90%")) ; |
this.add(valider,new RowLayoutData("10%")) ; |
|
// on ajoute les listeners |
ajouterListeners() ; |
|
} |
|
/** |
* Acesseur pour le médiateur |
* @return le médiateur associé à la vue |
*/ |
private ImageMediateur GetIMediateur() { |
|
return iMediateur ; |
94,7 → 134,8 |
} |
|
/** |
* @return the arbreMotsCles |
* Acesseur pour l'arbre des mots clés |
* @return le panel contenant l'arbre |
*/ |
public TreePanel getArbreMotsCles() { |
return arbreMotsCles; |
101,7 → 142,8 |
} |
|
/** |
* @return the te |
* Accesseur pour l'éditeur |
* @return l'éditeur associé à l'arbre |
*/ |
public TreeEditor getTe() { |
return te; |
108,16 → 150,21 |
} |
|
/** |
* @return the tfEdit |
* Acesseur pour le TextField associé à l'éditeur |
* @return le champ texte associé à l'éditeur |
*/ |
public TextField getTfEdit() { |
return tfEdit; |
} |
|
public void ajouterListeners() |
/** |
* Ajoute les listeners nécessaires pour la gestion des évènements |
*/ |
private void ajouterListeners() |
{ |
arbreMotsCles.addListener(new TreePanelListenerAdapter() { |
|
// gestion du clic sur un noeud |
public void onClick(TreeNode node, EventObject e) { |
|
e.stopEvent() ; |
124,7 → 171,7 |
gererClicNoeud(node); |
} |
|
|
// gestion du clic droit sur un noeud |
public void onContextMenu(TreeNode node, EventObject e) { |
|
e.stopEvent() ; |
132,6 → 179,7 |
|
} |
|
// gestion du double clic sur un noeud |
public void onDblClick(TreeNode node, EventObject e) { |
|
modifNoeud = true ; |
138,9 → 186,10 |
te.startEdit(node); |
} |
|
// gestion de la modification du texte d'un noeud |
public void onTextChange(TreeNode node, String text, String oldText) { |
|
|
// on récupère les informations associées au noeud |
TreeNode nd = node ; |
String[] usObject = new String[2] ; |
usObject[0] = text ; |
147,29 → 196,39 |
usObject[1] = ((String[])nd.getUserObject())[1] ; |
nd.setUserObject(usObject) ; |
|
// si c'est un nouveau noeud |
if(ajoutNoeud) |
{ |
// on notifie le médiateur de l'ajout et on lui passe l'arbre |
GetIMediateur().ajouterMotCleDansArbre(nd,getArbreMotsCles().getTree()) ; |
// et considière l'ajout achevé |
ajoutNoeud = false ; |
} |
// si c'est noeud déjà existant |
else |
{ |
// on notifie le médiateur de la modification et on lui passe l'arbre |
GetIMediateur().modifierMotCleDansArbre(nd,getArbreMotsCles().getTree()) ; |
// et on considère la modification achevée |
modifNoeud = false ; |
GetIMediateur().modifierMotCleDansArbre(nd,getArbreMotsCles().getTree()) ; |
} |
|
} |
|
// gestion du déplacement d'un noeud |
public void onMoveNode(Tree tree, TreeNode node, TreeNode oldParent, TreeNode newParent,int index) |
{ |
// on notifie le médiateur et on lui passe l'arbre |
GetIMediateur().deplacerMotCleDansArbre(node, getArbreMotsCles().getTree()) ; |
} |
|
|
// gestion du changement de valeur dans la checkbox |
public void onCheckChange(TreeNode node, boolean checked) { |
|
// si on a coché un noeud |
if(checked) |
{ |
// on remonte pour cocher tous les parents du noeud |
node.bubble(new NodeTraversalCallback() { |
|
public boolean execute(Node node) |
185,15 → 244,21 |
|
}) ; |
|
// gestion de la validation |
valider.addListener(new ButtonListenerAdapter() { |
|
// lors du clic |
public void onClick(Button button, EventObject e) { |
|
// on vide les mots clés en cours |
motsClesEnCours = "" ; |
// pour chaque noeud à partir de la racine |
getArbreMotsCles().getRootNode().cascade(new NodeTraversalCallback() { |
|
// on éxécute une fonction |
public boolean execute(Node node) { |
|
// on récupère le mot clé associé au noeud et ses infos |
TreeNode tn = getArbreMotsCles().getNodeById(node.getId()) ; |
|
String[] usObject = (String[])tn.getUserObject() ; |
201,6 → 266,7 |
|
if(tn.getUI().isChecked()) |
{ |
// et les concatène à la string des mots clés en cours |
motsClesEnCours += usObject[1]+"," ; |
} |
|
209,6 → 275,7 |
|
}); |
|
// enfin on notifie le médiateur et on lui passe l'arbre et la liste des mots clés ainsi obtenue |
GetIMediateur().mettreAjourMotsCles(motsClesEnCours,arbreMotsCles.getTree()) ; |
} |
}) ; |
215,6 → 282,9 |
|
} |
|
/** |
* Envoie une demande au médiateur pour obtenir l'arbre des mots clés |
*/ |
public void obtenirArbreMotsCles() { |
|
GetIMediateur().obtenirArbreMotsCles(this) ; |
221,39 → 291,61 |
|
} |
|
|
/** |
* Supprime un noeud de l'arbre |
* @param n le noeud à supprimer |
*/ |
public void supprimerNoeud(TreeNode n) |
{ |
|
// si ça n'est pas la racine (qu'on ne peut pas supprimer) |
if(!n.getId().equals(getArbreMotsCles().getRootNode().getId())) |
{ |
// on détache le noeud et on le détruit |
n.getParentNode().removeChild(n); |
n.destroy() ; |
// puis on en notifie le médiateur en lui passant le noeud supprimé et l'arbre |
GetIMediateur().supprimerMotCleDansArbre(n, arbreMotsCles.getTree()) ; |
} |
else |
{ |
// si l'utilisateur tente de supprimer la racine, on l'avertit de son erreur |
Window.alert("Impossible de supprimer la racine de l'arbre") ; |
} |
} |
|
/** |
* Ajoute un noeud dans l'arbre au parent donné |
* @param parent le futur parent du noeud à ajouter |
*/ |
public void ajouterNoeud(TreeNode parent) |
{ |
|
// on met l'ajout du noeud à vrai |
ajoutNoeud = true ; |
// on crée un nouveau noeud vide |
TreeNode nd = new TreeNode(""); |
nd.setIcon("tela.png") ; |
nd.setChecked(true); |
// on associe un objet au noeud qui contient des infos |
String[] usObject = new String[2] ; |
// l'objet contient le nom du noeud |
usObject[0] = "" ; |
// l'identifiant d'un noeud c'est son hashcode |
usObject[1] = Integer.toString(nd.hashCode()) ; |
// l'objet associé au noeud contient aussi son identifiant |
nd.setId(usObject[1]) ; |
nd.setUserObject(usObject) ; |
|
// on le concatène au parent et on étend ses enfants |
parent.appendChild(nd); |
parent.expand(); |
// enfin on place le curseur et on fait apparaitre le champ d'édition pour que l'utilisateur nomme son mot clé |
te.startEdit(nd); |
} |
|
/** |
* Coche le noeud s'il est décoché, le décoche sinon |
* @param node |
*/ |
public void gererClicNoeud(TreeNode node) |
{ |
if(node.getUI().isChecked()) |
266,16 → 358,24 |
} |
} |
|
/** |
* Parcourt l'arbre et coche les noeud qui font partie de la liste des mots clés à cocher |
* @param motsClesIds un tableau contenant les identifiants des mots clés à cocher |
*/ |
public void cocherMotsCles(final String[] motsClesIds) |
{ |
if(getArbreMotsCles() != null && getArbreMotsCles().getRootNode() != null) |
{ |
// à partir de la racine |
getArbreMotsCles().getRootNode().cascade(new NodeTraversalCallback() { |
|
// pour chaque noeud |
public boolean execute(Node node) { |
|
// on parcourt le tableau des mots clés |
for(int i = 0 ; i < motsClesIds.length ; i++) |
{ |
// si le mot clé fait partie des id à cocher on le coche |
String usObject[] = (String[])node.getUserObject() ; |
String nodeId = usObject[1] ; |
|
287,6 → 387,7 |
return true ; |
} |
} |
// et on passe au suivant |
return true; |
} |
|
294,32 → 395,53 |
} |
} |
|
/** |
* Méthode héritée de l'interface rafraichissable |
* @param nouvelleDonnees les nouvelles données pour l'objet |
* @param repandreRafraichissement booleen qui dit si on doit répandre l'évenement |
*/ |
public void rafraichir(Object nouvelleDonnees, |
boolean repandreRafraichissement) { |
|
// si on a reçu un arbre |
if(nouvelleDonnees instanceof Tree) |
{ |
Tree nouvelArbre = (Tree)nouvelleDonnees ; |
|
// on prend sa racine et on l'attache à l'arbre des mots clés |
getArbreMotsCles().getRootNode().appendChild(nouvelArbre.getRootNode()) ; |
getArbreMotsCles().expandAll() ; |
|
// si l'arbre n'était pas encore considéré comme instancié |
if(!estInstancie) |
{ |
// on signale que oui |
estInstancie = true ; |
} |
|
// s'il y a des mots clés en attente (lors du premier rendering) |
if(motsCleInitialises == false && motsClesEnAttente != null) |
{ |
// on les coche |
// TODO: corriger le bug qui fait que ça ne marche pas la premiere fois !!!! |
cocherMotsCles(motsClesEnAttente) ; |
motsCleInitialises = true ; |
} |
} |
|
|
// Si on reçoit un tableau de String (cas ou l'on séléectionne une nouvelle image) |
if(nouvelleDonnees instanceof String[]) |
{ |
// et que l'arbre est instancié |
if(estInstancie && nouvelleDonnees != null) |
{ |
// le tableau de String contient les id des mots clés associés à l'image |
// on coche les mots clés contenu dans le tableau |
String[] motsClesIds = (String[])nouvelleDonnees ; |
cocherMotsCles(motsClesIds) ; |
|
} |
// si l'arbre n'est pas encore instancié on met les mots clés en attente |
else |
{ |
motsClesEnAttente = (String[])nouvelleDonnees ; |