Annotation of modules/damieng/graphical_editor/daxe/lib/src/config.dart, revision 1.3

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>