File Source: Channel.java

         /* 
    P/P   *  Method: com.dmdirc.Channel__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;
    24  
    25  import com.dmdirc.actions.ActionManager;
    26  import com.dmdirc.actions.CoreActionType;
    27  import com.dmdirc.commandparser.CommandManager;
    28  import com.dmdirc.commandparser.CommandType;
    29  import com.dmdirc.config.ConfigManager;
    30  import com.dmdirc.interfaces.ConfigChangeListener;
    31  import com.dmdirc.parser.irc.ChannelClientInfo;
    32  import com.dmdirc.parser.irc.ChannelInfo;
    33  import com.dmdirc.parser.irc.ClientInfo;
    34  import com.dmdirc.ui.WindowManager;
    35  import com.dmdirc.ui.input.TabCompleter;
    36  import com.dmdirc.ui.input.TabCompletionType;
    37  import com.dmdirc.ui.interfaces.ChannelWindow;
    38  import com.dmdirc.ui.interfaces.InputWindow;
    39  import com.dmdirc.ui.messages.ColourManager;
    40  import com.dmdirc.ui.messages.Styliser;
    41  import com.dmdirc.util.RollingList;
    42  
    43  import java.awt.Color;
    44  import java.io.Serializable;
    45  import java.util.ArrayList;
    46  import java.util.Arrays;
    47  import java.util.List;
    48  import java.util.Map;
    49  
    50  /**
    51   * The Channel class represents the client's view of the channel. It handles
    52   * callbacks for channel events from the parser, maintains the corresponding
    53   * ChannelWindow, and handles user input for the channel.
    54   *
    55   * @author chris
    56   */
         /* 
    P/P   *  Method: Window getFrame()
          * 
          *  Preconditions:
          *    init'ed(this.window)
          * 
          *  Postconditions:
          *    return_value == this.window
          *    init'ed(return_value)
          */
    57  public class Channel extends MessageTarget implements ConfigChangeListener,
    58          Serializable {
    59  
    60      /**
    61       * A version number for this class. It should be changed whenever the class
    62       * structure is changed (or anything else that would prevent serialized
    63       * objects being unserialized with the new class).
    64       */
    65      private static final long serialVersionUID = 1;
    66  
    67      /** The parser's pChannel class. */
    68      private transient ChannelInfo channelInfo;
    69  
    70      /** The server this channel is on. */
    71      private Server server;
    72  
    73      /** The ChannelWindow used for this channel. */
    74      private ChannelWindow window;
    75  
    76      /** The tabcompleter used for this channel. */
    77      private final TabCompleter tabCompleter;
    78  
    79      /** A list of previous topics we've seen. */
    80      private final RollingList<Topic> topics;
    81  
    82      /** Our event handler. */
    83      private final ChannelEventHandler eventHandler;
    84  
    85      /** Whether we're in this channel or not. */
    86      private boolean onChannel;
    87  
    88      /** Whether we should send WHO requests for this channel. */
    89      private volatile boolean sendWho;
    90  
    91      /** Whether we should show mode prefixes in text. */
    92      private volatile boolean showModePrefix;
    93  
    94      /** Whether we should show colours in nicks. */
    95      private volatile boolean showColours;
    96  
    97      /**
    98       * Creates a new instance of Channel.
    99       *
   100       * @param newServer The server object that this channel belongs to
   101       * @param newChannelInfo The parser's channel object that corresponds to
   102       * this channel
   103       */
   104      public Channel(final Server newServer, final ChannelInfo newChannelInfo) {
                 /* 
    P/P           *  Method: void com.dmdirc.Channel(Server, ChannelInfo)
                  * 
                  *  Preconditions:
                  *    com/dmdirc/Main.controller != null
                  *    init'ed(com/dmdirc/actions/ActionManager.killSwitch)
                  *    newChannelInfo != null
                  *    newServer != null
                  *    newServer.parser != null
                  *    newServer.serverInfo != null
                  *    init'ed(newServer.window)
                  *    (soft) com.dmdirc.actions.CoreActionType__static_init.new CoreActionType(CoreActionType__static_init#40).type != null
                  *    (soft) newServer.invites != null
                  *    (soft) newServer.listeners != null
                  *    ...
                  * 
                  *  Presumptions:
                  *    init'ed(com.dmdirc.commandparser.CommandType.TYPE_CHANNEL)
                  *    init'ed(com.dmdirc.commandparser.CommandType.TYPE_CHAT)
                  *    init'ed(com.dmdirc.ui.input.TabCompletionType.COMMAND)
                  *    com.dmdirc.ui.interfaces.ChannelWindow:getInputHandler(...)@129 != null
                  *    com.dmdirc.ui.interfaces.UIController:getChannel(...)@127 != null
                  *    ...
                  * 
                  *  Postconditions:
                  *    com/dmdirc/ServerManager.me == old com/dmdirc/ServerManager.me
                  *    this.changer == &amp;new FrameContainer$IconChanger(FrameContainer#2)
                  *    this.channelInfo == newChannelInfo
                  *    this.channelInfo != null
                  *    this.config == &amp;new ConfigManager(Channel#1)
                  *    this.eventHandler == &amp;new ChannelEventHandler(Channel#4)
                  *    this.icon == &amp;"channel"
                  *    this.listeners == &amp;new ListenerList(FrameContainer#1)
                  *    this.notification == com/dmdirc/FrameContainer.java.awt.Color.BLACK
                  *    init'ed(this.notification)
                  *    ...
                  */
   105          super("channel", new ConfigManager(newServer.getIrcd(), newServer.getNetwork(),
   106                  newServer.getName(), newChannelInfo.getName()));
   107  
   108          channelInfo = newChannelInfo;
   109          server = newServer;
   110  
   111          getConfigManager().addChangeListener("channel", this);
   112          getConfigManager().addChangeListener("ui", "shownickcoloursintext", this);
   113  
   114          topics = new RollingList<Topic>(getConfigManager().getOptionInt("channel",
   115                  "topichistorysize"));
   116  
   117          sendWho = getConfigManager().getOptionBool("channel", "sendwho");
   118          showModePrefix = getConfigManager().getOptionBool("channel", "showmodeprefix");
   119          showColours = getConfigManager().getOptionBool("ui", "shownickcoloursintext");
   120  
   121          tabCompleter = new TabCompleter(server.getTabCompleter());
   122          tabCompleter.addEntries(TabCompletionType.COMMAND,
   123                  CommandManager.getCommandNames(CommandType.TYPE_CHANNEL));
   124          tabCompleter.addEntries(TabCompletionType.COMMAND,
   125                  CommandManager.getCommandNames(CommandType.TYPE_CHAT));
   126  
   127          window = Main.getUI().getChannel(Channel.this);
   128          WindowManager.addWindow(server.getFrame(), window);
   129          window.getInputHandler().setTabCompleter(tabCompleter);
   130  
   131          eventHandler = new ChannelEventHandler(this);
   132  
   133          registerCallbacks();
   134  
   135          ActionManager.processEvent(CoreActionType.CHANNEL_OPENED, null, this);
   136  
   137          updateTitle();
   138          selfJoin();
   139      }
   140  
   141      /**
   142       * Registers callbacks with the parser for this channel.
   143       */
   144      private void registerCallbacks() {
                 /* 
    P/P           *  Method: void registerCallbacks()
                  * 
                  *  Preconditions:
                  *    this.channelInfo != null
                  *    this.config != null
                  *    this.eventHandler != null
                  *    this.eventHandler.owner != null
                  *    this.server != null
                  *    this.server.parser != null
                  *    this.server.serverInfo != null
                  *    (soft) this...server != null
                  */
   145          eventHandler.registerCallbacks();
   146          getConfigManager().migrate(server.getIrcd(), server.getNetwork(),
   147                  server.getName(), channelInfo.getName());
   148      }
   149  
   150      /**
   151       * Shows this channel's window.
   152       */
   153      public void show() {
                 /* 
    P/P           *  Method: void show()
                  * 
                  *  Preconditions:
                  *    this.window != null
                  */
   154          window.open();
   155      }
   156  
   157      /** {@inheritDoc} */
   158      @Override
   159      public void sendLine(final String line) {
                 /* 
    P/P           *  Method: void sendLine(String)
                  * 
                  *  Preconditions:
                  *    this.server != null
                  *    this.server.myState != null
                  *    init'ed(this.server.myState.state)
                  *    (soft) com.dmdirc.actions.CoreActionType__static_init.new CoreActionType(CoreActionType__static_init#44).type != null
                  *    (soft) init'ed(com/dmdirc/actions/ActionManager.killSwitch)
                  *    (soft) this.channelInfo != null
                  *    (soft) this.server.parser != null
                  *    (soft) this.window != null
                  * 
                  *  Presumptions:
                  *    com.dmdirc.parser.irc.ChannelInfo:getUser(...)@167 != null
                  *    com.dmdirc.ui.interfaces.ChannelWindow:getTranscoder(...)@169 != null
                  *    com.dmdirc.util.StringTranscoder:encode(...)@169 != null
                  * 
                  *  Postconditions:
                  *    com/dmdirc/ServerManager.me == old com/dmdirc/ServerManager.me
                  *    init'ed(new ArrayList(ServerManager#1) num objects)
                  *    init'ed(new ServerManager(getServerManager#1) num objects)
                  *    new ServerManager(getServerManager#1).servers == null
                  * 
                  *  Test Vectors:
                  *    com.dmdirc.parser.irc.IRCParser:getChannelInfo(...)@160: Inverse{null}, Addr_Set{null}
                  *    java.util.Iterator:hasNext(...)@169: {0}, {1}
                  */
   160          if (server.getState() != ServerState.CONNECTED
   161                  || server.getParser().getChannelInfo(channelInfo.getName()) == null) {
   162              // We're not in the channel/connected to the server
   163              return;
   164          }
   165  
   166          final ClientInfo me = server.getParser().getMyself();
   167          final String[] details = getDetails(channelInfo.getUser(me), showColours);
   168  
   169          for (String part : splitLine(window.getTranscoder().encode(line))) {
   170              final StringBuffer buff = new StringBuffer("channelSelfMessage");
   171  
   172              ActionManager.processEvent(CoreActionType.CHANNEL_SELF_MESSAGE, buff,
   173                      this, channelInfo.getUser(me), part);
   174  
   175              addLine(buff, details[0], details[1], details[2], details[3],
   176                      part, channelInfo);
   177  
   178              channelInfo.sendMessage(part);
   179          }
   180      }
   181  
   182      /** {@inheritDoc} */
   183      @Override
   184      public int getMaxLineLength() {
                 /* 
    P/P           *  Method: int getMaxLineLength()
                  * 
                  *  Preconditions:
                  *    this.server != null
                  *    this.server.myState != null
                  *    init'ed(this.server.myState.state)
                  *    (soft) this.channelInfo != null
                  *    (soft) this.server.parser != null
                  * 
                  *  Postconditions:
                  *    init'ed(return_value)
                  */
   185          return server.getState() == ServerState.CONNECTED
   186                  ? server.getParser().getMaxLength("PRIVMSG", getChannelInfo().getName())
   187                  : -1;
   188      }
   189  
   190      /** {@inheritDoc} */
   191      @Override
   192      public void sendAction(final String action) {
                 /* 
    P/P           *  Method: void sendAction(String)
                  * 
                  *  Preconditions:
                  *    this.server != null
                  *    this.server.myState != null
                  *    init'ed(this.server.myState.state)
                  *    (soft) action != null
                  *    (soft) com.dmdirc.actions.CoreActionType__static_init.new CoreActionType(CoreActionType__static_init#45).type != null
                  *    (soft) init'ed(com/dmdirc/actions/ActionManager.killSwitch)
                  *    (soft) init'ed(com/dmdirc/ServerManager.me)
                  *    (soft) this.channelInfo != null
                  *    (soft) this.server.parser != null
                  *    (soft) this.window != null
                  * 
                  *  Presumptions:
                  *    com.dmdirc.parser.irc.ChannelInfo:getUser(...)@200 != null
                  *    com.dmdirc.ui.interfaces.ChannelWindow:getTranscoder(...)@211 != null
                  *    com.dmdirc.ui.interfaces.ChannelWindow:getTranscoder(...)@214 != null
                  * 
                  *  Postconditions:
                  *    com/dmdirc/ServerManager.me == old com/dmdirc/ServerManager.me
                  *    new ArrayList(ServerManager#1) num objects == 0, if init'ed
                  *    new ServerManager(getServerManager#1) num objects == 0, if init'ed
                  *    new ServerManager(getServerManager#1).servers == null
                  * 
                  *  Test Vectors:
                  *    com.dmdirc.parser.irc.IRCParser:getChannelInfo(...)@193: Inverse{null}, Addr_Set{null}
                  */
   193          if (server.getState() != ServerState.CONNECTED
   194                  || server.getParser().getChannelInfo(channelInfo.getName()) == null) {
   195              // We're not on the server/channel
   196              return;
   197          }
   198  
   199          final ClientInfo me = server.getParser().getMyself();
   200          final String[] details = getDetails(channelInfo.getUser(me), showColours);
   201  
   202          if (server.getParser().getMaxLength("PRIVMSG", getChannelInfo().getName())
   203                  <= action.length()) {
   204              addLine("actionTooLong", action.length());
   205          } else {
   206              final StringBuffer buff = new StringBuffer("channelSelfAction");
   207  
   208              ActionManager.processEvent(CoreActionType.CHANNEL_SELF_ACTION, buff,
   209                      this, channelInfo.getUser(me), action);
   210  
   211              addLine(buff, details[0], details[1], details[2], details[3],
   212                      window.getTranscoder().encode(action), channelInfo);
   213  
   214              channelInfo.sendAction(window.getTranscoder().encode(action));
   215          }
   216      }
   217  
   218      /**
   219       * Returns the server object that this channel belongs to.
   220       *
   221       * @return The server object
   222       */
   223      @Override
   224      public Server getServer() {
                 /* 
    P/P           *  Method: Server getServer()
                  * 
                  *  Preconditions:
                  *    init'ed(this.server)
                  * 
                  *  Postconditions:
                  *    return_value == this.server
                  *    init'ed(return_value)
                  */
   225          return server;
   226      }
   227  
   228      /**
   229       * Returns the parser's ChannelInfo object that this object is associated
   230       * with.
   231       *
   232       * @return The ChannelInfo object associated with this object
   233       */
   234      public ChannelInfo getChannelInfo() {
                 /* 
    P/P           *  Method: ChannelInfo getChannelInfo()
                  * 
                  *  Preconditions:
                  *    init'ed(this.channelInfo)
                  * 
                  *  Postconditions:
                  *    return_value == this.channelInfo
                  *    init'ed(return_value)
                  */
   235          return channelInfo;
   236      }
   237  
   238      /**
   239       * Sets this object's ChannelInfo reference to the one supplied. This only
   240       * needs to be done if the channel window (and hence this channel object)
   241       * has stayed open while the user has been out of the channel.
   242       *
   243       * @param newChannelInfo The new ChannelInfo object
   244       */
   245      public void setChannelInfo(final ChannelInfo newChannelInfo) {
                 /* 
    P/P           *  Method: void setChannelInfo(ChannelInfo)
                  * 
                  *  Preconditions:
                  *    newChannelInfo != null
                  *    this.config != null
                  *    this.eventHandler != null
                  *    this.eventHandler.owner != null
                  *    this.server != null
                  *    this.server.parser != null
                  *    this.server.serverInfo != null
                  *    (soft) this...server != null
                  * 
                  *  Postconditions:
                  *    this.channelInfo == newChannelInfo
                  *    this.channelInfo != null
                  */
   246          channelInfo = newChannelInfo;
   247          registerCallbacks();
   248      }
   249  
   250      /**
   251       * Returns the internal window belonging to this object.
   252       *
   253       * @return This object's internal window
   254       */
   255      @Override
   256      public InputWindow getFrame() {
                 /* 
    P/P           *  Method: InputWindow getFrame()
                  * 
                  *  Preconditions:
                  *    init'ed(this.window)
                  * 
                  *  Postconditions:
                  *    return_value == this.window
                  *    init'ed(return_value)
                  */
   257          return window;
   258      }
   259  
   260      /**
   261       * Returns the tab completer for this channel.
   262       *
   263       * @return This channel's tab completer
   264       */
   265      public TabCompleter getTabCompleter() {
                 /* 
    P/P           *  Method: TabCompleter getTabCompleter()
                  * 
                  *  Postconditions:
                  *    return_value == this.tabCompleter
                  *    init'ed(return_value)
                  */
   266          return tabCompleter;
   267      }
   268  
   269      /**
   270       * Called when we join this channel. Just needs to output a message.
   271       */
   272      public void selfJoin() {
                 /* 
    P/P           *  Method: void selfJoin()
                  * 
                  *  Preconditions:
                  *    this.channelInfo != null
                  *    this.config != null
                  *    this.listeners != null
                  *    this.server != null
                  *    this.server.parser != null
                  *    (soft) this.server.invites != null
                  *    (soft) this.server.listeners != null
                  * 
                  *  Presumptions:
                  *    com.dmdirc.parser.irc.IRCParser:getMyself(...)@275 != null
                  * 
                  *  Postconditions:
                  *    this.icon == &amp;"channel"
                  *    this.onChannel == 1
                  */
   273          onChannel = true;
   274  
   275          final ClientInfo me = server.getParser().getMyself();
   276          addLine("channelSelfJoin", "", me.getNickname(), me.getIdent(),
   277                  me.getHost(), channelInfo.getName());
   278  
   279          setIcon("channel");
   280  
   281          server.removeInvites(channelInfo.getName());
   282      }
   283  
   284      /**
   285       * Updates the title of the channel window, and of the main window if
   286       * appropriate.
   287       */
   288      private void updateTitle() {
                 /* 
    P/P           *  Method: void updateTitle()
                  * 
                  *  Preconditions:
                  *    this.channelInfo != null
                  *    this.window != null
                  * 
                  *  Presumptions:
                  *    com.dmdirc.parser.irc.ChannelInfo:getTopic(...)@291 != null
                  * 
                  *  Test Vectors:
                  *    java.lang.String:isEmpty(...)@291: {1}, {0}
                  */
   289          String temp = Styliser.stipControlCodes(channelInfo.getName());
   290  
   291          if (!channelInfo.getTopic().isEmpty()) {
   292              temp = temp + " - " + Styliser.stipControlCodes(channelInfo.getTopic());
   293          }
   294  
   295          window.setTitle(temp);
   296      }
   297  
   298      /**
   299       * Joins the specified channel. This only makes sense if used after a call
   300       * to part().
   301       */
   302      public void join() {
                 /* 
    P/P           *  Method: void join()
                  * 
                  *  Preconditions:
                  *    this.channelInfo != null
                  *    this.config != null
                  *    this.listeners != null
                  *    this.server != null
                  *    this.server.parser != null
                  * 
                  *  Postconditions:
                  *    this.icon == &amp;"channel"
                  */
   303          server.getParser().joinChannel(channelInfo.getName());
   304          activateFrame();
   305  
   306          setIcon("channel");
   307      }
   308  
   309      /**
   310       * Parts this channel with the specified message. Parting does NOT close the
   311       * channel window.
   312       *
   313       * @param reason The reason for parting the channel
   314       */
   315      public void part(final String reason) {
                 /* 
    P/P           *  Method: void part(String)
                  * 
                  *  Preconditions:
                  *    this.config != null
                  *    this.listeners != null
                  *    init'ed(this.server)
                  *    this.window != null
                  *    (soft) this.channelInfo != null
                  *    (soft) init'ed(this.server.parser)
                  * 
                  *  Postconditions:
                  *    this.icon == &amp;"channel-inactive"
                  *    this.onChannel == 0
                  * 
                  *  Test Vectors:
                  *    this.server: Addr_Set{null}, Inverse{null}
                  *    this.server.parser: Addr_Set{null}, Inverse{null}
                  */
   316          if (server != null && server.getParser() != null) {
   317              server.getParser().partChannel(channelInfo.getName(), reason);
   318          }
   319  
   320          resetWindow();
   321      }
   322  
   323      /**
   324       * Resets the window state after the client has left a channel.
   325       */
   326      public void resetWindow() {
                 /* 
    P/P           *  Method: void resetWindow()
                  * 
                  *  Preconditions:
                  *    this.config != null
                  *    this.listeners != null
                  *    this.window != null
                  * 
                  *  Postconditions:
                  *    this.icon == &amp;"channel-inactive"
                  *    this.onChannel == 0
                  */
   327          onChannel = false;
   328  
   329          setIcon("channel-inactive");
   330  
   331          window.updateNames(new ArrayList<ChannelClientInfo>());
   332      }
   333  
   334      /** {@inheritDoc} */
   335      @Override
   336      public void windowClosing() {
   337          // 1: Make the window non-visible
                 /* 
    P/P           *  Method: void windowClosing()
                  * 
                  *  Preconditions:
                  *    init'ed(com/dmdirc/actions/ActionManager.killSwitch)
                  *    init'ed(this.onChannel)
                  *    this.server != null
                  *    this.window != null
                  *    this.channelInfo != null
                  *    this.eventHandler != null
                  *    this.eventHandler.owner != null
                  *    this.server.channels != null
                  *    this.server.converter != null
                  *    init'ed(this.server.parser)
                  *    ...
                  * 
                  *  Presumptions:
                  *    com.dmdirc.parser.irc.IRCParser:getCallbackManager(...)@344 != null
                  * 
                  *  Postconditions:
                  *    com/dmdirc/ServerManager.me == old com/dmdirc/ServerManager.me
                  *    this.icon == One-of{old this.icon, &amp;"channel-inactive"}
                  *    this.onChannel == 0
                  *    this.server == null
                  *    this.window == null
                  *    new ArrayList(ServerManager#1) num objects == undefined
                  *    new ArrayList(ServerManager#1) num objects == 0, if init'ed
                  *    new ServerManager(getServerManager#1) num objects == new ArrayList(ServerManager#1) num objects
                  *    new ServerManager(getServerManager#1).servers == undefined
                  *    new ServerManager(getServerManager#1).servers == null
                  * 
                  *  Test Vectors:
                  *    this.onChannel: {0}, {1}
                  *    this.server.parser: Addr_Set{null}, Inverse{null}
                  */
   338          window.setVisible(false);
   339  
   340          // 2: Remove any callbacks or listeners
   341          eventHandler.unregisterCallbacks();
   342  
   343          if (server.getParser() != null) {
   344              server.getParser().getCallbackManager().delAllCallback(eventHandler);
   345          }
   346  
   347          // 3: Trigger any actions neccessary
   348          if (onChannel) {
   349              part(getConfigManager().getOption("general", "partmessage"));
   350          }
   351  
   352          // 4: Trigger action for the window closing
   353          ActionManager.processEvent(CoreActionType.CHANNEL_CLOSED, null, this);
   354  
   355          // 5: Inform any parents that the window is closing
   356          server.delChannel(channelInfo.getName());
   357  
   358          // 6: Remove the window from the window manager
   359          WindowManager.removeWindow(window);
   360  
   361          // 7: Remove any references to the window and parents
   362          window = null; // NOPMD
   363          server = null; // NOPMD
   364      }
   365  
   366      /**
   367       * Called every {general.whotime} seconds to check if the channel needs
   368       * to send a who request.
   369       */
   370      public void checkWho() {
                 /* 
    P/P           *  Method: void checkWho()
                  * 
                  *  Preconditions:
                  *    init'ed(this.onChannel)
                  *    (soft) this.channelInfo != null
                  *    (soft) this.server != null
                  *    (soft) this.server.parser != null
                  * 
                  *  Test Vectors:
                  *    this.onChannel: {0}, {1}
                  *    this.sendWho: {0}, {1}
                  */
   371          if (onChannel && sendWho) {
   372              server.getParser().sendLine("WHO :" + channelInfo.getName());
   373          }
   374      }
   375  
   376      /**
   377       * Adds a ChannelClient to this Channel.
   378       *
   379       * @param client The client to be added
   380       */
   381      public void addClient(final ChannelClientInfo client) {
                 /* 
    P/P           *  Method: void addClient(ChannelClientInfo)
                  * 
                  *  Preconditions:
                  *    client != null
                  *    this.tabCompleter != null
                  *    this.window != null
                  * 
                  *  Presumptions:
                  *    init'ed(com.dmdirc.ui.input.TabCompletionType.CHANNEL_NICK)
                  */
   382          window.addName(client);
   383          tabCompleter.addEntry(TabCompletionType.CHANNEL_NICK, client.getNickname());
   384      }
   385  
   386      /**
   387       * Removes the specified ChannelClient from this channel.
   388       *
   389       * @param client The client to be removed
   390       */
   391      public void removeClient(final ChannelClientInfo client) {
                 /* 
    P/P           *  Method: void removeClient(ChannelClientInfo)
                  * 
                  *  Preconditions:
                  *    client != null
                  *    this.server != null
                  *    this.server.parser != null
                  *    this.tabCompleter != null
                  *    this.window != null
                  *    (soft) this.config != null
                  *    (soft) this.listeners != null
                  * 
                  *  Presumptions:
                  *    com.dmdirc.parser.irc.ChannelClientInfo:getClient(...)@395 != null
                  *    init'ed(com.dmdirc.ui.input.TabCompletionType.CHANNEL_NICK)
                  * 
                  *  Postconditions:
                  *    this.icon == One-of{old this.icon, &amp;"channel-inactive"}
                  *    possibly_updated(this.onChannel)
                  * 
                  *  Test Vectors:
                  *    java.lang.Object:equals(...)@395: {0}, {1}
                  */
   392          window.removeName(client);
   393          tabCompleter.removeEntry(TabCompletionType.CHANNEL_NICK, client.getNickname());
   394  
   395          if (client.getClient().equals(server.getParser().getMyself())) {
   396              resetWindow();
   397          }
   398      }
   399  
   400      /**
   401       * Replaces the list of known clients on this channel with the specified
   402       * one.
   403       *
   404       * @param clients The list of clients to use
   405       */
   406      public void setClients(final List<ChannelClientInfo> clients) {
                 /* 
    P/P           *  Method: void setClients(List)
                  * 
                  *  Preconditions:
                  *    clients != null
                  *    this.tabCompleter != null
                  *    this.window != null
                  * 
                  *  Presumptions:
                  *    init'ed(com.dmdirc.ui.input.TabCompletionType.CHANNEL_NICK)
                  *    java.util.Iterator:next(...)@411 != null
                  * 
                  *  Test Vectors:
                  *    java.util.Iterator:hasNext(...)@411: {0}, {1}
                  */
   407          window.updateNames(clients);
   408  
   409          tabCompleter.clear(TabCompletionType.CHANNEL_NICK);
   410  
   411          for (ChannelClientInfo client : clients) {
   412              tabCompleter.addEntry(TabCompletionType.CHANNEL_NICK, client.getNickname());
   413          }
   414      }
   415  
   416      /**
   417       * Renames a client that is in this channel.
   418       *
   419       * @param oldName The old nickname of the client
   420       * @param newName The new nickname of the client
   421       */
   422      public void renameClient(final String oldName, final String newName) {
                 /* 
    P/P           *  Method: void renameClient(String, String)
                  * 
                  *  Preconditions:
                  *    this.tabCompleter != null
                  *    this.window != null
                  * 
                  *  Presumptions:
                  *    init'ed(com.dmdirc.ui.input.TabCompletionType.CHANNEL_NICK)
                  */
   423          tabCompleter.removeEntry(TabCompletionType.CHANNEL_NICK, oldName);
   424          tabCompleter.addEntry(TabCompletionType.CHANNEL_NICK, newName);
   425          refreshClients();
   426      }
   427  
   428      /**
   429       * Refreshes the list of clients stored by this channel. Should be called
   430       * when (visible) user modes or nicknames change.
   431       */
   432      public void refreshClients() {
                 /* 
    P/P           *  Method: void refreshClients()
                  * 
                  *  Preconditions:
                  *    this.window != null
                  */
   433          window.updateNames();
   434      }
   435  
   436      /**
   437       * Returns a string containing the most important mode for the specified
   438       * client.
   439       *
   440       * @param channelClient The channel client to check.
   441       * @return A string containing the most important mode, or an empty string
   442       * if there are no (known) modes.
   443       */
   444      private String getModes(final ChannelClientInfo channelClient) {
                 /* 
    P/P           *  Method: String getModes(ChannelClientInfo)
                  * 
                  *  Postconditions:
                  *    init'ed(return_value)
                  * 
                  *  Test Vectors:
                  *    channelClient: Addr_Set{null}, Inverse{null}
                  *    this.showModePrefix: {1}, {0}
                  */
   445          if (channelClient == null || !showModePrefix) {
   446              return "";
   447          } else {
   448              return channelClient.getImportantModePrefix();
   449          }
   450      }
   451  
   452      /**
   453       * Adds the specified topic to this channel's topic list.
   454       *
   455       * @param topic The topic to be added.
   456       */
   457      public void addTopic(final Topic topic) {
                 /* 
    P/P           *  Method: void addTopic(Topic)
                  * 
                  *  Preconditions:
                  *    this.channelInfo != null
                  *    this.topics != null
                  *    this.window != null
                  */
   458          topics.add(topic);
   459          updateTitle();
   460      }
   461  
   462      /**
   463       * Retrieve the topics that have been seen on this channel.
   464       *
   465       * @return A list of topics that have been seen on this channel, including
   466       * the current one.
   467       */
   468      public List<Topic> getTopics() {
                 /* 
    P/P           *  Method: List getTopics()
                  * 
                  *  Preconditions:
                  *    this.topics != null
                  * 
                  *  Postconditions:
                  *    init'ed(return_value)
                  */
   469          return topics.getList();
   470      }
   471  
   472      /**
   473       * Returns this channel's name.
   474       *
   475       * @return A string representation of this channel (i.e., its name)
   476       */
   477      @Override
   478      public String toString() {
                 /* 
    P/P           *  Method: String toString()
                  * 
                  *  Preconditions:
                  *    this.channelInfo != null
                  * 
                  *  Postconditions:
                  *    init'ed(return_value)
                  */
   479          return channelInfo.getName();
   480      }
   481  
   482      /** {@inheritDoc} */
   483      @Override
   484      public void configChanged(final String domain, final String key) {
                 /* 
    P/P           *  Method: void configChanged(String, String)
                  * 
                  *  Preconditions:
                  *    (soft) this.config != null
                  * 
                  *  Postconditions:
                  *    possibly_updated(this.sendWho)
                  *    possibly_updated(this.showColours)
                  *    possibly_updated(this.showModePrefix)
                  * 
                  *  Test Vectors:
                  *    java.lang.String:equals(...)@485: {0}, {1}
                  *    java.lang.String:equals(...)@487: {0}, {1}
                  *    java.lang.String:equals(...)@489: {0}, {1}
                  */
   485          if ("sendwho".equals(key)) {
   486              sendWho = getConfigManager().getOptionBool("channel", "sendwho");
   487          } else if ("showmodeprefix".equals(key)) {
   488              showModePrefix = getConfigManager().getOptionBool("channel", "showmodeprefix");
   489          } else if ("shownickcoloursintext".equals(key)) {
   490              showColours = getConfigManager().getOptionBool("ui", "shownickcoloursintext");
   491          }
   492      }
   493  
   494      /**
   495       * Returns a string[] containing the nickname/ident/host of a channel
   496       * client.
   497       *
   498       * @param client The channel client to check
   499       * @param showColours Whether or not to show colours
   500       * @return A string[] containing displayable components
   501       */
   502      private String[] getDetails(final ChannelClientInfo client,
   503              final boolean showColours) {
                 /* 
    P/P           *  Method: String[] getDetails(ChannelClientInfo, bool)
                  * 
                  *  Preconditions:
                  *    client != null
                  * 
                  *  Presumptions:
                  *    com.dmdirc.parser.irc.ChannelClientInfo:getClient(...)@513 != null
                  *    com.dmdirc.parser.irc.ChannelClientInfo:getClient(...)@514 != null
                  *    com.dmdirc.parser.irc.ChannelClientInfo:getMap(...)@517 != null
                  * 
                  *  Postconditions:
                  *    java.lang.StringBuilder:toString(...)._tainted == 0
                  *    return_value == &amp;new String[](getDetails#1)
                  *    new String[](getDetails#1) num objects == 1
                  *    return_value.length == 4
                  *    init'ed(return_value[0])
                  *    return_value[1] in Addr_Set{&amp;java.lang.StringBuilder:toString(...),&amp;java.lang.StringBuilder:toString(...)}
                  *    init'ed(return_value[2])
                  *    init'ed(return_value[3])
                  * 
                  *  Test Vectors:
                  *    showColours: {0}, {1}
                  *    java.util.Map:containsKey(...)@521: {0}, {1}
                  *    java.util.Map:containsKey(...)@524: {0}, {1}
                  */
   504          if (client == null) {
   505              // WTF?
   506              throw new UnsupportedOperationException("getDetails called with"
   507                       + " null ChannelClientInfo");
   508          }
   509  
   510          final String[] res = new String[4];
   511          res[0] = getModes(client);
   512          res[1] = Styliser.CODE_NICKNAME + client.getNickname() + Styliser.CODE_NICKNAME;
   513          res[2] = client.getClient().getIdent();
   514          res[3] = client.getClient().getHost();
   515  
   516          if (showColours) {
   517              final Map map = client.getMap();
   518              String prefix = null;
   519              Color colour;
   520  
   521              if (map.containsKey(ChannelClientProperty.TEXT_FOREGROUND)) {
   522                  colour = (Color) map.get(ChannelClientProperty.TEXT_FOREGROUND);
   523                  prefix = Styliser.CODE_HEXCOLOUR + ColourManager.getHex(colour);
   524                  if (map.containsKey(ChannelClientProperty.TEXT_BACKGROUND)) {
   525                      colour = (Color) map.get(ChannelClientProperty.TEXT_BACKGROUND);
   526                      prefix = "," + ColourManager.getHex(colour);
   527                  }
   528              }
   529  
   530              if (prefix != null) {
   531                  res[1] = prefix + res[1] + Styliser.CODE_HEXCOLOUR;
   532              }
   533          }
   534  
   535          return res;
   536      }
   537  
   538      /** {@inheritDoc} */
   539      @Override
   540      protected boolean processNotificationArg(final Object arg, final List<Object> args) {
                 /* 
    P/P           *  Method: bool processNotificationArg(Object, List)
                  * 
                  *  Preconditions:
                  *    (soft) arg.time in {-9_223_372_036_854_775..18_446_744_073_709_551}
                  *    (soft) args != null
                  * 
                  *  Postconditions:
                  *    init'ed(return_value)
                  */
   541          if (arg instanceof ClientInfo) {
   542              // Format ClientInfos
   543  
   544              final ClientInfo clientInfo = (ClientInfo) arg;
   545              args.add(clientInfo.getNickname());
   546              args.add(clientInfo.getIdent());
   547              args.add(clientInfo.getHost());
   548  
   549              return true;
   550          } else if (arg instanceof ChannelClientInfo) {
   551              // Format ChannelClientInfos
   552  
   553              final ChannelClientInfo clientInfo = (ChannelClientInfo) arg;
   554              args.addAll(Arrays.asList(getDetails(clientInfo, showColours)));
   555  
   556              return true;
   557          } else if (arg instanceof Topic) {
   558              // Format topics
   559  
   560              args.add("");
   561              args.addAll(Arrays.asList(ClientInfo.parseHostFull(((Topic) arg).getClient())));
   562              args.add(((Topic) arg).getTopic());
   563              args.add(((Topic) arg).getTime() * 1000);
   564  
   565              return true;
   566          } else {
   567              // Everything else - default formatting
   568  
   569              return super.processNotificationArg(arg, args);
   570          }
   571      }
   572  
   573      /** {@inheritDoc} */
   574      @Override
   575      protected void modifyNotificationArgs(final List<Object> actionArgs,
   576              final List<Object> messageArgs) {
                 /* 
    P/P           *  Method: void modifyNotificationArgs(List, List)
                  * 
                  *  Preconditions:
                  *    messageArgs != null
                  *    this.channelInfo != null
                  */
   577          messageArgs.add(channelInfo.getName());
   578      }
   579  
   580      // ------------------------------------------ PARSER METHOD DELEGATION -----
   581  
   582      /**
   583       * Attempts to set the topic of this channel.
   584       *
   585       * @param topic The new topic to be used. An empty string will clear the
   586       * current topic
   587       */
   588      public void setTopic(final String topic) {
                 /* 
    P/P           *  Method: void setTopic(String)
                  * 
                  *  Preconditions:
                  *    this.channelInfo != null
                  *    this.server != null
                  *    this.server.parser != null
                  */
   589          server.getParser().sendLine("TOPIC " + channelInfo.getName() + " :" + topic);
   590      }
   591  }








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