Visual Tagging Tool

VTT Markup Undo/Redo Design

I. Undoable Markup operations
VTT provides undo/redo for markup operations. Undoable and redoable operations include:

  • Add: tag a selected (highlight) text by adding a new markup
  • Change: change the tag (properties) for a selected markup
  • Delete: delete a selected markup
  • Join: join the selected markup with the next markup
  • Override: override all markups on the highlight text

II. Java Classes

  • Markups
    The Markups class maintains the whole markups list. It includes:
    • Vector<Markup> markups_: the list of all markups
    • int selectIndex_: the index of selected markup. The value is -1 if no markup is selected.
    • Notes:
      • The markups_ list should be implemented in a Hashtable. However, we used Java Vector because all markups in one file are a relatively small number and it takes short time to search through it then dump everything to a sorted Vector.
      • Markup objects are sorted by offset (smaller first), the length (bigger first). No Markup objects with same offset and length is allowed.
      • Tag of "Text/Clear" should not be used to avoid confusion. Tags should be deleted instead of clear so users get the real markup-tag on what they see
  • UndoBase
    The UndoBase class is the data structure for UndoBase Java object (used in UndoNode). Data members are:
    • int action_: basic method
      • ADD (0)
      • CHANGE (1)
      • DELETE (2)
    • Markup cur_: current markup after the operation
    • Markup prev_: previous markup before the current operation
  • UndoNode
    The UndoNode class is the data structure for UndoNode Java object (used in UndoManager). Data members are:
    • int action_: markup operation
      • ADD (0)
      • CHANGE (1)
      • DELETE (2)
      • JOIN (3)
      • ORVERRIDE (4)
    • Vector<UndoBase> undoBases_: a detail list of undoBase (method) included for the undoNode.
      Each UndoNode includes a list of UndoBase as illustrated in the following table:
      action_undoBases_: action in undoBases
      ADD
    • ADD a new markup
    • CHANGE
    • CHANGE the selected markup
    • DELETE
    • DELETE the selected markup
    • JOIN
    • DELETE the selected markup
    • DELETE the next markup
    • ADD the join markup
    • OVERRIDE
    • DELETE all markups overlap with highlighted text
    • ADD the override markup
  • UndoManager
    The UndoManage class manages the undo list of UndoNodes for undo and redo operations. Data members are:
    • int index_: the current undo/redo index to the position of the list. The initial value is -1 when no undo in the undos_ list.
    • Vector<UndoNode>undoNodes_: is the list of undoable/redoable markup operations.

    The UndoManager class provides a method, AddUndoNode( ) when adding a new undo Node to the undoNodes_ list:
    • if the index_ is at the end of the undoNodes_:
      • add the new specified undoNode to undoNodes_ list
      • index_++
    • else (if the index_ is not at the end of the undos_):
      • remove all undoNodes after index from undoNodes_ list
      • add the new specified undoNode to undoNodes_ list
      • index_++

    The following table demonstrates the data in a specified undoNode/undoBase when calling AddUndo( ):

    Markup action_prev_cur_
    offsetlengthtagNameannotationoffsetlengthtagNameannotation
    ADD (0)cur offsetcur lengthcur tagcur annotationcur offsetcur lengthcur tagcur annotation
    CHANGE (1)prev offsetprev lengthprev tagNameprev annotationcur offsetcur lengthcur tagNamecur annotation
    DELETE (2)cur offsetcur lengthcur tagcur annotationcur offsetcur lengthcur tagcur annotation

III. Undo Operations
The undo operation class performs the undo/redo basic operations of add/change/delete on markups.

  • Undo operations:
    • if not undoable (no UndoNode in undoNodes_ or index_ is -1)
      • set undo.setEnable(false)
      • beep
    • else
      • Get the current undoNode from undoNodes_ list
      • reduce index_ (in UndoManager) by 1
      • Update markups by undoNode
        • Go through all undoBases in the undoNode
        • Find the markup (index) from Markups_ list by the offset and length (unique) of current markup in UndoBase
        • ADD:
          • delete the added markup from markups_ list
          • set markup select index = -1 (no select)
          • Update text/markup style
          • set text highlight to the deleted markup (update markup style again)
        • CHANGE:
          • set properties of prev markup to the selected markup on Markups_ list
          • set markup select index to the changed markup
          • Update text/markup style
        • DELETE:
          • add the deleted markup back to markups_ list
          • set markup select index to the added markup
          • Update text/markup style
        • Update modeless dialogs: Markup and MarkupsDialog
  • Redo operations:
    • if not redoable (no UndoNode in undoNodes_ or index_ is at the end of the list)
      • set redo.setEnable(false)
      • beep
    • else
      • Get the next (current + 1) undoNode from undoNodes_ list
      • increase index_ (in UndoManager) by 1
      • Update markups by redoNode
        • Go through all redoBases in the redoNode
        • Find the markup (index) from Markups_ list by offset and length (unique) of current markup in RedoBase
          • ADD:
            • set markup select index to the markup to be added
            • add the markup to markups_ list
            • Update text/markup style
          • CHANGE:
            • set properties of prev markup to the selected markup on markups_ list
            • set markup select index to the changed markup
            • Update text/markup style
          • DELETE:
            • delete the selected markup from Markups_ list
            • set markup select index to the added markup
            • Update text/markup style
        • Update modeless dialogs: Markup and MarkupsDialog