/*
*
* 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