File Source: InputHandler.java

         /* 
    P/P   *  Method: com.dmdirc.ui.input.InputHandler__static_init
          */
     1  /*
     2   * Copyright (c) 2006-2009 Chris Smith, Shane Mc Cormack, Gregory Holmes
     3   *
     4   * Permission is hereby granted, free of charge, to any person obtaining a copy
     5   * of this software and associated documentation files (the "Software"), to deal
     6   * in the Software without restriction, including without limitation the rights
     7   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     8   * copies of the Software, and to permit persons to whom the Software is
     9   * furnished to do so, subject to the following conditions:
    10   *
    11   * The above copyright notice and this permission notice shall be included in
    12   * all copies or substantial portions of the Software.
    13   *
    14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    20   * SOFTWARE.
    21   */
    22  
    23  package com.dmdirc.ui.input;
    24  
    25  import com.dmdirc.actions.ActionManager;
    26  import com.dmdirc.actions.CoreActionType;
    27  import com.dmdirc.commandparser.CommandArguments;
    28  import com.dmdirc.commandparser.CommandInfo;
    29  import com.dmdirc.commandparser.CommandManager;
    30  import com.dmdirc.commandparser.commands.Command;
    31  import com.dmdirc.commandparser.commands.ValidatingCommand;
    32  import com.dmdirc.commandparser.commands.WrappableCommand;
    33  import com.dmdirc.commandparser.parsers.CommandParser;
    34  import com.dmdirc.config.prefs.validator.ValidationResponse;
    35  import com.dmdirc.interfaces.ConfigChangeListener;
    36  import com.dmdirc.plugins.PluginManager;
    37  import com.dmdirc.ui.input.tabstyles.TabCompletionResult;
    38  import com.dmdirc.ui.input.tabstyles.TabCompletionStyle;
    39  import com.dmdirc.ui.interfaces.InputField;
    40  import com.dmdirc.ui.interfaces.InputValidationListener;
    41  import com.dmdirc.ui.interfaces.InputWindow;
    42  import com.dmdirc.ui.messages.Styliser;
    43  import com.dmdirc.util.ListenerList;
    44  import com.dmdirc.util.RollingList;
    45  
    46  import java.awt.Toolkit;
    47  import java.awt.event.KeyEvent;
    48  import java.util.ArrayList;
    49  import java.util.List;
    50  import java.util.Map;
    51  
    52  /**
    53   * Handles events generated by a user typing into a textfield. Allows the user
    54   * to use shortcut keys for control characters (ctrl+b, etc), to tab complete
    55   * nicknames/channel names/etc, and to scroll through their previously issued
    56   * commands.
    57   *
    58   * @author chris
    59   */
    60  public abstract class InputHandler implements ConfigChangeListener {
    61  
    62      /**
    63       * Indicates that the caret should be moved to the end of a selection when
    64       * a control code has been inserted.
    65       */
    66      private static final int POSITION_END = 1;
    67      /**
    68       * Indicates that the caret should be moved to the start of a selection when
    69       * a control code has been inserted.
    70       */
    71      protected static final int POSITION_START = 2;
    72      /** Flag to indicate that this input handler should handle tab completion. */
    73      protected static final int HANDLE_TABCOMPLETION = 1;
    74      /** Flag to indicate that this input handler should maintain a back buffer. */
    75      protected static final int HANDLE_BACKBUFFER = 2;
    76      /** Flag to indicate that this input handler should handle formatting. */
    77      protected static final int HANDLE_FORMATTING = 4;
    78      /** Flag to indicate that this input handler should handle returns. */
    79      protected static final int HANDLE_RETURN = 8;
    80      /** The flags for this particular input handler. */
    81      protected int flags = HANDLE_TABCOMPLETION | HANDLE_BACKBUFFER
    82              | HANDLE_FORMATTING | HANDLE_RETURN;
    83      /** The input buffer. */
    84      protected RollingList<String> buffer;
    85      /** The textfield that we're handling input for. */
    86      protected final InputField target;
    87      /** The TabCompleter to use for tab completion. */
    88      protected TabCompleter tabCompleter;
    89      /** The CommandParser to use for our input. */
    90      protected final CommandParser commandParser;
    91      /** The frame that we belong to. */
    92      protected final InputWindow parentWindow;
    93      /** The tab completion style. */
    94      protected TabCompletionStyle style;
    95      /** Our listener list. */
    96      private final ListenerList listeners = new ListenerList();
    97  
    98      /**
    99       * Creates a new instance of InputHandler. Adds listeners to the target
   100       * that we need to operate.
   101       *
   102       * @param thisTarget The text field this input handler is dealing with.
   103       * @param thisCommandParser The command parser to use for this text field.
   104       * @param thisParentWindow The window that owns this input handler
   105       */
   106      public InputHandler(final InputField thisTarget,
   107              final CommandParser thisCommandParser,
                     /* 
    P/P               *  Method: void com.dmdirc.ui.input.InputHandler(InputField, CommandParser, InputWindow)
                      * 
                      *  Preconditions:
                      *    thisParentWindow != null
                      * 
                      *  Presumptions:
                      *    com.dmdirc.ui.interfaces.InputWindow:getConfigManager(...)@110 != null
                      *    com.dmdirc.ui.interfaces.InputWindow:getConfigManager(...)@119 != null
                      * 
                      *  Postconditions:
                      *    this.buffer == &amp;new RollingList(InputHandler#2)
                      *    this.commandParser == thisCommandParser
                      *    init'ed(this.commandParser)
                      *    this.flags == 15
                      *    this.listeners == &amp;new ListenerList(InputHandler#1)
                      *    this.parentWindow == thisParentWindow
                      *    this.parentWindow != null
                      *    init'ed(this.style)
                      *    init'ed(this.tabCompleter)
                      *    this.target == thisTarget
                      *    ...
                      */
   108              final InputWindow thisParentWindow) {
   109  
   110          buffer = new RollingList<String>(thisParentWindow.getConfigManager().
   111                  getOptionInt("ui", "inputbuffersize"), "");
   112  
   113          this.commandParser = thisCommandParser;
   114          this.parentWindow = thisParentWindow;
   115          this.target = thisTarget;
   116  
   117          setStyle();
   118  
   119          parentWindow.getConfigManager().addChangeListener("tabcompletion",
   120                  "style", this);
   121  
   122          addUpHandler();
   123          addDownHandler();
   124          addTabHandler();
   125          addKeyHandler();
   126          addEnterHandler();
   127      }
   128  
   129      /**
   130       * Adds an arrow up key handler.
   131       */
   132      protected abstract void addUpHandler();
   133  
   134      /**
   135       * Adds an arrow down key handler.
   136       */
   137      protected abstract void addDownHandler();
   138  
   139      /**
   140       * Adds an tab key handler.
   141       */
   142      protected abstract void addTabHandler();
   143  
   144      /**
   145       * Adds a key handler.
   146       */
   147      protected abstract void addKeyHandler();
   148      
   149      /** 
   150       * Adds an enter key handler.
   151       */
   152      protected abstract void addEnterHandler();
   153  
   154      /**
   155       * Indicates which types of input this handler should handle.
   156       * 
   157       * @param handleTabCompletion Whether or not to handle tab completion
   158       * @param handleBackBuffer Whether or not to maintain an input back buffer
   159       * @param handleFormatting Whether or not to handle formatting
   160       * @param handleReturn Whether or not to handle returns
   161       */
   162      public void setTypes(final boolean handleTabCompletion,
   163              final boolean handleBackBuffer,
   164              final boolean handleFormatting, final boolean handleReturn) {
                 /* 
    P/P           *  Method: void setTypes(bool, bool, bool, bool)
                  * 
                  *  Postconditions:
                  *    this.flags == One-of{8, 0} | One-of{4, 0} | One-of{1, 0} | One-of{2, 0}
                  *    this.flags in {0..15}
                  */
   165          flags = (handleTabCompletion ? HANDLE_TABCOMPLETION : 0) 
   166                  | (handleBackBuffer ? HANDLE_BACKBUFFER : 0)
   167                  | (handleFormatting ? HANDLE_FORMATTING : 0)
   168                  | (handleReturn ? HANDLE_RETURN : 0);
   169      }
   170  
   171      /**
   172       * Sets this inputhandler's tab completion style.
   173       */
   174      private void setStyle() {
                 /* 
    P/P           *  Method: void setStyle()
                  * 
                  *  Preconditions:
                  *    init'ed(com/dmdirc/plugins/PluginManager.me)
                  *    this.parentWindow != null
                  *    init'ed(this.tabCompleter)
                  *    (soft) com/dmdirc/plugins/GlobalClassLoader.me != null
                  * 
                  *  Presumptions:
                  *    com.dmdirc.ui.interfaces.InputWindow:getConfigManager(...)@175 != null
                  *    getPluginManager(...).services != null
                  *    getServiceProvider(...).exports@175 != null
                  * 
                  *  Postconditions:
                  *    init'ed(com/dmdirc/plugins/GlobalClassLoader.me)
                  *    com/dmdirc/plugins/PluginManager.me == One-of{old com/dmdirc/plugins/PluginManager.me, &amp;new PluginManager(getPluginManager#1)}
                  *    com/dmdirc/plugins/PluginManager.me != null
                  *    java.lang.StringBuilder:toString(...)._tainted == 0
                  *    init'ed(this.style)
                  *    new GlobalClassLoader(getGlobalClassLoader#1) num objects == 0
                  *    init'ed(new GlobalClassLoader(getGlobalClassLoader#1).resourcesList)
                  *    new HashMap(GlobalClassLoader#1) num objects == 0
                  *    new HashMap(PluginManager#2) num objects <= 1
                  *    new Hashtable(PluginManager#1) num objects == new HashMap(PluginManager#2) num objects
                  *    ...
                  */
   175          style = (TabCompletionStyle) PluginManager.getPluginManager()
   176                  .getServiceProvider("tabcompletion", parentWindow.getConfigManager()
   177                  .getOption("tabcompletion", "style"))
   178                  .getExportedService("getCompletionStyle").execute(tabCompleter, parentWindow);
   179      }
   180  
   181      /**
   182       * Sets this input handler's tab completer.
   183       *
   184       * @param newTabCompleter The new tab completer
   185       */
   186      public void setTabCompleter(final TabCompleter newTabCompleter) {
                 /* 
    P/P           *  Method: void setTabCompleter(TabCompleter)
                  * 
                  *  Postconditions:
                  *    this.style == old this.style
                  *    this.tabCompleter == newTabCompleter
                  *    init'ed(this.tabCompleter)
                  */
   187          tabCompleter = newTabCompleter;
   188          setStyle();
   189      }
   190  
   191      /**
   192       * Handles the pressing of a key. Inserts control chars as appropriate.
   193       *
   194       * @param line Text in the target
   195       * @param keyCode Keycode for the pressed key
   196       * @param shiftPressed Was shift pressed
   197       * @param ctrlPressed Was ctrl key pressed
   198       */
   199      protected void handleKeyPressed(final String line, final int keyCode,
   200              final boolean shiftPressed, final boolean ctrlPressed) {
                 /* 
    P/P           *  Method: void handleKeyPressed(String, int, bool, bool)
                  * 
                  *  Preconditions:
                  *    this.target != null
                  *    (soft) line != null
                  *    (soft) this.buffer != null
                  *    (soft) this.commandParser != null
                  *    (soft) init'ed(this.flags)
                  *    (soft) this.listeners != null
                  *    (soft) this.parentWindow != null
                  * 
                  *  Test Vectors:
                  *    ctrlPressed: {0}, {1}
                  *    this.flags &amp; 4: {0}, {1..4}
                  */
   201          target.hideColourPicker();
   202          
   203          if (ctrlPressed && (flags & HANDLE_FORMATTING) != 0) {
   204              handleControlKey(line, keyCode, shiftPressed);
   205          }
   206          
   207          validateText();
   208      }
   209      
   210      /**
   211       * Validates the text currently entered in the text field.
   212       */
   213      protected void validateText() {
                 /* 
    P/P           *  Method: void validateText()
                  * 
                  *  Preconditions:
                  *    this.target != null
                  *    (soft) this.listeners != null
                  *    (soft) this.parentWindow != null
                  * 
                  *  Presumptions:
                  *    com.dmdirc.commandparser.commands.ValidatingCommand:validateArguments(...)@223 != null
                  *    com.dmdirc.ui.interfaces.InputWindow:getContainer(...)@239 != null
                  *    java.util.Map_Entry:getValue(...)@223 != null
                  *    java.util.Map_Entry:getValue(...)@234 != null
                  * 
                  *  Test Vectors:
                  *    com.dmdirc.commandparser.CommandArguments:isCommand(...)@218: {0}, {1}
                  *    com.dmdirc.commandparser.CommandManager:getCommand(...)@219: Addr_Set{null}, Inverse{null}
                  *    com.dmdirc.config.prefs.validator.ValidationResponse:isFailure(...)@226: {0}, {1}
                  */
   214          final String text = target.getText();
   215  
   216          final CommandArguments args = new CommandArguments(text);
   217  
   218          if (args.isCommand()) {
   219              final Map.Entry<CommandInfo, Command> command
   220                      = CommandManager.getCommand(args.getCommandName());
   221              
   222              if (command != null && command.getValue() instanceof ValidatingCommand) {
   223                  final ValidationResponse vr = ((ValidatingCommand) command.getValue())
   224                          .validateArguments(parentWindow, args);
   225                  
   226                  if (vr.isFailure()) {
   227                      fireCommandFailure(vr.getFailureReason());
   228                  } else {
   229                      fireCommandPassed();
   230                  }
   231              }
   232              
   233              if (command != null && command.getValue() instanceof WrappableCommand) {
   234                  final int count = ((WrappableCommand) command.getValue())
   235                          .getLineCount(parentWindow, args);
   236                  fireLineWrap(count);
   237              }
   238          } else {
   239              final int lines = parentWindow.getContainer().getNumLines(text);
   240                  fireLineWrap(lines);
   241          }
   242      }
   243      
   244      /**
   245       * Fires the "illegalCommand" method of all validation listeners.
   246       * 
   247       * @param reason The reason for the command failure
   248       */
   249      private void fireCommandFailure(final String reason) {
                 /* 
    P/P           *  Method: void fireCommandFailure(String)
                  * 
                  *  Preconditions:
                  *    this.listeners != null
                  * 
                  *  Presumptions:
                  *    com.dmdirc.util.ListenerList:get(...)@250 != null
                  *    java.util.Iterator:next(...)@250 != null
                  * 
                  *  Test Vectors:
                  *    java.util.Iterator:hasNext(...)@250: {0}, {1}
                  */
   250          for (InputValidationListener listener : listeners.get(InputValidationListener.class)) {
   251              listener.illegalCommand(reason);
   252          }
   253      }
   254      
   255      /**
   256       * Fires the "legalCommand" method of all validation listeners.
   257       */
   258      private void fireCommandPassed() {
                 /* 
    P/P           *  Method: void fireCommandPassed()
                  * 
                  *  Preconditions:
                  *    this.listeners != null
                  * 
                  *  Presumptions:
                  *    com.dmdirc.util.ListenerList:get(...)@259 != null
                  *    java.util.Iterator:next(...)@259 != null
                  * 
                  *  Test Vectors:
                  *    java.util.Iterator:hasNext(...)@259: {0}, {1}
                  */
   259          for (InputValidationListener listener : listeners.get(InputValidationListener.class)) {
   260              listener.legalCommand();
   261          }
   262      }
   263      
   264      /**
   265       * Fires the "wrappedText" method of all validation listeners.
   266       * 
   267       * @param lines The number of lines that the text will wrap to
   268       */
   269      private void fireLineWrap(final int lines) {
                 /* 
    P/P           *  Method: void fireLineWrap(int)
                  * 
                  *  Preconditions:
                  *    this.listeners != null
                  * 
                  *  Presumptions:
                  *    com.dmdirc.util.ListenerList:get(...)@270 != null
                  *    java.util.Iterator:next(...)@270 != null
                  * 
                  *  Test Vectors:
                  *    java.util.Iterator:hasNext(...)@270: {0}, {1}
                  */
   270          for (InputValidationListener listener : listeners.get(InputValidationListener.class)) {
   271              listener.wrappedText(lines);
   272          }        
   273      }
   274      
   275      /**
   276       * Adds an InputValidationListener to this input handler.
   277       * 
   278       * @param listener The listener to be added
   279       */
   280      public void addValidationListener(final InputValidationListener listener) {
                 /* 
    P/P           *  Method: void addValidationListener(InputValidationListener)
                  * 
                  *  Preconditions:
                  *    this.listeners != null
                  */
   281          listeners.add(InputValidationListener.class, listener);
   282      }
   283  
   284      /**
   285       * Handles the pressing of a key while the control key is pressed.
   286       * Inserts control chars as appropriate.
   287       *
   288       * @param line Text in the target
   289       * @param keyCode Keycode for the pressed key
   290       * @param shiftPressed Was shift pressed
   291       */
   292      protected void handleControlKey(final String line, final int keyCode,
   293              final boolean shiftPressed) {
                 /* 
    P/P           *  Method: void handleControlKey(String, int, bool)
                  * 
                  *  Preconditions:
                  *    (soft) line != null
                  *    (soft) this.buffer != null
                  *    (soft) this.commandParser != null
                  *    (soft) init'ed(this.flags)
                  *    (soft) this.target != null
                  * 
                  *  Test Vectors:
                  *    keyCode: {10}, {66}, {70}, {73}, {75}, {79}, {85}, {-231..9, 11..65, 67..69, 71,72, 74, 76..78, 80..84, 86..232-1}
                  *    shiftPressed: {0}, {1}
                  *    this.flags &amp; 8: {0}, {1..8}
                  *    java.lang.String:isEmpty(...)@328: {1}, {0}
                  */
   294          switch (keyCode) {
   295              case KeyEvent.VK_B:
   296                  addControlCode(Styliser.CODE_BOLD, POSITION_END);
   297                  break;
   298  
   299              case KeyEvent.VK_U:
   300                  addControlCode(Styliser.CODE_UNDERLINE, POSITION_END);
   301                  break;
   302  
   303              case KeyEvent.VK_O:
   304                  addControlCode(Styliser.CODE_STOP, POSITION_END);
   305                  break;
   306  
   307              case KeyEvent.VK_I:
   308                  addControlCode(Styliser.CODE_ITALIC, POSITION_END);
   309                  break;
   310  
   311              case KeyEvent.VK_F:
   312                  if (shiftPressed) {
   313                      addControlCode(Styliser.CODE_FIXED, POSITION_END);
   314                  }
   315                  break;
   316  
   317              case KeyEvent.VK_K:
   318                  if (shiftPressed) {
   319                      addControlCode(Styliser.CODE_HEXCOLOUR, POSITION_START);
   320                      target.showColourPicker(false, true);
   321                  } else {
   322                      addControlCode(Styliser.CODE_COLOUR, POSITION_START);
   323                      target.showColourPicker(true, false);
   324                  }
   325                  break;
   326  
   327              case KeyEvent.VK_ENTER:
   328                  if ((flags & HANDLE_RETURN) != 0 && !line.isEmpty()) {
   329                      commandParser.parseCommandCtrl(parentWindow, line);
   330                      addToBuffer(line);
   331                  }
   332                  break;
   333  
   334              default:
   335                  /* Do nothing. */
   336                  break;
   337          }
   338      }
   339  
   340      /**
   341       * Calls when the user presses the up key.
   342       * Handles cycling through the input buffer.
   343       */
   344      protected void doBufferUp() {
                 /* 
    P/P           *  Method: void doBufferUp()
                  * 
                  *  Preconditions:
                  *    init'ed(this.flags)
                  *    this.target != null
                  *    (soft) this.buffer != null
                  *    (soft) this.listeners != null
                  *    (soft) this.parentWindow != null
                  * 
                  *  Presumptions:
                  *    java.awt.Toolkit:getDefaultToolkit(...)@349 != null
                  * 
                  *  Test Vectors:
                  *    this.flags &amp; 2: {0}, {1,2}
                  *    com.dmdirc.util.RollingList:hasPrevious(...)@346: {0}, {1}
                  */
   345          if ((flags & HANDLE_BACKBUFFER) != 0) {
   346              if (buffer.hasPrevious()) {
   347                  target.setText(buffer.getPrevious());
   348              } else {
   349                  Toolkit.getDefaultToolkit().beep();
   350              }
   351          }
   352          validateText();
   353      }
   354  
   355      /**
   356       * Called when the user presses the down key.
   357       * Handles cycling through the input buffer, and storing incomplete lines.
   358       */
   359      protected void doBufferDown() {
                 /* 
    P/P           *  Method: void doBufferDown()
                  * 
                  *  Preconditions:
                  *    init'ed(this.flags)
                  *    this.target != null
                  *    (soft) this.buffer != null
                  *    (soft) this.listeners != null
                  *    (soft) this.parentWindow != null
                  * 
                  *  Presumptions:
                  *    com.dmdirc.ui.interfaces.InputField:getText(...)@363 != null
                  *    java.awt.Toolkit:getDefaultToolkit(...)@364 != null
                  * 
                  *  Test Vectors:
                  *    this.flags &amp; 2: {0}, {1,2}
                  *    com.dmdirc.util.RollingList:hasNext(...)@361: {0}, {1}
                  *    java.lang.String:isEmpty(...)@363: {0}, {1}
                  */
   360          if ((flags & HANDLE_BACKBUFFER) != 0) {
   361              if (buffer.hasNext()) {
   362                  target.setText(buffer.getNext());
   363              } else if (target.getText().isEmpty()) {
   364                  Toolkit.getDefaultToolkit().beep();
   365              } else {
   366                  addToBuffer(target.getText());
   367                  target.setText("");
   368              }
   369          }
   370          validateText();
   371      }
   372      
   373      /**
   374       * Retrieves a list of all known entries in the input backbuffer.
   375       * 
   376       * @since 0.6
   377       * @return A copy of the input backbuffer.
   378       */
   379      public List<String> getBackBuffer() {
                 /* 
    P/P           *  Method: List getBackBuffer()
                  * 
                  *  Preconditions:
                  *    this.buffer != null
                  * 
                  *  Postconditions:
                  *    return_value == &amp;new ArrayList(getBackBuffer#1)
                  *    new ArrayList(getBackBuffer#1) num objects == 1
                  */
   380          return new ArrayList<String>(buffer.getList());
   381      }
   382  
   383      /**
   384       * Handles tab completion of a string. Called when the user presses tab.
   385       */
   386      protected void doTabCompletion() {
                 /* 
    P/P           *  Method: void doTabCompletion()
                  * 
                  *  Preconditions:
                  *    init'ed(this.tabCompleter)
                  *    (soft) init'ed(this.flags)
                  *    (soft) this.style != null
                  *    (soft) this.target != null
                  * 
                  *  Presumptions:
                  *    com.dmdirc.ui.interfaces.InputField:getCaretPosition(...)@398 >= -231+1
                  *    com.dmdirc.ui.interfaces.InputField:getText(...)@391 != null
                  * 
                  *  Test Vectors:
                  *    this.flags &amp; 2: {1,2}, {0}
                  *    this.tabCompleter: Addr_Set{null}, Inverse{null}
                  *    java.lang.String:charAt(...)@403: {32}, {0..31, 33..216-1}
                  *    java.lang.String:charAt(...)@406: {0..31, 33..216-1}, {32}
                  *    java.lang.String:charAt(...)@411: {32}, {0..31, 33..216-1}
                  *    java.lang.String:isEmpty(...)@393: {0}, {1}
                  */
   387          if (tabCompleter == null || (flags & HANDLE_BACKBUFFER) == 0) {
   388              return;
   389          }
   390          
   391          final String text = target.getText();
   392  
   393          if (text.isEmpty()) {
   394              doNormalTabCompletion(text, 0, 0, null);
   395              return;
   396          }
   397  
   398          final int pos = target.getCaretPosition() - 1;
   399          int start = (pos < 0) ? 0 : pos;
   400          int end = (pos < 0) ? 0 : pos;
   401  
   402          // Traverse backwards
   403          while (start > 0 && text.charAt(start) != ' ') {
   404              start--;
   405          }
   406          if (text.charAt(start) == ' ') {
   407              start++;
   408          }
   409  
   410          // And forwards
   411          while (end < text.length() && text.charAt(end) != ' ') {
   412              end++;
   413          }
   414  
   415          if (start > end) {
   416              end = start;
   417          }
   418  
   419          if (start > 0 && text.charAt(0) == CommandManager.getCommandChar()) {
   420              doCommandTabCompletion(text, start, end);
   421          } else {
   422              doNormalTabCompletion(text, start, end, null);
   423          }
   424      }
   425  
   426      /**
   427       * Handles potentially intelligent tab completion.
   428       *
   429       * @param text The text that is being completed
   430       * @param start The start index of the word we're completing
   431       * @param end The end index of the word we're completing
   432       */
   433      private void doCommandTabCompletion(final String text, final int start,
   434              final int end) {
                 /* 
    P/P           *  Method: void doCommandTabCompletion(String, int, int)
                  * 
                  *  Preconditions:
                  *    text != null
                  *    this.style != null
                  *    (soft) this.target != null
                  */
   435          doNormalTabCompletion(text, start, end,
   436                  TabCompleter.getIntelligentResults(text.substring(0, start)));
   437      }
   438  
   439      /**
   440       * Handles normal (non-intelligent-command) tab completion.
   441       *
   442       * @param text The text that is being completed
   443       * @param start The start index of the word we're completing
   444       * @param end The end index of the word we're completing
   445       * @param additional A list of additional strings to use
   446       */
   447      private void doNormalTabCompletion(final String text, final int start,
   448              final int end, final AdditionalTabTargets additional) {
                 /* 
    P/P           *  Method: void doNormalTabCompletion(String, int, int, AdditionalTabTargets)
                  * 
                  *  Preconditions:
                  *    this.style != null
                  *    (soft) this.target != null
                  * 
                  *  Test Vectors:
                  *    com.dmdirc.ui.input.tabstyles.TabCompletionStyle:getResult(...)@449: Addr_Set{null}, Inverse{null}
                  */
   449          final TabCompletionResult res = style.getResult(text, start, end,
   450                  additional);
   451  
   452          if (res != null) {
   453              target.setText(res.getText());
   454              target.setCaretPosition(res.getPosition());
   455          }
   456      }
   457  
   458      /**
   459       * Called when the user presses return in the text area. The line they
   460       * typed is added to the buffer for future use.
   461       * @param line The event that was fired
   462       */
   463      public void enterPressed(final String line) {
                 /* 
    P/P           *  Method: void enterPressed(String)
                  * 
                  *  Preconditions:
                  *    line != null
                  *    this.listeners != null
                  *    (soft) this.buffer != null
                  *    (soft) this.commandParser != null
                  *    (soft) this.parentWindow != null
                  * 
                  *  Presumptions:
                  *    init'ed(com.dmdirc.actions.CoreActionType.CLIENT_USER_INPUT)
                  * 
                  *  Test Vectors:
                  *    java.lang.String:isEmpty(...)@464: {1}, {0}
                  */
   464          if (!line.isEmpty()) {
   465              final StringBuffer thisBuffer = new StringBuffer(line);
   466  
   467              ActionManager.processEvent(CoreActionType.CLIENT_USER_INPUT, null,
   468                      parentWindow.getContainer(), thisBuffer);
   469  
   470              addToBuffer(thisBuffer.toString());
   471  
   472              commandParser.parseCommand(parentWindow, thisBuffer.toString());
   473          }
   474          fireLineWrap(0);
   475          fireCommandPassed();
   476      }
   477  
   478      /**
   479       * Adds the specified control code to the textarea. If the user has a range
   480       * of text selected, the characters are added before and after, and the
   481       * caret is positioned based on the position argument.
   482       * @param code The control code to add
   483       * @param position The position of the caret after a selection is altered
   484       */
   485      protected void addControlCode(final int code, final int position) {
                 /* 
    P/P           *  Method: void addControlCode(int, int)
                  * 
                  *  Preconditions:
                  *    code in {0..216-1}
                  *    this.target != null
                  * 
                  *  Presumptions:
                  *    com.dmdirc.ui.interfaces.InputField:getCaretPosition(...)@502 <= 232-2
                  *    com.dmdirc.ui.interfaces.InputField:getSelectionEnd(...)@487 <= 232-3
                  *    com.dmdirc.ui.interfaces.InputField:getText(...)@490 != null
                  *    com.dmdirc.ui.interfaces.InputField:getText(...)@503 != null
                  *    com.dmdirc.ui.interfaces.InputField:getText(...)@504 != null
                  *    ...
                  * 
                  *  Test Vectors:
                  *    position: {-231..0, 3..232-1}, {2}, {1}
                  */
   486          final String insert = String.valueOf((char) code);
   487          final int selectionEnd = target.getSelectionEnd();
   488          final int selectionStart = target.getSelectionStart();
   489          if (selectionStart < selectionEnd) {
   490              final String source = target.getText();
   491              final String before = source.substring(0, selectionStart);
   492              final String selected = target.getSelectedText();
   493              final String after =
   494                      source.substring(selectionEnd, source.length());
   495              target.setText(before + insert + selected + insert + after);
   496              if (position == POSITION_START) {
   497                  target.setCaretPosition(selectionStart + 1);
   498              } else if (position == POSITION_END) {
   499                  target.setCaretPosition(selectionEnd + 2);
   500              }
   501          } else {
   502              final int offset = target.getCaretPosition();
   503              final String source = target.getText();
   504              final String before = target.getText().substring(0, offset);
   505              final String after = target.getText().substring(offset,
   506                      source.length());
   507              target.setText(before + insert + after);
   508              target.setCaretPosition(offset + 1);
   509          }
   510      }
   511  
   512      /**
   513       * Adds all items in the string array to the buffer.
   514       *
   515       * @param lines lines to add to the buffer
   516       */
   517      public void addToBuffer(final String[] lines) {
                 /* 
    P/P           *  Method: void addToBuffer(String[])
                  * 
                  *  Preconditions:
                  *    lines != null
                  *    lines.length <= 232-1
                  *    (soft) init'ed(lines[...])
                  *    (soft) this.buffer != null
                  */
   518          for (String line : lines) {
   519              addToBuffer(line);
   520          }
   521      }
   522  
   523      /**
   524       * Adds the specified string to the buffer.
   525       * 
   526       * @param line The line to be added to the buffer
   527       */
   528      public void addToBuffer(final String line) {
                 /* 
    P/P           *  Method: void addToBuffer(String)
                  * 
                  *  Preconditions:
                  *    this.buffer != null
                  */
   529          buffer.add(line);
   530          buffer.seekToEnd();
   531      }
   532  
   533      /** {@inheritDoc} */
   534      @Override
   535      public void configChanged(final String domain, final String key) {
                 /* 
    P/P           *  Method: void configChanged(String, String)
                  * 
                  *  Postconditions:
                  *    this.style == old this.style
                  */
   536          setStyle();
   537      }
   538  }








SofCheck Inspector Build Version : 2.17854
InputHandler.java 2009-Jun-25 01:54:24
InputHandler.class 2009-Sep-02 17:04:12