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("&", "&amp;");
                   1449:     doc = doc.replaceAll("<", "&lt;");
                   1450:     doc = doc.replaceAll(">", "&gt;");
                   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>