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