File:  [Public] / Amaya / amaya / templateInstantiate.c
Revision 1.114: download - view: text, annotated - select for diffs
Tue Aug 18 14:33:16 2009 UTC (14 years, 9 months ago) by vatton
Branches: MAIN
CVS tags: HEAD
Allow the insertion of components within a template head and a XTiger library
+ allow the insertion of XHTML elements within a component
+ prepare the new function to create an import

Irene

/*
 *
 *  COPYRIGHT INRIA and W3C, 2006-2009
 *  Please first read the full copyright statement in file COPYRIGHT.
 *
 */

#include "templates.h"
#define THOT_EXPORT extern
#include "amaya.h"
#include "css.h"
#include "templateDeclarations.h"

#include "Elemlist.h"
#include "AHTURLTools_f.h"
#include "wxdialogapi_f.h"
#include "EDITimage_f.h"
#include "HTMLedit_f.h"
#include "HTMLsave_f.h"
#include "HTMLtable_f.h"
#include "html2thot_f.h"
#include "init_f.h"
#include "templates_f.h"
#include "templateDeclarations_f.h"
#include "templateInstantiate_f.h"
#include "Templatebuilder_f.h"
#include "templateLoad_f.h"
#include "templateUtils_f.h"
#include "fetchHTMLname_f.h"
#include "Template.h"
#include "fetchXMLname_f.h"
#include "styleparser_f.h"

#ifdef TEMPLATES
#define TEMPLATE_SCHEMA_NAME "Template"
#endif /* TEMPLATES */



/*----------------------------------------------------------------------
  Template_InsertRepeatChildAfter
  Insert a child to a xt:repeat
  The decl parameter must be valid and will not be verified. It must be a
    direct child element or the "use in the use" for union elements.
  @param el element (xt:repeat) in which insert a new element
  @param decl Template declaration of the element to insert
  @param elPrev Element (xt:use) after which insert the new elem, NULL if first.
  @return The inserted element 
  ----------------------------------------------------------------------*/
Element Template_InsertRepeatChildAfter (Document doc, Element el,
                                         Declaration decl, Element elPrev)
{
#ifdef TEMPLATES
  Element     child; /* First xt:use of the repeat.*/
  Element     use, parent; /* xt:use to insert.*/
  ElementType useType;  /* type of xt:use.*/
  char       *types = NULL;

  if (!TtaGetDocumentAccessMode (doc))
    return NULL;
  
  /* Copy xt:use with xt:types param */
  child = TtaGetFirstChild (el);
  useType = TtaGetElementType (child);
  use = TtaCopyElement (child, doc, doc, el);
  types = GetAttributeStringValueFromNum (child, Template_ATTR_types, NULL);
  if (useType.ElTypeNum != Template_EL_useSimple)
    TtaChangeElementType (use, Template_EL_useSimple);
  if (types)
    {
      SetAttributeStringValueWithUndo (use, Template_ATTR_types, types);
      TtaFreeMemory (types);
    }
  else
    SetAttributeStringValueWithUndo (use, Template_ATTR_types, decl->name);
  /* insert it */
  if (elPrev)
    TtaInsertSibling (use, elPrev, FALSE, doc);
  else
    TtaInsertSibling (use, child, TRUE, doc);
  // look for the enclosing target element
  parent = GetParentLine (use, useType.ElSSchema);
  Template_InsertUseChildren(doc, use, decl, parent, TRUE);
  SetAttributeStringValueWithUndo (use, Template_ATTR_title, decl->name);
  SetAttributeStringValueWithUndo (use, Template_ATTR_currentType, decl->name);
  TtaRegisterElementCreate (use, doc);
  return use;
#else /* TEMPLATES */
  return NULL;
#endif /* TEMPLATES */
}

/*----------------------------------------------------------------------
  Template_InsertBagChild
  Insert a child to a xt:bag at the current insertion point.
  The decl parameter must be valid and will not be verified.
  @param sel the refered element. If NULL use the selection
  @param bag element (xt:bag) in which insert a new element
  @param decl Template declaration of the element to insert
  @return The inserted element
  ----------------------------------------------------------------------*/
Element Template_InsertBagChild (Document doc, Element sel, Element bag,
                                 Declaration decl, ThotBool before)
{
#ifdef TEMPLATES
  ElementType newElType, selType;
  Element     use = NULL, el, dummy = NULL;
  SSchema     sstempl;
  int         start, end;
  ThotBool    open;

  if (!TtaGetDocumentAccessMode (doc) || !decl)
    return NULL;

  TtaGiveFirstSelectedElement (doc, &el, &start, &end);
  if (sel == NULL)
    sel = el;
  if (sel == bag || TtaIsAncestor (sel, bag))
    {
      // opent the undo sequence if needed
      open = TtaHasUndoSequence (doc);
      if (!open)
        TtaOpenUndoSequence (doc, NULL, NULL, 0, 0);
      sstempl = TtaGetSSchema ("Template", doc);
      selType = TtaGetElementType (sel);
      if (decl->blockLevel == 2 && 
          (TtaIsLeaf (selType) || !IsTemplateElement (sel)))
        {
          // force the insertion of a block level element at the right position
          while (sel && IsCharacterLevelElement (sel))
            sel = TtaGetParent (sel);
          if (sel)
            TtaSelectElement (doc, sel);
        }

      if (decl->nature == XmlElementNat)
        {
          if (el == NULL && sel != bag)
            // force a selection
            TtaSelectElement (doc, sel);
          if (sel == bag)
            {
              // insert first an empty element
              if (DocumentTypes[doc] == docHTML)
                newElType.ElTypeNum = HTML_EL_Element;
              else if (DocumentTypes[doc] == docMath)
                newElType.ElTypeNum = MathML_EL_Construct;
              else
                newElType.ElTypeNum = XML_EL_XML_Element;
              newElType.ElSSchema = TtaGetDocumentSSchema (doc);
              dummy = TtaNewElement(doc, newElType);
              TtaInsertFirstChild (&dummy, bag, doc);
              TtaRegisterElementCreate (dummy, doc);
              TtaSelectElement (doc, dummy);
            }
          GIType (decl->name, &newElType, doc);
          TtaInsertAnyElement (doc, before);
          TtaExtendUndoSequence (doc);
          TtaInsertElement (newElType, doc);
          TtaGiveFirstSelectedElement (doc, &sel, &start, &end);
          if (dummy)
            {
              TtaRegisterElementDelete (dummy, doc);
              TtaDeleteTree (dummy, doc);
            }
        }
      else if (decl->nature == ComponentNat)
        {
          // create a use element
          newElType.ElTypeNum = Template_EL_useSimple;
          newElType.ElSSchema = sstempl;
          use = TtaNewElement(doc, newElType);
          if (use)
            {
              Template_InsertUseChildren (doc, use, decl, NULL, TRUE);
              if (sel != bag)
                TtaInsertSibling (use, sel, before, doc);
              else
                 TtaInsertFirstChild (&use, bag, doc);
              SetAttributeStringValueWithUndo (use, Template_ATTR_types, decl->name);
              SetAttributeStringValueWithUndo (use, Template_ATTR_title, decl->name);
              SetAttributeStringValueWithUndo (use, Template_ATTR_currentType, decl->name);
              TtaRegisterElementCreate (use, doc);
              
              sel = use;
            }
        }
      else if (decl->nature == UnionNat)
        {
          newElType.ElTypeNum = Template_EL_useEl;
          newElType.ElSSchema = sstempl;
        }
      // close the undo sequence
      if (!open)
        TtaCloseUndoSequence (doc);
      return sel;
    }
#endif /* TEMPLATES */
  return NULL;
}

/*----------------------------------------------------------------------
  InstantiateAttribute
  ----------------------------------------------------------------------*/
static void InstantiateAttribute (XTigerTemplate t, Element el, Document doc)
{
#ifdef TEMPLATES
  AttributeType  useType, nameType, defaultType, attrType;
  Attribute      useAttr, nameAttr, defAttr, attr;
  ElementType    elType;
  Element        parent;
  char           *text, *elementName;
  ThotBool       level;
  NotifyAttribute event;
  int             val;

  parent = TtaGetParent (el);
  if (!parent)
    return;
  // if attribute "use" has value "optional", don't do anything
  useType.AttrSSchema = TtaGetSSchema (TEMPLATE_SCHEMA_NAME, doc);
  useType.AttrTypeNum = Template_ATTR_useAt;
  useAttr = TtaGetAttribute (el, useType);
  if (useAttr)
    // there is a "use" attribute. Check its value
    {
      val = TtaGetAttributeValue(useAttr);
      if (val == Template_ATTR_useAt_VAL_optional)
      {
        return;
      }
    }
    
  // get the "name" and "default" attributes
  nameType.AttrSSchema = defaultType.AttrSSchema = TtaGetSSchema (TEMPLATE_SCHEMA_NAME, doc);
  nameType.AttrTypeNum = Template_ATTR_ref_name;
  defaultType.AttrTypeNum = Template_ATTR_defaultAt;
  nameAttr = TtaGetAttribute (el, nameType);
  defAttr = TtaGetAttribute (el, defaultType);
  if (nameAttr)
    {
      text = GetAttributeStringValue (el, nameAttr, NULL);
      if (text)
        {
          elType = TtaGetElementType (parent);
          elementName = TtaGetElementTypeName (elType);
          level = TRUE;
          MapHTMLAttribute (text, &attrType, elementName, &level, doc);
          TtaFreeMemory(text);
          attr = TtaNewAttribute (attrType);
          if (attr)
            {
              TtaAttachAttribute (parent, attr, doc);
              if (defAttr)
                {
                  text = GetAttributeStringValue (el, defAttr, NULL);
                  if (text)
                    TtaSetAttributeText(attr, text, parent, doc);
                  TtaFreeMemory(text);
                  // if it's a src arttribute for an image, load the image
                  if (!strcmp (TtaGetSSchemaName (elType.ElSSchema), "HTML") &&
                      elType.ElTypeNum == HTML_EL_IMG)
                    if (attrType.AttrTypeNum == HTML_ATTR_SRC &&
                        attrType.AttrSSchema == elType.ElSSchema)
                      {
                        event.document = doc;
                        event.element = parent;
                        event.attribute = attr;
                        SRCattrModified (&event);
                      }
                }
            }
        }
    }
#endif /* TEMPLATES */
}

/*----------------------------------------------------------------------
  ParseTemplate
  parentLine points to the enclosing pseudo paragraph or paragraph
  Parameter loading is TRUE when the document is not already loaded.
  Return the parentline to be considered for next elements
  ----------------------------------------------------------------------*/
Element ParseTemplate (XTigerTemplate t, Element el, Document doc,
                       Element parentLine, ThotBool loading)
{
#ifdef TEMPLATES
  AttributeType attType;
  Attribute     att;
  Element       next, child = NULL, savedInline, prev, parent = NULL;
  ElementType   elType, otherType;
  Declaration   dec;
  int           option;
  char         *name, *types;
  ThotBool      opt;

  if (!t || !el)
    return parentLine;

  savedInline = parentLine;
  elType = TtaGetElementType (el);
  attType.AttrSSchema = elType.ElSSchema;
  name = TtaGetSSchemaName (elType.ElSSchema);
  if (!strcmp (name, "Template"))
    {
      switch (elType.ElTypeNum)
        {
        case Template_EL_head :
          //Remove it and all of its children
          TtaDeleteTree(el, doc);
          //We must stop searching into this tree
          return parentLine;
        case Template_EL_component :
          // remove the name attribute
          attType.AttrTypeNum = Template_ATTR_name;
          name = GetAttributeStringValueFromNum (el, Template_ATTR_name, NULL);
          TtaRemoveAttribute (el, TtaGetAttribute (el, attType), doc);
          // replace the component by a use
          prev = el;
          TtaPreviousSibling (&prev);
          if (prev == NULL)
            {
              next = el;
              TtaNextSibling (&next);
              if (next == NULL)
                parent = TtaGetParent (el);
            }
          TtaRemoveTree (el, doc);
          TtaChangeElementType (el, Template_EL_useSimple);
          // generate the types attribute
          attType.AttrTypeNum = Template_ATTR_types;
          att = TtaNewAttribute (attType);
          TtaAttachAttribute (el, att, doc);
          if (name)
            TtaSetAttributeText (att, name, el, doc);
          // generate the title attribute
          attType.AttrTypeNum = Template_ATTR_title;
          att = TtaNewAttribute (attType);
          TtaAttachAttribute (el, att, doc);
          if (name)
            TtaSetAttributeText (att, name, el, doc);
          // generate the currentType attribute
          attType.AttrTypeNum = Template_ATTR_currentType;
          att = TtaNewAttribute (attType);
          TtaAttachAttribute (el, att, doc);
          if (name)
            TtaSetAttributeText (att, name, el, doc);
          /* now reinsert the element new map */
          if (prev != NULL)
            TtaInsertSibling (el, prev, FALSE, doc);
          else if (next != NULL)
            TtaInsertSibling (el, next, TRUE, doc);
          else
            TtaInsertFirstChild (&el, parent, doc);
          TtaFreeMemory(name);
          Template_FixAccessRight (t, el, doc);
          TtaUpdateAccessRightInViews (doc, el);
          break;
        case Template_EL_bag :
          Template_FixAccessRight (t, el, doc);
          TtaUpdateAccessRightInViews (doc, el);
          break;
        case Template_EL_useEl :
        case Template_EL_useSimple :
          /* if this use element is not empty, don't do anything: it is
             supposed to contain a valid instance. This should be
             checked, though */
            // add the initial indicator
          types = GetAttributeStringValueFromNum (el, Template_ATTR_types, NULL);
          if (types)
            {
              child = TtaGetFirstChild (el);
              if (!strcmp (types, "string") || !strcmp (types, "number"))
                AddPromptIndicator (el, doc);
              else
                {
                  // avoid to have a block element within a pseudo paragraph
                  dec = Template_GetDeclaration (t, types);
                  if (dec && dec->blockLevel == 2 && parentLine)
                    {
                      // move the use element after the paragraph
                      child = TtaGetParent (el);
                      otherType = TtaGetElementType (child);
                      if (otherType.ElSSchema != elType.ElSSchema ||
                          otherType.ElTypeNum == Template_EL_repeat)
                        // not need to move the parent element
                          child = el;
                      next = child;
                      prev = parentLine;
                      while (child)
                        {
                          // move the element and next siblings after the pseudo paragraph
                          TtaNextSibling (&next);
                          TtaRemoveTree (child, doc);
                          TtaInsertSibling (child, prev, FALSE, doc);
                          prev = child;
                          child = next;
                        }
                      // elements are now out of the parent line
                      savedInline = NULL;
                      parentLine = NULL;
                      child = TtaGetFirstChild (el);
                    }

                  // generate the currentType attribute
                  otherType = TtaGetElementType (child);
                  if (otherType.ElSSchema == elType.ElSSchema &&
                      otherType.ElTypeNum == Template_EL_TemplateObject)
                    {
                      // not already instantiated
                      TtaDeleteTree (child, doc);
                      child = NULL;
                    }
                  else
                    {
                      attType.AttrTypeNum = Template_ATTR_currentType;
                      att = TtaGetAttribute (el, attType);
                      if (att == NULL)
                        {
                          att = TtaNewAttribute (attType);
                          TtaAttachAttribute (el, att, doc);
                        }
                      if (otherType.ElTypeNum == 1)
                        TtaSetAttributeText (att, "string", el, doc);
                      else
                        {
                          name = (char *)GetXMLElementName (otherType, doc);
                          if (name && strcmp (name,"???"))
                            TtaSetAttributeText (att, name, el, doc);
                        }
                    }
                }
            }
          if (child == NULL)
            {
              option = GetAttributeIntValueFromNum (el, Template_ATTR_option);
              opt = (option == Template_ATTR_option_VAL_option_set);
              InstantiateUse (t, el, doc, parentLine, FALSE);
            }
          else
            {
              Template_FixAccessRight (t, el, doc);
              TtaUpdateAccessRightInViews (doc, el);
            }
          TtaFreeMemory (types);
          break;
        case Template_EL_attribute :
          if (!loading)
            InstantiateAttribute (t, el, doc);
          break;
        case Template_EL_repeat :
          InstantiateRepeat (t, el, doc, parentLine, FALSE);
          break;
        default :
          break;
        }
    }
  else if (!strcmp (name, "HTML") &&
           (elType.ElTypeNum == HTML_EL_Pseudo_paragraph ||
            elType.ElTypeNum == HTML_EL_Paragraph))
    parentLine = el;

  child = TtaGetFirstChild (el);
  while (child)
    {
      next = child;
      TtaNextSibling (&next);
      parentLine = ParseTemplate (t, child, doc, parentLine, loading);
      child = next;
    }
  return savedInline;
#endif /* TEMPLATES */
}

/*----------------------------------------------------------------------
  CreateTemplate
  Create a template from any document.
  ----------------------------------------------------------------------*/
void CreateTemplate (Document doc, char *templatePath)
{
#ifdef TEMPLATES
  Element           root, head, elem, xt, title, child, last;
  ElementType       elType, xtType;
  char             *s;
  SSchema           templSchema;
  XTigerTemplate    t;
  
  if (IsTemplateInstanceDocument(doc))
    {
      ShowMessage(TtaGetMessage (AMAYA, AM_TEMPLATE_ERR_INSTANCE),
          TtaGetMessage (AMAYA, AM_TEMPLATE_ERR_CREATION));
      return;
    }

  if (IsTemplateDocument(doc))
    {
      ShowMessage(TtaGetMessage (AMAYA, AM_TEMPLATE_ERR_TEMPLATE),
          TtaGetMessage (AMAYA, AM_TEMPLATE_ERR_CREATION));
      return;
    }
  
  root = TtaGetRootElement(doc);
  elType = TtaGetElementType (root);
  // get the target document type
  s = TtaGetSSchemaName (elType.ElSSchema);
  
  TtaNewNature (doc, elType.ElSSchema,  NULL, "Template", "TemplateP");
  TtaSetANamespaceDeclaration (doc, root, "xt", Template_URI);
  templSchema = TtaGetSSchema ("Template", doc);
  TtaSetUriSSchema (templSchema, Template_URI);

  // Insert xt:head and others
  TtaSetStructureChecking (FALSE, doc);
  if (strcmp (s, "HTML") == 0)
    {
      // Initialize the xt:head
      elType.ElTypeNum = HTML_EL_HEAD;
      xtType.ElSSchema = templSchema;
      head = TtaSearchTypedElement (elType, SearchInTree, root);
      if(head)
        {
          xtType.ElTypeNum = Template_EL_head;
          xt = TtaNewElement(doc, xtType);
          elem = TtaGetLastChild(head);
          if(elem)
              TtaInsertSibling(xt, elem, FALSE, doc);
          else
              TtaInsertFirstChild(&xt, head, doc);
          
          SetAttributeStringValue(xt, Template_ATTR_version, Template_Current_Version);
          SetAttributeStringValue(xt, Template_ATTR_templateVersion, "1.0");
        }
      
      // Initialize the document title
      elType.ElTypeNum = HTML_EL_TITLE;
      title = TtaSearchTypedElement (elType, SearchInTree, root);
      if (title)
        {
          // Create xt:use for title
          xtType.ElTypeNum = Template_EL_useSimple;
          xt = TtaNewElement (doc, xtType);
          TtaInsertFirstChild(&xt, title, doc);
          SetAttributeStringValue (xt, Template_ATTR_types, "string");
          SetAttributeStringValue (xt, Template_ATTR_title, "title");
          
          // Move current title content to xt:use
          last = NULL;
          while(child = TtaGetLastChild(title), child!=NULL)
            {
              if (child == xt)
                break;
              TtaRemoveTree (child, doc);
              if (last)
                TtaInsertSibling (child, last, FALSE, doc);
              else
                TtaInsertFirstChild (&child, xt, doc);
              last = child;
            }
        }
    }
  else
    {
      xtType.ElSSchema = templSchema;
      xtType.ElTypeNum = Template_EL_head;
      xt = TtaNewElement (doc, xtType);
      TtaInsertFirstChild (&xt, root, doc);
      SetAttributeStringValue (xt, Template_ATTR_version, Template_Current_Version);
      SetAttributeStringValue (xt, Template_ATTR_templateVersion, "1.0");      
    }
  // Save changes
  TtaSetStructureChecking (TRUE, doc);
  if (DocumentTypes[doc] == docHTML)
    // avoid positionned boxes to overlap the xt:head section
    SetBodyAbsolutePosition (doc);

  TtaClearUndoHistory (doc);
  RemoveParsingErrors (doc);

  TtaFreeMemory(DocumentURLs[doc]);
  DocumentURLs[doc] = TtaStrdup(templatePath);
  
  if(DocumentMeta[doc]==NULL)
    DocumentMeta[doc] = DocumentMetaDataAlloc();
  
  DocumentMeta[doc]->method = CE_TEMPLATE;
  if(DocumentMeta[doc]->initial_url)
    {
      TtaFreeMemory(DocumentMeta[doc]->initial_url);
      DocumentMeta[doc]->initial_url = NULL;
    }
  TtaSetDocumentModified (doc);

  // Load template-related infos :
  // like LoadTemplate(..)
  t = LookForXTigerTemplate(templatePath);
  t->doc = doc;
  Template_PrepareTemplate(t, doc);
  //  DocumentTypes[doc] = docTemplate;
  t->state |= templloaded|templTemplate;

#ifdef TEMPLATE_DEBUG  
    DumpAllDeclarations();
#endif /* TEMPLATE_DEBUG */
    
  /* Update the URL combo box */
  AddURLInCombobox (DocumentURLs[doc], NULL, FALSE);
  TtaSetTextZone (doc, 1, URL_list);
  /* Update template menus */
  UpdateTemplateMenus(doc);

#endif /* TEMPLATES */  
}

/*----------------------------------------------------------------------
  CreateInstance
  basedoc is the displayed doc that launchs the creation of instance
  ----------------------------------------------------------------------*/
void CreateInstance (char *templatePath, char *instancePath,
                     char *docname,  DocumentType docType, int basedoc)
{
#ifdef TEMPLATES
  Document          doc = 0, newdoc = 0;
  Element           root, title, text;
  ElementType       elType;
  CHARSET           charset, ocharset;
  char             *s, *charsetname, *ocharsetname, *localFile;

  XTigerTemplate t = GetXTigerTemplate(templatePath);
  if (t == NULL)
    {
      // the template cannot be loaded
      InitConfirm (doc, 1, TtaGetMessage (AMAYA, AM_BAD_TEMPLATE));
      return;
    }
  // the template document
  doc = GetTemplateDocument (t);
  // localize the new created document
  if (DontReplaceOldDoc)
    newdoc = TtaGetNextDocumentIndex ();
  else
    newdoc = basedoc;
  
  // close current undo sepquence in the template document
  if (TtaHasUndoSequence (doc))
    TtaCloseUndoSequence (doc);

  // update the charset if needed
  charsetname = TtaGetEnvString ("DOCUMENT_CHARSET");
  charset = TtaGetCharset (charsetname);
  ocharsetname = DocumentMeta[doc]->charset;
  ocharset =  TtaGetCharset (ocharsetname);
  if (charset != UNDEFINED_CHARSET &&
      DocumentMeta[doc]->charset &&
      strcmp (charsetname, DocumentMeta[doc]->charset))
    {
      TtaSetDocumentCharset (doc, charset, FALSE);
      DocumentMeta[doc]->charset = TtaStrdup (charsetname);
      SetNamespacesAndDTD (doc, FALSE);
    }

  // register the document type to open the right page model
  DocumentTypes[newdoc] = docType;
  // Generate the instance content as a copy of the template
  localFile = SaveDocumentToNewDoc(doc, newdoc, instancePath);
  Template_PrepareInstance (instancePath, newdoc, t->version, templatePath);
  Template_AddReference (t);

  // Revert template changes
  TtaSetDocumentCharset (doc, ocharset, FALSE);
  TtaFreeMemory (DocumentMeta[doc]->charset);
  DocumentMeta[doc]->charset = ocharsetname;
  // Now parse the instance
  // The xtiger PI will be added and components will be removed
  GetAmayaDoc (instancePath, NULL, basedoc, basedoc, CE_INSTANCE,
               !DontReplaceOldDoc, NULL, NULL);
  if (DocumentMeta[newdoc])
    DocumentMeta[newdoc]->method = CE_ABSOLUTE;
  // Generate the HTML document title
  root = TtaGetRootElement(newdoc);
  elType = TtaGetElementType (root);
  // get the target document type
  s = TtaGetSSchemaName (elType.ElSSchema);
  if (strcmp (s, "HTML") == 0)
    {
      // Initialize the document title
      elType.ElTypeNum = HTML_EL_TITLE;
      title = TtaSearchTypedElement (elType, SearchInTree, root);
      text = TtaGetFirstChild (title);
      while (text)
        {
          elType = TtaGetElementType (text);
          if (elType.ElTypeNum == HTML_EL_TEXT_UNIT && Answer_text[0] != EOS)
            {
              TtaSetTextContent (text, (unsigned char*)Answer_text,
                                 TtaGetDefaultLanguage (), newdoc);
              text = NULL;
              SetNewTitle (newdoc);
            }
          else if ((elType.ElTypeNum == Template_EL_useEl ||
                    elType.ElTypeNum == Template_EL_useSimple) &&
                   !strcmp (TtaGetSSchemaName (elType.ElSSchema), "Template"))
            // Ignore the template use element
            text = TtaGetFirstChild (text);
          else
            // Look for the first text child
            TtaNextSibling (&text);
        }
    }

  // Insert XTiger PI
  Template_InsertXTigerPI(newdoc, t);   
  // Parse template to fill structure and remove extra data
  ParseTemplate (t, root, newdoc, NULL, FALSE);
  TtaFreeMemory (localFile);
  TtaClearUndoHistory (newdoc);
  RemoveParsingErrors (newdoc);
  TtaSetDocumentModified (newdoc);
  UpdateTemplateMenus(newdoc);
#endif /* TEMPLATES */
}


#ifdef TEMPLATES
/*----------------------------------------------------------------------
  ProcessAttr
  Look for all "attribute" elements in the subtree and instantiate them
  ----------------------------------------------------------------------*/
static void ProcessAttr (XTigerTemplate t, Element el, Document doc)
{
  Element      child;
  ElementType  elType;

  for (child = TtaGetFirstChild (el); child; TtaNextSibling(&child))
    {
      elType = TtaGetElementType (child);
      if (elType.ElTypeNum == Template_EL_attribute &&
          !strcmp (TtaGetSSchemaName (elType.ElSSchema), TEMPLATE_SCHEMA_NAME))
        InstantiateAttribute (t, child, doc);
      else
        ProcessAttr (t, child, doc);
    }
}
#endif /* TEMPLATES */


/*----------------------------------------------------------------------
  Template_GetNewSimpleTypeInstance
  Create an new instance of xt:use/SimpleType for the document doc.
  Return the new element
  ----------------------------------------------------------------------*/
Element Template_GetNewSimpleTypeInstance(Document doc)
{
  Element           newEl = NULL;
#ifdef TEMPLATES
  ElementType       elType;
  const char       *empty = " ";

  elType.ElSSchema = TtaGetSSchema("Template", doc);
  elType.ElTypeNum = Template_EL_TEXT_UNIT;
  newEl = TtaNewElement (doc, elType);
  TtaSetTextContent (newEl, (unsigned char*) empty, 0, doc);
#endif /* TEMPLATES */
  return newEl;
}

/*----------------------------------------------------------------------
  Template_GetNewXmlElementInstance
  Create an new instance of xt:use/XmlElement for the document doc.
  The parameter decl gives the type of the element of new element.
  Return the new element
  ----------------------------------------------------------------------*/
Element Template_GetNewXmlElementInstance(Document doc, Declaration decl)
{
  Element           newEl = NULL;
#ifdef TEMPLATES
  ElementType       elType;

  GIType (decl->name, &elType, doc);
  if (elType.ElTypeNum != 0)
    newEl = TtaNewTree (doc, elType, "");
#endif /* TEMPLATES */
  return newEl;
}


/*----------------------------------------------------------------------
  InsertWithNotify applies pre and post functions when inserting the new
  element el after child (if not NULL) or as first child of parent.
  ----------------------------------------------------------------------*/
Element InsertWithNotify (Element el, Element child, Element parent, Document doc)
{
  ElementType      elType;
  NotifyElement    event;
  char            *name;
  ThotBool         isRow = FALSE, isCell = FALSE;
  ThotBool         isImage = FALSE;
  ThotBool         oldStructureChecking;

  // avoid to check attributes now
  oldStructureChecking = TtaGetStructureChecking (doc);
  TtaSetStructureChecking (FALSE, doc);

  elType = TtaGetElementType (el);
  name = TtaGetSSchemaName (elType.ElSSchema);
  isCell = ((!strcmp (name,"HTML") &&
             elType.ElTypeNum == HTML_EL_Data_cell ||
             elType.ElTypeNum == HTML_EL_Heading_cell) ||
            (!strcmp (name,"MathML") && elType.ElTypeNum == MathML_EL_MTD));
  isRow = ((!strcmp (name,"HTML") && elType.ElTypeNum == HTML_EL_Table_row) ||
           (!strcmp (name,"MathML") &&
            (elType.ElTypeNum == MathML_EL_MTR ||
             elType.ElTypeNum == MathML_EL_MLABELEDTR)));
  isImage = (!strcmp (name,"HTML") && 
              (elType.ElTypeNum == HTML_EL_IMG || elType.ElTypeNum == HTML_EL_Object));
  if (child)
    TtaInsertSibling (el, child, FALSE, doc);
  else
    TtaInsertFirstChild (&el, parent, doc);
  TtaSetStructureChecking (oldStructureChecking, doc);

  if (isImage)
    InsertImageOrObject (el, doc);
  else if (isCell)
    {
      // a cell is created
      NewCell (el, doc, TRUE, TRUE, TRUE);
    }
  else if (isRow)
    {
      // a row is created
      event.element = el;
      event.document = doc;
      RowPasted (&event);
    }
  
  if (!strcmp (name,"HTML"))
    {
      // special management for images and objets
      elType.ElTypeNum = HTML_EL_IMG;
      child = TtaSearchTypedElement (elType, SearchInTree, el);
      while (child)
        {
          InsertImageOrObject (child, doc);
          child = TtaSearchTypedElementInTree (elType, SearchForward, el, child);
        }
      elType.ElTypeNum = HTML_EL_Object;
      child = TtaSearchTypedElement (elType, SearchInTree, el);
      while (child)
        {
          InsertImageOrObject (child, doc);
          child = TtaSearchTypedElementInTree (elType, SearchForward, el, child);
        }
    }
  return el;
}


/*----------------------------------------------------------------------
  Template_InsertUseChildren
  Insert children to a xt:use
  The dec parameter must be valid and will not be verified. It must be a
    direct child element (for union elements).
  @param el element (xt:use) in which insert a new element
  @param dec Template declaration of the element to insert
  @return The inserted element (the xt:use element if insertion is multiple as component)
  The parentLine parameter points to the enclosing line if any.
  ----------------------------------------------------------------------*/
Element Template_InsertUseChildren (Document doc, Element el, Declaration dec,
                                    Element parentLine, ThotBool registerUndo)
{
  Element         newEl = NULL;
#ifdef TEMPLATES
  Element         current = NULL;
  Element         child = NULL, prev, next;
  ElementType     childType, elType; 
  SSchema         sshtml;
  XTigerTemplate  t;
  
  if (TtaGetDocumentAccessMode(doc))
  {
    switch (dec->nature)
    {
      case SimpleTypeNat:
        newEl = Template_GetNewSimpleTypeInstance(doc);
        newEl = InsertWithNotify (newEl, NULL, el, doc);
        break;
      case XmlElementNat:
        newEl = Template_GetNewXmlElementInstance(doc, dec);
        newEl = InsertWithNotify (newEl, NULL, el, doc);
        break;
      case ComponentNat:
        newEl = TtaCopyTree(dec->componentType.content, doc, doc, el);
        ProcessAttr (dec->usedIn, newEl, doc);
        elType = TtaGetElementType (el);
        /* Copy elements from new use to existing use. */
#ifdef TEMPLATE_DEBUG
        DumpSubtree(newEl, doc, 0);
#endif /* TEMPLATE_DEBUG */
        sshtml = TtaGetSSchema ("HTML", doc);
        t = GetXTigerDocTemplate( doc);
        child = TtaGetFirstChild  (newEl);
        while (child)
          {
            // move the new subtree to the document
            TtaRemoveTree (child, doc);
            childType = TtaGetElementType (child);
            if (parentLine)
              {
                if (childType.ElSSchema == sshtml &&
                    childType.ElTypeNum == HTML_EL_Pseudo_paragraph)
                  {
                    prev = TtaGetFirstChild  (child);
                    while (prev)
                      {
                        next = prev;
                        TtaNextSibling (&next);
                        TtaRemoveTree (prev, doc);
                        current = InsertWithNotify (prev, current, el, doc);
                        prev = next;
                      }
                    TtaDeleteTree (child, doc);
                  }
                else
                  current = InsertWithNotify (child, current, el, doc);
              }
            else
              {
                current = InsertWithNotify (child, current, el, doc);
                // check if a new paragraph is inserted
                if (childType.ElSSchema == sshtml &&
                    childType.ElTypeNum == HTML_EL_Paragraph)
                  Template_SetInline (child, elType.ElSSchema, doc, registerUndo);
                else
                  {
                    childType.ElSSchema = sshtml;
                    childType.ElTypeNum = HTML_EL_Paragraph;
                    child = TtaSearchTypedElement (childType, SearchInTree, current);
                    while (child)
                      {
                        Template_SetInline (child, elType.ElSSchema, doc, registerUndo);
                        child = TtaSearchTypedElement (childType, SearchInTree, child);
                      }
                  }
              }
            child = TtaGetFirstChild (newEl);
          }

        TtaDeleteTree (newEl, doc);
        newEl = el;
        break;
      default :
        //Impossible
        break;   
    }
    Template_FixAccessRight (dec->usedIn, el, doc);
    if (dec->nature == ComponentNat)
      Component_FixAccessRight (el, doc);
    TtaUpdateAccessRightInViews (doc, el);
  }  
#endif /* TEMPLATES */
  return newEl;
}


/*----------------------------------------------------------------------
  Component_FixAccessRight locks children of the component
  ----------------------------------------------------------------------*/
void Component_FixAccessRight (Element el, Document doc)
{
#ifdef TEMPLATES
  Element     child;
  
  if (el && doc)
    {
      TtaSetAccessRight (el, ReadOnly, doc);
      // fix access right to children
      child = TtaGetFirstChild (el);
      while (child)
        {
          TtaSetAccessRight (child, ReadOnly, doc);
          TtaNextSibling (&child);
        }
    }
#endif /* TEMPLATES */
}

/*----------------------------------------------------------------------
  Template_FixAccessRight fixes access rights of the el element
  ----------------------------------------------------------------------*/
void Template_FixAccessRight (XTigerTemplate t, Element el, Document doc)
{
#ifdef TEMPLATES
  ElementType elType;
  Element     child;
  Declaration decl;
  char        currentType[MAX_LENGTH], *ptr;
  
  if (t && el && doc)
    {
      elType = TtaGetElementType(el);
      if (elType.ElSSchema == TtaGetSSchema ("Template", doc))
        {
          switch (elType.ElTypeNum)
            {
            case Template_EL_TEXT_UNIT:
              //TtaSetAccessRight( el, ReadWrite, doc);
              return;
            case Template_EL_component:
              Component_FixAccessRight (el, doc);
              break;
            case Template_EL_useEl:
            case Template_EL_useSimple:
              GiveAttributeStringValueFromNum(el, Template_ATTR_currentType,
                                              (char*)currentType, NULL);
              if (currentType[0] == EOS)
                {
                  GiveAttributeStringValueFromNum(el, Template_ATTR_types,
                                                  (char*)currentType, NULL);
                  ptr = strstr (currentType, " ");
                  if (ptr)
                    *ptr = EOS;
                }
              decl = Template_GetDeclaration(t, currentType);
              if (decl)
                {
                  switch (decl->nature)
                    {
                      case SimpleTypeNat:
                        TtaSetAccessRight (el, ReadWrite, doc);
                        return;
                      case ComponentNat:
                        TtaSetAccessRight (el, ReadOnly, doc);
                         break;
                        //Component_FixAccessRight (el, doc);
                        //return;
                      case XmlElementNat:
                        if (TtaIsSetReadOnly (el))
                          break;
                        child = TtaGetFirstChild (el);
                        if (child)
                          TtaSetAccessRight (child, ReadWrite, doc);
                      default:
                        TtaSetAccessRight (el, ReadOnly, doc);
                         break;
                    }
                }
              break;
            case Template_EL_bag:
            case Template_EL_repeat:
              TtaSetAccessRight(el, ReadWrite, doc);
              break;
            default:
              TtaSetAccessRight(el, ReadOnly, doc);
              break;
            }
        }

      // fix access right to children
      child = TtaGetFirstChild (el);
      while (child)
        {
          Template_FixAccessRight (t, child, doc);
          TtaNextSibling (&child);
        }
    }
#endif /* TEMPLATES */
}

/*----------------------------------------------------------------------
  AddPromptIndicator
  ----------------------------------------------------------------------*/
void AddPromptIndicator (Element el, Document doc)
{
#ifdef TEMPLATES
  ElementType         elType;
  AttributeType       attrType;
  Attribute           att;

  if (el)
    {
      elType = TtaGetElementType (el);
      attrType.AttrSSchema = elType.ElSSchema;
      attrType.AttrTypeNum = Template_ATTR_prompt;
      att = TtaGetAttribute (el, attrType);
      if (att == NULL)
        {
          att = TtaNewAttribute (attrType);
          TtaAttachAttribute (el, att, doc);
        }
    }
#endif /* TEMPLATES */
}

/*----------------------------------------------------------------------
  Template_SetInline manages inline elements
  registerUndo says if changes must be registered
  ----------------------------------------------------------------------*/
void Template_SetInline (Element el, SSchema sstempl, Document doc, ThotBool registerUndo)
{
#ifdef TEMPLATES
  Element         child = NULL;
  ElementType     elType1, elType2, elType3;

  if (el)
    {
      elType1 = TtaGetElementType (el);
      if (elType1.ElSSchema == sstempl)
        // apply to hte current template element
        SetAttributeIntValue (el, Template_ATTR_SetInLine,
                              Template_ATTR_SetInLine_VAL_Yes_, registerUndo);
      else
        elType1.ElSSchema = sstempl;
      elType1.ElTypeNum = Template_EL_useSimple;
      elType2.ElTypeNum = Template_EL_useEl;
      elType2.ElSSchema = elType1.ElSSchema;
      elType3.ElTypeNum = Template_EL_repeat;
      elType3.ElSSchema = elType1.ElSSchema;
      child = TtaSearchElementAmong5Types (elType1, elType2, elType3, elType3, elType3,
                                           SearchForward, el);
      while (child && TtaIsAncestor (child, el))
        {
          SetAttributeIntValue (child, Template_ATTR_SetInLine,
                                Template_ATTR_SetInLine_VAL_Yes_, registerUndo);
          child = TtaSearchElementAmong5Types (elType1, elType2,
                                               elType3, elType3, elType3,
                                               SearchForward, child);
        }
    }
#endif /* TEMPLATES */
}

/*----------------------------------------------------------------------
  InstantiateUse intantiate the use element el.
  The parentLine parameter points to the enclosing line if any.
  ----------------------------------------------------------------------*/
Element InstantiateUse (XTigerTemplate t, Element el, Document doc,
                        Element parentLine, ThotBool registerUndo)
{
#ifdef TEMPLATES
  Element          child = NULL;
  ElementType      elType;
  Declaration      dec;
  int              size, nbitems, i, option;
  struct menuType  *items;
  char             *types;
  ThotBool          oldStructureChecking, hidden;

  if (!t)
    return NULL;

  /* get the value of the "types" attribute */
  elType = TtaGetElementType (el);
  types = GetAttributeStringValueFromNum (el, Template_ATTR_types, &size);
  if (!types || types[0] == EOS)
    {
      TtaFreeMemory (types);
      return NULL;
    }
  if (!strcmp (types, "string") || !strcmp (types, "number"))
    {
      child = TtaGetFirstChild (el);
      if (child == NULL)
        {
          child = Template_GetNewSimpleTypeInstance(doc);
          child = InsertWithNotify (child, NULL, el, doc);
        }
      AddPromptIndicator (el, doc);
    }
  else
    {
      giveItems (types, size, &items, &nbitems);
      // No structure checking
      oldStructureChecking = TtaGetStructureChecking (doc);
      TtaSetStructureChecking (FALSE, doc);
      hidden = ElementIsOptional (el);
      if (hidden)
        {
          // check the current option value
          option = GetAttributeIntValueFromNum (el, Template_ATTR_option);
          hidden = (option == Template_ATTR_option_VAL_option_unset);
        }
      if (nbitems == 1 || !hidden)
        /* only one type in the "types" attribute */
        {
          dec = Template_GetDeclaration (t, items[0].label);
          if (dec)
            child = Template_InsertUseChildren (doc, el, dec, parentLine, registerUndo);
          if (nbitems == 1 && elType.ElTypeNum != Template_EL_useSimple)
            {
              TtaChangeTypeOfElement (el, doc, Template_EL_useSimple);
              if (registerUndo)
                TtaRegisterElementTypeChange (el, Template_EL_useEl, doc);
            }
        }
      else
        {
          // insert almost a pseudo element
          elType.ElTypeNum = Template_EL_TemplateObject;
          child = TtaNewElement (doc, elType);
          TtaInsertFirstChild (&child, el, doc);
        }

      for (i = 0; i < nbitems; i++)
        TtaFreeMemory(items[i].label);
      TtaFreeMemory(items);

      if (parentLine)
        // display the element in line
        Template_SetInline (el, elType.ElSSchema, doc, registerUndo);
      TtaSetStructureChecking (oldStructureChecking, doc);
    }
  TtaFreeMemory (types);
  Template_FixAccessRight (t, el, doc);
  TtaUpdateAccessRightInViews (doc, el);
  return child;
#else /* TEMPLATES */
  return NULL;
#endif /* TEMPLATES */
}

/*----------------------------------------------------------------------
  InstantiateRepeat
  Check for min and max param and validate xt:repeat element content.
  @param registerUndo True to register undo creation sequences.
  The parentLine parameter points to the enclosing line if any.
  ----------------------------------------------------------------------*/
void InstantiateRepeat (XTigerTemplate t, Element el, Document doc,
                        Element parentLine, ThotBool registerUndo)
{
#ifdef TEMPLATES
  Element        child, newChild;
  ElementType    newElType;
  Attribute      minAtt,  maxAtt;
  AttributeType  minType, maxType;
  char          *text, *types = NULL, *title = NULL;
  int            curVal, minVal,  maxVal;
  int            childrenCount;

  if (!t)
    return;

  //Preparing types
  minType.AttrSSchema = TtaGetSSchema (TEMPLATE_SCHEMA_NAME, doc);
  minType.AttrTypeNum = Template_ATTR_minOccurs;
  maxType.AttrSSchema =  minType.AttrSSchema;
  maxType.AttrTypeNum = Template_ATTR_maxOccurs;
  newElType.ElSSchema = minType.AttrSSchema;
  //Get minOccurs and maxOccurs attributes
  minAtt = TtaGetAttribute (el, minType);
  maxAtt = TtaGetAttribute (el, maxType);
  //Get the values
  if (minAtt)
    {
      text = GetAttributeStringValue(el, minAtt, NULL);
      if (text)
        {
          minVal = atoi(text);
          TtaFreeMemory(text);
          curVal = minVal;
        }
      else
        //Error : Attribute with no value
        return;
    }
  else
    {
      minVal = 0;
      curVal = 1;
    }

  if (maxAtt)
    {
      text = GetAttributeStringValue (el, maxAtt, NULL);
      if (text)
        {
          if (!strcmp (text, "*"))
            maxVal = INT_MAX;
          else
            maxVal = atoi (text);
          TtaFreeMemory (text);
        }
      else
        //Error : Attribute with no value
        return;
    }
  else
    maxVal = INT_MAX;

  text = (char*)TtaGetMemory(MAX_LENGTH);
  //Create non existing min max attributes
  if (minAtt == NULL)
    {      
      minAtt = TtaNewAttribute (minType);
      sprintf (text, "%d", minVal);
      TtaAttachAttribute (el, minAtt, doc);
      TtaSetAttributeText (minAtt, text, el, doc);
      if (registerUndo)
        TtaRegisterAttributeCreate (minAtt, el, doc);
    }

  if (maxAtt == NULL)
    {  
      maxAtt = TtaNewAttribute (maxType);
      if (maxVal < INT_MAX)
        sprintf(text, "%d", maxVal);
      else
        sprintf (text, "*");
      TtaAttachAttribute (el, maxAtt, doc);      
      TtaSetAttributeText (maxAtt, text, el, doc);
      if (registerUndo)
        TtaRegisterAttributeCreate (maxAtt, el, doc);
    }
  TtaFreeMemory(text);

  //We must have minOccurs children
  child = TtaGetFirstChild (el);
  if (!child)
    //Error : a repeat must have at least one child which will be the model
    return;
  
  for (childrenCount = 0; child; TtaNextSibling(&child))
    //TODO : Check that every child is valid
    childrenCount ++;

  if (childrenCount > maxVal)
    //Error : too many children!
    return;  


  if (parentLine)
    // display the element in line
    Template_SetInline (el, minType.AttrSSchema, doc, registerUndo);

  child = TtaGetLastChild(el);
  types = GetAttributeStringValueFromNum (child, Template_ATTR_types, NULL);
  title = GetAttributeStringValueFromNum (child, Template_ATTR_title, NULL);
  newElType.ElTypeNum = Template_EL_useEl;
  while (childrenCount < curVal)
    {
      newChild = TtaNewElement (doc, newElType);
      // Insert it
      TtaInsertSibling (newChild, child, FALSE, doc);
      SetAttributeStringValueWithUndo (newChild, Template_ATTR_types, types);
      SetAttributeStringValueWithUndo (newChild, Template_ATTR_title, title);
      InstantiateUse (t, newChild, doc, parentLine, TRUE);
      
      if (registerUndo)
        TtaRegisterElementCreate (newChild, doc);
      child = newChild;
      childrenCount++;
    }
    
  Template_FixAccessRight (t, el, doc);
  TtaUpdateAccessRightInViews (doc, el);
  TtaFreeMemory (types);
  TtaFreeMemory (title);
#endif /* TEMPLATES */
}

/*----------------------------------------------------------------------
  Template_InsertXTigerPI
  Insert the XTiger PI element in template instance.
  Param t is the XTigerTemplate structure of the template,
  not the template instance one.
  ----------------------------------------------------------------------*/
void Template_InsertXTigerPI(Document doc, XTigerTemplate t)
{
#ifdef TEMPLATES
  ElementType     elType;
  Element         root, piElem, doctype, line, text, elNew, elFound;
  char           *s, *charsetname = NULL, buffer[MAX_LENGTH];
  int             pi_type;

  if (!t || !doc)
    return;

  root =  TtaGetMainRoot (doc);
  if (root == NULL)
    return;
  //Look for PIs
  /* check if the document has a DOCTYPE declaration */
#ifdef ANNOTATIONS
  if (DocumentTypes[doc]  == docAnnot)
    elType = TtaGetElementType (root);
  else
#endif /* ANNOTATIONS */
    elType = TtaGetElementType (root);
  s = TtaGetSSchemaName (elType.ElSSchema);
  if (strcmp (s, "HTML") == 0)
    {
      elType.ElTypeNum = HTML_EL_DOCTYPE;
      pi_type = HTML_EL_XMLPI;
    }
#ifdef _SVG
  else if (strcmp (s, "SVG") == 0)
    {
      elType.ElTypeNum = SVG_EL_DOCTYPE;
      pi_type = SVG_EL_XMLPI;
    }
#endif /* _SVG */
  else if (strcmp (s, "MathML") == 0)
    {
      elType.ElTypeNum = MathML_EL_DOCTYPE;
      pi_type = MathML_EL_XMLPI;
    }
  else
    {
      elType.ElTypeNum = XML_EL_doctype;
      pi_type = XML_EL_xmlpi;
    }

  doctype = TtaSearchTypedElement (elType, SearchInTree, root);
  if (doctype == NULL)
    {
      elType.ElTypeNum = pi_type;      
      piElem = TtaSearchTypedElement (elType, SearchInTree, root);
      if (piElem == NULL)
        {
          /* generate the XML declaration */
          /* Check the Thot abstract tree against the structure schema. */
          TtaSetStructureChecking (FALSE, doc);
          piElem = TtaNewTree (doc, elType, "");
          TtaInsertFirstChild (&piElem, root, doc);
          line = TtaGetFirstChild (piElem);
          text = TtaGetFirstChild (line);
          strcpy (buffer, "xml version=\"1.0\" encoding=\"");
          charsetname = UpdateDocumentCharset (doc);
          strcat (buffer, charsetname);
          strcat (buffer, "\"");
          TtaSetTextContent (text, (unsigned char*)buffer,  Latin_Script, doc);
          TtaSetStructureChecking (TRUE, doc);
          TtaFreeMemory (charsetname);
          TtaRegisterElementCreate (piElem, doc);
        }
    }
  
  /* generate the XTiger PI */
  /* Check the Thot abstract tree against the structure schema. */
  TtaSetStructureChecking (FALSE, doc);
  elType.ElTypeNum = pi_type;
  elNew = TtaNewTree (doc, elType, "");
  if (doctype)
    TtaInsertSibling (elNew, doctype, FALSE, doc);
  else
    TtaInsertSibling (elNew, piElem, FALSE, doc);
  line = TtaGetFirstChild (elNew);
  text = TtaGetFirstChild (line);
  strcpy (buffer, "xtiger template=\"");
  if (t->uri)
    strcat (buffer, t->uri);
  else if (t->base_uri)
    strcat (buffer, t->uri);
  strcat (buffer, "\" version=\"");
  if (t->version)
    strcat (buffer, t->version);
  else
    strcat (buffer, "0.8");
  strcat (buffer, "\"");
  if (t->templateVersion)
    {
      strcat (buffer, " templateVersion=\"");
      strcat (buffer, t->templateVersion);
      strcat (buffer, "\"");
    }
  TtaSetTextContent (text, (unsigned char*)buffer,  Latin_Script, doc);
  TtaRegisterElementCreate (elNew, doc);
  TtaSetStructureChecking (TRUE, doc);

  // update the document title
  if (!strcmp (s, "HTML"))
    {
      elType.ElTypeNum = HTML_EL_TITLE;
      elFound = TtaSearchTypedElement (elType, SearchInTree, root);
      text = TtaGetFirstChild (elFound);
      while (text)
        {
          elType = TtaGetElementType (text);
          if (elType.ElTypeNum == HTML_EL_TEXT_UNIT && Answer_text[0] != EOS)
            {
              TtaRegisterElementReplace (text, doc);
              TtaSetTextContent (text, (unsigned char*)Answer_text,
                                 TtaGetDefaultLanguage (), doc);
              text = NULL;
            }
          else if ((elType.ElTypeNum == Template_EL_useEl ||
                    elType.ElTypeNum == Template_EL_useSimple) &&
                   !strcmp (TtaGetSSchemaName (elType.ElSSchema), "Template"))
            // Ignore the template use element
            text = TtaGetFirstChild (text);
          else
            // Look for the first text child
            TtaNextSibling (&text);
        }
    }
#endif /* TEMPLATES */
}


/*----------------------------------------------------------------------
  Template_PreInstantiateComponents
  Instantiates all components in order to improve editing.
  ----------------------------------------------------------------------*/
void Template_PreInstantiateComponents (XTigerTemplate t)
{
#ifdef TEMPLATES 
  ForwardIterator iter;
  Declaration     dec;
  SearchSetNode   node;

  if (!t)
    return;

  if (Template_IsInstance (t))
    {
#ifdef TEMPLATE_DEBUG
      DumpAllDeclarations();
#endif /* TEMPLATE_DEBUG */  
      iter = SearchSet_GetForwardIterator(GetComponents(t));
#ifdef TEMPLATE_DEBUG
      printf("Template_PreInstantiateComponents %s\n", t->uri);
#endif /* TEMPLATE_DEBUG */  
      ITERATOR_FOREACH(iter, SearchSetNode, node)
        {
          dec = (Declaration) node->elem;
          ParseTemplate(t, GetComponentContent(dec), GetTemplateDocument(t), NULL, TRUE);
        }
      TtaFreeMemory(iter);
    }
#endif /* TEMPLATES */
}

/*----------------------------------------------------------------------
  Template_SetName
  Set the xt:component or xt:union element xt:name attribute.
  Make it unique.
  Return TRUE if the name is not modified.
  ----------------------------------------------------------------------*/
ThotBool Template_SetName (Document doc, Element el, const char *name, ThotBool withUndo)
{
#ifdef TEMPLATES 
  AttributeType attType;
  Attribute     attr;
  ThotBool      res, res2;

  if (doc && el && name)
    {
      attType.AttrSSchema = TtaGetElementType(el).ElSSchema;
      attType.AttrTypeNum = Template_ATTR_name;
      attr = TtaGetAttribute(el, attType);
      if (attr == NULL)
        {
          attr = TtaNewAttribute (attType);
          TtaAttachAttribute (el, attr, doc);
          if (withUndo)
            TtaRegisterAttributeCreate (attr, el, doc);
        }
      if (withUndo)
         TtaRegisterAttributeReplace(attr, el, doc);
      TtaSetAttributeText (attr, name, el, doc);
      res = TtaIsValidID (attr, TRUE);
      res2 = !MakeUniqueName(el, doc, TRUE, FALSE);
      return (res || res2);
    }
#endif /* TEMPLATES */
  return FALSE;
}

/*----------------------------------------------------------------------
  Template_SetName
  Set the xt:component or xt:union element xt:name attribute.
  Make it unique.
  Return TRUE if the name is not modified.
  ----------------------------------------------------------------------*/
ThotBool Template_SetLabel (Document doc, Element el, const char *label, ThotBool withUndo)
{
#ifdef TEMPLATES 
  AttributeType attType;
  Attribute     attr;

  if (doc && el && label)
    {
      attType.AttrSSchema = TtaGetElementType(el).ElSSchema;
      attType.AttrTypeNum = Template_ATTR_title;
      attr = TtaGetAttribute(el, attType);
      if (attr == NULL)
        {
          attr = TtaNewAttribute (attType);
          TtaAttachAttribute (el, attr, doc);
          if (withUndo)
            TtaRegisterAttributeCreate (attr, el, doc);
        }
      if (withUndo)
         TtaRegisterAttributeReplace(attr, el, doc);
      TtaSetAttributeText (attr, label, el, doc);
      return TtaIsValidID (attr, TRUE);
    }
#endif /* TEMPLATES */
  return FALSE;
}


Webmaster