New file |
0,0 → 1,677 |
package org.tela_botanica.client.vues.image; |
|
import org.tela_botanica.client.cel2; |
import org.tela_botanica.client.interfaces.Rafraichissable; |
import org.tela_botanica.client.util.MotsClesUtilitaire; |
|
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; |
private String cheminTemporaireAjout; |
|
/** |
* 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); |
protected abstract void surRetourWebService(Tree arbre); |
|
/** |
* 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(!MotsClesUtilitaire.estUnMotCleAutorise(text)) { |
te.startEdit(node); |
Window.alert("Un mot clé ne peut pas être vide ou contenir les caractères suivants : "+MotsClesUtilitaire.getChaineCaracteresInterdits()); |
return; |
} |
|
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()); |
arbreMotsCles.disable(); |
} |
// 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()); |
arbreMotsCles.disable(); |
} |
} |
} |
|
// 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) { |
ajoutNoeud = true; |
TreeNode nd = MotsClesUtilitaire.ajouterNoeud(parent, true); |
// on le concatène au parent et on étend ses enfants |
parent.appendChild(nd); |
parent.expand(); |
cheminTemporaireAjout = nd.getId(); |
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) { |
|
String usObject[] = (String[]) node |
.getUserObject(); |
String nodeId = usObject[1]; |
|
TreeNode tn = getArbreMotsCles().getNodeById(node.getId()); |
if(tn != null) { |
tn.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 |
|
if (nodeId.equals(motsClesIds[i])) { |
tn.getUI().toggleCheck(true); |
tn.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); |
} |
}); |
} |
} |
|
// reception d'un nouvel identifiant de mot clé |
if(nouvelleDonnees instanceof Integer) { |
if(cheminTemporaireAjout != null) { |
String id = ((Integer)(nouvelleDonnees)).toString(); |
TreeNode noeudEnAjout = arbreMotsCles.getNodeById(cheminTemporaireAjout); |
String[] userObj = {noeudEnAjout.getText(), id}; |
noeudEnAjout.setUserObject(userObj); |
cheminTemporaireAjout = null; |
} |
} |
surRetourWebService(arbreMotsCles.getTree()); |
arbreMotsCles.enable(); |
} |
|
/** |
* 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); |
} |
} |
|