Subversion Repositories eFlore/Applications.cel

Rev

Rev 1292 | Blame | Last modification | View Log | RSS feed

package org.tela_botanica.client.vues.image;

import org.tela_botanica.client.interfaces.Rafraichissable;

import com.google.gwt.core.client.JavaScriptObject;
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.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.Panel;
import com.gwtext.client.widgets.Toolbar;
import com.gwtext.client.widgets.ToolbarButton;
import com.gwtext.client.widgets.event.ButtonListenerAdapter;
import com.gwtext.client.widgets.event.ContainerListener;
import com.gwtext.client.widgets.event.PanelListener;
import com.gwtext.client.widgets.event.WindowListener;
import com.gwtext.client.widgets.event.WindowListenerAdapter;
import com.gwtext.client.widgets.form.TextField;
import com.gwtext.client.widgets.layout.FitLayout;
import com.gwtext.client.widgets.layout.HorizontalLayout;
import com.gwtext.client.widgets.layout.RowLayout;
import com.gwtext.client.widgets.layout.RowLayoutData;
import com.gwtext.client.widgets.layout.VerticalLayout;
import com.gwtext.client.widgets.tree.DropNodeCallback;
import com.gwtext.client.widgets.tree.MultiSelectionModel;
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.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 abstract class FenetreGestionMotsCles extends com.gwtext.client.widgets.Window implements Rafraichissable {

        /**
         * 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;
        
        /**
         * Bouton d'annulation
         */
        private Button annuler = null;
        
        /**
         * Bouton d'ajout de tag
         */
        private ToolbarButton ajouterTag = null;
        
        /**
         * Bouton de suppression de tag
         */
        private ToolbarButton supprimerTag = null;
        
        /**
         * Bouton de renommage de tag
         */
        private ToolbarButton renommerTag = 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;
        
        /**
         * panneau intermédiaire contenant l'arbre
         */
        private Panel panelIntermediaire;

        /**
         * Constructeur avec paramètre
         * 
         * @param im
         *            le médiateur à associer
         */
        public FenetreGestionMotsCles() {
                                
                // on crée le panel
                setTitle("Mots clés");
                this.setLayoutData(new RowLayout());

                // 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-imgs");

                arbreMotsCles.setSelectionModel(new MultiSelectionModel());

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

                        @Override
                        public void onClick(Node node, EventObject e) {
                                if(!arbreCharge) {
                                        expand();
                                }
                        }

                        @Override
                        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");
                annuler = new Button("Annuler");
                arbreMotsCles.add(te);
                
                panelIntermediaire = new Panel();
                panelIntermediaire.setLayout(new FitLayout());
                panelIntermediaire.setAutoScroll(true);
                panelIntermediaire.setWidth("100%");
                arbreMotsCles.setWidth("100%");
                arbreMotsCles.setHeight("100%");
                
                Panel panelBoutons = new Panel();
                panelBoutons.setLayout(new HorizontalLayout(130));
                panelBoutons.setWidth("100%");

                // on met en forme le layout
                panelIntermediaire.add(arbreMotsCles);
                panelBoutons.add(annuler);
                panelBoutons.add(valider);
                
                this.add(panelIntermediaire, new RowLayoutData());
                this.add(panelBoutons, new RowLayoutData(30));
                arbreMotsCles.setHeight("100%");
                arbreMotsCles.setAutoScroll(true);
                
                Toolbar barreBouton = new Toolbar();
                ajouterTag = new ToolbarButton("Nouveau Tag");
                ajouterTag.setIcon("mot_cle_ajouter.png");
                renommerTag = new ToolbarButton("Renommer");
                renommerTag.setIcon("mot_cle_editer.png");
                renommerTag.disable();
                supprimerTag = new ToolbarButton("Supprimer");
                supprimerTag.setIcon("mot_cle_supprimer.png");
                supprimerTag.disable();
                barreBouton.addButton(ajouterTag);
                barreBouton.addSeparator();
                barreBouton.addButton(renommerTag);
                barreBouton.addSeparator();
                barreBouton.addButton(supprimerTag);
                this.setTopToolbar(barreBouton);
                
                setCloseAction(com.gwtext.client.widgets.Window.HIDE);          
                // on ajoute les listeners
                ajouterListeners();

        }


        /**
         * 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;
        }
        
        protected abstract void surAffichageMenuContextuel(TreeNode node, EventObject e, TreeEditor te);
        protected abstract void surAjoutMotCle(TreeNode node, Tree arbre);
        protected abstract void surSuppressionMotCle(TreeNode node, Tree arbre);
        protected abstract void surDeplacementMotCle(TreeNode node, Tree arbre);
        protected abstract void surChangementTexte(TreeNode node, Tree arbre);
        protected abstract void surClicValider(String chaineMotsCles, Tree arbre);
        protected abstract void demanderArbreMotsCles(Rafraichissable r);

        /**
         * Ajoute les listeners nécessaires pour la gestion des évènements
         */
        private void ajouterListeners() {
                
                this.addListener(new WindowListenerAdapter() {                  
                        @Override
                        public void onResize(com.gwtext.client.widgets.Window source, int width,
                                        int height) {
                                        panelIntermediaire.setHeight(getHeight() - 80);         
                        }
                });
                                                
                arbreMotsCles.addListener(new TreePanelListenerAdapter() {
                        @Override
                        public void onAfterLayout(Container self) {
                                panelIntermediaire.setHeight(getHeight() - 80);         
                        }
                        
                        @Override
                        public void onExpandNode(TreeNode node) {               
                                cocherMotsCles(tableauMotsClesEnCours);
                        }

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

                                e.stopEvent();
                                gererClicNoeud(node);
                                if(!node.equals(arbreMotsCles.getRootNode())) {
                                        supprimerTag.enable();
                                        renommerTag.enable();
                                }
                        }

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

                                e.stopEvent();
                                surAffichageMenuContextuel(node, e, getTe());
                                if(!node.equals(arbreMotsCles.getRootNode())) {
                                        supprimerTag.enable();
                                        renommerTag.enable();
                                }
                        }

                        // gestion de la modification du texte d'un noeud
                        @Override
                        public void onTextChange(TreeNode node, String text, String oldText) {

                                if(node.equals(arbreMotsCles.getRootNode())) {
                                        return;
                                }

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

                        }

                        // gestion du déplacement d'un noeud
                        @Override
                        public void onMoveNode(Tree tree, TreeNode node,
                                        TreeNode oldParent, TreeNode newParent, int index) {
                                // on notifie le médiateur et on lui passe l'arbre
                                surDeplacementMotCle(node, getArbreMotsCles().getTree());
                        }

                });

                // gestion de la validation
                valider.addListener(new ButtonListenerAdapter() {

                        // lors du clic
                        @Override
                        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
                                                        @Override
                                                        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
                                surClicValider(motsClesEnCours, arbreMotsCles.getTree());
                        }
                });
                
                annuler.addListener(new ButtonListenerAdapter() {
                        @Override
                        public void onClick(Button button, EventObject e) {
                                hide();
                        }
                });
                
                renommerTag.addListener(new ButtonListenerAdapter() {
                        @Override
                        public void onClick(Button button, EventObject e) {
                                TreeNode[] noeuds = ((MultiSelectionModel)arbreMotsCles.getSelectionModel()).getSelectedNodes();
                                TreeNode noeudRenommage;
                                if(noeuds.length > 0) {
                                        noeudRenommage = noeuds[noeuds.length - 1];
                                } else {
                                        noeudRenommage = arbreMotsCles.getRootNode();
                                }
                                renommerNoeud(noeudRenommage);
                        }
                });
                
                ajouterTag.addListener(new ButtonListenerAdapter() {
                        @Override
                        public void onClick(Button button, EventObject e) {
                                
                                TreeNode[] noeuds = ((MultiSelectionModel)arbreMotsCles.getSelectionModel()).getSelectedNodes();
                                TreeNode noeudAjout;
                                if(noeuds.length > 0) {
                                        noeudAjout = noeuds[noeuds.length - 1];
                                } else {
                                        noeudAjout = arbreMotsCles.getRootNode();
                                }

                                ajouterNoeud(noeudAjout);
                        }
                });
                
                supprimerTag.addListener(new ButtonListenerAdapter() {
                        @Override
                        public void onClick(Button button, EventObject e) {
                                
                                TreeNode[] noeuds = ((MultiSelectionModel)arbreMotsCles.getSelectionModel()).getSelectedNodes();
                                for (int i = 0; i < noeuds.length; i++) {
                                        supprimerNoeud(noeuds[i]);
                                }
                        }
                });
        }

        /**
         * Envoie une demande au médiateur pour obtenir l'arbre des mots clés
         */
        public void obtenirArbreMotsCles() {
                demanderArbreMotsCles(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())) {
                        if(Window.confirm("Êtes vous sur de vouloir supprimer le mot clé "+n.getText()+" ?")) {
                                // 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
                                surSuppressionMotCle(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);

        }

        /**
         * Renomme le noeud passé en paramètre
         */
        public void renommerNoeud(TreeNode n) {
                // TODO Auto-generated method stub
                te.startEdit(n);
        }

        /**
         * 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
                                                @Override
                                                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);
                                                                        getArbreMotsCles().getNodeById(nodeId).ensureVisible();
                                                                        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
         */
        @Override
        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;
                        }
                }

                // 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 tableau
                                tableauMotsClesEnCours = (String[]) nouvelleDonnees;
                                if(this.isVisible()) {
                                        cocherMotsCles(tableauMotsClesEnCours);
                                } else {
                                        addListener(new WindowListenerAdapter() {
                                                
                                                @Override
                                                public void onShow(Component component) {
                                                        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);
                                }

                        }
                }
        }


        public void activerBoutonValider(boolean activer) {
                valider.setVisible(activer);
        }
}