public void setEnabled(boolean enabled) {
    if (!enabled && this.enabled && lastElement != null) {
      // Insert a timeout to the last generated command
      Editor ed = editorPnl.getEditor();
      if (lastElement.getDocument().equals(ed.getDocument())) {
        Element e = ed.getCurrentElement();
        int offset = ed.getCaretPosition() - e.getStartOffset();
        ed.setCaretPosition(lastElement.getStartOffset());
        String text = DocumentUtils.getElementText(lastElement);
        int pos = text.indexOf(" ");
        String cmd = pos >= 0 ? text.substring(0, pos) : text;
        String time = convertTime(System.currentTimeMillis() - lastInsertTime);
        CommandHandler h =
            (CommandHandler) scriptManager.getCommandHandlers().get(cmd.toUpperCase());

        if (h != null
            && h.getContextAttributes() != null
            && h.getContextAttributes().containsKey("wait")) {
          text += " wait=" + time;
        } else {
          text += "\nWait " + time;
        }
        insertLine(text, true, false, false);
      }
    }
    this.enabled = enabled;
    fb.setRecordingMode(enabled);
    if (enabled) {
      firstRecord = true;
      lastElement = null;
      lastInsertTime = -1;
      lastMouseMoveEvent = null;
      events.clear();
      synchronized (rfbEvents) {
        rfbEvents.clear();
      }
    }
  }
  public void keyTyped(KeyEvent e) {
    if (debug) {
      System.out.println(
          "--- RecordingModule: key typed = "
              + e
              + "\n  > Key char->int = "
              + (int) e.getKeyChar());
      System.out.println(" -- isActionKey() = " + e.isActionKey());
      System.out.println(" -- isISOControl() = " + Character.isISOControl(e.getKeyChar()));
      System.out.println(" -- isWhitespace() = " + Character.isWhitespace(e.getKeyChar()));
    }

    if (isKeyReserved(e)) {
      return;
    }

    if (enabled && !readOnly && lastKeyPressEvent != null) {

      if (enableKeyboard) {
        boolean replace = false;
        String text = "";
        if (isControl(e)) {
          if (lastKeyPressEvent.getKeyCode() == KeyEvent.VK_ENTER) {

            // Change the Type cmd prior to Typeline if the delay from the last type key is less
            // than 1 sec
            if (useTypeline && e.getModifiers() == 0 && lastElement != null) {
              String s = DocumentUtils.getElementText(lastElement);
              if (s.startsWith("Type ")
                  && (System.currentTimeMillis() - lastInsertTime) < typelineDelay) {
                replace = true;
                text = s.replaceFirst("Type", "Typeline");
              }
            }
          }

          if ("".equals(text)) {
            int count = 1;
            KeyEvent e2;

            long lastEventTime = e.getWhen();

            // We go through the vector of events and check whether there are events corresponding
            // to a typed text.
            for (int i = 0; i < events.size() && events.get(i) instanceof KeyEvent; i++) {
              e2 = (KeyEvent) events.get(i);
              if (e.getID() == e2.getID()
                  && e.getKeyChar() == e2.getKeyChar()
                  && e.getKeyCode() == e2.getKeyCode()
                  && e.getModifiers() == e2.getModifiers()
                  && (lastEventTime - e2.getWhen() < keyMutiDelay)) {
                count++;
                replace = true;
                lastEventTime = e2.getWhen();
              } else {
                break;
              }
            }

            text = "Press ";
            //                    String modifiers = KeyEvent.getKeyModifiersText(e.getModifiers());
            String modifiers = parser.modifiersToString(e.getModifiers());
            if (!"".equals(modifiers)) {
              text += modifiers + "+";
            }
            String charText = KeyEvent.getKeyText(lastKeyPressEvent.getKeyCode());
            if (charText == null) {
              charText = "<unknown>";
            }
            text += charText;
            if (count > 1) {
              text += " " + PressCommand.PARAM_COUNT + "=" + count;
            }

            if (debug) {
              System.out.println("--- RecordingModule: Inserting '" + text + "'");
            }
          }

        } else {
          text = "" + e.getKeyChar();
          KeyEvent e2;

          // We go through the vector of events and check whether there are events corresponding to
          // a typed text.
          for (int i = 0; i < events.size() && events.get(i) instanceof KeyEvent; i++) {
            e2 = (KeyEvent) events.get(i);
            if (!isControl(e2) && !e2.isActionKey()) {
              text = e2.getKeyChar() + text;
              replace = true;
            } else {
              break;
            }
          }

          text = "Type \"" + Utils.escapeUnescapedDoubleQuotes(text) + "\"";
        }

        // Insert the command to the current editor
        insertLine(text, replace, true, false);
      }
      insertEvent(e);
    }
  }
  public synchronized Element insertLine(
      String command,
      boolean replaceLast,
      boolean insertPrecedingWait,
      boolean removePrecedingWait) {
    //        System.out.println("insertLine(\"" + command + "\")");
    EditorPnl editor = getEditorPnl();
    if (editor != null) {
      try {
        Document doc = editor.getEditor().getDocument();
        int caretPos = editor.getEditor().getCaretPosition();
        //                System.out.println("  -->Initial caret position: " + caretPos);
        int elemIndex = doc.getDefaultRootElement().getElementIndex(caretPos);
        boolean insertNewLine = true;

        Element ce = doc.getDefaultRootElement().getElement(elemIndex);
        String txt = DocumentUtils.getElementText(ce).trim();
        if (!replaceLast && caretPos == 0 && elemIndex == 0 && !"".equals(txt)) {
          doc.insertString(0, "\n", null);
          txt = "";
          insertNewLine = false;
        }

        // The following code finds out if we are in an empty line or not.
        // If the current line contains some text, a new line is inserted
        // and the caret is moved there.
        if (!txt.equals("")) {
          Element next = doc.getDefaultRootElement().getElement(elemIndex + 1);
          if (next == null || !DocumentUtils.getElementText(next).trim().equals("")) {
            //                        DocumentUtils.analyzeEditorDocument(editor.getEditor(),
            // false);
            //                        System.out.println("Inserting an empty line to offset " +
            // ce.getEndOffset());
            doc.insertString(ce.getEndOffset() - 1, "\n", null);
            //                        DocumentUtils.analyzeEditorDocument(editor.getEditor(),
            // false);
            next =
                doc.getDefaultRootElement()
                    .getElement(doc.getDefaultRootElement().getElementIndex(ce.getEndOffset() + 1));
          }
          //                    caretPos = next.getEndOffset()-1;
          caretPos = ce.getEndOffset();
          //                    System.out.println("Setting caret position to "+caretPos);
          //                    System.out.println("  -->1. Setting caret position to: " +
          // caretPos);
          editor.getEditor().setCaretPosition(caretPos);
        }

        Element e = DocumentUtils.getCommandElementPriorTo(doc, caretPos);
        //                System.out.println(" --> Element prior: " +
        // DocumentUtils.getElementText(e));

        // First look if we should insert a Wait command
        if (!replaceLast
            && (insertPrecedingWait || removePrecedingWait)
            && (!firstRecord && !removePrecedingWait)
            && e != null) {
          String prevCmd = DocumentUtils.getElementText(e);
          int pos = prevCmd.indexOf(" ");
          String cmd = pos >= 0 ? prevCmd.substring(0, pos) : prevCmd;
          String time = convertTime(System.currentTimeMillis() - lastInsertTime);
          CommandHandler h =
              (CommandHandler) scriptManager.getCommandHandlers().get(cmd.toUpperCase());

          if (!"waitfor".equalsIgnoreCase(cmd) && !"screenshot".equalsIgnoreCase(cmd)) {

            if (h != null
                && h.getContextAttributes() != null
                && h.getContextAttributes().containsKey("wait")) {
              doc.remove(e.getStartOffset(), prevCmd.length());
              String replaceStr = insertPrecedingWait ? " wait=" + time : "";
              String s =
                  prevCmd
                          .replaceAll("\\n", "")
                          .replaceAll("\\swait=[\"]*[0-9]*[sSmMhHdD]*[\"]*", "")
                      + replaceStr;
              doc.insertString(e.getStartOffset(), s, null);
              caretPos = e.getEndOffset();
              //                            System.out.println("  -->2. Setting caret position to: "
              // + caretPos);
            } else {
              String waitCmd = "Wait " + time + '\n';
              doc.insertString(caretPos, waitCmd, null);
              caretPos += waitCmd.length();
              //                            System.out.println("  -->3. Setting caret position to: "
              // + caretPos);
            }
          }
        }

        firstRecord = false;

        if (replaceLast && e != null) {
          int length = e.getEndOffset() - e.getStartOffset();
          doc.remove(e.getStartOffset(), length);
          caretPos = e.getStartOffset();
        }
        command = insertNewLine && !replaceLast ? command + "\n" : command;
        doc.insertString(caretPos, command, null);
        editor.getEditor().setCaretPosition(caretPos + 1);

        //                System.out.println(" --> Inserted, caretPos = " +
        // editor.getEditor().getCaretPosition());

        //                DocumentUtils.analyzeEditorDocument(editor.getEditor(), true);
        lastElement =
            doc.getDefaultRootElement()
                .getElement(doc.getDefaultRootElement().getElementIndex(caretPos));
        lastInsertTime = System.currentTimeMillis();
        filterRfbEvents();

      } catch (Exception ex) {
        ex.printStackTrace();
      }
    }
    return lastElement;
  }