Spatio-Temporel editor (SpTeEditor)
Intégré dans le framework XED d'édition XML de Scenari, un SpTeEditor permet d'éditer des propriétés graphiques ou temporelles d'une structure de données XML imbriquant ainsi une vision logique du contenu éditorial classique au sens Scenari et une vision spatiale et/ou temporelle en fonction du SpTeEditor.
Principe du SpTeEditor
Un SpTeEditor est un composant XUL/XBL intégré dans un XED et qui interagit avec le framework XED. Il gère l'affichage et l'interaction spatio-temporelle d'un contenu XML en parallèle de la strcture XED 'classique'. Un SpTeEditor est toujours instancié sous forme de singleton dans un éditeur XED. Des widgets XED spécifiques (SpTeXxxx) intégrés dans la structure logique du XED permettent de synchroniser le SpTeEditor avec les modifications de la structure logique.
Pour simplifier l'API et permettre d'implémenter un éditeur dans une simple page XUL ou SVG (moins contraignant qu'un XBL), il existe une implémentation générique de SpTeEditor qui encapsule un éditeur dans une iframe. voir SpTeEditorIFrame et SpTeEditorFixedIFrame.
API à implémenter par SpTeEditor
Interface ISpTeEditor :
- onxedload() : Api standard XED permettant au SpTeEditor de s'initialiser. Attention, en fonction de la structure du XED des appels préalables à connectStruct() pourraient déjà avoir eu lieu. L'implémentation de SpTeEditorBase.onxedload() permet en particulier :
- d'enregistrer un handler sur l'event "XEDStatusInit" sur xed.getEditor(), pour finaliser l'init une fois le processus onxedload() réalisé (redirection vers SpTeEditorBase.onXedInit()) .
- d'enregistrer un handler sur l'event "XEDDataRemove" à la racine de l'éditor pour capter toutes les suppressions structurelles et appeler les removeStruct() et gérer l'historique undo/redo.
- d'enregistrer un listener au près de xed.getXedContent().addFocusStabilizedListener() pour synchroniser les changements de focus de l'éditeur structurel Xed vers le SpTeEditor. (Note : Lorsque le SpTeEditor est à l'origine d'un changement de focus il doit appeler la méthode pSpTeStruct.spTeFocus() ).
- connectStruct(pSpTeStruct) : permet de connecter une structure XED de l'arbre d'édition XML au singleton SpTeEditor. Exemple : connexion de la source audio d'une part et de chaque segment d'autre part. Le paramètre pSpTeStruct est le noeud Xed de destination instancié dans l'éditeur.
Note : à l'initialisation, la connexion explicite des noeuds Xed n'est pas obligatoire : si le SpTeEditor doit gérer un arbre de segments, il est probablement plus pertinent de paramétrer dans le SpTeEditor un treeWalker qui va découvrir automatiquement tous les segments pour construire sa propre structure interne optimisée. Par contre, en cours d'édition, le SpTeEditor doit prendre en compte les insertions manuelles de segments via cette méthode.
- getStatusEditor() : combinaison de bits décrivant l'état du SpTeEditor:
- 1 : le SpTeEditor a été initialisé (via onxedload ou autre voie).
- 2 : le SpTeEditor est opérationnel, accepte les interactions utilisateurs. Même une fois initialisé, l'éditeur peut ne pas être en état opérationnel. Exemple : un segmenteur audio dont la source audio n'est pas déclarée.
- 4 : on est en mode batch (après un 1er appel à beginBatch(), et avant le dernier endBatch()).
- 8 : le SpTeEditor est en mode readOnly.
- isStatusInited() : correspond au status 1.
- isStatusReady() : correspond au status 2.
- isStatusInBatch() : correspond au status 4.
- isStatusReadOnly() : correspond au status 8 (mode read-only).
- setReadOnlyMode(pBoolean) : affecte l'état read-only du SpTeEditor.
- beginBatch() : permet à l'environnement XED de bloquer tout refresh graphique du SpTeEditor pendant une succession de modifications. Plusieurs beginBatch() peuvent s'imbriquer (Le SpTeEditor gèrera un compteur d'appels à beginBatch()/endBatch()). Il est impératif d'appeler la méthode endBatch() pour chaque appel à beginBatch() dans un bloc try/finally : try{beginBatch(); ... updates ...}finally{endBatch()}, .
- endBatch() : clos un processus de batch et s'il est le dernier de la pile, lance automatiquement un refresh().
- refresh() : force un recalcul graphique du SpTeEditor (ne devrait jamais être appelé en direct. Voir beginBatch() / endBatch().
- removeStruct(pSpTeStruct) : supprime la connexion à une structure XED. Cette méthode est généralement automatiquement appelée par le handler sur l'event "XEDDataRemove" posée par le SpTeEditorBase (voir onxedload() ).
- updateStruct(pSpTeStruct) : informe le SpTeEditor d'une modification des data associées à ce noeud. Cette méthode est généralement appelée par les Widgets SpTeStructXxxx.
- setStructFocus(pSpTeStruct) -> ISpTeStruct : informe le SpTeEditor qu'un nouveau SpTeStruct a acquis le focus dans l'éditeur XED.
- getStructFocus() -> ISpTeStruct : retourne le SpTeStruct qui détient le focus dans le SpTeEditor.
Interface IXedTransaction (interface non spécifique à SpTe)
TODO : Ajouter dans xed une implémentation de XedTransaction.
Cet objet permet d'aggréger des transactions de type undo/redo pour être vu comme une seule transaction auprès du XedEditor. Il est instancié par le widget à l'origine de la modification (et gère ainsi les problèmes de focus) et est ensuite passé en paramètre pour enregistré toutes les autres modifications connexes à la modification principale. Par exemple, dans un segmenteur audio, le changement de durée d'un segment entraine la changement de durée d'un ou plusieurs autres segments.
- undo() : API du transactionManager de XedEditor.
- redo() : API du transactionManager de XedEditor.
- focusAfterUndo(pXedDstNode) : Noeud à focuser après un Undo.
- focusAfterRedo(pXedDstNode) : Noeud à focuser après un Redo.
- append(pTrans) : ajoute une transaction (undo() / redo()) à la fin.
- insertAtFirst(pTrans) : ajoute une transaction (undo() / redo()) au début.
Widgets XED de synchronisation avec le SpTeEditor
Les widgets XED de synchronisation avec le SpTeEditor permettent :
- d'assurer la mise à jour des données qu'elles soient issues du SpTeEditor ou de l'éditeur structurel logique XED.
- de gérer l'historique undo/redo vis à vis de xed.getEditor() en lien avec le IXedTransaction.
Ces widgets doivent envelopper la structure de donnée Focusable correspondant à chaque objet manipulé dans le SpTeEditor (un segment temporel, une zone graphique, une case de diagramme, etc.). Ils peuvent aussi être l'élément focusable directement.
Toutes les méthodes commencent par spTeXxxx pour éviter les risques de conflits.
Interface ISpTeStruct
Méthodes communes à tous les widgets de synchronisation.
- onxedload() : Api standard XED. Permet notamment aux noeuds XED de se déclarer au près du SpTeEditor.
- spTeFocus() : Permet au SpTeEditor de signifier que la représentation des data associés à ce widget (dans le SpTeEditor) détient le focus. Ce widget doit alors impacter le focus dans l'arbre Xed pour le synchroniser avec l'état du SpTeEditor.
- spTeStructType : Propriété retournant le type de structure (type String). Par exemple, dans un segmenteur audio, on trouvera une structure de type "srcAudio" et N de type "segment".
Widget SpTeStructUri
Ce widget générique permet de connecter une URI d'item (audio, image, video...) et doit contenir en élément Fils un ptrItem.
- spTeGetUri() : retourne l'uri spécifiée dans la source Xml.
- spTeSetUri(pUri, pTransaction) -> Transaction : affecte un nouvelle uri source. Utilisé par le SpTeEditor si une action utilisateur entraine l'effacement ou la modification cette Uri.
- Si pTransaction est null, une nouvelle transaction est instanciée en considérant que ce noeud est à l'origine de l'action utilisateur (gestion des focus).
- Si pTransaction est non null, cette action est considérée comme esclave d'une autre et effectue simplement les modifs des données.
Widget SpTeStructString
Ce widget générique permet de connecter un champ texte (exemple : un titre) et doit contenir un widget de type input.
- spTeGetValue() : retourne la propriété spécifiée dans la source Xml.
- spTeSetValue(pValue, pTransaction) -> Transaction : affecte un nouvelle valeur. Utilisé par le SpTeEditor si une action utilisateur entraine l'effacement ou la modification cette valeur.
- Si pTransaction est null, une nouvelle transaction est instanciée en considérant que ce noeud est à l'origine de l'action utilisateur (gestion des focus).
- Si pTransaction est non null, cette action est considérée comme esclave d'une autre et effectue simplement les modifs des données.
Widget SpTeStructDomFragment
Ce widget générique permet de connecter un fragment xml pour lequel le SpTeEditor peut en modifier les valeurs. Problème : Comment gérer l'historique si on ne fait pas une méthode par propriété éditable (start/end, x1,y1,x2,y2, etc.) ? On clone le fragment systématiquement -> lourd. Idée : On reporte la connaissance de la dtd du fragment sur le SpTeEditor qui instanciera un DtdInterpreter (ce n'est pas choquant : ce sont des props techniques t1, t2, x1, y1, etc., la dtd n'est pas métier, donc peut-être figée par la primitive et le SpTeEditor).
- spTeGetDomFragment() : retourne le noeud DOM de la source Xml.
- spTeInitDtdInterpreter(pDtdInterpreter) : initialise ce widget avec l'objet responsable de traduire un couple key/value en une modification dans un Dom. Méthodes de DtdInterpreter :
- getValue(pDom, pKey) -> value
- setValue(pDom, pKey, pValue) -> true si modif réalisée, false sinon.
- spTeGetValue(pKey) : retourne une propriété correspondant à pKey (via le DtdInterpreter).
- spTeSetValue(pKey, pValue, pTransaction) -> Transaction : affecte un nouvelle valeur. Utilisé par le SpTeEditor si une action utilisateur entraine l'effacement ou la modification cette valeur.
- Si pTransaction est null, une nouvelle transaction est instanciée en considérant que ce noeud est à l'origine de l'action utilisateur (gestion des focus).
- Si pTransaction est non null, cette action est considérée comme esclave d'une autre et effectue simplement les modifs des données.
Widget SpTeStructXxxx
On peut envisager de coder des widgets totalement dédiés à un usage. Par exemple SpTeStructAudioSegment pour des segments temporels avec les getter / setter des propriétés start/end/title d'un segment et des méthodes comportementales supplémentaires comme cutSegment() qui permet de couper un segment en deux, etc.
Widget SpTeFocusFilter
Ce widget (qui n'est pas un objet de synchro) placé en ancêtre d'un ensemble de ISpTeStruct va assurer l'affichage d'un seul objet à la fois, celui pour lequel spTeEditor détient le focus. Dans ce cas, seul le SpTeEditor offre une vue global des objets éditables et permet une navigation et la gestion du focus. La vue structurelle est réduite à l'objet en cours dans le SpTeEditor.