File:  [Public] / Amaya / amaya / insertelem.c
Revision 1.20: download - view: text, annotated - select for diffs
Thu Nov 15 13:45:59 2007 UTC (16 years, 7 months ago) by vatton
Branches: MAIN
CVS tags: HEAD
Fixing a problem with the selection after insertion into a XTiger bag
Irene

/*
 *
 *  COPYRIGHT INRIA and W3C, 1996-2007
 *  Please first read the full copyright statement in file COPYRIGHT.
 *
 */
 
/*
 * Authors: Emilien Kia
 *
 */

#define THOT_EXPORT extern
#include "amaya.h"
#include "document.h"

#include "containers.h"
#include "Elemlist.h"

#ifdef TEMPLATES
#include "Template.h"
#include "templates.h"
#include "templates_f.h"
#include "templateDeclarations.h"

#include "templateLoad_f.h"
#include "templateDeclarations_f.h"
#include "templateInstantiate_f.h"
#include "templateUtils_f.h"
#include "appdialogue_wx.h"
#include "init_f.h"
#include "wxdialogapi_f.h"
#include "AHTURLTools_f.h"

#endif /* TEMPLATES */


#include "fetchXMLname_f.h"
#include "MENUconf.h"
#include "parser.h"
#include "fetchXMLname_f.h"

typedef struct _sInsertableElementList *InsertableElementList;
typedef struct _sInsertableElementList
{
  /** Current selected element.*/
  Element elem;
  /** Insertable element list.*/
  DLList list;
} sInsertableElementList;


static HashMap InsertableElementMap = NULL;


/*----------------------------------------------------------------------
  ----------------------------------------------------------------------*/
static InsertableElementList InsertableElementList_Create(Element elem, DLList list)
{
  InsertableElementList lst = (InsertableElementList)TtaGetMemory(sizeof(sInsertableElementList));
  lst->elem = elem;
  lst->list = list;
  return lst; 
}

static void InsertableElementList_Destroy(InsertableElementList list)
{
  if (list->list)
    DLList_Destroy(list->list);
  TtaFreeMemory(list);
}

/*----------------------------------------------------------------------
  InsertableElement_Init
  Initialize the module.
  ----------------------------------------------------------------------*/
void InsertableElement_Init()
{
  if (!InsertableElementMap)
    InsertableElementMap = PointerHashMap_Create((Container_DestroyElementFunction)InsertableElementList_Destroy, 32);
}

/*----------------------------------------------------------------------
  InsertableElement_Final
  Finalize the module.
  ----------------------------------------------------------------------*/
void InsertableElement_Final()
{
  if (InsertableElementMap)
  {
    HashMap_Destroy(InsertableElementMap);
    InsertableElementMap = NULL;
  }
}


#ifdef TEMPLATES
/*----------------------------------------------------------------------
  FillUnionResolvedPossibleElement
  Fill an element list with all possible element, resolving them if union.
  @param name Element name
  @param elem Document element to attach
  @param resolvedPath Path of different succesive union name.
  @param list List to fill.
  ----------------------------------------------------------------------*/
static void FillUnionResolvedPossibleElement(XTigerTemplate t, const char* name,
                                             Element elem, const char* resolvedPath,
                                             DLList list, int level)
{
  Declaration dec = Template_GetDeclaration (t, name);
  Document    doc = TtaGetDocument(elem);
  if (dec == NULL)
    return;
  
  if (dec->nature==ComponentNat)
  {
    DLList_Append(list, ElemListElement_CreateComponent(level, dec->name, (void*)dec,
                                                        resolvedPath, elem));
  }
  else if (dec->nature==UnionNat)
  {
    DLList          tempList = ElemList_Create();
    ForwardIterator iter = HashMap_GetForwardIterator(dec->unionType.include);
    HashMapNode     mapnode;
    DLListNode      listnode;

    int len1 = 0 , len2 = strlen(dec->name);
    if (resolvedPath!=NULL)
      len1 = strlen(resolvedPath);
    char* newPath = (char*)TtaGetMemory(len1+len2+2);
    if (len1 > 0)
    {
      strcpy(newPath, resolvedPath);
      newPath[len1] = '/';
      strcpy(newPath+len1+1, dec->name);
    }
    else
    {
      strcpy(newPath, dec->name);
    }
    
    ITERATOR_FOREACH(iter, HashMapNode, mapnode)
      {
        FillUnionResolvedPossibleElement(t, (char*)mapnode->key, elem, newPath, tempList, level);
      }
    TtaFreeMemory(iter);
    
    iter = DLList_GetForwardIterator(tempList);
    
    
    listnode = (DLListNode) ForwardIterator_GetFirst(iter);
    ITERATOR_FOREACH(iter, DLListNode, listnode)
      DLList_Append(list, listnode->elem);
    TtaFreeMemory(iter);

    tempList->destroyElement = NULL;
    DLList_Destroy(tempList);
    
    TtaFreeMemory(newPath);
    
    /** todo Remove excluded elements.*/
  }
  else if (dec->nature==SimpleTypeNat)
  {
    DLList_Append(list, ElemListElement_CreateBaseType(level, dec->name, resolvedPath,
                                                       elem));
    /* Do nothing. */
  }
  else
  {
    /* Search in tgt std elements. */
    int xmlType; /* See parser.h */
    for(xmlType=XHTML_TYPE; xmlType<Template_TYPE; xmlType++)
    {
      ElementType elType = {0,0};
      char*       mappedName;
      char       content;
      ThotBool    checkProfile;
      MapXMLElementType(xmlType, dec->name, &elType, &mappedName, &content,
                        &checkProfile, doc);
      if (elType.ElTypeNum!=0)
      {
        if(TemplateCanInsertFirstChild(elType, elem, doc))
          DLList_Append(list, ElemListElement_CreateLanguageElement(level, elType,
                                                                  resolvedPath, elem));
        break;
      }
    }
  }
}

/*----------------------------------------------------------------------
  FillInsertableElementFromElemAttribute
  Fill an element list with all possible elements from an attribute list.
  ----------------------------------------------------------------------*/
static void FillInsertableElementFromElemAttribute (XTigerTemplate t,
                                                    Element elem, Element refelem,
                                                    int attrib, DLList list, int level)
{
  ElementType     type = TtaGetElementType(elem);
  AttributeType   attributeType = {type.ElSSchema, attrib};
  Attribute       att = TtaGetAttribute (elem, attributeType);
  int             size = TtaGetTextAttributeLength (att);
  char*           types = (char *) TtaGetMemory (size+1); 

  TtaGiveTextAttributeValue (att, types, &size);
  
  HashMap         basemap = KeywordHashMap_CreateFromList(NULL, -1, types);
  HashMap         map     = Template_ExpandHashMapTypes(t, basemap);
  ForwardIterator iter;
  HashMapNode     node;
   
  iter = HashMap_GetForwardIterator(map);
  ITERATOR_FOREACH(iter, HashMapNode, node)
    {
      FillUnionResolvedPossibleElement(t, (const char*)node->key, refelem, NULL, list, level);
    }
  HashMap_Destroy (map);
  HashMap_Destroy (basemap);
  
  TtaFreeMemory (types);
}
#endif/* TEMPLATES */

/*----------------------------------------------------------------------
  SortInsertableElemList
  Sort a list of KeywordHashMap<Declaration> to be user friendly
  First components and then XmlElements and sorted alphabeticaly.
  ----------------------------------------------------------------------*/
static int SortInsertableElemList(ElemListElement elem1 ,ElemListElement elem2)
{
#ifdef TEMPLATES
  if(elem1->typeClass==elem2->typeClass)
      return strcmp(ElemListElement_GetName(elem1),ElemListElement_GetName(elem2));
  else
    return elem1->typeClass - elem2->typeClass;
#else  /* TEMPLATES */
  return 0;
#endif /* TEMPLATES */
}


/*----------------------------------------------------------------------
  FillInsertableElemList
  Fill an element list with all insertable elements (base element or
  XTiger comonent).
  ----------------------------------------------------------------------*/
void FillInsertableElemList (Document doc, Element elem, DLList list)
{
  ElementType      type;
  Element          parent;
#ifdef TEMPLATES
  Element          child;
  ElementType      childType;
  XTigerTemplate   t;
  ThotBool         haveAncestorBag = FALSE;
#endif/* TEMPLATES */
  int level;
  ThotBool cont = TRUE;

  if (elem)
  {
    if (doc==0)
      doc = TtaGetDocument(elem);

#ifdef TEMPLATES
    t = GetXTigerTemplate(DocumentMeta[doc]->template_url);

    if (!IsTemplateElement(elem))
      elem = GetFirstTemplateParentElement(elem);

    // Search for first xt:bag ancestor.
    parent = elem;
    while (parent!= NULL && cont)
      {
        type = TtaGetElementType(parent);
        if (type.ElTypeNum == Template_EL_bag)
          {
            haveAncestorBag = TRUE;
            cont = FALSE;
          }
        parent = GetFirstTemplateParentElement(parent);
      }

    level = 0;
    cont = TRUE;

    // Process for each ancestor.
    while (elem!=NULL && cont)
    {
      type = TtaGetElementType(elem);
      switch(type.ElTypeNum)
        {
        case Template_EL_repeat:
          child = TtaGetFirstChild(elem);
          childType = TtaGetElementType(child);
          switch(childType.ElTypeNum)
          {
            case Template_EL_useEl:
            case Template_EL_useSimple:
            case Template_EL_bag:
              FillInsertableElementFromElemAttribute(t, child, elem,
                                                     Template_ATTR_types, list, level);
              break;
            default:
              break;
          }
          cont = FALSE; //haveAncestorBag;
          break;
        case Template_EL_useEl:
          // Fill for xt:use only if have no child.
          if (TtaGetFirstChild(elem)==NULL){
            FillInsertableElementFromElemAttribute(t, elem, elem,
                                                   Template_ATTR_types, list, level);
            cont = FALSE; //haveAncestorBag;
          }
          break;
        case Template_EL_bag:
          FillInsertableElementFromElemAttribute(t, elem, elem,
                                                 Template_ATTR_types, list, level);
          cont = FALSE;
          break;
        }
      elem = GetFirstTemplateParentElement(elem);
      level ++;
    }
#endif/* TEMPLATES */
  }
  DLList_Sort(list, (Container_CompareFunction)SortInsertableElemList);
}

/*----------------------------------------------------------------------
  InsertableElement_GetList
  Get the insertable element list for a document.
  @param doc Document
  @return The insertable element list or NULL.
  ----------------------------------------------------------------------*/
DLList InsertableElement_GetList(Document doc)
{
  InsertableElementList list;

  list = (InsertableElementList) HashMap_Get(InsertableElementMap, (void*)doc);
  if (list)
    return list->list;
  else
    return NULL;
}

/*----------------------------------------------------------------------
  InsertableElement_Update
  Update the insertable element list for a document.
  @param el Selected element, cant be NULL.
  @param document Document, can be NULL.
  @return List of insertable elements.
  ----------------------------------------------------------------------*/
DLList InsertableElement_Update(Document doc, Element el)
{
  InsertableElementList list;

  if (doc == 0)
    doc= TtaGetDocument (el);
  list = (InsertableElementList) HashMap_Get (InsertableElementMap, (void*)doc);
  if (list == NULL)
  {
    list = InsertableElementList_Create (0, DLList_Create());
    HashMap_Set (InsertableElementMap, (void*)doc, list);
  }
  
  DLList_Empty (list->list);
  FillInsertableElemList (doc, el, list->list);
  list->elem = el;
  return list->list;
}

/*----------------------------------------------------------------------
  InsertableElement_ComputeList
  Update a insertable element list for a document.
  @param el Selected element, cant be NULL.
  @param document Document, can be NULL.
  @return List of insertable elements.
  ----------------------------------------------------------------------*/
DLList InsertableElement_ComputeList(Document doc, Element el)
{
  DLList list = DLList_Create();
  FillInsertableElemList (doc, el, list);
  return list;
}


/*----------------------------------------------------------------------
  InsertableElement_DoInsertElement
  Insert the specified element.
  @param el Element to insert (ElemListElement)
  ----------------------------------------------------------------------*/
void InsertableElement_DoInsertElement (void* el)
{
  ElemListElement elem = (ElemListElement) el;
  Element         ref = elem->refElem;
  ElementType     refType = TtaGetElementType (ref);
  Document        doc = TtaGetDocument (ref);
  Element         newEl = NULL;
  SSchema         templateSSchema;

#ifdef AMAYA_DEBUG
  printf("insert %s into %s\n", ElemListElement_GetName(elem),
         TtaGetElementTypeName (refType));
#endif /* AMAYA_DEBUG */

#ifdef TEMPLATES
  templateSSchema = TtaGetSSchema ("Template", doc);
  if (templateSSchema && refType.ElSSchema == templateSSchema)
  {
    switch(refType.ElTypeNum)
    {
      case Template_EL_repeat:
        if (elem->typeClass==DefinedComponent)
          newEl = Template_InsertRepeatChild (doc, ref,
                                              (Declaration)elem->elem.component.declaration,
                                              -1);
        break;
      case Template_EL_bag:
        newEl = Template_InsertBagChild (doc, ref,
                                         (Declaration)elem->elem.component.declaration,
                                         FALSE);
        break;
      default:
        break;
    }
  }
#endif /* TEMPLATES */

  if (newEl)
    TtaSelectElement (doc, newEl);
}

/*----------------------------------------------------------------------
  GetFirstChildElementTo
  Find and retrieve the first child of root element which is an ascendent
  of the leaf element.
  If leaf is a child of root, return leaf itself.
  ----------------------------------------------------------------------*/
static Element GetFirstChildElementTo(Element root, Element leaf)
{
  Element parent = TtaGetParent(leaf);
  if(root==0 || leaf==0 || parent==0)
    return 0;
  
  while(parent)
    {
      if(parent==root)
        return leaf;
      leaf = parent;
      parent = TtaGetParent(parent);
    }
  return 0;
}

/*----------------------------------------------------------------------
  InsertableElement_InsertElement
  Insert the specified element in the given document before or after the selection.
  \param el Element to insert (ElemListElement)
  \param before True if inserting before given element, false after.
  ----------------------------------------------------------------------*/
Element InsertableElement_InsertElement (ElemListElement elem, ThotBool before)
{
#ifdef TEMPLATES
  Element         ref = elem->refElem;
  ElementType     refType = TtaGetElementType (ref);
  Document        doc = TtaGetDocument (ref);
  Element         newEl = NULL, sibling = NULL;
  SSchema         templateSSchema;
  Element         sel;
  int             car1, car2;
  XTigerTemplate  t = NULL;
  Declaration     dec = NULL;

  templateSSchema = TtaGetSSchema ("Template", doc);

  if (templateSSchema && refType.ElSSchema == templateSSchema)
  {
    switch(refType.ElTypeNum)
    {
      case Template_EL_repeat:
        if(elem->typeClass==DefinedComponent)
          dec = (Declaration)elem->elem.component.declaration;
        else if (elem->typeClass==LanguageElement)
          {
            t = GetXTigerDocTemplate(TtaGetDocument(elem->refElem));
            if (t)
                dec = Template_GetElementDeclaration(t, ElemListElement_GetName(elem));
          }
        if (dec)
          {
            
            TtaGiveFirstSelectedElement(doc, &sel, &car1, &car2);
            sibling = GetFirstChildElementTo(ref, sel);
            if(sibling)
              {
                if(before)
                  TtaPreviousSibling(&sibling);
                newEl = Template_InsertRepeatChildAfter (doc, ref, dec, sibling);
              }
          }
        break;
      case Template_EL_bag:
        if(elem->typeClass==DefinedComponent)
          dec = (Declaration)elem->elem.component.declaration;
        else if (elem->typeClass==LanguageElement)
          {
            t = GetXTigerDocTemplate(TtaGetDocument(elem->refElem));
            if (t)
                dec = Template_GetElementDeclaration(t, ElemListElement_GetName(elem));
          }
        if (dec)
            newEl = Template_InsertBagChild (doc, ref, dec, before);           
        break;
      default:
        break;
    }
  }
  return newEl;
#else /* TEMPLATES */
  return NULL;
#endif /* TEMPLATES */
}


/*----------------------------------------------------------------------
  InsertableElement_QueryInsertElement(void* el, ThotBool bAfter)
  Do a InsertableElement_InsertElement with undo/redo management.
  ----------------------------------------------------------------------*/
void InsertableElement_QueryInsertElement(ElemListElement elem, ThotBool before)
{
#ifdef TEMPLATES
  Element     elSel, newEl, firstEl;
  int         firstSel, lastSel;
  Document    doc = TtaGetDocument(elem->refElem);
  
  ThotBool    oldStructureChecking;
  DisplayMode dispMode;
  
  // If document is readonly, dont do anything
  if (!TtaGetDocumentAccessMode(doc))
    return;

  TtaGiveFirstSelectedElement(doc, &elSel, &firstSel, &lastSel);

  
  dispMode = TtaGetDisplayMode (doc);
  if (dispMode == DisplayImmediately)
    /* don't set NoComputedDisplay
       -> it breaks down views formatting when Enter generates new elements  */
    TtaSetDisplayMode (doc, DeferredDisplay);

  /* Prepare insertion.*/          
  oldStructureChecking = TtaGetStructureChecking (doc);
  TtaSetStructureChecking (FALSE, doc);
  TtaOpenUndoSequence (doc, NULL, NULL, 0, 0);
  
  /* Do the insertion */
  newEl = InsertableElement_InsertElement (elem, before);
  
  /* Finish insertion.*/
  TtaCloseUndoSequence (doc);
  TtaSetDocumentModified (doc);
  TtaSetStructureChecking (oldStructureChecking, doc);
  // restore the display
  TtaSetDisplayMode (doc, dispMode);

  if (newEl)
    {
      firstEl = GetFirstEditableElement (newEl);
      if (firstEl)
        {
          TtaSelectElement (doc, firstEl);
          TtaSetStatusSelectedElement (doc, 1, firstEl);
        }
      else
        {
          TtaSelectElement (doc, newEl);
          TtaSetStatusSelectedElement (doc, 1, newEl);
        }
    }
#endif /* TEMPLATES */
}

Webmaster