Subversion Repositories eFlore/Applications.cel

Rev

Rev 135 | Blame | 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.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.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.TreeNodeListenerAdapter;
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 = 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 panel
                super("Mots clés");
                this.setLayout(new VerticalLayout());
                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);
                arbreMotsCles.setId("x-view-tree-keyword");

                // on crée une racine pour l'arbre
                TreeNode 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'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 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() {

                        // 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();
                                getIMediateur().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")) {
                                        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
                                        getIMediateur().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
                                                getIMediateur().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
                                getIMediateur().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();
                                                                getIMediateur().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
                                getIMediateur().mettreAjourMotsCles(motsClesEnCours,
                                                arbreMotsCles.getTree());
                        }
                });
                
                /*this.addListener(new PanelListenerAdapter() {
                        
                        public void onAfterLayout(Container c) {
                                if(!arbreCharge) {
                                        //obtenirArbreMotsCles();
                                }
                        }
                });*/

        }

        /**
         * 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é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.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)
                                                                                        .getUI().toggleCheck(true);
                                                                        return true;
                                                                }
                                                        }
                                                        // et on passe au suivant
                                                        return 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
         */
        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;
                                
                                Window.alert("des mots clés en attente : "+motsClesEnAttente[0]);
                        }
                }
        }

        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);
                                }

                        }
                }
        }
}