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 == &new FrameContainer$IconChanger(FrameContainer#2)
* this.channelInfo == newChannelInfo
* this.channelInfo != null
* this.config == &new ConfigManager(Channel#1)
* this.eventHandler == &new ChannelEventHandler(Channel#4)
* this.icon == &"channel"
* this.listeners == &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 == &"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 == &"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 == &"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 == &"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, &"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, &"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 == &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{&java.lang.StringBuilder:toString(...),&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 |