/**
   * Checks whether the selection & caret is inside editable text, and changes their positions
   * accordingly if not.
   */
  void checkAndFixCaret() {
    Document3 doc = getOmDocument();
    if (doc == null) {
      // doc is not active
      return;
    }
    if (!doc.isEditMode()) {
      return;
    }

    // int pos = m_editor.getCaretPosition();
    int spos = getSelectionStart();
    int epos = getSelectionEnd();
    /*
     * int start = m_segmentStartOffset + m_sourceDisplayLength +
     * OConsts.segmentStartStringFull.length();
     */
    int start = doc.getTranslationStart();
    // -1 for space before tag, -2 for newlines
    /*
     * int end = editor.getTextLength() - m_segmentEndInset -
     * OConsts.segmentEndStringFull.length();
     */
    int end = doc.getTranslationEnd();

    if (spos != epos) {
      // dealing with a selection here - make sure it's w/in bounds
      if (spos < start) {
        fixSelectionStart(start);
      } else if (spos > end) {
        fixSelectionStart(end);
      }
      if (epos > end) {
        fixSelectionEnd(end);
      } else if (epos < start) {
        fixSelectionStart(start);
      }
    } else {
      // non selected text
      if (spos < start) {
        setCaretPosition(start);
      } else if (spos > end) {
        setCaretPosition(end);
      }
    }
  }
  /**
   * Redefine some keys behavior. We can't use key listeners, because we have to make something
   * AFTER standard keys processing.
   */
  @Override
  protected void processKeyEvent(KeyEvent e) {
    if (e.getID() != KeyEvent.KEY_PRESSED) {
      // key released
      super.processKeyEvent(e);
      return;
    }

    boolean processed = false;

    boolean mac = StaticUtils.onMacOSX();

    Document3 doc = getOmDocument();

    // non-standard processing
    if (isKey(e, KeyEvent.VK_TAB, 0)) {
      // press TAB when 'Use TAB to advance'
      if (controller.settings.isUseTabForAdvance()) {
        controller.nextEntry();
        processed = true;
      }
    } else if (isKey(e, KeyEvent.VK_TAB, KeyEvent.SHIFT_MASK)) {
      // press Shift+TAB when 'Use TAB to advance'
      if (controller.settings.isUseTabForAdvance()) {
        controller.prevEntry();
        processed = true;
      }
    } else if (isKey(e, KeyEvent.VK_ENTER, 0)) {
      // press ENTER
      if (!controller.settings.isUseTabForAdvance()) {
        controller.nextEntry();
        processed = true;
      } else {
        processed = true;
      }
    } else if ((!mac && isKey(e, KeyEvent.VK_ENTER, KeyEvent.CTRL_MASK))
        || (mac && isKey(e, KeyEvent.VK_ENTER, KeyEvent.META_MASK))) {
      // press Ctrl+ENTER (Cmd+Enter for MacOS)
      if (!controller.settings.isUseTabForAdvance()) {
        controller.prevEntry();
        processed = true;
      }
    } else if (isKey(e, KeyEvent.VK_ENTER, KeyEvent.SHIFT_MASK)) {
      // convert Shift+Enter event to straight enter key
      KeyEvent ke =
          new KeyEvent(e.getComponent(), e.getID(), e.getWhen(), 0, KeyEvent.VK_ENTER, '\n');
      super.processKeyEvent(ke);
      processed = true;
    } else if ((!mac && isKey(e, KeyEvent.VK_A, KeyEvent.CTRL_MASK))
        || (mac && isKey(e, KeyEvent.VK_A, KeyEvent.META_MASK))) {
      // handling Ctrl+A manually (Cmd+A for MacOS)
      setSelectionStart(doc.getTranslationStart());
      setSelectionEnd(doc.getTranslationEnd());
      processed = true;
    } else if (isKey(e, KeyEvent.VK_O, KeyEvent.CTRL_MASK | KeyEvent.SHIFT_MASK)) {
      // handle Ctrl+Shift+O - toggle orientation LTR-RTL
      controller.toggleOrientation();
      processed = true;
    } else if ((!mac && isKey(e, KeyEvent.VK_BACK_SPACE, KeyEvent.CTRL_MASK))
        || (mac && isKey(e, KeyEvent.VK_BACK_SPACE, KeyEvent.ALT_MASK))) {
      // handle Ctrl+Backspace (Alt+Backspace for MacOS)
      try {
        int offset = getCaretPosition();
        int prevWord = Utilities.getPreviousWord(this, offset);
        int c = Math.max(prevWord, doc.getTranslationStart());
        setSelectionStart(c);
        setSelectionEnd(offset);
        replaceSelection("");

        processed = true;
      } catch (BadLocationException ex) {
        // do nothing
      }
    } else if ((!mac && isKey(e, KeyEvent.VK_DELETE, KeyEvent.CTRL_MASK))
        || (mac && isKey(e, KeyEvent.VK_DELETE, KeyEvent.ALT_MASK))) {
      // handle Ctrl+Backspace (Alt+Delete for MacOS)
      try {
        int offset = getCaretPosition();
        int nextWord = Utilities.getNextWord(this, offset);
        int c = Math.min(nextWord, doc.getTranslationEnd());
        setSelectionStart(offset);
        setSelectionEnd(c);
        replaceSelection("");

        processed = true;
      } catch (BadLocationException ex) {
        // do nothing
      }
    } else if ((!mac && isKey(e, KeyEvent.VK_PAGE_UP, KeyEvent.CTRL_MASK))
        || (mac && isKey(e, KeyEvent.VK_PAGE_UP, KeyEvent.META_MASK))) {
      // Ctrl+PgUp - to the begin of document(Cmd+PgUp for MacOS)
      setCaretPosition(0);
      processed = true;
    } else if ((!mac && isKey(e, KeyEvent.VK_PAGE_DOWN, KeyEvent.CTRL_MASK))
        || (mac && isKey(e, KeyEvent.VK_PAGE_DOWN, KeyEvent.META_MASK))) {
      // Ctrl+PgDn - to the end of document(Cmd+PgDn for MacOS)
      setCaretPosition(getOmDocument().getLength());
      processed = true;
    }

    // leave standard processing if need
    if (processed) {
      e.consume();
    } else {
      if ((e.getModifiers() & (KeyEvent.CTRL_MASK | KeyEvent.META_MASK | KeyEvent.ALT_MASK)) == 0) {
        // there is no Alt,Ctrl,Cmd keys, i.e. it's char
        if (e.getKeyCode() != KeyEvent.VK_SHIFT) {
          // it's not a single 'shift' press
          checkAndFixCaret();
        }
      }
      super.processKeyEvent(e);
    }

    controller.showLengthMessage();

    // some after-processing catches
    if (!processed && e.getKeyChar() != 0) {
      switch (e.getKeyCode()) {
        case KeyEvent.VK_HOME:
        case KeyEvent.VK_END:
        case KeyEvent.VK_LEFT:
        case KeyEvent.VK_RIGHT:
        case KeyEvent.VK_UP:
        case KeyEvent.VK_DOWN:
          checkAndFixCaret();
      }
    }
  }
 @Test
 public void testAbstractClass() {
   Document3 document = JSInterfaceFactory.create(context, Document3.class);
   WebElement element = unwrapWebElement(browser.findElement(By.tagName("h1")));
   Assert.assertEquals(element, document.getHeader());
 }