Rev 1009 | Rev 2042 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
package org.tela_botanica.client.vues;import org.tela_botanica.client.image.ImageMediateur;import org.tela_botanica.client.interfaces.Rafraichissable;import com.google.gwt.user.client.Window;import com.gwtext.client.core.EventObject;import com.gwtext.client.data.Node;import com.gwtext.client.data.NodeTraversalCallback;import com.gwtext.client.data.Tree;import com.gwtext.client.widgets.Button;import com.gwtext.client.widgets.Panel;import com.gwtext.client.widgets.event.ButtonListenerAdapter;import com.gwtext.client.widgets.form.TextField;import com.gwtext.client.widgets.layout.VerticalLayout;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.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 = "";private String[] tableauMotsClesEnCours = new String[0];/*** 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 = new String[0];/*** 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 arbreCharge = 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)*/@SuppressWarnings("unused")private ArbreMotsClesVue() {super();}/*** Constructeur avec paramètre** @param im* le médiateur à associer*/public ArbreMotsClesVue(ImageMediateur im) {// on crée le panelsuper("Mots clés");this.setLayout(new VerticalLayout());iMediateur = im;// on crée le conteneur de l'arbrearbreMotsCles = new TreePanel();// on permet le drag and drop dans l'arbrearbreMotsCles.setEnableDD(true);arbreMotsCles.setId("x-view-tree-keyword");// on crée une racine pour l'arbreTreeNode root = new TreeNode("Tags");root.setId("racine");String[] usObject = { "Mots clés", "racine" };root.setUserObject(usObject);arbreMotsCles.setRootNode(root);arbreMotsCles.setRootVisible(true);arbreMotsCles.setBorder(false);arbreMotsCles.setWidth(500);// on crée l'éditeur pour l'arbretfEdit = new TextField();tfEdit.setAutoWidth(true);te = new TreeEditor(arbreMotsCles, tfEdit);valider = new Button("Appliquer");arbreMotsCles.add(te);// on met en forme le layoutthis.add(arbreMotsCles);this.add(valider);this.setBorder(false);this.setCollapsible(true);this.setTitleCollapse(true);// on ajoute les listenersajouterListeners();}/*** Acesseur pour le médiateur** @return le médiateur associé à la vue*/private ImageMediateur getIMediateur() {return iMediateur;}/*** Acesseur pour l'arbre des mots clés** @return le panel contenant l'arbre*/public TreePanel getArbreMotsCles() {return arbreMotsCles;}/*** Accesseur pour l'éditeur** @return l'éditeur associé à l'arbre*/public TreeEditor getTe() {return te;}/*** Acesseur pour le TextField associé à l'éditeur** @return le champ texte associé à l'éditeur*/public TextField getTfEdit() {return tfEdit;}/*** Ajoute les listeners nécessaires pour la gestion des évènements*/private void ajouterListeners() {arbreMotsCles.addListener(new TreePanelListenerAdapter() {@Overridepublic void onExpandNode(TreeNode node) {cocherMotsCles(tableauMotsClesEnCours);}// gestion du clic sur un noeud@Overridepublic void onClick(TreeNode node, EventObject e) {e.stopEvent();gererClicNoeud(node);}// gestion du clic droit sur un noeud@Overridepublic void onContextMenu(TreeNode node, EventObject e) {e.stopEvent();getIMediateur().montrerContextMenuArbre(node, e, getTe());}// gestion du double clic sur un noeud@Overridepublic void onDblClick(TreeNode node, EventObject e) {modifNoeud = true;if (!node.getId().equals("racine")) {te.startEdit(node);}}// gestion de la modification du texte d'un noeud@Overridepublic void onTextChange(TreeNode node, String text, String oldText) {// on récupère les informations associées au noeudTreeNode nd = node;String[] usObject = new String[2];usObject[0] = text;usObject[1] = ((String[]) nd.getUserObject())[1];nd.setUserObject(usObject);// si c'est un nouveau noeudif (ajoutNoeud) {// on considère l'ajout achevéajoutNoeud = false;// et on notifie le médiateur de l'ajout et on lui passe// l'arbregetIMediateur().ajouterMotCleDansArbre(nd,getArbreMotsCles().getTree());}// si c'est noeud déjà existantelse {// et on considère la modification achevéemodifNoeud = false;// on notifie le médiateur de la modification et on lui// passe l'arbregetIMediateur().modifierMotCleDansArbre(nd,getArbreMotsCles().getTree());}}// gestion du déplacement d'un noeud@Overridepublic void onMoveNode(Tree tree, TreeNode node,TreeNode oldParent, TreeNode newParent, int index) {// on notifie le médiateur et on lui passe l'arbregetIMediateur().deplacerMotCleDansArbre(node,getArbreMotsCles().getTree());}});// gestion de la validationvalider.addListener(new ButtonListenerAdapter() {// lors du clic@Overridepublic void onClick(Button button, EventObject e) {// on vide les mots clés en coursmotsClesEnCours = "";// pour chaque noeud à partir de la racinegetArbreMotsCles().getRootNode().cascade(new NodeTraversalCallback() {// on éxécute une fonction@Overridepublic boolean execute(Node node) {// on récupère le mot clé associé au noeud et// ses infosTreeNode tn = getArbreMotsCles().getNodeById(node.getId());String[] usObject = (String[]) tn.getUserObject();getIMediateur().mettreAjourMotsClesId(usObject[0], usObject[1]);if (tn.getUI().isChecked()) {// et les concatène à la string des mots// clés en coursmotsClesEnCours += usObject[1] + ",";}return true;}});// enfin on notifie le médiateur et on lui passe l'arbre et la// liste des mots clés ainsi obtenuegetIMediateur().mettreAjourMotsCles(motsClesEnCours,arbreMotsCles.getTree());}});}/*** Envoie une demande au médiateur pour obtenir l'arbre des mots clés*/public void obtenirArbreMotsCles() {getIMediateur().obtenirArbreMotsCles(this);}/*** 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étruitn.getParentNode().removeChild(n);n.destroy();// puis on en notifie le médiateur en lui passant le noeud supprimé// et l'arbregetIMediateur().supprimerMotCleDansArbre(n, arbreMotsCles.getTree());} else {// si l'utilisateur tente de supprimer la racine, on l'avertit de// son erreurWindow.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 à vraiajoutNoeud = true;// on crée un nouveau noeud videTreeNode nd = new TreeNode("");nd.setCls("x-view-treenode-keyword");nd.setChecked(true);// on associe un objet au noeud qui contient des infosString[] usObject = new String[2];// l'objet contient le nom du noeudusObject[0] = "";usObject[1] = genererIdMotCle(nd);nd.setId(usObject[1]);nd.setUserObject(usObject);// l'identifiant d'un noeud c'est son hashcode// l'objet associé au noeud contient aussi son identifiant// on le concatène au parent et on étend ses enfantsparent.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()) {node.getUI().toggleCheck(false);} else {node.getUI().toggleCheck(true);}}/*** 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 racinegetArbreMotsCles().getRootNode().cascade(new NodeTraversalCallback() {// pour chaque noeud@Overridepublic boolean execute(Node node) {getArbreMotsCles().getNodeById(node.getId()).getUI().toggleCheck(false);// on parcourt le tableau des mots clésfor (int i = 0; i < motsClesIds.length; i++) {// si le mot clé fait partie des id à cocher on// le cocheString usObject[] = (String[]) node.getUserObject();String nodeId = usObject[1];if (nodeId.equals(motsClesIds[i])) {getArbreMotsCles().getNodeById(nodeId).getUI().toggleCheck(true);return true;}}// et on passe au suivantreturn true;}});}}/*** 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*/@Overridepublic void rafraichir(Object nouvelleDonnees,boolean repandreRafraichissement) {if(nouvelleDonnees instanceof Tree) {Tree nouvelArbre = (Tree)nouvelleDonnees ;// on prend sa racine et on l'attache à l'arbre des mots clésNode[] rootChild = getArbreMotsCles().getRootNode().getChildNodes();for (int i = 0; i < rootChild.length; i++) {rootChild[i].remove();}copierFilsNoeud(nouvelArbre.getRootNode(),getArbreMotsCles().getRootNode());// si l'arbre n'était pas encore considéré comme instanciéif (!arbreCharge) {// on signale que ouiarbreCharge = true;}}// Si on reçoit un tableau de String (cas ou l'on séléectionne une// nouvelle image)if (nouvelleDonnees instanceof String[]) {// le tableau de String contient les id des mots clés associés à// l'image// on coche les mots clés contenu dans le tableautableauMotsClesEnCours = (String[]) nouvelleDonnees;cocherMotsCles(tableauMotsClesEnCours);}}private String genererIdMotCle(TreeNode nd) {return "" + (nd.hashCode() + (Math.random() * 10000));}/*** Fonction récursive qui prend deux noeuds d'arbre en paramètre et crée un* copie du sous arbre du premier noeud, qu'elle concatène au deuxième** @param ndPereOriginal* le père des noeuds de l'arbre original* @param ndPereCopie* le père qui va recevoir les copies*/private void copierFilsNoeud(Node ndPereOriginal, TreeNode ndPereCopie) {if (ndPereCopie != null && ndPereOriginal != null) {Node[] ndNodeFils = ndPereOriginal.getChildNodes();for (int i = 0; i < ndNodeFils.length; i++) {String[] usObj = (String[]) ndNodeFils[i].getUserObject();TreeNode child = new TreeNode(usObj[0]);child.setId(usObj[1]);child.setChecked(false);child.setUserObject(usObj);ndPereCopie.appendChild(child);if (!ndNodeFils[i].isLeaf()) {copierFilsNoeud(ndNodeFils[i], child);}}}}}