Plugin pour saisie de chemin

Help
2010-10-10
2013-05-01
  • Frédéric Brégier

    Bonjour,

    Je propose un plugin (JElement) pour permettre la sélection d'un chemin (fichier ou répertoire) dans Jaxe.
    Deux paramètres (optionnels) permettraient de définir
    - si la cible est un fichier ou un répertoire ou l'un des deux: type= FILE, DIRECTORY, BOTH
    - si le chemin est relatif ou absolu par rapport au contenu d'un autre champ du fichier excel résultat: absolute= nom du champ

    Ca marche correctement directement sous la forme suivante:

    <AFFICHAGE_ELEMENT element="cheminbase" type="plugin">
    <PARAMETRE nom="classe" valeur="jaxe.elements.JEChemin"/>
    <PARAMETRE nom="type" valeur="DIRECTORY"/>
    </AFFICHAGE_ELEMENT>

    => cheminbase est un répertoire

    <AFFICHAGE_ELEMENT element="second" type="plugin">
    <PARAMETRE nom="classe" valeur="jaxe.elements.JEChemin"/>
    <PARAMETRE nom="type" valeur="BOTH"/>
    <PARAMETRE nom="absolute" valeur="cheminbase"/>
    </AFFICHAGE_ELEMENT>

    => second est un fichier ou un répertoire dont le chemin sera calculé depuis le chemin de cheminbase (si possible).

    Je n'arrive pas par contre à insérer un tel objet dans un contexte de formulaire, comme:

    <AFFICHAGE_ELEMENT element="chemins" type="formulaire">
    </AFFICHAGE_ELEMENT>
    <AFFICHAGE_ELEMENT element="cheminbase" type="plugin">
    <PARAMETRE nom="classe" valeur="jaxe.elements.JEChemin"/>
    <PARAMETRE nom="type" valeur="DIRECTORY"/>
    </AFFICHAGE_ELEMENT>
    <AFFICHAGE_ELEMENT element="second" type="plugin">
    <PARAMETRE nom="classe" valeur="jaxe.elements.JEChemin"/>
    <PARAMETRE nom="type" valeur="BOTH"/>
    <PARAMETRE nom="absolute" valeur="cheminbase"/>
    </AFFICHAGE_ELEMENT>
    (d'autres paramètres simples suivent)

    Les champs cheminbase et second (qui sont des strings dans le xsd correspondants) et sont sous le noeud "chemins"
    sont affichés comme string et  ne prennent absolument pas en compte la spécification plugin du fichier de config.

    Savez vous comment faire pour obtenir ce fonctionnement ?
    Ou à défaut comment obtenir une présentation sympa dans Jaxe de l'édition souhaitée (j'ai plusieurs sous-ensembles dans le fichier XML édité que je souhaite regrouper en plusieurs blocs, ce que "formulaire" fait très bien) ?

    Autre question annexe : existe-t-il un moyen de forcer le xml produit (généré) à avec des tabulations, des sauts à la ligne, … bref un format lisible humainement a posteriori sans Jaxe ?

    Sinon, super produit !!! Félicitations !!!

    Cordialement,
    Frédéric

    Ci dessous le code proposé (libre de droit, of course)

    package jaxe.elements;

    /**
    * @author Frederic Bregier
    *
    */

    import java.awt.event.MouseAdapter;
    import java.awt.event.MouseEvent;
    import java.io.File;

    import javax.swing.BorderFactory;
    import javax.swing.JFileChooser;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JOptionPane;
    import javax.swing.JPanel;
    import javax.swing.JTextField;
    import javax.swing.border.BevelBorder;
    import javax.swing.border.Border;
    import javax.swing.text.Position;

    import jaxe.JaxeElement;

    import org.w3c.dom.Element;
    import org.w3c.dom.Node;
    import org.w3c.dom.NodeList;

    /**
    * Fichier ou Répertoire externe. Le fichier ou le répertoire n'est pas affiché.
    * Il s'agit d'une méthode pour obtenir un chemin à partir d'un popup pour le placer dans un champ XML.
    * Type d'élément Jaxe: 'JEChemin'
    * Valeur : le nom de l'attribut donnant le nom du fichier ou du répertoire
    * paramètre: type: FILE (defaut) DIRECTORY BOTH
    * paramètre: absolute: nom du champ texte où se trouve la valeur saisie du chemin de base absolu (le premier)
    */
    public class JEChemin extends JaxeElement {

        public final static String defaultTypeAttr = "type";
        public String typeAttr = "FILE";
        public int type = JFileChooser.FILES_ONLY;
        public final static String defaultAbsAttr = "absolute";
        public String absAttr = null;
        public boolean absReady = false;
        public String absolute = null;

        JPanel panel = null;
        JLabel label = null;
        JTextField chemin = null;
        private JEFichierMouseListener listener;

        /**
         * Renvoit le titre qui sera affiché sur les balises de début et de fin :
         * nom de l'élément ou titre, en fonction des options d'affichage.
         */
        public String titreElement() {
            if (refElement != null)
                return(doc.cfg.titreElement(refElement));
            else if (noeud != null)
                return(noeud.getNodeName());
            else if (refElement != null)
                return(doc.cfg.nomElement(refElement));
            else
                return(null);
        }

        // initialisation de l'affichage pour un élément DOM
        public void init(Position pos, Node noeud) {
            // lecture de la valeur de l'élément
            String titre = titreElement();//el.getTagName();
            Node child = noeud.getFirstChild();
            String texte = null;
            if (child != null)
                texte = child.getNodeValue();

            // création du composant Swing
            panel = new JPanel();
            Border border = BorderFactory.createBevelBorder(BevelBorder.LOWERED);
            panel.setBorder(border);
            label = new JLabel(titre);
            chemin = new JTextField(texte);
            panel.add(label);
            panel.add(chemin);
            listener = new JEFichierMouseListener(this, doc.jframe);
            chemin.addMouseListener(listener);

            // insertion du composant dans le texte (insertComponent est une méthode de JaxeElement)
            insertComponent(pos, panel);
        }

        // création d'un nouvel élément DOM
        public Node nouvelElement(Element refElement) {
            if (refElement != null) {
                // récupére le type
                typeAttr = doc.cfg.valeurParametreElement(refElement, defaultTypeAttr, "FILE");
                absAttr = doc.cfg.valeurParametreElement(refElement, defaultAbsAttr, "");
                absReady = true;
                if (absAttr == null || absAttr.length() == 0) {
                    absAttr = null;
                    absolute = null;
                }
            }
            if (typeAttr.compareToIgnoreCase("FILE") == 0) {
                type = JFileChooser.FILES_ONLY;
            } else if (typeAttr.compareToIgnoreCase("DIRECTORY") == 0) {
                type = JFileChooser.DIRECTORIES_ONLY;
            } else if (typeAttr.compareToIgnoreCase("BOTH") == 0) {
                type = JFileChooser.FILES_AND_DIRECTORIES;
            } else {
                JOptionPane.showMessageDialog(doc.jframe,
                        "Type not specified: FILE by default",
                        defaultTypeAttr+": FILE, DIRECTORY, BOTH",
                        JOptionPane.INFORMATION_MESSAGE);
            }
            Element newel = nouvelElementDOM(doc, refElement);
            String newchemin = selectionnerFichier(null);
            Node textnode = doc.DOMdoc.createTextNode(newchemin);
            newel.appendChild(textnode);
            return (newel);
        }

        // mise à jour de l'affichage des attributs en fonction du DOM
        public void majAffichage() {
            Node child = noeud.getFirstChild();
            if (child != null) {
                String valeur = child.getNodeValue();
                chemin.setText(valeur);
            }
        }

        @Override
        public void afficherDialogue(final JFrame jframe) {
            String newchemin = selectionnerFichier(chemin.getText());
            if (newchemin != null) {
                setValeur(newchemin);
                majAffichage();
            }
        }

        public void setValeur(String valeur) {
            Element el = (Element)noeud;
            Node child = noeud.getFirstChild();
            if (child != null)
                child.setNodeValue(valeur);
            else {
                Node textnode = doc.DOMdoc.createTextNode(valeur);
                el.appendChild(textnode);
            }
            doc.setModif(true);
        }

        public String selectionnerFichier(String oldchemin) {
            String newchemin = oldchemin == null ? "" : oldchemin;
            if (!absReady) {
                absAttr = doc.cfg.valeurParametreElement(refElement, defaultAbsAttr, "");
                absReady = true;
                if (absAttr == null || absAttr.length() == 0) {
                    absAttr = null;
                    absolute = null;
                }
            }
            if (absAttr != null && absAttr.length() > 0) {
                NodeList list = doc.DOMdoc.getElementsByTagName(absAttr);
                if (list != null && list.getLength() > 0) {
                    absolute = list.item(0).getTextContent();
                    File file = new File(newchemin);
                    if (! file.isAbsolute()) {
                        newchemin = absolute+"/"+newchemin;
                    }
                } else {
                    absolute = null;
                }
            } else {
                absolute = null;
            }
            JFileChooser fileChooser = new JFileChooser(newchemin);
            fileChooser.setFileSelectionMode(type);
            String title = "Choose a ";
            if (type == JFileChooser.FILES_ONLY) {
                title += "File";
            } else if (type == JFileChooser.DIRECTORIES_ONLY) {
                title += "Directory";
            } else {
                title += "File or Directory";
            }
            int returnVal = fileChooser.showDialog(this.doc.jframe, title);
            if (returnVal == JFileChooser.APPROVE_OPTION) {
                newchemin = fileChooser.getSelectedFile().getAbsolutePath();
                if (absolute != null) {
                    if (newchemin.startsWith(absolute)) {
                        newchemin = newchemin.substring(absolute.length()+1);
                    }
                }
                return newchemin;
            }
            return null;
        }

        class JEFichierMouseListener extends MouseAdapter {
            JEChemin jei;
            JFrame jframe;
            public JEFichierMouseListener(final JEChemin obj, final JFrame jframe) {
                super();
                jei = obj;
                this.jframe = jframe;
            }
            @Override
            public void mouseClicked(final MouseEvent e) {
                jei.afficherDialogue(jframe);
            }

        }
    }

     
  • Damien Guillaume

    Merci, je vais l'ajouter dans la liste des plugins.
    Pour la licence, il faudrait préciser si c'est bien GPL comme Jaxe (qui n'est pas "libre de droits", mais "libre" au sens de la GPL).

    > Je n'arrive pas par contre à insérer un tel objet dans un contexte de formulaire
    Ce n'est pas possible, l'affichage "formulaire" définit l'affichage pour tous les sous-éléments. Il y a une requête d'amélioration à ce sujet :
    https://sourceforge.net/tracker/?func=detail&aid=1930058&group_id=55234&atid=476297
    Les plugins ne marchent donc pas dans ce cadre…

    > Autre question annexe : existe-t-il un moyen de forcer le xml produit (généré) à avec des tabulations, des sauts à la ligne, … bref un format lisible humainement a posteriori sans Jaxe ?
    Non, j'ai longtemps essayé de faire ça automatiquement, mais je n'ai jamais obtenu de résultat satisfaisant. Il y a bien une option pour faire une sortie indentée avec les parsers XML utilisés par Jaxe, mais le problème se pose quand il y a des zones de texte sur plusieurs lignes (surtout quand il y a des éléments XML dedans): en général, les indentations ne sont pas ce qu'on attend, et le résultat est très moche, voire moins lisible que quand il n'y a pas d'indentation.
    Je pourrais programmer une sortie texte moi-même, mais c'est compliqué et je n'ai pas encore eu le courage de me lancer là-dedans. En attendant, il existe des programmes qui ajoutent automatiquement des indentations, par exemple http://xmlindent.sourceforge.net/ qui gère assez bien les grandes zones de texte.

     
  • Damien Guillaume

    J'oubliais: il faudrait mettre la classe dans un autre package que jaxe.elements, puisqu'elle ne fait pas partie de Jaxe lui-même. A vous de choisir un autre nom…

     
  • Frédéric Brégier

    OK, je place le code GPL en entête et je transforme le package.
    Je retransmet ce soir…
    Si tu souhaites l'intégrer dans Jaxe, j'accepte de laisser la paternité de ce code au projet dont une très grande partie est de toute façon basée sur ton propre code…

    Je n'avais pas vu ce ticket (formulaire). Y-a-t-il un autre moyen pour obtenir une vue similaire, c'est à dire un cadre autour d'un ensemble de valeurs à remplir, autre que le mode "formulaire" ?

    A défaut d'indentation, est il possible au moins d'avoir un saut de ligne automatique entre chaque champ (element) ?

    Mon besoin est lié (comme un autre utilisateur ayant posté il y a quelques temps) à l'édition de fichier de paramétrage un peu complexe de logiciels Java utilisant XML comme format de fichier de configuration (à l'instar de Tomcat par exemple).
    Je souhaite donc autoriser la modification en mode texte directement dans le fichier si nécessaire, tout en encourageant l'usage d'un éditeur (et hop Jaxe) pour faciliter la saisie et les options associées.
    Mais du coup, les champs sont les uns à la suite des autres (sauf si je vais manuellement à la ligne dans l'éditeur Jaxe).
    J'aurais aimé que ces champs soient les uns en dessous des autres sans que l'utilisateur est à manuellement faire cette entrée de retour à la ligne.
    De même, à l'édition sous Jaxe, Y-a-t-il un moyen de forcer la mise les uns sous les autres des éléments de saisie (comme le faire le mode "formulaire") ? Est-ce via le tableau ? Mais je n'ai pas trop compris comment on s'en sert… hélas…

    La seule solution pour le moment que j'ai trouvé est de fournir un fichier xml pré-rempli des champs vides comme base pour créer un nouveau fichier, mais ce n'est pas très convivial et en dehors de l'esprit de Jaxe il me semble (qui permet de créer un fichier de zéro sur la base du config et du xsd)…

    Si tu as des suggestions, je suis preneur !

    Merci encore pour ta réponse rapide…

    Frédéric

     
  • Damien Guillaume

    > Si tu souhaites l'intégrer dans Jaxe, j'accepte de laisser la paternité de ce code au projet dont une très grande partie est de toute façon basée sur ton propre code…

    Je vais y réfléchir, mais j'ai peur que ça fasse double usage avec fichier/JEFichier, qui affiche déjà le chemin quand il ne peut pas afficher une image. On pourrait ajouter un paramètre à JEFichier pour qu'il permette de sélectionner les répertoires. Logiquement, il devrait y avoir un type image/JEImage à la place, et ce serait plus clair. Le nom actuel est resté pour des raisons historiques. Peut-être devrait-il y avoir "image" et "chemin" en remplacement de "fichier"…

    > Je n'avais pas vu ce ticket (formulaire). Y-a-t-il un autre moyen pour obtenir une vue similaire, c'est à dire un cadre autour d'un ensemble de valeurs à remplir, autre que le mode "formulaire" ?

    Non. Et on ne peut pas facilement afficher un élément Jaxe dans un formulaire, parce-qu'à la base c'est prévu pour être inséré dans la zone de texte, avec des sous-éléments etc… S'il y avait un moyen de définir des affichages à l'intérieur d'un formulaire, il faudrait que ce soit limité à certains éléments Jaxe (qui n'auraient qu'un JComponent), sinon ce serait trop lourd et complexe à gérer.

    > A défaut d'indentation, est il possible au moins d'avoir un saut de ligne automatique entre chaque champ (element) ?

    Je viens de faire un test, pour vérifier, et il y a bien un saut de ligne entre chaque sous-élément dans un formulaire… Je ne comprend pas le problème…

    > De même, à l'édition sous Jaxe, Y-a-t-il un moyen de forcer la mise les uns sous les autres des éléments de saisie (comme le faire le mode "formulaire") ? Est-ce via le tableau ? Mais je n'ai pas trop compris comment on s'en sert… hélas…

    Le tableau sert juste à éditer des tableaux comme l'élément table en HTML (avec tr/td comme sous-élements), l'usage est donc restreint. Quand on utilise des éléments de type "zone" ou "division", et qu'on insère un élément juste après un autre, un saut de ligne est automatiquement ajouté si nécessaire. Si les éléments doivent être entrés dans un ordre particulier, le panneau d'insertion aide à s'y retrouver, et Jaxe n'autorise pas l'insertion d'un élément au mauvais endroit… Mais ça reste moins simple qu'un formulaire. On peut mélanger les 2, à condition de n'utiliser les formulaires qu'au plus bas niveau.

    > La seule solution pour le moment que j'ai trouvé est de fournir un fichier xml pré-rempli des champs vides comme base pour créer un nouveau fichier, mais ce n'est pas très convivial et en dehors de l'esprit de Jaxe il me semble

    Effectivement, ce n'est pas idéal, mais ça peut être une solution…

     
  • Damien Guillaume

    Je n'ai pas encore eu le temps de tester, mais je l'ai ajouté à la liste des plugins. Merci !

     

Get latest updates about Open Source Projects, Conferences and News.

Sign up for the SourceForge newsletter:





No, thanks