Annotation of modules/damieng/graphical_editor/daxe/lib/src/config.dart, revision 1.2
1.1 damieng 1: /*
2: This file is part of Daxe.
3:
4: Daxe is free software: you can redistribute it and/or modify
5: it under the terms of the GNU General Public License as published by
6: the Free Software Foundation, either version 3 of the License, or
7: (at your option) any later version.
8:
9: Daxe is distributed in the hope that it will be useful,
10: but WITHOUT ANY WARRANTY; without even the implied warranty of
11: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12: GNU General Public License for more details.
13:
14: You should have received a copy of the GNU General Public License
15: along with Daxe. If not, see <http://www.gnu.org/licenses/>.
16: */
17:
18: part of daxe;
19:
20:
21: /**
22: * A Jaxe configuration file. Includes many useful methods to use XML schemas.
23: */
24: class Config {
25: static final String _typeAffichageParDefaut = "string";
26:
27: x.Element _cfgroot; // config file root element
28:
29: String schemaURL; // schema file URL
30:
31: String _cfgdir; // config folder URL (in which the config file must be)
32:
33: HashMap<String, x.Element> _elementDisplayCache; // cache for associations nom -> AFFICHAGE_ELEMENT
34: HashMap<x.Element, String> _elementsToNamesCache; // cache for associations element reference -> name
35: HashMap<x.Element, String> _elementsTitlesCache; // cache for associations element reference -> title
36: HashMap<x.Element, Pattern> _insertCache = null; // cache for regular expressions for insertions
37: HashMap<x.Element, Pattern> _validPatternCache = null;
38: HashMap<x.Element, HashMap<String, List<String>>> _parametersCache = null;
39: List<String> _namespaceCache = null; // namespace list
40:
41: InterfaceSchema _schema; // all the schema management (validity...)
42:
43: // nodes for the config file main elements
44: x.Element _languageNode;
45: x.Element _savingNode;
46: x.Element _menusNode;
47: x.Element _displayNode;
48: x.Element _exportsNode;
49: List<x.Element> _listeStrings;
50:
51:
52: // CONSTRUCTORS AND INITIALIZATION
53:
54: /**
55: * Constructor (load must be called afterwards)
56: */
57: Config() {
58: }
59:
60: /**
61: * Load a config file
62: *
63: * @param cfgFilePath path to the config file
64: */
65: Future load(final String cfgFilePath) { // throws DaxeException
66: Completer completer = new Completer();
67: if (cfgFilePath == null) {
68: _cfgroot = null;
69: return(new Future.error(new DaxeException("Config.load: null path")));
70: }
71:
72: x.DOMParser dp = new x.DOMParser();
73: dp.parseFromURL(cfgFilePath).then((x.Document configdoc) {
74: String resource;
75: if (configdoc.documentElement.nodeName == "CONFIG_JAXE")
76: resource = null;
77: else
78: resource = _getResource(configdoc.documentElement);
79:
80: _cfgdir = _getParentURL(cfgFilePath);
81:
82: _cfgroot = configdoc.documentElement;
83:
84: // AUTRE_CONFIG: ignored
85:
86: _buildElementDisplayCache();
87:
88: _elementsTitlesCache = new HashMap<x.Element, String>();
89:
90: final String noms = schemaName();
91: if (noms == null) {
92: final x.Element schema_simple = _findElement(_getLanguage(), "SCHEMA_SIMPLE");
93: if (schema_simple == null) {
94: completer.completeError(new DaxeException("Error: no XML schema is defined in the config file $cfgFilePath"));
95: return;
96: }
97: _schema = new SimpleSchema(schema_simple, _titlesHash());
98: schemaURL = null;
99: _buildElementsToNamesCache();
100: completer.complete();
101: return;
102: }
103:
104: if (_cfgdir != null)
105: schemaURL = "${_cfgdir}/$noms";
106: else
107: schemaURL = noms;
108: _schema = new DaxeWXS(_titlesHash());
109: (_schema as DaxeWXS).load(schemaURL).then((_) {
110: _buildElementsToNamesCache();
111: completer.complete();
112: }, onError: (WXSException ex) {
113: completer.completeError(new DaxeException("Error reading schemaURL: $ex"));
114: });
115: }, onError: (x.DOMException ex) {
116: completer.completeError(new DaxeException("Error reading $cfgFilePath: $ex"));
117: });
118: return(completer.future);
119: }
120:
121: /**
122: * Returns the URL of the parent of the given URL (file or directory),
123: * or null if the parent directory cannot be found
124: */
125: static String _getParentURL(final String u) {
126: final int index = u.lastIndexOf("/");
127: if (index >= 0) {
128: return(u.substring(0, index));
129: }
130: return(null);
131: }
132:
133:
134: // METHODS RELATED TO THE CONFIG FILE
135:
136: /**
137: * Returns the name of the first possible root element, or null if none are defined.
138: */
139: String nameOfFirstRootElement() {
140: final x.Element racine = _findElement(_getLanguage(), "RACINE");
141: if (racine == null)
142: return(null);
143: return(racine.getAttribute("element"));
144: }
145:
146: /**
147: * Returns the reference to the first possible root element, or null if none are defined.
148: */
149: x.Element firstRootElement() {
150: final String nom = nameOfFirstRootElement();
151: return(_schema.elementReferenceByName(nom));
152: }
153:
154: /**
155: * Returns the list of names of the possible root elements
156: */
157: List<String> listOfRoots() {
158: final List<String> liste = new List<String>();
159: x.Element racine = _findElement(_getLanguage(), "RACINE");
160: while (racine != null) {
161: liste.add(racine.getAttribute("element"));
162: racine = _nextElement(racine, "RACINE");
163: }
164: return(liste);
165: }
166:
167: /**
168: * Returns the list of references to the possible root elements
169: */
170: List<x.Element> rootElements() {
171: // pour éviter une erreur dans le cas d'un schéma définissant un élément global et un élément local
172: // sous le même nom mais avec des types différents, on est obligé d'aller d'abord chercher les références
173: // des éléments racines en fonction de l'implémentation du schéma, puis de chercher dedans les éléments
174: // avec les noms donnés dans la config.
175: final List<x.Element> liste = new List<x.Element>();
176: final List<x.Element> racinesPossibles = _schema.rootElements();
177: x.Element racine = _findElement(_getLanguage(), "RACINE");
178: while (racine != null) {
179: final String nom = racine.getAttribute("element");
180: for (final x.Element ref in racinesPossibles)
181: if (nom == _schema.elementName(ref))
182: liste.add(ref);
183: racine = _nextElement(racine, "RACINE");
184: }
185: return(liste);
186: }
187:
188: /**
189: * Adds the attributes for the namespaces to the root node
190: */
191: void addNamespaceAttributes(final DaxeNode root) {
192: final List<String> espaces = _namespaceList();
193: for (final String espace in espaces) {
194: if (espace != "") {
195: final String prefixe = namespacePrefix(espace);
196: String nomatt;
197: if (prefixe != null && prefixe != "")
198: nomatt = "xmlns:$prefixe";
199: else
200: nomatt = "xmlns";
201: root.setAttributeNS("http://www.w3.org/2000/xmlns/", nomatt, espace);
202: }
203: }
204: final String schemaLocation = getSchemaLocation();
205: final String noNamespaceSchemaLocation = getNoNamespaceSchemaLocation();
206: if (schemaLocation != null || noNamespaceSchemaLocation != null) {
207: root.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
208: if (schemaLocation != null)
209: root.setAttributeNS("http://www.w3.org/2001/XMLSchema-instance",
210: "xsi:schemaLocation", schemaLocation);
211: if (noNamespaceSchemaLocation != null)
212: root.setAttributeNS("http://www.w3.org/2001/XMLSchema-instance",
213: "xsi:noNamespaceSchemaLocation", noNamespaceSchemaLocation);
214: }
215: }
216:
217: /**
218: * Returns the name of the schema file as given in the config file
219: * (FICHIER_SCHEMA/@nom)
220: * Returns null if none is defined
221: */
222: String schemaName() {
223: final x.Element fichierschema = _findElement(_getLanguage(), "FICHIER_SCHEMA");
224: if (fichierschema == null)
225: return(null);
226: String nom = fichierschema.getAttribute("nom");
227: if (nom == "")
228: nom = null;
229: return(nom);
230: }
231:
232: /**
233: * Returns the hash table by name of the element displays in the config file
234: * (element AFFICHAGE_ELEMENT)
235: */
236: HashMap<String, x.Element> _buildElementDisplayCache() {
237: _elementDisplayCache = new HashMap<String, x.Element>();
238: if (_cfgroot == null)
239: return(_elementDisplayCache);
240: x.Element affel = _findElement(_getNodeDisplay(), "AFFICHAGE_ELEMENT");
241: while (affel != null) {
242: final String nom = affel.getAttribute("element");
243: _elementDisplayCache[nom] = affel;
244: affel = _nextElement(affel, "AFFICHAGE_ELEMENT");
245: }
246: return(_elementDisplayCache);
247: }
248:
249: HashMap<x.Element, String> _getElementsToNamesCache() {
250: return(_elementsToNamesCache);
251: }
252:
253: x.Element getElementDisplay(String name) {
254: return _elementDisplayCache[name];
255: }
256:
257: /**
258: * Builds the hash table of associations schema reference -> element name
259: */
260: void _buildElementsToNamesCache() {
261: _elementsToNamesCache = new HashMap<x.Element, String>();
262: if (_cfgroot == null)
263: return;
264: final List<x.Element> elements = _schema.allElements();
265: for (final x.Element ref in elements) {
266: final String nom = _schema.elementName(ref);
267: if (nom != null)
268: _elementsToNamesCache[ref] = nom;
269: }
270: }
271:
272: /**
273: * Return the name of the resource bundle to use.
274: *
275: * @return the name of the resource bundle, null if not defined.
276: */
277: String _getResource(final x.Element root) {
278: final x.Element bundle = _findElement(root, "FICHIERTITRES");
279: if (bundle == null)
280: return(null);
281: return(bundle.getAttribute("nom"));
282: }
283:
284: /**
285: * Returns the list of export references, depending on the output (HTML or XML)
286: */
287: List<x.Element> exportsList(final String output) {
288: if (_cfgroot == null)
289: return(null);
290: final List<x.Element> liste = new List<x.Element>();
291: x.Element export = _findElement(_getExports(), "EXPORT");
292: while (export != null) {
293: if (output == export.getAttribute("sortie"))
294: liste.add(export);
295: export = _nextElement(export, "EXPORT");
296: }
297: return(liste);
298: }
299:
300: /**
301: * Returns an export name based on its reference
302: */
303: String exportName(final x.Element exportRef) {
304: return(exportRef.getAttribute("nom"));
305: }
306:
307: /**
308: * Returns the output of an export based on its reference
309: */
310: String exportOutput(final x.Element exportRef) {
311: return(exportRef.getAttribute("sortie"));
312: }
313:
314: /**
315: * Returns the character encoding to use for new XML documents
316: */
317: String getEncoding() {
318: final x.Element encodage = _findElement(_getSaving(), "ENCODAGE");
319: if (encodage == null)
320: return(null);
321: return(_dom_elementValue(encodage));
322: }
323:
324: String getPublicId() {
325: final x.Element doctype = _findElement(_getSaving(), "DOCTYPE");
326: if (doctype != null)
327: return doctype.getAttribute("publicId");
328:
329: return(null);
330: }
331:
332: String getSystemId() {
333: final x.Element doctype = _findElement(_getSaving(), "DOCTYPE");
334: if (doctype != null)
335: return doctype.getAttribute("systemId");
336: return(null);
337: }
338:
339: String getSchemaLocation() {
340: final x.Element sl = _findElement(_getSaving(), "SCHEMALOCATION");
341: if (sl != null) {
342: final String schemaLocation = sl.getAttribute("schemaLocation");
343: if (schemaLocation != "")
344: return(schemaLocation);
345: }
346: return(null);
347: }
348:
349: String getNoNamespaceSchemaLocation() {
350: final x.Element sl = _findElement(_getSaving(), "SCHEMALOCATION");
351: if (sl != null) {
352: final String noNamespaceSchemaLocation = sl.getAttribute("noNamespaceSchemaLocation");
353: if (noNamespaceSchemaLocation != "")
354: return(noNamespaceSchemaLocation);
355: }
356: return(null);
357: }
358:
359: /**
360: * Returns a prefix to use for the given namespace, or null if none is found
361: */
362: String namespacePrefix(final String namespace) {
363: if (namespace == "http://www.w3.org/XML/1998/namespace")
364: return("xml");
365: x.Element pe = _findElement(_getSaving(), "PREFIXE_ESPACE");
366: while (pe != null) {
367: if (namespace == pe.getAttribute("uri"))
368: return(pe.getAttribute("prefixe"));
369: pe = _nextElement(pe, "PREFIXE_ESPACE");
370: }
371: return(_schema.namespacePrefix(namespace));
372: }
373:
374:
375: // METHODS FOR THE ELEMENT INSERT MENUS
376:
377: /**
378: * Returns a menu matching the menu definition in the config file.
379: *
380: * @param doc The Daxe document
381: * @param menudef The MENU element in the config file
382: */
383: Menu _creationMenu(final DaxeDocument doc, final x.Element menudef) {
384: final String nomMenu = menudef.getAttribute("nom");
385: String titreM = menuTitle(nomMenu);
386: final Menu menu = new Menu(titreM);
387: String docMenu = menuDocumentation(nomMenu);
388: if (docMenu != null) {
389: //docMenu = "<html><body>{docMenu.replaceAll('\n', '<br>')}</body></html>";
390: menu.toolTipText = docMenu;
391: }
392: x.Node menunode = menudef.firstChild;
393: while (menunode != null) {
394: MenuItem item = null;
395: final String nodename = menunode.nodeName;
396: String shortcut = null;
397: if (menunode is x.Element) {
398: final String commande = (menunode as x.Element).getAttribute("raccourci");
399: if (commande != null && commande != "") {
400: shortcut = commande.toUpperCase()[0];
401: }
402: }
403: if (nodename == "MENU_INSERTION") {
404: final x.Element insnoeud = menunode as x.Element;
405: final String nom = insnoeud.getAttribute("nom");
406: final String titre = menuTitle(nom);
407: String typeNoeud = insnoeud.getAttribute("type_noeud");
408: if (typeNoeud == "")
409: typeNoeud = "element";
410: x.Element refElement;
411: if (typeNoeud == "element") {
412: refElement = elementReference(nom);
413: if (refElement == null)
414: logError("Erreur: MENU_INSERTION: pas de référence pour '$nom' dans le schéma");
415: } else
416: refElement = null;
417: item = new MenuItem(titre, () => doc.insertNewNode(refElement, typeNoeud), shortcut: shortcut, data: refElement);
418: menu.add(item);
419: String itemdoc = documentation(refElement);
420: if (itemdoc != null) {
421: //itemdoc = formatDoc(itemdoc);
422: item.toolTipText = itemdoc;
423: }
424: } else if (nodename == "MENU_FONCTION") {
425: final x.Element fonction = menunode as x.Element;
426: final String classe = fonction.getAttribute("classe");
427: final String nom = fonction.getAttribute("nom");
428: final String titre = menuTitle(nom);
429: item = new MenuItem(titre, () => doc.executeFunction(classe, fonction), shortcut: shortcut);
430: menu.add(item);
431: String itemdoc = menuDocumentation(nom);
432: if (itemdoc != null) {
433: //itemdoc = formatDoc(itemdoc);
434: item.toolTipText = itemdoc;
435: }
436: } else if (nodename == "MENU") {
437: item = _creationMenu(doc, menunode as x.Element);
438: menu.add(item);
439: } else if (nodename == "SEPARATEUR")
440: menu.addSeparator();
441:
442: menunode = menunode.nextSibling;
443: }
444: return(menu);
445: }
446:
447: /**
448: * Returns a menubar to insert menus.
449: *
450: * @param doc The Daxe document
451: */
452: MenuBar makeMenus(final DaxeDocument doc) {
453: final MenuBar mbar = new MenuBar();
454:
455: final x.Element menus = _getMenus();
456: if (menus != null) {
457: x.Element menudef = _findElement(menus, "MENU");
458: while (menudef != null) {
459: final Menu jmenu = _creationMenu(doc, menudef);
460: jmenu.parent = mbar;
461: mbar.add(jmenu);
462: menudef = _nextElement(menudef, "MENU");
463: }
464: }
465: return(mbar);
466: }
467:
468:
469: // METHODS RELATED TO THE SCHEMA
470:
471: InterfaceSchema getSchema() {
472: return(_schema);
473: }
474:
475: /**
476: * Returns the references for all the elements in the schema
477: */
478: List<x.Element> allElementsList() {
479: final List<x.Element> liste = _schema.allElements();
480: return(liste);
481: }
482:
483: bool _elementInSchema(final x.Element elementRef) {
484: return(_schema.elementInSchema(elementRef));
485: }
486:
487: /**
488: * Returns the name of the element
489: */
490: String elementName(final x.Element elementRef) {
491: return(_elementsToNamesCache[elementRef]);
492: }
493:
494: /**
495: * Returns the reference of the first matching element in the schema,
496: * based on the element and the reference of its parent
497: */
498: x.Element getElementRef(final x.Element el, final x.Element parentRef) {
499: return(_schema.elementReference(el, parentRef));
500: }
501:
502: /**
503: * Returns the reference for the first element with the given name
504: */
505: x.Element elementReference(final String name) {
506: final x.Element el = _schema.elementReferenceByName(localValue(name));
507: return(el);
508: }
509:
510: /**
511: * Returns the references of the elements with the given name
512: */
513: List<x.Element> elementReferences(final String name) {
514: return(_schema.elementReferencesByName(localValue(name)));
515: }
516:
517: /**
518: * Returns the namespace to use for the element,
519: * or null the namespace is undefined.
520: */
521: String elementNamespace(final x.Element elementRef) {
522: return(_schema.elementNamespace(elementRef));
523: }
524:
525: /**
526: * Returns the prefix to use for a new element with the given reference,
527: * or null if no prefix should be used.
528: */
529: String elementPrefix(final x.Element elementRef) {
530: final String espace = elementNamespace(elementRef);
531: if (espace == null)
532: return(null);
533: return(namespacePrefix(espace));
534: }
535:
536: /**
537: * Returns the list of possible values for an element.
538: * Returns null if there are an infinity of possible values.
539: */
540: List<String> elementValues(final x.Element elementRef) {
541: final List<String> liste = _schema.elementValues(elementRef);
542: return(liste);
543: }
544:
545: /**
546: * Returns true if the given value is valid for the element
547: */
548: bool isElementValueValid(final x.Element elementRef, final String value) {
549: return(_schema.elementValueIsValid(elementRef, value));
550: }
551:
552: /**
553: * Returns the list of all namespaces in the schema
554: */
555: List<String> _namespaceList() {
556: if (_namespaceCache != null)
557: return(_namespaceCache);
558: final List<String> liste = new List<String>();
559: final List<String> espacesSchema = _schema.namespaceList();
560: if (espacesSchema != null)
561: liste.addAll(espacesSchema);
562: _namespaceCache = liste;
563: return(liste);
564: }
565:
566: /**
567: * Returns a number for the given namespace, starting from 0.
568: * A unique number is given for each namespace.
569: * Returns -1 if the namespace is not found in the config.
570: */
571: int namespaceNumber(final String namespace) {
572: final List<String> liste = _namespaceList();
573: return(liste.indexOf(namespace));
574: }
575:
576: /**
577: * Returns true if the namspace is defined in the config
578: */
579: bool hasNamespace(final String namespace) {
580: return(_schema.hasNamespace(namespace));
581: }
582:
583: /**
584: * Returns the target namespace for the schema (targetNamespace attribute for WXS)
585: */
586: String targetNamespace() {
587: return(_schema.getTargetNamespace());
588: }
589:
590: /**
591: * Returns the references of the elements which are not in the given namespace
592: */
593: List<x.Element> elementsOutsideNamespace(final String namespace) {
594: return(_schema.elementsOutsideNamespace(namespace));
595: }
596:
597: /**
598: * Returns the references of the elements which are in the given namespaces
599: */
600: List<x.Element> elementsWithinNamespaces(final Set<String> namespaces) {
601: return(_schema.elementsWithinNamespaces(namespaces));
602: }
603:
604: /**
605: * Returns true if the child is required under the parent.
606: */
607: bool requiredElement(final x.Element parentRef, final x.Element childRef) {
608: return(_schema.requiredElement(parentRef, childRef));
609: }
610:
611: /**
612: * Returns true if there is a relation parent-child between the 2 elements
613: */
614: bool isSubElement(final x.Element parentRef, final x.Element childRef) {
615: final List<x.Element> children = subElements(parentRef);
616: if (children == null)
617: return(false);
618: return(children.contains(childRef));
619: }
620:
621: /**
622: * Returns the first reference in the list that is a child of the parent, or null if none is found.
623: */
624: x.Element findSubElement(final x.Element parentRef, final List<x.Element> refs) {
625: final List<x.Element> children = subElements(parentRef);
626: if (children == null)
627: return(null);
628: for (x.Element ref in refs)
629: if (children.contains(ref))
630: return(ref);
631: return(null);
632: }
633:
634: /**
635: * Returns true if the given name matches a possible child for the given parent
636: */
637: bool isSubElementByName(final x.Element parentRef, String childName) {
638: final int inds = childName.indexOf(':');
639: if (inds != -1)
640: childName = childName.substring(inds+1);
641: final List<String> noms = subElementsNames(parentRef);
642: return(noms.contains(childName));
643: }
644:
645: /**
646: * Returns the references of the given element's children
647: */
648: List<x.Element> subElements(final x.Element parentRef) {
649: return(_schema.subElements(parentRef));
650: }
651:
652: /**
653: * Returns the names of the given element's children
654: */
655: List<String> subElementsNames(final x.Element parentRef) {
656: final List<x.Element> listeReferences = subElements(parentRef);
657: final List<String> listeNoms = new List<String>();
658: for (final x.Element ref in listeReferences) {
659: final String nom = _elementsToNamesCache[ref];
660: if (!listeNoms.contains(nom))
661: listeNoms.add(nom);
662: }
663: return(listeNoms);
664: }
665:
666: /**
667: * Regular expression for a given element
668: * @param modevisu True to get a regular expression to display to the user
669: * @param modevalid For strict validation instead of checking if an insert is possible
670: */
671: String _regularExpression(final x.Element parentRef, final bool modevisu, final bool modevalid) {
672: return(_schema.regularExpression(parentRef, modevisu, modevalid));
673: }
674:
675: /**
676: * Regular expression based on the schema for a given parent element
677: */
678: String regularExpression(final x.Element parentRef) {
679: return(_schema.regularExpression(parentRef, true, false));
680: }
681:
682: /**
683: * Returns true if the toInsert element can be inserted under the parent element
684: * on the selection defined by the start and end positions
685: */
686: bool insertIsPossible(DaxeNode parent, final int startOffset, final int endOffset, final x.Element toInsert) {
687: if (parent.nodeType == DaxeNode.DOCUMENT_NODE) {
688: for (DaxeNode dn in parent.childNodes) {
689: if (dn.nodeType == DaxeNode.ELEMENT_NODE)
690: return(false);
691: }
692: return(true);
693: }
694: assert(parent.nodeType == DaxeNode.ELEMENT_NODE);
695: if (_schema is SimpleSchema)
696: return(true); // on suppose que le test de sous-élément a déjà été fait
697: if (startOffset < 0) {
698: logError("Config.insertionPossible: debutSelection < parent.debut");
699: return(false);
700: }
701: if (_schema is DaxeWXS) {
702: final List<x.Element> sousElements = new List<x.Element>();
703: bool ajoute = false;
704: for (DaxeNode dn = parent.firstChild; dn != null; dn = dn.nextSibling) {
705: if (dn.nodeType == DaxeNode.ELEMENT_NODE) {
706: int offset = parent.offsetOf(dn);
707: if (offset < startOffset || offset >= endOffset) {
708: if (!ajoute && offset >= endOffset) {
709: sousElements.add(toInsert);
710: ajoute = true;
711: }
712: sousElements.add(dn.ref);
713: }
714: }
715: }
716: if (!ajoute)
717: sousElements.add(toInsert);
718: final bool insertionOK = (_schema as DaxeWXS).validElement(parent.ref, sousElements, true);
719: return(insertionOK);
720: }
721: return(false);
722: /*
723: pb: on ne peut pas tester l'ordre des éléments dans certains cas, par exemple:
724: <html>
725: <head>
726: <xsl:if test='truc'>
727: <title>xxx</title>
728: </xsl:if>
729: <xsl:if test='not(truc)'>
730: <title>yyy</title>
731: </xsl:if>
732: </head>
733: </html>
734: Ici on autorise deux éléments title sous head alors qu'un seul est normalement autorisé.
735: Par contre on peut tester les imbrications (title est autorisé sous head).
736: */
737: }
738:
739: /**
740: * Returns true if the parent element is valid, considering its attributes,
741: * its first level children, its node value, and its parent if there is one.
742: */
743: bool elementIsValid(final DaxeNode parent) {
744: if (parent is DNComment || parent is DNProcessingInstruction || parent is DNCData)
745: return(true);
746:
747: if (parent.ref == null)
748: return(false);
749:
750: if (!attributesAreValid(parent))
751: return(false);
752:
753: if (parent.parent != null && parent.parent.ref != null && !isSubElement(parent.parent.ref, parent.ref))
754: return(false);
755:
756: if (parent.firstChild == null && !isElementValueValid(parent.ref, ''))
757: return(false);
758: else if (parent.childNodes.length == 1 && parent.firstChild is DNText && parent.firstChild.nodeValue != null &&
759: !isElementValueValid(parent.ref, parent.firstChild.nodeValue))
760: return(false);
761:
762: if (_schema is SimpleSchema)
763: return(true); // on suppose que le test de sous-balise a déjà été fait
764: if (_schema is DaxeWXS) {
765: final List<x.Element> sousElements = new List<x.Element>();
766: bool avectexte = false;
767: for (DaxeNode dn = parent.firstChild; dn != null; dn = dn.nextSibling) {
768: if (dn.nodeType == DaxeNode.ELEMENT_NODE && dn.ref != null) {
769: sousElements.add(dn.ref);
770: } else if (dn.nodeType == DaxeNode.TEXT_NODE) {
771: if (dn.nodeValue.trim() != "")
772: avectexte = true;
773: } else if (dn is DNCData) {
774: if (dn.firstChild != null && dn.firstChild.nodeValue.trim() != '')
775: avectexte = true;
776: }
777: }
778: if (avectexte && !_schema.canContainText(parent.ref))
779: return(false);
780: final DaxeWXS sch = _schema as DaxeWXS;
781: return(sch.validElement(parent.ref, sousElements, false));
782: }
783:
784: final x.Element refParent = parent.ref;
785: final StringBuffer cettexp = new StringBuffer();
786: if (_validPatternCache == null)
787: _validPatternCache = new HashMap<x.Element, Pattern>();
788:
789: bool avectexte = false;
790: DaxeNode child = parent.firstChild;
791: while (child != null) {
792: if (child is DNCData) {
793: if (child.firstChild != null && child.firstChild.nodeValue.trim() != '')
794: avectexte = true;
795: } else if (child.nodeType == DaxeNode.ELEMENT_NODE && child is! DNComment && child is! DNProcessingInstruction) {
796: cettexp.write(child.localName);
797: cettexp.write(",");
798: } else if (child.nodeType == DaxeNode.TEXT_NODE) {
799: if (child.nodeValue.trim() != '')
800: avectexte = true;
801: }
802: child = child.nextSibling;
803: }
804: if (avectexte && !_schema.canContainText(refParent))
805: return(false);
806: RegExp r = _validPatternCache[refParent];
807: if (r == null) {
808: final String expr = _regularExpression(refParent, false, true);
809: if (expr == null || expr == "")
810: return(true);
811: try {
812: r = new RegExp(r"^$expr$");
813: } on Exception catch(ex) {
814: logError("elementValide(JaxeElement, bool, List<String>) - Malformed Pattern: ^${expr}\$:", ex);
815: return(true);
816: }
817: _validPatternCache[refParent] = r;
818: }
819:
820: final bool matched = r.hasMatch(cettexp.toString());
821: return(matched);
822: }
823:
824: /**
825: * Returns true if the element attributes are valid and if there is not missing required attribute.
826: */
827: bool attributesAreValid(final DaxeNode dn) {
828: if (dn.nodeType != DaxeNode.ELEMENT_NODE) {
829: logError("Config.attributsValides : ce n'est pas un élément: $dn");
830: return(false);
831: }
832: // vérif des attributs qui sont dans le schéma
833: final List<x.Element> lattref = elementAttributes(dn.ref);
834: List<String> noms = new List<String>(lattref.length);
835: List<String> espaces = new List<String>(noms.length);
836: for (int i=0; i<lattref.length; i++) {
837: final x.Element attref = lattref[i];
838: noms[i] = attributeName(attref);
839: espaces[i] = attributeNamespace(attref);
840: final String valeur = dn.getAttribute(noms[i]);
841: if (valeur == null || valeur == '') {
842: if (requiredAttribute(dn.ref, attref))
843: return(false);
844: } else if (!validAttributeValue(attref, valeur))
845: return(false);
846: }
847: // vérif s'il y a des attributs en plus qui ne sont pas dans le schéma
848: final List<DaxeAttr> latt = dn.attributes;
849: for (int i=0; i<latt.length; i++) {
850: DaxeAttr att = latt[i];
851: final String prefixe = att.prefix;
852: if (prefixe == "xml" || prefixe == "xmlns")
853: continue;
854: final String nom = att.localName;
855: if (prefixe == null && nom == "xmlns")
856: continue;
857: final String espace = att.namespaceURI;
858: if (espace == "http://www.w3.org/2001/XMLSchema-instance")
859: continue;
860: bool trouve = false;
861: for (int j=0; j<noms.length; j++) {
862: if (noms[j] == nom && espaces[j] == espace) {
863: trouve = true;
864: break;
865: }
866: }
867: if (!trouve)
868: return(false);
869: }
870: return(true);
871: }
872:
873: /**
874: * Returns the list of possible parent elements for a given element
875: */
876: List<x.Element> parentElements(final x.Element elementRef) {
877: return(_schema.parentElements(elementRef));
878: }
879:
880: /**
881: * Returns the list of names for possible parent elements for a given element
882: */
883: List<String> parentNames(final x.Element elementRef) {
884: final List<x.Element> listeReferences = parentElements(elementRef);
885: final List<String> listeNoms = new List<String>();
886: for (final x.Element ref in listeReferences) {
887: final String nom = _elementsToNamesCache[ref];
888: if (!listeNoms.contains(nom))
889: listeNoms.add(nom);
890: }
891: return(listeNoms);
892: }
893:
894: /**
895: * Returns true if the given element can contain text
896: */
897: bool canContainText(final x.Element elementRef) {
898: if (elementRef == null)
899: return(true);
900: return(_schema.canContainText(elementRef));
901: }
902:
903: /**
904: * Returns the list of possible attributes for a given element.
905: */
906: List<x.Element> elementAttributes(final x.Element elementRef) {
907: return(_schema.elementAttributes(elementRef));
908: }
909:
910: /**
911: * Returns the name of an attribute based on its reference.
912: */
913: String attributeName(final x.Element attributeRef) {
914: return(_schema.attributeName(attributeRef));
915: }
916:
917: /**
918: * Returns the qualified name of an attribute based on its reference.
919: */
920: String attributeQualifiedName(final x.Element parentRef, final x.Element attributeRef) {
921: String name = _schema.attributeName(attributeRef);
922: String namespace = _schema.attributeNamespace(attributeRef);
923: if (namespace != null) {
924: String prefix = attributePrefix(parentRef, attributeRef);
925: if (prefix != null)
926: name = "$prefix:$name";
927: }
928: return(name);
929: }
930:
931: /**
932: * Returns an attribute namespace based on its reference, or null if none is defined.
933: */
934: String attributeNamespace(final x.Element attributeRef) {
935: return(_schema.attributeNamespace(attributeRef));
936: }
937:
938: /**
939: * Returns the prefix tu use to create an attribute, given the parent element and the attribute reference,
940: * or null if no prefix should be used.
941: */
942: String attributePrefix(final x.Element parent, final x.Element attributeRef) {
943: final String espace = attributeNamespace(attributeRef);
944: if (espace == null)
945: return(null);
946: if (espace == "http://www.w3.org/XML/1998/namespace")
947: return("xml");
948: if (espace == "http://www.w3.org/2000/xmlns/" && attributeName(attributeRef) != "xmlns")
949: return("xmlns");
950: // on essaye lookupPrefix avec le parent et avec son document
951: // (cas d'un élément en cours de création, pas encore inséré dans le document)
952: String prefixe = parent.lookupPrefix(espace);
953: if (prefixe == null) {
954: if (parent.ownerDocument.documentElement != null) // si l'élément racine existe
955: prefixe = parent.ownerDocument.lookupPrefix(espace);
956: else
957: prefixe = namespacePrefix(espace); // on suppose que la racine sera créée avec ajouterAttributsEspaces
958: }
959: return(prefixe);
960: }
961:
962: /**
963: * Returns an attribute namespace based on its full name (including the prefix).
964: */
965: String attributeNamespaceByName(final String name) {
966: return(_schema.attributeNamespaceByName(name));
967: }
968:
969: /**
970: * Returns true if the attribute is required for the parent element.
971: */
972: bool requiredAttribute(final x.Element parentRef, final x.Element attributeRef) {
973: return(_schema.attributeIsRequired(parentRef, attributeRef));
974: }
975:
976: /**
977: * Returns the list of possible values for an attribute.
978: * Returns null if there are an infinity of possible values.
979: */
980: List<String> attributeValues(final x.Element attributeRef) {
981: final List<String> liste = _schema.attributeValues(attributeRef);
982: return(liste);
983: }
984:
985: /**
986: * Returns an attribute's default value based on its reference.
987: */
988: String defaultAttributeValue(final x.Element attributeRef) {
989: return(_schema.defaultAttributeValue(attributeRef));
990: }
991:
992: /**
993: * Returns true if the given String is a valid value for the attribute.
994: */
995: bool validAttributeValue(final x.Element attributeRef, final String value) {
996: return(_schema.attributeIsValid(attributeRef, value));
997: }
998:
999: /**
1000: * Returns the local part of an element's name (by removing the prefix).
1001: */
1002: static String localValue(final String s) {
1003: if (s == null)
1004: return(null);
1005: final int ind = s.indexOf(':');
1006: if (ind == -1)
1007: return(s);
1008: return(s.substring(ind + 1));
1009: }
1010:
1011:
1012: // METHODS FOR DISPLAY TYPES
1013:
1014: /**
1015: * Returns a node display type based on the element reference, the node name and the DOM node type.
1016: */
1017: String nodeDisplayType(final x.Element elementRef, final String name, final int nodeType) {
1018: if (nodeType == x.Node.ELEMENT_NODE) {
1019: final x.Element affel = getElementDisplay(localValue(name));
1020: if (affel == null)
1021: return(_typeAffichageParDefaut);
1022: return(affel.getAttribute("type"));
1023: } else if (nodeType == x.Node.PROCESSING_INSTRUCTION_NODE) {
1024: x.Element elplug = _findElement(_getNodeDisplay(), "PLUGIN_INSTRUCTION");
1025: while (elplug != null) {
1026: if (name != null && name == elplug.getAttribute("cible"))
1027: return("plugin");
1028: elplug = _nextElement(elplug, "PLUGIN_INSTRUCTION");
1029: }
1030: return("instruction");
1031: } else if (nodeType == x.Node.COMMENT_NODE) {
1032: final x.Element elplug = _findElement(_getNodeDisplay(), "PLUGIN_COMMENTAIRE");
1033: if (elplug != null)
1034: return("plugin");
1035: return("commentaire");
1036: } else if (nodeType == x.Node.CDATA_SECTION_NODE) {
1037: final x.Element elplug = _findElement(_getNodeDisplay(), "PLUGIN_CDATA");
1038: if (elplug != null)
1039: return("plugin");
1040: return("cdata");
1041: } else if (nodeType == x.Node.TEXT_NODE) {
1042: return("texte");
1043: }
1044: return(null);
1045: }
1046:
1047: /**
1048: * Returns an element display type based on its reference.
1049: */
1050: String elementDisplayType(final x.Element elementRef) {
1051: final x.Element affel = getElementDisplay(elementName(elementRef));
1052: if (affel == null)
1053: return(_typeAffichageParDefaut);
1054: return(affel.getAttribute("type"));
1055: }
1056:
1057: /**
1058: * Returns the reference of the first element with the given display type in the config file.
1059: */
1060: x.Element firstElementWithType(final String displayType) {
1061: if (_cfgroot == null)
1062: return(null);
1063: x.Element affel = _findElement(_getNodeDisplay(), "AFFICHAGE_ELEMENT");
1064: while (affel != null) {
1065: if (displayType == affel.getAttribute("type"))
1066: return(elementReference(affel.getAttribute("element")));
1067: affel = _nextElement(affel, "AFFICHAGE_ELEMENT");
1068: }
1069: return(null);
1070: }
1071:
1072: /**
1073: * Returns the references of the elements with the given display type in the config file.
1074: */
1075: List<x.Element> elementsWithType(final String displayType) {
1076: if (_cfgroot == null)
1077: return(null);
1078: List<x.Element> list = new List<x.Element>();
1079: x.Element affel = _findElement(_getNodeDisplay(), "AFFICHAGE_ELEMENT");
1080: while (affel != null) {
1081: if (displayType == affel.getAttribute("type"))
1082: list.addAll(elementReferences(affel.getAttribute("element")));
1083: affel = _nextElement(affel, "AFFICHAGE_ELEMENT");
1084: }
1085: return(list);
1086: }
1087:
1088: /**
1089: * Returns the value of an element display parameter.
1090: * @param elementRef element reference
1091: * @param parameterName parameter name
1092: * @param defaultValue default value, used if the parameter is not found
1093: */
1094: String elementParameterValue(final x.Element elementRef, final String parameterName, final String defaultValue) {
1095: return nodeParameterValue(elementRef, "element", null, parameterName, defaultValue);
1096: }
1097:
1098: /**
1099: * Returns the value of a node display parameter.
1100: * The node type can be used to find display parameters for comments or PIs.
1101: */
1102: String nodeParameterValue(final x.Element elementRef, final String nodeType,
1103: final String name, final String parameterName, final String defaultValue) {
1104: final HashMap<String, List<String>> table = getNodeParameters(elementRef, nodeType, name);
1105: final List<String> lval = table[parameterName];
1106: String valeur;
1107: if (lval != null && lval.length > 0)
1108: valeur = lval[0];
1109: else
1110: valeur = defaultValue;
1111: return valeur;
1112: }
1113:
1114: /**
1115: * Returns a function parameter value.
1116: * @param fctdef Element for the function menu in the config file
1117: * @param parameterName parameter name
1118: * @param defaultValue default value, used if the parameter is not found
1119: */
1120: String functionParameterValue(final x.Element fctdef, final String parameterName, final String defaultValue) {
1121: x.Element parel = _findElement(fctdef, "PARAMETRE");
1122: while (parel != null) {
1123: final String nom = parel.getAttribute("nom");
1124: if (nom == parameterName)
1125: return(parel.getAttribute("valeur"));
1126: parel = _nextElement(parel, "PARAMETRE");
1127: }
1128: return(defaultValue);
1129: }
1130:
1131: HashMap<String, List<String>> _buildParameterCache(final x.Element base) {
1132: final HashMap<String, List<String>> hashparams = new HashMap<String, List<String>>();
1133: x.Element parel = _findElement(base, "PARAMETRE");
1134: while (parel != null) {
1135: final String nom = parel.getAttribute("nom");
1136: final String valeur = parel.getAttribute("valeur");
1137: List<String> lval = hashparams[nom];
1138: if (lval == null) {
1139: lval = new List<String>();
1140: lval.add(valeur);
1141: hashparams[nom] = lval;
1142: } else
1143: lval.add(valeur);
1144: parel = _nextElement(parel, "PARAMETRE");
1145: }
1146: _parametersCache[base] = hashparams;
1147: return(hashparams);
1148: }
1149:
1150: /**
1151: * Returns the table of an element display parameters.
1152: */
1153: HashMap<String, List<String>> getElementParameters(final x.Element elementRef) {
1154: return(getNodeParameters(elementRef, "element", null));
1155: }
1156:
1157: /**
1158: * Returns the table of a node display parameters.
1159: * The name can be null if nodeType is "element" and elementRef is not null.
1160: */
1161: HashMap<String, List<String>> getNodeParameters(final x.Element elementRef, final String nodeType, final String name) {
1162: x.Element base;
1163: if (nodeType == "element")
1164: base = getElementDisplay(elementName(elementRef));
1165: else if (nodeType == "instruction") {
1166: base = null;
1167: x.Element elplug = _findElement(_getNodeDisplay(), "PLUGIN_INSTRUCTION");
1168: while (elplug != null) {
1169: if (name != null && name == elplug.getAttribute("cible")) {
1170: base = elplug;
1171: break;
1172: }
1173: elplug = _nextElement(elplug, "PLUGIN_INSTRUCTION");
1174: }
1175: } else if (nodeType == "commentaire") {
1176: final x.Element elplug = _findElement(_getNodeDisplay(), "PLUGIN_COMMENTAIRE");
1177: if (elplug == null) {
1178: base = null;
1179: } else {
1180: base = elplug;
1181: }
1182: } else
1183: base = null;
1184: if (base == null)
1185: return(new HashMap<String, List<String>>());
1186: if (_parametersCache == null)
1187: _parametersCache = new HashMap<x.Element, HashMap<String, List<String>>>();
1188: HashMap<String, List<String>> hashparams = _parametersCache[base];
1189: if (hashparams == null)
1190: hashparams = _buildParameterCache(base);
1191: return(hashparams);
1192: }
1193:
1194: /**
1195: * Returns the list of suggested values for a given element.
1196: * Returns null if there is no suggestion.
1197: */
1198: List<String> elementSuggestedValues(final x.Element elementRef) {
1199: final Set<String> set = new LinkedHashSet<String>();
1200: List<String> schemaSuggestions = _schema.suggestedElementValues(elementRef);
1201: if (schemaSuggestions != null)
1202: set.addAll(_schema.suggestedElementValues(elementRef));
1203: final x.Element affel = getElementDisplay(elementName(elementRef));
1204: if (affel != null) {
1205: x.Element vs = _findElement(affel, "VALEUR_SUGGEREE");
1206: while (vs != null) {
1207: final String v = _dom_elementValue(vs);
1208: if (v != null)
1209: set.add(v);
1210: vs = _nextElement(vs, "VALEUR_SUGGEREE");
1211: }
1212: }
1213: if (set.length == 0)
1214: return(null);
1215: else
1216: return(set.toList());
1217: }
1218:
1219: /**
1220: * Returns the list of suggested values for an attribute,
1221: * based on the parent element reference and the attribute reference.
1222: * Returns null if there is no suggestion.
1223: */
1224: List<String> attributeSuggestedValues(final x.Element parentRef, final x.Element attributeRef) {
1225: final Set<String> set = new LinkedHashSet<String>();
1226: List<String> schemaSuggestions = _schema.suggestedAttributeValues(attributeRef);
1227: if (schemaSuggestions != null)
1228: set.addAll(schemaSuggestions);
1229: final x.Element affel = getElementDisplay(elementName(parentRef));
1230: if (affel != null) {
1231: final String nomAtt = attributeName(attributeRef);
1232: x.Element aa = _findElement(affel, "AFFICHAGE_ATTRIBUT");
1233: while (aa != null) {
1234: if (aa.getAttribute("attribut") == nomAtt) {
1235: x.Element vs = _findElement(aa, "VALEUR_SUGGEREE");
1236: while (vs != null) {
1237: final String v = _dom_elementValue(vs);
1238: if (v != null)
1239: set.add(v);
1240: vs = _nextElement(vs, "VALEUR_SUGGEREE");
1241: }
1242: }
1243: aa = _nextElement(aa, "AFFICHAGE_ATTRIBUT");
1244: }
1245: }
1246: if (set.length == 0)
1247: return(null);
1248: else
1249: return(set.toList());
1250: }
1251:
1252:
1253: // METHODS FOR THE STRINGS
1254:
1255: /**
1256: * Returns a list of the STRINGS elements in the config file,
1257: * ordered by preference based on the user language and country.
1258: */
1259: List<x.Element> _stringsElements() {
1260: final Locale defaut = new Locale();
1261: final List<x.Element> liste = new List<x.Element>();
1262:
1263: final List<x.Element> lstrings = _getStrings();
1264: for (final x.Element strings in lstrings) {
1265: final String langue = strings.getAttribute("langue");
1266: if (langue != "") {
1267: Locale strloc;
1268: if (strings.getAttribute("pays") == "")
1269: strloc = new Locale.l(langue);
1270: else
1271: strloc = new Locale.lc(langue, strings.getAttribute("pays"));
1272: if (defaut == strloc && !liste.contains(strings))
1273: liste.add(strings);
1274: }
1275: }
1276: for (final x.Element strings in lstrings) {
1277: final String langue = strings.getAttribute("langue");
1278: if (langue != "") {
1279: final Locale test = new Locale.lc(defaut.language, defaut.country);
1280: Locale strloc;
1281: if (strings.getAttribute("pays") == "")
1282: strloc = new Locale.l(langue);
1283: else
1284: strloc = new Locale.lc(langue, strings.getAttribute("pays"));
1285: if (test == strloc && !liste.contains(strings))
1286: liste.add(strings);
1287: }
1288: }
1289: for (final x.Element strings in lstrings) {
1290: final String langue = strings.getAttribute("langue");
1291: if (langue != "") {
1292: final Locale test = new Locale.l(defaut.language);
1293: if (test == new Locale.l(langue) && !liste.contains(strings))
1294: liste.add(strings);
1295: }
1296: }
1297: for (final x.Element strings in lstrings) {
1298: if (!liste.contains(strings))
1299: liste.add(strings);
1300: }
1301: return(liste);
1302: }
1303:
1304: /**
1305: * Returns the config description (element DESCRIPTION_CONFIG).
1306: */
1307: String description() {
1308: final List<x.Element> lstrings = _stringsElements();
1309: for (final x.Element strings in lstrings) {
1310: final x.Element descel = _findElement(strings, "DESCRIPTION_CONFIG");
1311: if (descel == null || descel.firstChild == null)
1312: break;
1313: String desc = _dom_elementValue(descel);
1314: return(desc);
1315: }
1316: return(null);
1317: }
1318:
1319: /**
1320: * Returns a menu title based on its name
1321: */
1322: String menuTitle(final String name) {
1323: final List<x.Element> lstrings = _stringsElements();
1324: for (final x.Element strings in lstrings) {
1325: x.Element sm = _findElementDeep(strings, "STRINGS_MENU");
1326: while (sm != null) {
1327: if (name == sm.getAttribute("menu")) {
1328: final x.Element eltitre = _findElement(sm, "TITRE");
1329: if (eltitre != null && eltitre.firstChild != null) {
1330: return(_dom_elementValue(eltitre));
1331: }
1332: break;
1333: }
1334: sm = _nextElementDeep(strings, sm, "STRINGS_MENU");
1335: }
1336: }
1337: final x.Element refel = elementReference(name);
1338: if (refel != null)
1339: return(elementTitle(refel));
1340: return(name);
1341: }
1342:
1343: /**
1344: * Returns a menu documentation based on its name.
1345: */
1346: String menuDocumentation(final String name) {
1347: final List<x.Element> lstrings = _stringsElements();
1348: for (final x.Element strings in lstrings) {
1349: x.Element sm = _findElementDeep(strings, "STRINGS_MENU");
1350: while (sm != null) {
1351: if (name == sm.getAttribute("menu")) {
1352: final x.Element eldoc = _findElement(sm, "DOCUMENTATION");
1353: if (eldoc != null && eldoc.firstChild != null) {
1354: return(_dom_elementValue(eldoc));
1355: }
1356: break;
1357: }
1358: sm = _nextElementDeep(strings, sm, "STRINGS_MENU");
1359: }
1360: }
1361: return(null);
1362: }
1363:
1364: HashMap<String, String> _titlesHash() {
1365: HashMap<String, String> h = new HashMap<String, String>();
1366: final List<x.Element> lstrings = _stringsElements();
1367: for (final x.Element strings in lstrings) {
1368: x.Element sel = _findElement(strings, "STRINGS_ELEMENT");
1369: while (sel != null) {
1370: String nom = sel.getAttribute("element");
1371: if (h[nom] == null) {
1372: String titre = nom;
1373: final x.Element eltitre = _findElement(sel, "TITRE");
1374: if (eltitre != null && eltitre.firstChild != null)
1375: titre = _dom_elementValue(eltitre);
1376: h[nom] = titre;
1377: }
1378: sel = _nextElement(sel, "STRINGS_ELEMENT");
1379: }
1380: }
1381: return(h);
1382: }
1383:
1384: /**
1385: * Returns an element title based on its reference.
1386: */
1387: String elementTitle(final x.Element elementRef) {
1388: String titre = null;
1389: titre = _elementsTitlesCache[elementRef];
1390: if (titre != null)
1391: return(titre);
1392: final String nom = elementName(elementRef);
1393: if (nom == null) {
1394: logError("Config.elementTitle : no name for $elementRef");
1395: return(null);
1396: }
1397: final List<x.Element> lstrings = _stringsElements();
1398: for (final x.Element strings in lstrings) {
1399: if (titre == null) {
1400: x.Element sel = _findElement(strings, "STRINGS_ELEMENT");
1401: while (sel != null) {
1402: if (sel.getAttribute("element") == nom) {
1403: final x.Element eltitre = _findElement(sel, "TITRE");
1404: if (eltitre != null && eltitre.firstChild != null) {
1405: titre = _dom_elementValue(eltitre);
1406: break;
1407: }
1408: break;
1409: }
1410: sel = _nextElement(sel, "STRINGS_ELEMENT");
1411: }
1412: }
1413: }
1414: if (titre == null || titre == "")
1415: titre = nom;
1416: _elementsTitlesCache[elementRef] = titre;
1417: return(titre);
1418: }
1419:
1420: /**
1421: * Returns an element documentation
1422: */
1423: String documentation(final x.Element elementRef) {
1424: if (elementRef == null)
1425: return(null);
1426: final String nom = elementName(elementRef);
1427: final List<x.Element> lstrings = _stringsElements();
1428: for (final x.Element strings in lstrings) {
1429: x.Element sel = _findElement(strings, "STRINGS_ELEMENT");
1430: while (sel != null) {
1431: if (nom == sel.getAttribute("element")) {
1432: final x.Element eldoc = _findElement(sel, "DOCUMENTATION");
1433: if (eldoc != null && eldoc.firstChild != null)
1434: return(_dom_elementValue(eldoc));
1435: break;
1436: }
1437: sel = _nextElement(sel, "STRINGS_ELEMENT");
1438: }
1439: }
1440: return(_schema.elementDocumentation(elementRef));
1441: }
1442:
1443: /**
1444: * Formats the documentation in HTML.
1445: */
1446: static String formatDoc(final String documentation) {
1.2 ! damieng 1447: String doc = documentation.trim();
1.1 damieng 1448: doc = doc.replaceAll("&", "&");
1449: doc = doc.replaceAll("<", "<");
1450: doc = doc.replaceAll(">", ">");
1451: /*
1452: if (doc.length > 100) {
1453: int p = 0;
1454: for (int i=0; i<doc.length; i++) {
1455: if (i-p > 90 && doc[i] == ' ') {
1456: doc = "${doc.substring(0, i)}\n${doc.substring(i+1)}";
1457: p = i;
1458: } else if (doc[i] == '\n')
1459: p = i;
1460: }
1461: }
1462: */
1463: doc = doc.replaceAll("\n", "<br>");
1464: return(doc);
1465: }
1466:
1467: /**
1468: * Returns the title for an element value, based on the element reference and the value.
1469: */
1470: String elementValueTitle(final x.Element elementRef, final String value) {
1471: final String nom = elementName(elementRef);
1472: final List<x.Element> lstrings = _stringsElements();
1473: final String langueSyst = (new Locale()).language;
1474: for (final x.Element strings in lstrings) {
1475: x.Element sel = _findElement(strings, "STRINGS_ELEMENT");
1476: while (sel != null) {
1477: if (sel.getAttribute("element") == nom) {
1478: x.Element eltitrev = _findElement(sel, "TITRE_VALEUR");
1479: while (eltitrev != null) {
1480: if (eltitrev.getAttribute("valeur") == value &&
1481: eltitrev.firstChild != null)
1482: return(_dom_elementValue(eltitrev));
1483: eltitrev = _nextElement(eltitrev, "TITRE_VALEUR");
1484: }
1485: break;
1486: }
1487: sel = _nextElement(sel, "STRINGS_ELEMENT");
1488: }
1489: // la langue est trouvée mais il n'y a pas de TITRE_VALEUR correspondant
1490: // -> on renvoie la vraie valeur plutôt que de chercher un titre
1491: // dans d'autres langues.
1492: final String langue = strings.getAttribute("langue");
1493: if (langue == langueSyst)
1494: return(value);
1495: }
1496: return(value);
1497: }
1498:
1499: /**
1500: * Returns an attribute title based on the parent element reference and the attribute reference.
1501: */
1502: String attributeTitle(final x.Element parentRef, final x.Element attributeRef) {
1503: final String nomEl = elementName(parentRef);
1504: final String nomAtt = attributeName(attributeRef);
1505: final List<x.Element> lstrings = _stringsElements();
1506: for (final x.Element strings in lstrings) {
1507: x.Element sel = _findElement(strings, "STRINGS_ELEMENT");
1508: while (sel != null) {
1509: if (sel.getAttribute("element") == nomEl) {
1510: x.Element sat = _findElement(sel, "STRINGS_ATTRIBUT");
1511: while (sat != null) {
1512: if (sat.getAttribute("attribut") == nomAtt) {
1513: final x.Element eltitre = _findElement(sat, "TITRE");
1514: if (eltitre != null && eltitre.firstChild != null)
1515: return(_dom_elementValue(eltitre));
1516: break;
1517: }
1518: sat = _nextElement(sat, "STRINGS_ATTRIBUT");
1519: }
1520: }
1521: sel = _nextElement(sel, "STRINGS_ELEMENT");
1522: }
1523: }
1524: final String prefixe = attributePrefix(parentRef, attributeRef);
1525: if (prefixe != null)
1526: return("$prefixe:$nomAtt");
1527: return(nomAtt);
1528: }
1529:
1530: /**
1531: * Returns the title for an attribute value, based on the parent element reference,
1532: * the attribute reference and the value.
1533: */
1534: String attributeValueTitle(final x.Element parentRef, final x.Element attributeRef, final String value) {
1535: final String nomEl = elementName(parentRef);
1536: final String nomAtt = attributeName(attributeRef);
1537: final List<x.Element> lstrings = _stringsElements();
1538: final String langueSyst = (new Locale()).language;
1539: for (final x.Element strings in lstrings) {
1540: x.Element sel = _findElement(strings, "STRINGS_ELEMENT");
1541: while (sel != null) {
1542: if (sel.getAttribute("element") == nomEl) {
1543: x.Element sat = _findElement(sel, "STRINGS_ATTRIBUT");
1544: while (sat != null) {
1545: if (sat.getAttribute("attribut") == nomAtt) {
1546: x.Element eltitrev = _findElement(sat, "TITRE_VALEUR");
1547: while (eltitrev != null) {
1548: if (eltitrev.getAttribute("valeur") == value &&
1549: eltitrev.firstChild != null)
1550: return(_dom_elementValue(eltitrev));
1551: eltitrev = _nextElement(eltitrev, "TITRE_VALEUR");
1552: }
1553: break;
1554: }
1555: sat = _nextElement(sat, "STRINGS_ATTRIBUT");
1556: }
1557: }
1558: sel = _nextElement(sel, "STRINGS_ELEMENT");
1559: }
1560: // la langue est trouvée mais il n'y a pas de TITRE_VALEUR correspondant
1561: // -> on renvoie la vraie valeur d'attribut plutôt que de chercher un titre
1562: // dans d'autres langues.
1563: final String langue = strings.getAttribute("langue");
1564: if (langue == langueSyst)
1565: return(value);
1566: }
1567: return(value);
1568: }
1569:
1570: /**
1571: * Returns an attribute's documentation based on the parent element reference and
1572: * the attribute reference.
1573: */
1574: String attributeDocumentation(final x.Element parentRef, final x.Element attributeRef) {
1575: final String nomEl = elementName(parentRef);
1576: final String nomAtt = attributeName(attributeRef);
1577: final List<x.Element> lstrings = _stringsElements();
1578: for (final x.Element strings in lstrings) {
1579: x.Element sel = _findElement(strings, "STRINGS_ELEMENT");
1580: while (sel != null) {
1581: if (sel.getAttribute("element") == nomEl) {
1582: x.Element sat = _findElement(sel, "STRINGS_ATTRIBUT");
1583: while (sat != null) {
1584: if (sat.getAttribute("attribut") == nomAtt) {
1585: final x.Element eldoc = _findElement(sat, "DOCUMENTATION");
1586: if (eldoc != null &&eldoc.firstChild != null)
1587: return(_dom_elementValue(eldoc));
1588: break;
1589: }
1590: sat = _nextElement(sat, "STRINGS_ATTRIBUT");
1591: }
1592: }
1593: sel = _nextElement(sel, "STRINGS_ELEMENT");
1594: }
1595: }
1596: return(_schema.attributeDocumentation(attributeRef));
1597: }
1598:
1599: /**
1600: * Returns an export's title based on its reference.
1601: */
1602: String exportTitle(final x.Element exportRef) {
1603: final String nom = exportName(exportRef);
1604: final List<x.Element> lstrings = _stringsElements();
1605: for (final x.Element strings in lstrings) {
1606: x.Element export = _findElement(strings, "STRINGS_EXPORT");
1607: while (export != null) {
1608: if (nom == export.getAttribute("export")) {
1609: final x.Element eltitre = _findElement(export, "TITRE");
1610: if (eltitre != null && eltitre.firstChild != null)
1611: return(_dom_elementValue(eltitre));
1612: break;
1613: }
1614: export = _nextElement(export, "STRINGS_EXPORT");
1615: }
1616: }
1617: return(nom);
1618: }
1619:
1620: /**
1621: * Returns an export's documentation based on its reference.
1622: */
1623: String exportDocumentation(final x.Element exportRef) {
1624: final String nom = exportName(exportRef);
1625: final List<x.Element> lstrings = _stringsElements();
1626: for (final x.Element strings in lstrings) {
1627: x.Element export = _findElement(strings, "STRINGS_EXPORT");
1628: while (export != null) {
1629: if (nom == export.getAttribute("export")) {
1630: final x.Element eldoc = _findElement(export, "DOCUMENTATION");
1631: if (eldoc != null && eldoc.firstChild != null)
1632: return(_dom_elementValue(eldoc));
1633: break;
1634: }
1635: export = _nextElement(export, "STRINGS_EXPORT");
1636: }
1637: }
1638: return(null);
1639: }
1640:
1641:
1642: // TOOLS
1643:
1644: /**
1645: * Returns the value of the first child node, removing leading and trailing whites.
1646: * Returns null if there is not child node.
1647: */
1648: static String _dom_elementValue(final x.Node el) {
1649: final x.Node fc = el.firstChild;
1650: if (fc == null)
1651: return(null);
1652: final String v = fc.nodeValue;
1653: if (v == null)
1654: return(null);
1655: return(v.trim());
1656: }
1657:
1658: x.Element _getLanguage() {
1659: if (_languageNode == null) {
1660: _languageNode = _findElement(_cfgroot, "LANGAGE");
1661: }
1662: return _languageNode;
1663: }
1664:
1665: x.Element _getSaving() {
1666: if (_savingNode == null) {
1667: _savingNode = _findElement(_cfgroot, "ENREGISTREMENT");
1668: if (_savingNode == null) {
1669: _savingNode = _cfgroot.ownerDocument.createElement("ENREGISTREMENT");
1670: }
1671: }
1672: return _savingNode;
1673: }
1674:
1675: x.Element _getMenus() {
1676: if (_menusNode == null) {
1677: _menusNode = _findElement(_cfgroot, "MENUS");
1678: if (_menusNode == null) {
1679: _menusNode = _cfgroot.ownerDocument.createElement("MENUS");
1680: }
1681: }
1682: return _menusNode;
1683: }
1684:
1685: x.Element _getNodeDisplay() {
1686: if (_displayNode == null) {
1687: _displayNode = _findElement(_cfgroot, "AFFICHAGE_NOEUDS");
1688: if (_displayNode == null) {
1689: _displayNode = _cfgroot.ownerDocument.createElement("AFFICHAGE_NOEUDS");
1690: }
1691: }
1692: return _displayNode;
1693: }
1694:
1695: x.Element _getExports() {
1696: if (_exportsNode == null) {
1697: _exportsNode = _findElement(_cfgroot, "EXPORTS");
1698: if (_exportsNode == null) {
1699: _exportsNode = _cfgroot.ownerDocument.createElement("EXPORTS");
1700: }
1701: }
1702: return _exportsNode;
1703: }
1704:
1705: List<x.Element> _getStrings() {
1706: if (_listeStrings == null) {
1707: _listeStrings = new List<x.Element>();
1708: x.Node child = _cfgroot.firstChild;
1709: while (child != null) {
1710: if (child.nodeType == x.Node.ELEMENT_NODE && child.nodeName == "STRINGS") {
1711: _listeStrings.add(child as x.Element);
1712: }
1713: child = child.nextSibling;
1714: }
1715: }
1716: return _listeStrings;
1717: }
1718:
1719:
1720: static x.Element _findElement(final x.Node n, final String name) {
1721: final x.Node child = n.firstChild;
1722: return _nextNode(child, name);
1723: }
1724:
1725: static x.Element _nextElement(final x.Node n, final String name) {
1726: final x.Node child = n.nextSibling;
1727: return _nextNode(child, name);
1728: }
1729:
1730: static x.Element _nextNode(x.Node child, final String name) {
1731: if (name == null)
1732: return null;
1733: while (child != null) {
1734: if (child.nodeType == x.Node.ELEMENT_NODE && name == child.nodeName) {
1735: return child as x.Element;
1736: }
1737: child = child.nextSibling;
1738: }
1739: return null;
1740: }
1741:
1742: static x.Element _findElementDeep(final x.Node n, final String name) {
1743: return _nextElementDeep(n, n, name);
1744: }
1745:
1746: static x.Element _nextElementDeep(final x.Node parent, final x.Node n, final String name) {
1747: x.Node current = n;
1748: x.Node next;
1749: while (current != null) {
1750: if (current.hasChildNodes()) {
1751: current = (current.firstChild);
1752: } else if (current != parent && null != (next = current.nextSibling)) {
1753: current = next;
1754: } else {
1755: next = null;
1756: while (current != parent) {
1757:
1758: next = current.nextSibling;
1759: if (next != null)
1760: break;
1761: current = current.parentNode;
1762: }
1763: current = next;
1764: }
1765: if (current != parent && current != null && current.nodeType == x.Node.ELEMENT_NODE
1766: && current.nodeName == name) {
1767: return current as x.Element;
1768: }
1769: }
1770: return null;
1771: }
1772:
1773: static void logError(String message, [Exception ex]) {
1774: if (ex != null)
1775: print("Config: $message: $ex");
1776: else
1777: print("Config: $message");
1778: }
1779: }
1780:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>