#include #include #include static HTList * history; /* List of visited anchors */ /* Navigation ** ========== */ /* Record the jump to an anchor ** ---------------------------- */ void HTHistory_record ARGS1 (HTAnchor *,destination) { if (destination) { if (! history) history = HTList_new(); HTList_addObject (history, destination); } } /* Go back in history (find the last visited node) ** ------------------ */ HTAnchor * HTHistory_backtrack NOARGS /* FIXME: Should we add a `sticky' option ? */ { if (HTHistory_canBacktrack()) HTList_removeLastObject(history); return(HTAnchor *)HTList_lastObject(history); /* is Home if can't backtrack */ } BOOL HTHistory_canBacktrack NOARGS { return (HTList_objectAt (history, 1) != NULL); } /* Browse through references in the same parent node ** ------------------------------------------------- ** ** Take the n-th child's link after or before the one we took to get here. ** Positive offset means go towards most recently added children. */ HTAnchor * HTHistory_moveBy ARGS1 (int,offset) { HTAnchor * last = (HTAnchor *)HTList_objectAt (history, 1); if (! last) return NULL; /* No last visited node */ if (last != (HTAnchor *) last->parent) { /* Was a child */ HTList * kids = last->parent->children; int i = HTList_indexOf (kids, last); HTAnchor * nextOne = (HTAnchor *)HTList_objectAt (kids, i - offset); if (nextOne) { HTAnchor * destination = HTAnchor_followMainLink (nextOne); if (destination) { HTList_removeLastObject (history); HTList_removeLastObject (history); HTList_addObject (history, nextOne); HTList_addObject (history, destination); } return destination; } else { CTRACE(tfp, "HTHistory_moveBy: offset by %+d goes out of list %p.\n", offset, (void*)kids); return NULL; } } else { /* Was a parent */ return NULL; /* FIXME we could possibly follow the next link... */ } } BOOL HTHistory_canMoveBy ARGS1 (int,offset) { HTAnchor * last = (HTAnchor *)HTList_objectAt (history, 1); if (! last) return NO; /* No last visited node */ if (last != (HTAnchor *) last->parent) { /* Was a child */ HTList * kids = last->parent->children; int i = HTList_indexOf (kids, last); return (HTList_objectAt (kids, i - offset) != NULL); } else { /* Was a parent */ return NO; /* FIXME we could possibly follow the next link... */ } } /* Retrieval ** ========= */ /* Read numbered visited anchor (1 is the oldest) ** ---------------------------- */ HTAnchor * HTHistory_read ARGS1 (int,number) { return (HTAnchor *)HTList_objectAt(history, HTList_count (history) - number); } /* Recall numbered visited anchor (1 is the oldest) ** ------------------------------ ** This reads the anchor and stores it again in the list, except if last. */ HTAnchor * HTHistory_recall ARGS1 (int,number) { HTAnchor * destination = (HTAnchor *)HTList_objectAt (history, HTList_count (history) - number); if (destination && destination != (HTAnchor *)HTList_lastObject (history)) HTList_addObject (history, destination); return destination; } /* Number of Anchors stored ** ------------------------ ** ** This is needed in order to check the validity of certain commands ** for menus, etc. (not needed for now. Use canBacktrack, etc.) int HTHistory_count NOARGS { return HTList_count (history); } */ /* Change last history entry ** ------------------------- ** ** Sometimes we load a node by one anchor but leave by a different ** one, and it is the one we left from which we want to remember. */ void HTHistory_leavingFrom ARGS1 (HTAnchor *,anchor) { if (HTList_removeLastObject (history)) { HTList_addObject (history, anchor); } else { CTRACE(tfp, "HTHistory_leavingFrom: empty history !\n"); } }