Subversion Repositories eFlore/Applications.cel

Rev

Rev 155 | 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 org.tela_botanica.client.observation.ObservationMediateur;

import com.google.gwt.core.client.GWT;
import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONObject;
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.data.event.NodeListener;
import com.gwtext.client.widgets.Button;
import com.gwtext.client.widgets.Container;
import com.gwtext.client.widgets.Panel;
import com.gwtext.client.widgets.event.ButtonListenerAdapter;
import com.gwtext.client.widgets.event.PanelListenerAdapter;
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.TreeNodeListener;
import com.gwtext.client.widgets.tree.event.TreeNodeListenerAdapter;
import com.gwtext.client.widgets.tree.event.TreePanelListenerAdapter;

public class ArbreMotsClesObsVue extends Panel implements Rafraichissable {

                /**
                 * Le médiateur associé à la vue
                 */
                private ObservationMediateur oMediateur = null;

                /**
                 * Le treepanel qui affiche l'arbre
                 */
                private static 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 = 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 ArbreMotsClesObsVue() {
                        super();
                }

                /**
                 * Constructeur avec paramètre
                 * 
                 * @param im
                 *            le médiateur à associer
                 */
                public ArbreMotsClesObsVue(ObservationMediateur om) {
                        // on crée le panel
                        super("Mots clés");
                        this.setLayout(new VerticalLayout());
                        oMediateur = om;

                        // on crée le conteneur de l'arbre
                        arbreMotsCles = new TreePanel();
                        // on permet le drag and drop dans l'arbre
                        arbreMotsCles.setEnableDD(true);
                        arbreMotsCles.setId("x-view-tree-keyword-obs");

                        // on crée une racine pour l'arbre
                        TreeNode root = new TreeNode("Tags");
                        root.setId("racine_obs");
                        String[] usObject = { "Mots clés", "racine" };
                        root.setUserObject(usObject);
                        root.setExpandable(true);
                        arbreMotsCles.setRootNode(root);
                        arbreMotsCles.setRootVisible(true);
                        arbreMotsCles.setBorder(false);
                        arbreMotsCles.setWidth(500);
                        
                        arbreMotsCles.getRootNode().addListener(new TreeNodeListenerAdapter() {
                                public void onClick(Node node, EventObject e) {
                                        if(!arbreCharge) {
                                                expand();
                                        }
                                }

                                public void onExpand(Node node) {
                                        if(!arbreCharge) {
                                                obtenirArbreMotsCles();
                                                arbreCharge = true;
                                        }
                                }
                        });

                        // on crée l'éditeur pour l'arbre
                        tfEdit = new TextField();
                        tfEdit.setAutoWidth(true);
                        te = new TreeEditor(arbreMotsCles, tfEdit);
                        valider = new Button("Appliquer");
                        arbreMotsCles.add(te);

                        // on met en forme le layout
                        this.add(arbreMotsCles);
                        this.add(valider);

                        this.setBorder(false);
                        this.setCollapsible(true);
                        this.setTitleCollapse(true);
                        
                        // on ajoute les listeners
                        ajouterListeners();

                }

                /**
                 * Acesseur pour le médiateur
                 * 
                 * @return le médiateur associé à la vue
                 */
                private ObservationMediateur getOMediateur() {

                        return oMediateur;

                }

                /**
                 * 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() {

                                // gestion du clic sur un noeud
                                public void onClick(TreeNode node, EventObject e) {

                                        e.stopEvent();
                                        gererClicNoeud(node);
                                }

                                // gestion du clic droit sur un noeud
                                public void onContextMenu(TreeNode node, EventObject e) {

                                        e.stopEvent();
                                        getOMediateur().montrerContextMenuArbre(node, e, getTe());

                                }

                                // gestion du double clic sur un noeud
                                public void onDblClick(TreeNode node, EventObject e) {

                                        modifNoeud = true;
                                        if (!node.getId().equals("racine_obs")) {
                                                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;
                                        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
                                                getOMediateur().ajouterMotCleDansArbre(nd,
                                                                getArbreMotsCles().getTree());
                                                // et considère l'ajout achevé
                                                ajoutNoeud = false;
                                        }
                                        // si c'est noeud déjà existant
                                        else {
                                                if (modifNoeud) {
                                                        // on notifie le médiateur de la modification et on lui
                                                        // passe l'arbre
                                                        getOMediateur().modifierMotCleDansArbre(nd,
                                                                        getArbreMotsCles().getTree());
                                                        // et on considère la modification achevée
                                                        modifNoeud = false;
                                                }
                                        }

                                }

                                // 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
                                        getOMediateur().deplacerMotCleDansArbre(node,
                                                        getArbreMotsCles().getTree());
                                }

                        });

                        // 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();
                                                                        getOMediateur().mettreAjourMotsClesId(
                                                                                        usObject[0], usObject[1]);

                                                                        if (tn.getUI().isChecked()) {
                                                                                // et les concatène à la string des mots
                                                                                // clés en cours
                                                                                motsClesEnCours += usObject[1] + ",";
                                                                        }

                                                                        return true;
                                                                }

                                                        });

                                        // enfin on notifie le médiateur et on lui passe l'arbre et la
                                        // liste des mots clés ainsi obtenue
                                        getOMediateur().mettreAjourMotsCles(motsClesEnCours,
                                                        arbreMotsCles.getTree());
                                }
                        });

                }

                /**
                 * Envoie une demande au médiateur pour obtenir l'arbre des mots clés
                 */
                public void obtenirArbreMotsCles() {

                        getOMediateur().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étruit
                                n.getParentNode().removeChild(n);
                                n.destroy();
                                // puis on en notifie le médiateur en lui passant le noeud supprimé
                                // et l'arbre
                                getOMediateur()
                                                .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.setCls("x-view-treenode-keyword");
                        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] = "";
                        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 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()) {
                                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 racine
                                getArbreMotsCles().getRootNode().cascade(
                                                new NodeTraversalCallback() {

                                                        // pour chaque noeud
                                                        public boolean execute(Node node) {

                                                                getArbreMotsCles().getNodeById(node.getId())
                                                                .getUI().toggleCheck(false);
                                                                
                                                                // 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];

                                                                        if (nodeId.equals(motsClesIds[i])) {
                                                                                        getArbreMotsCles().getNodeById(nodeId+"_obs")
                                                                                                        .getUI().toggleCheck(true);
                                                                                
                                                                                        return true;
                                                                        }
                                                                }
                                                                // et on passe au suivant
                                                                return true;
                                                        }

                                                });
                        }
                        else {
                                motsClesEnAttente = motsClesIds ;
                        }
                }

                /**
                 * 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) {
                        
                        if(nouvelleDonnees instanceof Tree) {

                                Tree nouvelArbre = (Tree)nouvelleDonnees ;

                                // on prend sa racine et on l'attache à l'arbre des mots clés
                                Node[] 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 oui
                                        arbreCharge = true;
                                }

                                // s'il y a des mots clés en attente (lors du premier rendering)
                                if (motsCleInitialises == false && motsClesEnAttente != null) {
                                        // on les coche
                                        // cocherMotsCles(motsClesEnAttente) ;
                                        motsCleInitialises = true;
                                }
                                
                                if(motsClesEnAttente.length > 0) {
                                                        cocherMotsCles(motsClesEnAttente);
                                }
                        }

                        // 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 (arbreCharge) {
                                        // 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;
                                }
                        }
                }

                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] +"_obs");
                                        child.setChecked(false);
                                        child.setUserObject(usObj);
                                        ndPereCopie.appendChild(child);

                                        if (!ndNodeFils[i].isLeaf()) {
                                                copierFilsNoeud(ndNodeFils[i], child);
                                        }

                                }
                        }
                }
}