super.insertUpdate(ev, attr);
int offs = ev.getOffset(); int len = ev.getLength(); int endOffs = offs + len;
  protected void insertUpdate(DefaultDocumentEvent ev, AttributeSet attr)  {    super.insertUpdate(ev, attr);    // If the attribute set is null, use an empty attribute set.    if (attr == null)      attr = SimpleAttributeSet.EMPTY;    int offset = ev.getOffset();    int length = ev.getLength();    int endOffset = offset + length;    AttributeSet paragraphAttributes = getParagraphElement(endOffset).getAttributes();    Segment txt = new Segment();    try      {        getText(offset, length, txt);      }    catch (BadLocationException ex)      {        AssertionError ae = new AssertionError("Unexpected bad location");        ae.initCause(ex);        throw ae;      }    int len = 0;    Vector specs = new Vector();    ElementSpec finalStartTag = null;    short finalStartDirection = ElementSpec.OriginateDirection;    boolean prevCharWasNewline = false;    Element prev = getCharacterElement(offset);    Element next = getCharacterElement(endOffset);    Element prevParagraph = getParagraphElement(offset);    Element paragraph = getParagraphElement(endOffset);    int segmentEnd = txt.offset + txt.count;        // Check to see if we're inserting immediately after a newline.    if (offset > 0)      {        try        {          String s = getText(offset - 1, 1);          if (s.equals("\n"))            {                finalStartDirection = handleInsertAfterNewline(specs, offset,                                                               endOffset,                                         prevParagraph,                                         paragraph,                                         paragraphAttributes);                            prevCharWasNewline = true;              // Find the final start tag from the ones just created.              for (int i = 0; i < specs.size(); i++)                  if (((ElementSpec) specs.get(i)).getType() == ElementSpec.StartTagType)                    finalStartTag = (ElementSpec) specs.get(i);            }        }        catch (BadLocationException ble)        {                    // This shouldn't happen.          AssertionError ae = new AssertionError();          ae.initCause(ble);          throw ae;        }              }    for (int i = txt.offset; i < segmentEnd; ++i)      {        len++;        if (txt.array[i] == '\n')          {            // Add the ElementSpec for the content.            specs.add(new ElementSpec(attr, ElementSpec.ContentType, len));                        // Add ElementSpecs for the newline.            specs.add(new ElementSpec(null, ElementSpec.EndTagType));            finalStartTag = new ElementSpec(paragraphAttributes,                                                   ElementSpec.StartTagType);            specs.add(finalStartTag);            len = 0;          }      }    // Create last element if last character hasn't been a newline.    if (len > 0)      specs.add(new ElementSpec(attr, ElementSpec.ContentType, len));          // Set the direction of the last spec of type StartTagType.      // If we are inserting after a newline then this value comes from     // handleInsertAfterNewline.    if (finalStartTag != null)      {                if (prevCharWasNewline)          finalStartTag.setDirection(finalStartDirection);        else if (prevParagraph.getEndOffset() != endOffset)                  finalStartTag.setDirection(ElementSpec.JoinFractureDirection);        else          {            // If there is an element AFTER this one, then set the             // direction to JoinNextDirection.            Element parent = prevParagraph.getParentElement();            int index = parent.getElementIndex(offset);            if (index + 1 < parent.getElementCount()                && !parent.getElement(index + 1).isLeaf())              finalStartTag.setDirection(ElementSpec.JoinNextDirection);          }      }        // If we are at the last index, then check if we could probably be    // joined with the next element.    // This means:    //  - we must be a ContentTag    //  - if there is a next Element, we must have the same attributes    //  - if there is no next Element, but one will be created,    //    we must have the same attributes as the higher-level run.    ElementSpec last = (ElementSpec) specs.lastElement();    if (last.getType() == ElementSpec.ContentType)      {        Element currentRun = prevParagraph.getElement(prevParagraph.getElementIndex(offset));        if (currentRun.getEndOffset() == endOffset)          {            if (endOffset < getLength() && next.getAttributes().isEqual(attr)                && last.getType() == ElementSpec.ContentType)      last.setDirection(ElementSpec.JoinNextDirection);              }        else          {            if (finalStartTag != null                && finalStartTag.getDirection() == ElementSpec.JoinFractureDirection                && currentRun.getAttributes().isEqual(attr))              {                last.setDirection(ElementSpec.JoinNextDirection);              }          }      }            // If we are at the first new element, then check if it could be        // joined with the previous element.    ElementSpec first = (ElementSpec) specs.firstElement();    if (prev.getAttributes().isEqual(attr)        && first.getType() == ElementSpec.ContentType)      first.setDirection(ElementSpec.JoinPreviousDirection);    ElementSpec[] elSpecs = (ElementSpec[]) specs.toArray(new ElementSpec[specs.size()]);    buffer.insert(offset, length, elSpecs, ev);  }  