Rev 965 | Rev 2042 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
package org.tela_botanica.client.vues.observation.filtres;
import org.tela_botanica.client.interfaces.Filtrable;
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.dd.DragData;
import com.gwtext.client.dd.DragDrop;
import com.gwtext.client.dd.DropTargetConfig;
import com.gwtext.client.widgets.Button;
import com.gwtext.client.widgets.Component;
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.menu.BaseItem;
import com.gwtext.client.widgets.menu.Item;
import com.gwtext.client.widgets.menu.Menu;
import com.gwtext.client.widgets.menu.event.MenuListenerAdapter;
import com.gwtext.client.widgets.tree.DropNodeCallback;
import com.gwtext.client.widgets.tree.MultiSelectionModel;
import com.gwtext.client.widgets.tree.TreeDragData;
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;
public class ArbreMotsClesObservationVue extends Panel implements Rafraichissable, Filtrable {
/**
* 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 ajouterMotCle = 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 nécessaire pour l'affichage
*
*/
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;
private Component livue = null;
MultiSelectionModel msModel = null;
/**
* Constructeur sans paramètre (privé car interdit d'utilisation)
*/
@SuppressWarnings("unused")
private ArbreMotsClesObservationVue() {
super();
}
/**
* Constructeur avec paramètre
*
* @param im
* le médiateur à associer
*/
public ArbreMotsClesObservationVue(ObservationMediateur om) {
// on crée le panel
super("Projets");
this.setLayout(new VerticalLayout());
oMediateur = om;
setBorder(false);
setCollapsible(true);
setTitleCollapse(true);
setAutoScroll(true);
// on ajoute les listeners
ajouterListenersPanel();
}
/**
* Ajoute les listeners pour le rendu du panel
*/
private void ajouterListenersPanel() {
this.addListener(new PanelListenerAdapter() {
// on instancie réellement les composants au moment du rendu pour
// accélérer l'affichage
// et éviter des bugs
@Override
public void onRender(Component component) {
livue = oMediateur.getListeObservation();
// 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");
msModel = new MultiSelectionModel();
arbreMotsCles.setSelectionModel(msModel);
// on crée une racine pour l'arbre
TreeNode root = new TreeNode("Projets");
root.setId("racine_obs");
String[] usObject = { "Projets", "racine_obs" };
root.setUserObject(usObject);
root.setExpandable(true);
arbreMotsCles.setRootNode(root);
// on crée l'éditeur pour l'arbre
tfEdit = new TextField();
te = new TreeEditor(arbreMotsCles, tfEdit);
ajouterMotCle = new Button("Ajouter un projet");
arbreMotsCles.add(te);
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 interdit le drag and drop dans l'arbre
arbreMotsCles.setRootVisible(true);
arbreMotsCles.setBorder(false);
// on met en forme le layout
add(arbreMotsCles);
add(ajouterMotCle);
// enfin on considère le composant comme instancié
estInstancie = true;
configDragAndDrop();
// on ajoute les listeners d'évenements
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
@Override
public void onClick(TreeNode node, EventObject e) {
e.stopEvent();
boolean multi = false;
if(e.hasModifier()) {
multi = true;
}
gererClicNoeud(node,multi);
}
// gestion du clic droit sur un noeud
@Override
public void onContextMenu(TreeNode node, EventObject e) {
e.stopEvent();
montrerContextMenuArbre(node, e, getTe());
}
// gestion du double clic sur un noeud
@Override
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
@Override
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
@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
getOMediateur().deplacerMotCleDansArbre(node,
getArbreMotsCles().getTree());
}
@Override
public boolean doBeforeNodeDrop(TreePanel treePanel,
TreeNode target, DragData dragData,
String point, DragDrop source,
TreeNode dropNode,
DropNodeCallback dropNodeCallback) {
if(dragData instanceof TreeDragData) {
return true;
}
String idMotCle = ((String[])target.getUserObject())[1];
if(oMediateur.gererDDObsSurMotCle(target, dragData)) {
cocherMotCle(idMotCle);
return true;
}
return false;
}
@Override
public void onNodeDrop(TreePanel treePanel,
TreeNode target, DragData dragData,
String point, DragDrop source, TreeNode dropNode) {
}
});
// gestion de la validation
ajouterMotCle.addListener(new ButtonListenerAdapter() {
// lors du clic
@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);
}
});
}
/**
* Configure le drag 'n drop pour la liste
*/
private void configDragAndDrop()
{
// on fabrique la nouvelle configuration
// les éléments sur lesquels on fait du drag 'n drop doivent tous avoir le même ddGroup
arbreMotsCles.setDdGroup("ObsMotsClesGroup");
//arbreMotsCles.setEnableDD(true);
arbreMotsCles.setEnableDrag(true);
arbreMotsCles.setEnableDrop(true);
DropTargetConfig dtc = new DropTargetConfig();
dtc.setdDdGroup("ObsMotsClesGroup");
}
/**
* 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())) {
if(Window.confirm("Etes vous sur de vouloir supprimer ce projet ?")) {
// 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");
// 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);
}
/**
* Fonction de gestion sur le clic sur le noeud
*
* @param node
*/
public void gererClicNoeud(TreeNode node, boolean multi) {
if(!arbreCharge) {
obtenirArbreMotsCles();
} else {
if(multi) {
}
((MultiSelectionModel)arbreMotsCles.getSelectionModel()).select(node, multi);
oMediateur.obtenirNombreObservation();
}
}
/**
* 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) {
// 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().getTextEl().addClassName("x-tree-node-text-kw");
return true;
}
}
if((getArbreMotsCles().getNodeById(node.getId()).getUI().getTextEl()) != null) {
getArbreMotsCles().getNodeById(node.getId())
.getUI().getTextEl().removeClassName("x-tree-node-text-kw");
}
// et on passe au suivant
return true;
}
});
}
else {
motsClesEnAttente = motsClesIds ;
}
}
public void cocherMotCle(String motCleId) {
getArbreMotsCles().getNodeById(motCleId)
.getUI().getTextEl().addClassName("x-tree-node-text-kw");
}
public void initialiser() {
arbreCharge = false ;
motsClesEnCours = "";
arbreMotsCles.collapseAll();
// on vide l'ancien arbre
Node[] rootChild = arbreMotsCles.getRootNode().getChildNodes();
for (int i = 0; i < rootChild.length; i++) {
rootChild[i].remove();
}
arbreMotsCles.getRootNode().addListener(new TreeNodeListenerAdapter() {
@Override
public void onExpand(Node node) {
if(!arbreCharge)
{
obtenirArbreMotsCles() ;
arbreCharge = 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;
}
// 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 obs)
if (nouvelleDonnees instanceof String) {
String chaineMc = (String)nouvelleDonnees;
String[] motsClesIds = chaineMc.split(";");
// 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
cocherMotsCles(motsClesIds);
}
// si l'arbre n'est pas encore instancié on met les mots clés en
// attente
else {
motsClesEnAttente = motsClesIds;
}
}
}
private String genererIdMotCle(TreeNode nd) {
double IdMC = (nd.hashCode() + ((Math.random() * 10000) + 1));
return ""+IdMC;
}
/**
* 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.setUserObject(usObj);
ndPereCopie.appendChild(child);
if (!ndNodeFils[i].isLeaf()) {
copierFilsNoeud(ndNodeFils[i], child);
}
}
}
}
public void raz() {
arbreCharge = false ;
arbreMotsCles.collapseAll();
arbreMotsCles.clear() ;
// on crée une racine pour l'arbre
TreeNode root = new TreeNode("Projets");
root.setId("racine_obs");
String[] usObject = { "Projets", "racine_obs" };
root.setUserObject(usObject);
root.setExpandable(true);
arbreMotsCles.setRootNode(root);
arbreMotsCles.getRootNode().addListener(new TreeNodeListenerAdapter() {
@Override
public void onExpand(Node node) {
if(!arbreCharge)
{
obtenirArbreMotsCles() ;
arbreCharge = true ;
}
}
}) ;
motsClesEnCours = "";
}
@Override
public boolean renvoyerEtatFiltre() {
// TODO Auto-generated method stub
return false;
}
@Override
public String renvoyerNomFiltre() {
// TODO Auto-generated method stub
return null;
}
@Override
public String[] renvoyerValeursAFiltrer() {
String val = "";
TreeNode[] noeuds = ((MultiSelectionModel)arbreMotsCles.getSelectionModel()).getSelectedNodes();
for(int i = 0; i< noeuds.length ; i++) {
if(noeuds[i].getDepth() > 0) {
val += ";"+noeuds[i].getId();
}
}
val = val.replaceFirst(";", "");
String[] valeursFiltres = {"id_mots_cles", val};
return valeursFiltres;
}
@Override
public void valider() {
// TODO Auto-generated method stub
}
public void montrerContextMenuArbre(final TreeNode n, EventObject e,
TreeEditor te) {
Menu mn = new Menu();
final com.gwtext.client.widgets.menu.Item ajoutN = new Item(
"Ajouter un projet");
final com.gwtext.client.widgets.menu.Item suppN = new Item(
"Supprimer projet");
mn.addItem(ajoutN);
mn.addItem(suppN);
mn.addListener(new MenuListenerAdapter() {
@Override
public void onItemClick(BaseItem item, EventObject e) {
if (item.equals(suppN)) {
supprimerNoeud(n);
}
if (item.equals(ajoutN)) {
ajouterNoeud(n);
}
}
});
mn.showAt(e.getXY());
}
@Override
public void viderFiltre() {
arbreMotsCles.getSelectionModel().clearSelections();
motsClesEnCours = "";
}
}