Annotation of Amaya/amaya/insertelem.c, revision 1.27

1.1       kia         1: /*
                      2:  *
1.21      vatton      3:  *  COPYRIGHT INRIA and W3C, 1996-2008
1.1       kia         4:  *  Please first read the full copyright statement in file COPYRIGHT.
                      5:  *
                      6:  */
                      7:  
                      8: /*
                      9:  * Authors: Emilien Kia
                     10:  *
                     11:  */
                     12: 
                     13: #define THOT_EXPORT extern
                     14: #include "amaya.h"
                     15: #include "document.h"
                     16: 
                     17: #include "containers.h"
                     18: #include "Elemlist.h"
                     19: 
                     20: #ifdef TEMPLATES
                     21: #include "Template.h"
                     22: #include "templates.h"
                     23: #include "templates_f.h"
                     24: #include "templateDeclarations.h"
                     25: 
                     26: #include "templateLoad_f.h"
                     27: #include "templateDeclarations_f.h"
                     28: #include "templateInstantiate_f.h"
1.19      kia        29: #include "templateUtils_f.h"
1.1       kia        30: #include "appdialogue_wx.h"
                     31: #include "init_f.h"
                     32: #include "wxdialogapi_f.h"
                     33: #include "AHTURLTools_f.h"
                     34: 
                     35: #endif /* TEMPLATES */
                     36: 
                     37: 
                     38: #include "fetchXMLname_f.h"
                     39: #include "MENUconf.h"
                     40: #include "parser.h"
                     41: #include "fetchXMLname_f.h"
                     42: 
1.2       cvs        43: typedef struct _sInsertableElementList *InsertableElementList;
                     44: typedef struct _sInsertableElementList
1.1       kia        45: {
                     46:   /** Current selected element.*/
                     47:   Element elem;
                     48:   /** Insertable element list.*/
                     49:   DLList list;
1.2       cvs        50: } sInsertableElementList;
1.1       kia        51: 
                     52: 
                     53: static HashMap InsertableElementMap = NULL;
                     54: 
                     55: 
1.6       vatton     56: /*----------------------------------------------------------------------
                     57:   ----------------------------------------------------------------------*/
1.1       kia        58: static InsertableElementList InsertableElementList_Create(Element elem, DLList list)
                     59: {
                     60:   InsertableElementList lst = (InsertableElementList)TtaGetMemory(sizeof(sInsertableElementList));
                     61:   lst->elem = elem;
                     62:   lst->list = list;
                     63:   return lst; 
                     64: }
                     65: 
                     66: static void InsertableElementList_Destroy(InsertableElementList list)
                     67: {
1.8       vatton     68:   if (list->list)
1.1       kia        69:     DLList_Destroy(list->list);
                     70:   TtaFreeMemory(list);
                     71: }
                     72: 
                     73: /*----------------------------------------------------------------------
                     74:   InsertableElement_Init
                     75:   Initialize the module.
                     76:   ----------------------------------------------------------------------*/
                     77: void InsertableElement_Init()
                     78: {
1.8       vatton     79:   if (!InsertableElementMap)
1.1       kia        80:     InsertableElementMap = PointerHashMap_Create((Container_DestroyElementFunction)InsertableElementList_Destroy, 32);
                     81: }
                     82: 
                     83: /*----------------------------------------------------------------------
                     84:   InsertableElement_Final
                     85:   Finalize the module.
                     86:   ----------------------------------------------------------------------*/
                     87: void InsertableElement_Final()
                     88: {
1.8       vatton     89:   if (InsertableElementMap)
1.1       kia        90:   {
                     91:     HashMap_Destroy(InsertableElementMap);
                     92:     InsertableElementMap = NULL;
                     93:   }
                     94: }
                     95: 
                     96: 
                     97: #ifdef TEMPLATES
                     98: /*----------------------------------------------------------------------
                     99:   FillUnionResolvedPossibleElement
                    100:   Fill an element list with all possible element, resolving them if union.
                    101:   @param name Element name
                    102:   @param elem Document element to attach
                    103:   @param resolvedPath Path of different succesive union name.
                    104:   @param list List to fill.
                    105:   ----------------------------------------------------------------------*/
1.25      kia       106: static void FillUnionResolvedPossibleElement(XTigerTemplate t, Declaration dec,
1.6       vatton    107:                                              Element elem, const char* resolvedPath,
                    108:                                              DLList list, int level)
1.1       kia       109: {
1.25      kia       110:   Document    doc;
                    111:   if(t && dec && elem)
1.1       kia       112:     {
1.25      kia       113:       doc = TtaGetDocument(elem);
                    114:       if (dec->nature==ComponentNat)
                    115:         DLList_Append(list, ElemListElement_CreateComponent(level, dec->name, (void*)dec,
                    116:                                                             resolvedPath, elem));
                    117:       else if (dec->nature==UnionNat)
                    118:         {
                    119:           DLList          tempList = ElemList_Create();
                    120:           ForwardIterator iter = SearchSet_GetForwardIterator(dec->unionType.include);
                    121:           SearchSetNode   mapnode;
                    122:           DLListNode      listnode;
                    123:       
                    124:           int len1 = 0 , len2 = strlen(dec->name);
                    125:           if (resolvedPath!=NULL)
                    126:             len1 = strlen(resolvedPath);
                    127:           char* newPath = (char*)TtaGetMemory(len1+len2+2);
                    128:           if (len1 > 0)
                    129:             {
                    130:               strcpy(newPath, resolvedPath);
                    131:               newPath[len1] = '/';
                    132:               strcpy(newPath+len1+1, dec->name);
                    133:             }
                    134:           else
                    135:             strcpy(newPath, dec->name);
                    136:           
                    137:           ITERATOR_FOREACH(iter, SearchSetNode, mapnode)
                    138:             {
                    139:               FillUnionResolvedPossibleElement(t, (Declaration)mapnode->elem, elem, newPath, tempList, level);
                    140:             }
                    141:           TtaFreeMemory(iter);
                    142:           
                    143:           iter = DLList_GetForwardIterator(tempList);
                    144:           
                    145:           
                    146:           listnode = (DLListNode) ForwardIterator_GetFirst(iter);
                    147:           ITERATOR_FOREACH(iter, DLListNode, listnode)
                    148:             DLList_Append(list, listnode->elem);
                    149:           TtaFreeMemory(iter);
                    150:       
                    151:           tempList->destroyElement = NULL;
                    152:           DLList_Destroy(tempList);
                    153:           
                    154:           TtaFreeMemory(newPath);
                    155:           
                    156:           /** todo Remove excluded elements.*/
                    157:         }
                    158:       else if (dec->nature==SimpleTypeNat)
                    159:         DLList_Append(list, ElemListElement_CreateBaseType(level, dec->name, resolvedPath,
                    160:                                                            elem));
                    161:         /* Do nothing. */
                    162:       else
                    163:         {
                    164:           /* Search in tgt std elements. */
                    165:           int xmlType; /* See parser.h */
                    166:           for(xmlType=XHTML_TYPE; xmlType<Template_TYPE; xmlType++)
                    167:             {
                    168:               ElementType elType = {0,0};
                    169:               char*       mappedName;
                    170:               char       content;
                    171:               ThotBool    checkProfile;
                    172:               MapXMLElementType(xmlType, dec->name, &elType, &mappedName, &content,
                    173:                                 &checkProfile, doc);
                    174:               if (elType.ElTypeNum!=0)
                    175:                 {
                    176:                   if(TemplateCanInsertFirstChild(elType, elem, doc))
                    177:                     DLList_Append(list, ElemListElement_CreateLanguageElement(level, elType,
                    178:                                                                             resolvedPath, elem));
                    179:                   break;
                    180:                 }
                    181:             }
                    182:         }
1.1       kia       183:     }
                    184: }
                    185: 
                    186: /*----------------------------------------------------------------------
                    187:   FillInsertableElementFromElemAttribute
                    188:   Fill an element list with all possible elements from an attribute list.
                    189:   ----------------------------------------------------------------------*/
1.16      vatton    190: static void FillInsertableElementFromElemAttribute (XTigerTemplate t,
                    191:                                                     Element elem, Element refelem,
                    192:                                                     int attrib, DLList list, int level)
1.1       kia       193: {
1.26      vatton    194:   ElementType     elType = TtaGetElementType(elem);
1.21      vatton    195:   AttributeType   attributeType = {elType.ElSSchema, attrib};
1.26      vatton    196:   Attribute       att = TtaGetAttribute (elem, attributeType);
                    197: 
                    198:   if (att)
1.14      kia       199:     {
1.26      vatton    200:       int             size = TtaGetTextAttributeLength (att);
                    201:       char           *types = (char *) TtaGetMemory (size+1);
                    202:       SearchSet       set;
                    203:       ForwardIterator iter;
                    204:       SearchSetNode   node;
                    205: 
                    206:       TtaGiveTextAttributeValue (att, types, &size);
                    207:       set = Template_GetDeclarationSetFromNames(t, types, true);
                    208:       iter = SearchSet_GetForwardIterator(set);
                    209:       ITERATOR_FOREACH(iter, SearchSetNode, node)
                    210:         {
                    211:           FillUnionResolvedPossibleElement(t, (Declaration)node->elem, refelem, NULL, list, level);
                    212:         }
                    213:       SearchSet_Destroy (set);
                    214:       TtaFreeMemory (types);
1.14      kia       215:     }
1.1       kia       216: }
                    217: #endif/* TEMPLATES */
                    218: 
                    219: /*----------------------------------------------------------------------
1.19      kia       220:   SortInsertableElemList
                    221:   Sort a list of KeywordHashMap<Declaration> to be user friendly
                    222:   First components and then XmlElements and sorted alphabeticaly.
                    223:   ----------------------------------------------------------------------*/
                    224: static int SortInsertableElemList(ElemListElement elem1 ,ElemListElement elem2)
                    225: {
                    226: #ifdef TEMPLATES
                    227:   if(elem1->typeClass==elem2->typeClass)
                    228:       return strcmp(ElemListElement_GetName(elem1),ElemListElement_GetName(elem2));
                    229:   else
                    230:     return elem1->typeClass - elem2->typeClass;
                    231: #else  /* TEMPLATES */
                    232:   return 0;
                    233: #endif /* TEMPLATES */
                    234: }
                    235: 
                    236: 
                    237: /*----------------------------------------------------------------------
1.1       kia       238:   FillInsertableElemList
                    239:   Fill an element list with all insertable elements (base element or
                    240:   XTiger comonent).
                    241:   ----------------------------------------------------------------------*/
1.21      vatton    242: void FillInsertableElemList (Document doc, Element el, DLList list)
1.1       kia       243: {
1.4       cvs       244: #ifdef TEMPLATES
1.21      vatton    245:   Element          child, elem;
                    246:   ElementType      elType, childType;
1.6       vatton    247:   XTigerTemplate   t;
1.4       cvs       248: #endif/* TEMPLATES */
1.2       cvs       249:   int level;
1.17      cvs       250:   ThotBool cont = TRUE;
1.2       cvs       251: 
1.22      vatton    252:   if (el)
1.21      vatton    253:     {
                    254:     if (doc == 0)
1.22      vatton    255:       doc = TtaGetDocument(el);
1.1       kia       256: 
                    257: #ifdef TEMPLATES
1.24      kia       258:     t = GetXTigerDocTemplate(doc);
1.2       cvs       259:     level = 0;
                    260:     cont = TRUE;
1.21      vatton    261:     elem = el;
1.15      kia       262:     // Process for each ancestor.
1.21      vatton    263:     while (elem && cont)
1.1       kia       264:     {
1.21      vatton    265:       elType = TtaGetElementType (elem);
1.26      vatton    266:       if (!strcmp (TtaGetSSchemaName (elType.ElSSchema), "Template"))
                    267:       {
1.21      vatton    268:       switch (elType.ElTypeNum)
1.15      kia       269:         {
1.1       kia       270:         case Template_EL_repeat:
                    271:           child = TtaGetFirstChild(elem);
                    272:           childType = TtaGetElementType(child);
1.21      vatton    273:           switch (childType.ElTypeNum)
1.1       kia       274:           {
                    275:             case Template_EL_useEl:
                    276:             case Template_EL_useSimple:
                    277:             case Template_EL_bag:
1.21      vatton    278:               FillInsertableElementFromElemAttribute(t, el, elem,
1.6       vatton    279:                                                      Template_ATTR_types, list, level);
1.1       kia       280:               break;
                    281:             default:
                    282:               break;
                    283:           }
1.21      vatton    284:           cont = FALSE;
1.1       kia       285:           break;
                    286:         case Template_EL_useEl:
                    287:           // Fill for xt:use only if have no child.
1.8       vatton    288:           if (TtaGetFirstChild(elem)==NULL){
1.21      vatton    289:             FillInsertableElementFromElemAttribute(t, el, elem,
1.6       vatton    290:                                                    Template_ATTR_types, list, level);
1.21      vatton    291:             cont = FALSE;
1.1       kia       292:           }
                    293:           break;
                    294:         case Template_EL_bag:
1.6       vatton    295:           FillInsertableElementFromElemAttribute(t, elem, elem,
                    296:                                                  Template_ATTR_types, list, level);
1.15      kia       297:           cont = FALSE;
1.1       kia       298:           break;
1.15      kia       299:         }
1.26      vatton    300:       }
1.21      vatton    301:       elem = GetFirstTemplateParentElement (elem);
1.1       kia       302:       level ++;
1.15      kia       303:     }
                    304: #endif/* TEMPLATES */
1.21      vatton    305:     }
1.19      kia       306:   DLList_Sort(list, (Container_CompareFunction)SortInsertableElemList);
1.1       kia       307: }
                    308: 
                    309: /*----------------------------------------------------------------------
                    310:   InsertableElement_GetList
                    311:   Get the insertable element list for a document.
                    312:   @param doc Document
                    313:   @return The insertable element list or NULL.
                    314:   ----------------------------------------------------------------------*/
                    315: DLList InsertableElement_GetList(Document doc)
                    316: {
1.16      vatton    317:   InsertableElementList list;
                    318: 
                    319:   list = (InsertableElementList) HashMap_Get(InsertableElementMap, (void*)doc);
1.6       vatton    320:   if (list)
1.1       kia       321:     return list->list;
                    322:   else
                    323:     return NULL;
                    324: }
                    325: 
                    326: /*----------------------------------------------------------------------
                    327:   InsertableElement_Update
                    328:   Update the insertable element list for a document.
                    329:   @param el Selected element, cant be NULL.
                    330:   @param document Document, can be NULL.
                    331:   @return List of insertable elements.
                    332:   ----------------------------------------------------------------------*/
1.7       kia       333: DLList InsertableElement_Update(Document doc, Element el)
1.1       kia       334: {
1.2       cvs       335:   InsertableElementList list;
1.16      vatton    336: 
                    337:   if (doc == 0)
                    338:     doc= TtaGetDocument (el);
                    339:   list = (InsertableElementList) HashMap_Get (InsertableElementMap, (void*)doc);
                    340:   if (list == NULL)
1.1       kia       341:   {
1.16      vatton    342:     list = InsertableElementList_Create (0, DLList_Create());
                    343:     HashMap_Set (InsertableElementMap, (void*)doc, list);
1.1       kia       344:   }
1.7       kia       345:   
1.16      vatton    346:   DLList_Empty (list->list);
                    347:   FillInsertableElemList (doc, el, list->list);
1.7       kia       348:   list->elem = el;
1.19      kia       349:   return list->list;
                    350: }
1.7       kia       351: 
1.19      kia       352: /*----------------------------------------------------------------------
                    353:   InsertableElement_ComputeList
                    354:   Update a insertable element list for a document.
                    355:   @param el Selected element, cant be NULL.
                    356:   @param document Document, can be NULL.
                    357:   @return List of insertable elements.
                    358:   ----------------------------------------------------------------------*/
                    359: DLList InsertableElement_ComputeList(Document doc, Element el)
                    360: {
                    361:   DLList list = DLList_Create();
                    362:   FillInsertableElemList (doc, el, list);
                    363:   return list;
1.1       kia       364: }
                    365: 
1.19      kia       366: 
1.3       kia       367: /*----------------------------------------------------------------------
                    368:   InsertableElement_DoInsertElement
                    369:   Insert the specified element.
                    370:   @param el Element to insert (ElemListElement)
                    371:   ----------------------------------------------------------------------*/
1.16      vatton    372: void InsertableElement_DoInsertElement (void* el)
1.3       kia       373: {
1.16      vatton    374:   ElemListElement elem = (ElemListElement) el;
                    375:   Element         ref = elem->refElem;
                    376:   ElementType     refType = TtaGetElementType (ref);
                    377:   Document        doc = TtaGetDocument (ref);
                    378:   Element         newEl = NULL;
                    379:   SSchema         templateSSchema;
1.10      kia       380: 
1.6       vatton    381: #ifdef AMAYA_DEBUG
1.12      vatton    382:   printf("insert %s into %s\n", ElemListElement_GetName(elem),
1.16      vatton    383:          TtaGetElementTypeName (refType));
1.6       vatton    384: #endif /* AMAYA_DEBUG */
1.11      kia       385: 
                    386: #ifdef TEMPLATES
1.16      vatton    387:   templateSSchema = TtaGetSSchema ("Template", doc);
                    388:   if (templateSSchema && refType.ElSSchema == templateSSchema)
1.3       kia       389:   {
1.11      kia       390:     switch(refType.ElTypeNum)
                    391:     {
                    392:       case Template_EL_repeat:
                    393:         if (elem->typeClass==DefinedComponent)
1.27    ! kia       394:           newEl = Template_InsertRepeatChildAfter (doc, ref,
1.16      vatton    395:                                               (Declaration)elem->elem.component.declaration,
1.27    ! kia       396:                                               TtaGetLastChild(ref));
1.11      kia       397:         break;
                    398:       case Template_EL_bag:
1.16      vatton    399:         newEl = Template_InsertBagChild (doc, ref,
1.18      kia       400:                                          (Declaration)elem->elem.component.declaration,
                    401:                                          FALSE);
1.11      kia       402:         break;
                    403:       default:
                    404:         break;
                    405:     }
                    406:   }
1.3       kia       407: #endif /* TEMPLATES */
1.11      kia       408: 
1.12      vatton    409:   if (newEl)
1.16      vatton    410:     TtaSelectElement (doc, newEl);
1.3       kia       411: }
1.18      kia       412: 
                    413: /*----------------------------------------------------------------------
                    414:   GetFirstChildElementTo
                    415:   Find and retrieve the first child of root element which is an ascendent
                    416:   of the leaf element.
                    417:   If leaf is a child of root, return leaf itself.
                    418:   ----------------------------------------------------------------------*/
                    419: static Element GetFirstChildElementTo(Element root, Element leaf)
                    420: {
                    421:   Element parent = TtaGetParent(leaf);
                    422:   if(root==0 || leaf==0 || parent==0)
                    423:     return 0;
                    424:   
                    425:   while(parent)
                    426:     {
                    427:       if(parent==root)
                    428:         return leaf;
                    429:       leaf = parent;
                    430:       parent = TtaGetParent(parent);
                    431:     }
                    432:   return 0;
                    433: }
                    434: 
                    435: /*----------------------------------------------------------------------
                    436:   InsertableElement_InsertElement
                    437:   Insert the specified element in the given document before or after the selection.
                    438:   \param el Element to insert (ElemListElement)
                    439:   \param before True if inserting before given element, false after.
                    440:   ----------------------------------------------------------------------*/
1.19      kia       441: Element InsertableElement_InsertElement (ElemListElement elem, ThotBool before)
1.18      kia       442: {
                    443: #ifdef TEMPLATES
                    444:   Element         ref = elem->refElem;
                    445:   ElementType     refType = TtaGetElementType (ref);
                    446:   Document        doc = TtaGetDocument (ref);
                    447:   Element         newEl = NULL, sibling = NULL;
                    448:   SSchema         templateSSchema;
1.19      kia       449:   Element         sel;
                    450:   int             car1, car2;
                    451:   XTigerTemplate  t = NULL;
                    452:   Declaration     dec = NULL;
1.18      kia       453: 
                    454:   templateSSchema = TtaGetSSchema ("Template", doc);
                    455: 
                    456:   if (templateSSchema && refType.ElSSchema == templateSSchema)
                    457:   {
                    458:     switch(refType.ElTypeNum)
                    459:     {
                    460:       case Template_EL_repeat:
1.19      kia       461:         if(elem->typeClass==DefinedComponent)
                    462:           dec = (Declaration)elem->elem.component.declaration;
                    463:         else if (elem->typeClass==LanguageElement)
                    464:           {
                    465:             t = GetXTigerDocTemplate(TtaGetDocument(elem->refElem));
                    466:             if (t)
                    467:                 dec = Template_GetElementDeclaration(t, ElemListElement_GetName(elem));
                    468:           }
                    469:         if (dec)
1.18      kia       470:           {
1.19      kia       471:             
1.18      kia       472:             TtaGiveFirstSelectedElement(doc, &sel, &car1, &car2);
                    473:             sibling = GetFirstChildElementTo(ref, sel);
                    474:             if(sibling)
                    475:               {
                    476:                 if(before)
                    477:                   TtaPreviousSibling(&sibling);
1.19      kia       478:                 newEl = Template_InsertRepeatChildAfter (doc, ref, dec, sibling);
1.18      kia       479:               }
                    480:           }
                    481:         break;
                    482:       case Template_EL_bag:
1.19      kia       483:         if(elem->typeClass==DefinedComponent)
                    484:           dec = (Declaration)elem->elem.component.declaration;
                    485:         else if (elem->typeClass==LanguageElement)
                    486:           {
                    487:             t = GetXTigerDocTemplate(TtaGetDocument(elem->refElem));
                    488:             if (t)
                    489:                 dec = Template_GetElementDeclaration(t, ElemListElement_GetName(elem));
                    490:           }
                    491:         if (dec)
                    492:             newEl = Template_InsertBagChild (doc, ref, dec, before);           
1.18      kia       493:         break;
                    494:       default:
                    495:         break;
                    496:     }
                    497:   }
1.19      kia       498:   return newEl;
                    499: #else /* TEMPLATES */
                    500:   return NULL;
1.18      kia       501: #endif /* TEMPLATES */
                    502: }
                    503: 
                    504: 
                    505: /*----------------------------------------------------------------------
                    506:   InsertableElement_QueryInsertElement(void* el, ThotBool bAfter)
                    507:   Do a InsertableElement_InsertElement with undo/redo management.
                    508:   ----------------------------------------------------------------------*/
1.19      kia       509: void InsertableElement_QueryInsertElement(ElemListElement elem, ThotBool before)
1.18      kia       510: {
                    511: #ifdef TEMPLATES
1.19      kia       512:   Element     elSel, newEl, firstEl;
                    513:   int         firstSel, lastSel;
                    514:   Document    doc = TtaGetDocument(elem->refElem);
                    515:   
                    516:   ThotBool    oldStructureChecking;
                    517:   DisplayMode dispMode;
                    518:   
                    519:   // If document is readonly, dont do anything
                    520:   if (!TtaGetDocumentAccessMode(doc))
                    521:     return;
                    522: 
                    523:   TtaGiveFirstSelectedElement(doc, &elSel, &firstSel, &lastSel);
                    524: 
                    525:   
                    526:   dispMode = TtaGetDisplayMode (doc);
                    527:   if (dispMode == DisplayImmediately)
                    528:     /* don't set NoComputedDisplay
                    529:        -> it breaks down views formatting when Enter generates new elements  */
                    530:     TtaSetDisplayMode (doc, DeferredDisplay);
                    531: 
                    532:   /* Prepare insertion.*/          
                    533:   oldStructureChecking = TtaGetStructureChecking (doc);
                    534:   TtaSetStructureChecking (FALSE, doc);
1.20      vatton    535:   TtaOpenUndoSequence (doc, NULL, NULL, 0, 0);
1.19      kia       536:   
                    537:   /* Do the insertion */
                    538:   newEl = InsertableElement_InsertElement (elem, before);
                    539:   
                    540:   /* Finish insertion.*/
                    541:   TtaCloseUndoSequence (doc);
                    542:   TtaSetDocumentModified (doc);
                    543:   TtaSetStructureChecking (oldStructureChecking, doc);
                    544:   // restore the display
                    545:   TtaSetDisplayMode (doc, dispMode);
                    546: 
1.20      vatton    547:   if (newEl)
1.19      kia       548:     {
1.20      vatton    549:       firstEl = GetFirstEditableElement (newEl);
                    550:       if (firstEl)
                    551:         {
                    552:           TtaSelectElement (doc, firstEl);
                    553:           TtaSetStatusSelectedElement (doc, 1, firstEl);
                    554:         }
                    555:       else
                    556:         {
                    557:           TtaSelectElement (doc, newEl);
                    558:           TtaSetStatusSelectedElement (doc, 1, newEl);
                    559:         }
1.19      kia       560:     }
1.18      kia       561: #endif /* TEMPLATES */
                    562: }

Webmaster