Browse Source

Merge branch 'master' of https://github.com/DMDirc/DMDirc

pull/525/head
Greg Holmes 9 years ago
parent
commit
b686682a55

+ 0
- 2
res/com/dmdirc/config/defaults/default/defaults View File

@@ -182,8 +182,6 @@ treeview:
182 182
   foregroundcolour=false:0
183 183
 
184 184
 channel:
185
-  splitusermodes=false
186
-  hideduplicatemodes=false
187 185
   showmodeprefix=true
188 186
   topichistorysize=10
189 187
   encoding=UTF-8

+ 36
- 14
res/com/dmdirc/ui/messages/format.yml View File

@@ -8,6 +8,42 @@ ServerCtcpEvent:
8 8
 ServerCtcpReplyEvent:
9 9
   format: "-!- CTCP {{type}} reply from {{user.nickname}}: {{content}}."
10 10
   colour: 4
11
+ServerDisconnectedEvent:
12
+  format: "-!- You have been disconnected from the server."
13
+  colour: 2
14
+ServerConnectErrorEvent:
15
+  format: "Error connecting: {{message}}"
16
+  colour: 2
17
+ServerReconnectScheduledEvent:
18
+  format: "Reconnecting in {{seconds}} seconds..."
19
+  colour: 2
20
+ServerStonedEvent:
21
+  format: "-!- Disconnected from a non-responsive server."
22
+  colour: 2
23
+ServerMotdStartEvent:
24
+  format: "{{message}}"
25
+  colour: 10
26
+ServerMotdLineEvent:
27
+  format: "{{message}}"
28
+  colour: 10
29
+ServerMotdEndEvent:
30
+  format: "{{message}}"
31
+  colour: 10
32
+ServerAwayEvent:
33
+  format: "You are now marked as away ({{reason}})."
34
+  colour: 14
35
+ServerBackEvent:
36
+  format: "You are no longer marked as away."
37
+  colour: 14
38
+
39
+################## Server messaging events #########################################################
40
+
41
+ServerNoticeEvent:
42
+  format: "-{{user.nickname}}- {{message}}"
43
+  colour: 5
44
+ServerServerNoticeEvent:
45
+  format: "-{{user.nickname}}- {{message}}"
46
+  colour: 5
11 47
 
12 48
 ################## Channel join/part/quit events ###################################################
13 49
 
@@ -127,11 +163,8 @@ CommandOutputEvent:
127 163
   format: "{{message}}"
128 164
 
129 165
 ################## TODO ############################################################################
130
-#  channelSplitUserMode_default=3* %1$s%2$s sets mode %9$s on %6$s.
131 166
 #  channelNoModes=3* There are no channel modes for %2$s.
132 167
 #  channelModeDiscovered=3* Channel modes for %2$s are: %1$s.
133
-#  privateNotice=5-%1$s- %4$s
134
-#  serverNotice=5-%1$s- %4$s
135 168
 #  userModeChanged=3* %1$s sets user mode: %4$s.
136 169
 #  userNoModes=3* No user modes.
137 170
 #  userModeDiscovered=3* User modes are: %4$s.
@@ -142,23 +175,12 @@ CommandOutputEvent:
142 175
 #  selfCTCP=4->- [%1$s] %2$s
143 176
 #  selfNotice=5>%1$s> %2$s
144 177
 #  selfMessage=>[%1$s]> %2$s
145
-#  connectError=2Error connecting: %2$s
146
-#  connectRetry=2Reconnecting in %2$u...
147 178
 #  serverConnecting=Connecting to %1$s:%2$s...
148
-#  back=14You are no longer marked as away.
149 179
 #  serverDisconnectInProgress=A disconnection attempt is in progress, please wait...
150 180
 #  serverConnectInProgress=A connection attempt is in progress, please wait...
151 181
 #  authNotice=5-AUTH- %1$s
152
-#  away=14You are now marked as away (%1$s14).
153 182
 #  rawCommand=10>>> %1$s
154 183
 #  unknownCommand=14Unknown command %1$s.
155
-#  socketClosed=2-!- You have been disconnected from the server.
156
-#  stonedServer=2-!- Disconnected from a non-responsive server.
157
-#  motdStart=10%1$s
158
-#  motdLine=10%1$s
159
-#  motdEnd=10%1$s
160
-#  rawIn=<< %1$s
161
-#  rawOut=>> %1$s
162 184
 #  commandOutput=%1$s
163 185
 #  actionTooLong=Warning: action too long to be sent
164 186
 #  tabCompletion=14Multiple possibilities: %1$s

+ 0
- 13
src/com/dmdirc/Channel.java View File

@@ -86,9 +86,6 @@ public class Channel extends FrameContainer implements GroupChat {
86 86
     private final GroupChatUserManager groupChatUserManager;
87 87
     /** Whether we're in this channel or not. */
88 88
     private boolean isOnChannel;
89
-    /** Whether we should send WHO requests for this channel. */
90
-    @ConfigBinding(domain = "channel", key = "sendwho")
91
-    private volatile boolean sendWho;
92 89
     /** Whether we should show mode prefixes in text. */
93 90
     @ConfigBinding(domain = "channel", key = "showmodeprefix")
94 91
     private volatile boolean showModePrefix;
@@ -229,7 +226,6 @@ public class Channel extends FrameContainer implements GroupChat {
229 226
         final User me = connection.getLocalUser().get();
230 227
         getEventBus().publishAsync(new ChannelSelfJoinEvent(this, me));
231 228
 
232
-        checkWho();
233 229
         setIcon("channel");
234 230
 
235 231
         connection.getInviteManager().removeInvites(channelInfo.getName());
@@ -299,15 +295,6 @@ public class Channel extends FrameContainer implements GroupChat {
299 295
         getEventBus().publish(new ChannelClosedEvent(this));
300 296
     }
301 297
 
302
-    /**
303
-     * Called every {general.whotime} seconds to check if the channel needs to send a who request.
304
-     */
305
-    public void checkWho() {
306
-        if (isOnChannel && sendWho) {
307
-            channelInfo.sendWho();
308
-        }
309
-    }
310
-
311 298
     /**
312 299
      * Adds a ChannelClient to this Channel.
313 300
      *

+ 14
- 70
src/com/dmdirc/ChannelEventHandler.java View File

@@ -45,7 +45,6 @@ import com.dmdirc.events.ChannelTopicChangeEvent;
45 45
 import com.dmdirc.events.ChannelTopicUnsetEvent;
46 46
 import com.dmdirc.events.ChannelUserAwayEvent;
47 47
 import com.dmdirc.events.ChannelUserBackEvent;
48
-import com.dmdirc.events.ChannelUserModeChangeEvent;
49 48
 import com.dmdirc.interfaces.Connection;
50 49
 import com.dmdirc.parser.common.AwayState;
51 50
 import com.dmdirc.parser.common.CallbackManager;
@@ -64,12 +63,10 @@ import com.dmdirc.parser.interfaces.callbacks.ChannelModeChangeListener;
64 63
 import com.dmdirc.parser.interfaces.callbacks.ChannelModeNoticeListener;
65 64
 import com.dmdirc.parser.interfaces.callbacks.ChannelNamesListener;
66 65
 import com.dmdirc.parser.interfaces.callbacks.ChannelNickChangeListener;
67
-import com.dmdirc.parser.interfaces.callbacks.ChannelNonUserModeChangeListener;
68 66
 import com.dmdirc.parser.interfaces.callbacks.ChannelNoticeListener;
69 67
 import com.dmdirc.parser.interfaces.callbacks.ChannelPartListener;
70 68
 import com.dmdirc.parser.interfaces.callbacks.ChannelQuitListener;
71 69
 import com.dmdirc.parser.interfaces.callbacks.ChannelTopicListener;
72
-import com.dmdirc.parser.interfaces.callbacks.ChannelUserModeChangeListener;
73 70
 import com.dmdirc.parser.interfaces.callbacks.OtherAwayStateListener;
74 71
 import com.dmdirc.util.EventUtils;
75 72
 
@@ -88,10 +85,8 @@ public class ChannelEventHandler extends EventHandler implements
88 85
         ChannelMessageListener, ChannelNamesListener, ChannelTopicListener,
89 86
         ChannelJoinListener, ChannelPartListener, ChannelKickListener,
90 87
         ChannelQuitListener, ChannelActionListener, ChannelNickChangeListener,
91
-        ChannelModeChangeListener, ChannelUserModeChangeListener,
92
-        ChannelCtcpListener, OtherAwayStateListener, ChannelNoticeListener,
93
-        ChannelNonUserModeChangeListener, ChannelModeNoticeListener,
94
-        ChannelListModeListener {
88
+        ChannelModeChangeListener, ChannelCtcpListener, OtherAwayStateListener,
89
+        ChannelNoticeListener, ChannelModeNoticeListener, ChannelListModeListener {
95 90
 
96 91
     /** The channel that owns this event handler. */
97 92
     private final Channel owner;
@@ -279,48 +274,23 @@ public class ChannelEventHandler extends EventHandler implements
279 274
             final String modes) {
280 275
         checkParser(parser);
281 276
 
282
-        if (!owner.getConfigManager().getOptionBool("channel", "splitusermodes")
283
-                || !owner.getConfigManager().getOptionBool("channel", "hideduplicatemodes")) {
284
-            if (host.isEmpty()) {
285
-                final ChannelModesDiscoveredEvent event = new ChannelModesDiscoveredEvent(
286
-                        date.getTime(), owner, modes.length() <= 1 ? "" : modes);
287
-                final String format = EventUtils.postDisplayable(eventBus, event,
288
-                        modes.length() <= 1 ? "channelNoModes" : "channelModeDiscovered");
289
-                owner.doNotification(date, format, modes.length() <= 1 ? "" : modes);
290
-            } else if (isMyself(client)) {
291
-                eventBus.publishAsync(new ChannelSelfModeChangeEvent(date.getTime(), owner,
292
-                        groupChatUserManager.getUserFromClient(client, owner), modes));
293
-            } else {
294
-                eventBus.publishAsync(new ChannelModeChangeEvent(date.getTime(), owner,
295
-                        groupChatUserManager.getUserFromClient(client, owner), modes));
296
-            }
277
+        if (host.isEmpty()) {
278
+            final ChannelModesDiscoveredEvent event = new ChannelModesDiscoveredEvent(
279
+                    date.getTime(), owner, modes.length() <= 1 ? "" : modes);
280
+            final String format = EventUtils.postDisplayable(eventBus, event,
281
+                    modes.length() <= 1 ? "channelNoModes" : "channelModeDiscovered");
282
+            owner.doNotification(date, format, modes.length() <= 1 ? "" : modes);
283
+        } else if (isMyself(client)) {
284
+            eventBus.publishAsync(new ChannelSelfModeChangeEvent(date.getTime(), owner,
285
+                    groupChatUserManager.getUserFromClient(client, owner), modes));
286
+        } else {
287
+            eventBus.publishAsync(new ChannelModeChangeEvent(date.getTime(), owner,
288
+                    groupChatUserManager.getUserFromClient(client, owner), modes));
297 289
         }
298 290
 
299 291
         owner.refreshClients();
300 292
     }
301 293
 
302
-    @Override
303
-    public void onChannelUserModeChanged(final Parser parser, final Date date,
304
-            final ChannelInfo channel, final ChannelClientInfo targetClient,
305
-            final ChannelClientInfo client, final String host, final String mode) {
306
-        checkParser(parser);
307
-
308
-        if (owner.getConfigManager().getOptionBool("channel", "splitusermodes")) {
309
-            String format = "channelSplitUserMode_" + mode;
310
-
311
-            if (!owner.getConfigManager().hasOptionString("formatter", format)) {
312
-                format = "channelSplitUserMode_default";
313
-            }
314
-
315
-            final ChannelUserModeChangeEvent event = new ChannelUserModeChangeEvent(date.getTime(),
316
-                    owner, groupChatUserManager.getUserFromClient(client, owner),
317
-                    groupChatUserManager.getUserFromClient(targetClient, owner), mode);
318
-            final String result = EventUtils.postDisplayable(eventBus, event, format);
319
-            owner.doNotification(date, result, groupChatUserManager.getUserFromClient(client, owner),
320
-                    groupChatUserManager.getUserFromClient(targetClient, owner), mode);
321
-        }
322
-    }
323
-
324 294
     @Override
325 295
     public void onChannelCTCP(final Parser parser, final Date date,
326 296
             final ChannelInfo channel, final ChannelClientInfo client,
@@ -359,32 +329,6 @@ public class ChannelEventHandler extends EventHandler implements
359 329
                 groupChatUserManager.getUserFromClient(client, owner), message));
360 330
     }
361 331
 
362
-    @Override
363
-    public void onChannelNonUserModeChanged(final Parser parser, final Date date,
364
-            final ChannelInfo channel, final ChannelClientInfo client,
365
-            final String host, final String modes) {
366
-        checkParser(parser);
367
-
368
-        if (owner.getConfigManager().getOptionBool("channel", "splitusermodes")
369
-                && owner.getConfigManager().getOptionBool("channel", "hideduplicatemodes")) {
370
-            if (host.isEmpty()) {
371
-                final ChannelModesDiscoveredEvent event = new ChannelModesDiscoveredEvent(
372
-                        date.getTime(), owner, modes.length() <= 1 ? "" : modes);
373
-                final String format = EventUtils.postDisplayable(eventBus, event,
374
-                        modes.length() <= 1 ? "channelNoModes" : "channelModeDiscovered");
375
-                owner.doNotification(date, format, modes.length() <= 1 ? "" : modes);
376
-            } else if (isMyself(client)) {
377
-                eventBus.publishAsync(new ChannelSelfModeChangeEvent(date.getTime(), owner,
378
-                        groupChatUserManager.getUserFromClient(client, owner), modes));
379
-            } else {
380
-                eventBus.publishAsync(new ChannelModeChangeEvent(date.getTime(), owner,
381
-                        groupChatUserManager.getUserFromClient(client, owner), modes));
382
-            }
383
-        }
384
-
385
-        owner.refreshClients();
386
-    }
387
-
388 332
     @Override
389 333
     public void onChannelModeNotice(final Parser parser, final Date date,
390 334
             final ChannelInfo channel, final char prefix,

+ 2
- 5
src/com/dmdirc/Server.java View File

@@ -30,6 +30,7 @@ import com.dmdirc.events.ServerConnectErrorEvent;
30 30
 import com.dmdirc.events.ServerConnectedEvent;
31 31
 import com.dmdirc.events.ServerConnectingEvent;
32 32
 import com.dmdirc.events.ServerDisconnectedEvent;
33
+import com.dmdirc.events.ServerReconnectScheduledEvent;
33 34
 import com.dmdirc.interfaces.Connection;
34 35
 import com.dmdirc.interfaces.GroupChatManager;
35 36
 import com.dmdirc.interfaces.InviteManager;
@@ -439,7 +440,7 @@ public class Server extends FrameContainer implements Connection {
439 440
             final int delay = Math.max(1000,
440 441
                     getConfigManager().getOptionInt(DOMAIN_GENERAL, "reconnectdelay"));
441 442
 
442
-            handleNotification("connectRetry", getAddress(), delay / 1000);
443
+            getEventBus().publishAsync(new ServerReconnectScheduledEvent(this, delay / 1000));
443 444
 
444 445
             reconnectTimerFuture = executorService.schedule(() -> {
445 446
                 synchronized (myStateLock) {
@@ -850,8 +851,6 @@ public class Server extends FrameContainer implements Connection {
850 851
             return;
851 852
         }
852 853
 
853
-        handleNotification("socketClosed", getAddress());
854
-
855 854
         getEventBus().publish(new ServerDisconnectedEvent(this));
856 855
 
857 856
         eventHandler.unregisterCallbacks();
@@ -956,8 +955,6 @@ public class Server extends FrameContainer implements Connection {
956 955
 
957 956
             getEventBus().publish(new ServerConnectErrorEvent(this, description));
958 957
 
959
-            handleNotification("connectError", getAddress(), description);
960
-
961 958
             if (getConfigManager().getOptionBool(DOMAIN_GENERAL, "reconnectonconnectfailure")) {
962 959
                 doDelayedReconnect();
963 960
             }

+ 12
- 33
src/com/dmdirc/ServerEventHandler.java View File

@@ -42,6 +42,7 @@ import com.dmdirc.events.ServerNoticeEvent;
42 42
 import com.dmdirc.events.ServerNumericEvent;
43 43
 import com.dmdirc.events.ServerPingSentEvent;
44 44
 import com.dmdirc.events.ServerServerNoticeEvent;
45
+import com.dmdirc.events.ServerStonedEvent;
45 46
 import com.dmdirc.events.ServerUnknownActionEvent;
46 47
 import com.dmdirc.events.ServerUnknownMessageEvent;
47 48
 import com.dmdirc.events.ServerUnknownNoticeEvent;
@@ -184,9 +185,9 @@ public class ServerEventHandler extends EventHandler implements
184 185
         }
185 186
     }
186 187
 
188
+    @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
187 189
     @Override
188 190
     public void onErrorInfo(final Parser parser, final Date date, final ParserError errorInfo) {
189
-        final ErrorLevel errorLevel = ErrorLevel.UNKNOWN;
190 191
 
191 192
         final StringBuilder errorString = new StringBuilder();
192 193
         errorString.append("Parser exception.\n\n");
@@ -205,6 +206,7 @@ public class ServerEventHandler extends EventHandler implements
205 206
         final Exception ex = errorInfo.isException() ? errorInfo.getException()
206 207
                 : new Exception(errorString.toString()); // NOPMD
207 208
 
209
+        final ErrorLevel errorLevel = ErrorLevel.UNKNOWN;
208 210
         if (errorInfo.isUserError()) {
209 211
             eventBus.publishAsync(new UserErrorEvent(errorLevel, ex, errorInfo.getData(), ""));
210 212
         } else {
@@ -229,7 +231,6 @@ public class ServerEventHandler extends EventHandler implements
229 231
     public void onPrivateCTCPReply(final Parser parser, final Date date, final String type,
230 232
             final String message, final String host) {
231 233
         checkParser(parser);
232
-
233 234
         eventBus.publish(new ServerCtcpReplyEvent(owner, owner.getUser(host), type, message));
234 235
     }
235 236
 
@@ -244,50 +245,34 @@ public class ServerEventHandler extends EventHandler implements
244 245
     public void onPrivateNotice(final Parser parser, final Date date,
245 246
             final String message, final String host) {
246 247
         checkParser(parser);
247
-
248
-        final ServerNoticeEvent event = new ServerNoticeEvent(owner, owner.getLocalUser().get(),
249
-                message);
250
-        final String format = EventUtils.postDisplayable(eventBus, event, "privateNotice");
251
-        owner.doNotification(format, owner.getUser(host), message);
248
+        eventBus.publishAsync(new ServerNoticeEvent(owner, owner.getLocalUser().get(), message));
252 249
     }
253 250
 
254 251
     @Override
255 252
     public void onServerNotice(final Parser parser, final Date date,
256 253
             final String message, final String host) {
257 254
         checkParser(parser);
258
-
259
-        final ServerServerNoticeEvent event = new ServerServerNoticeEvent(owner,
260
-                owner.getLocalUser().get(), message);
261
-        final String format = EventUtils.postDisplayable(eventBus, event, "serverNotice");
262
-        owner.doNotification(format, owner.getUser(host), message);
255
+        eventBus.publishAsync(new ServerServerNoticeEvent(owner, owner.getLocalUser().get(),
256
+                message));
263 257
     }
264 258
 
265 259
     @Override
266 260
     public void onMOTDStart(final Parser parser, final Date date, final String data) {
267 261
         checkParser(parser);
268
-
269
-        final ServerMotdStartEvent event = new ServerMotdStartEvent(owner, data);
270
-        final String format = EventUtils.postDisplayable(eventBus, event, "motdStart");
271
-        owner.doNotification(format, data);
262
+        eventBus.publishAsync(new ServerMotdStartEvent(owner, data));
272 263
     }
273 264
 
274 265
     @Override
275 266
     public void onMOTDLine(final Parser parser, final Date date, final String data) {
276 267
         checkParser(parser);
277
-
278
-        final ServerMotdLineEvent event = new ServerMotdLineEvent(owner, data);
279
-        final String format = EventUtils.postDisplayable(eventBus, event, "motdLine");
280
-        owner.doNotification(format, data);
268
+        eventBus.publishAsync(new ServerMotdLineEvent(owner, data));
281 269
     }
282 270
 
283 271
     @Override
284 272
     public void onMOTDEnd(final Parser parser, final Date date,
285 273
             final boolean noMOTD, final String data) {
286 274
         checkParser(parser);
287
-
288
-        final ServerMotdEndEvent event = new ServerMotdEndEvent(owner, data);
289
-        final String format = EventUtils.postDisplayable(eventBus, event, "motdEnd");
290
-        owner.doNotification(format, data);
275
+        eventBus.publishAsync(new ServerMotdEndEvent(owner, data));
291 276
     }
292 277
 
293 278
     @Override
@@ -331,7 +316,7 @@ public class ServerEventHandler extends EventHandler implements
331 316
         if (parser.getPingTime()
332 317
                 >= owner.getConfigManager().getOptionInt("server", "pingtimeout")) {
333 318
             LOG.warn("Server appears to be stoned, reconnecting");
334
-            owner.handleNotification("stonedServer", owner.getAddress());
319
+            eventBus.publishAsync(new ServerStonedEvent(owner));
335 320
             owner.reconnect();
336 321
         }
337 322
     }
@@ -339,14 +324,12 @@ public class ServerEventHandler extends EventHandler implements
339 324
     @Override
340 325
     public void onPingSent(final Parser parser, final Date date) {
341 326
         checkParser(parser);
342
-
343 327
         eventBus.publishAsync(new ServerPingSentEvent(owner));
344 328
     }
345 329
 
346 330
     @Override
347 331
     public void onPingSuccess(final Parser parser, final Date date) {
348 332
         checkParser(parser);
349
-
350 333
         eventBus.publishAsync(new ServerGotPingEvent(owner,
351 334
                 owner.getParser().get().getServerLatency()));
352 335
     }
@@ -359,13 +342,9 @@ public class ServerEventHandler extends EventHandler implements
359 342
         owner.updateAwayState(currentState == AwayState.AWAY ? Optional.of(reason) : Optional.empty());
360 343
 
361 344
         if (currentState == AwayState.AWAY) {
362
-            final ServerAwayEvent event = new ServerAwayEvent(owner, reason);
363
-            final String format = EventUtils.postDisplayable(eventBus, event, "away");
364
-            owner.doNotification(format, reason);
345
+            eventBus.publishAsync(new ServerAwayEvent(owner, reason));
365 346
         } else if (oldState != AwayState.UNKNOWN) {
366
-            final ServerBackEvent event = new ServerBackEvent(owner);
367
-            final String format = EventUtils.postDisplayable(eventBus, event, "back");
368
-            owner.doNotification(format);
347
+            eventBus.publishAsync(new ServerBackEvent(owner));
369 348
         }
370 349
     }
371 350
 

+ 5
- 3
src/com/dmdirc/commandparser/CommandManager.java View File

@@ -34,7 +34,9 @@ import com.dmdirc.interfaces.GroupChat;
34 34
 import com.dmdirc.interfaces.config.AggregateConfigProvider;
35 35
 import com.dmdirc.ui.input.TabCompleter;
36 36
 import com.dmdirc.ui.input.TabCompletionType;
37
-import com.dmdirc.util.collections.MapList;
37
+
38
+import com.google.common.collect.ArrayListMultimap;
39
+import com.google.common.collect.Multimap;
38 40
 
39 41
 import java.util.HashMap;
40 42
 import java.util.List;
@@ -52,7 +54,7 @@ public class CommandManager implements CommandController {
52 54
     /** A list of commands that have been instantiated. */
53 55
     private final Map<CommandInfo, Command> commands = new HashMap<>();
54 56
     /** A list of command parsers that have been instantiated. */
55
-    private final MapList<CommandType, CommandParser> parsers = new MapList<>();
57
+    private final Multimap<CommandType, CommandParser> parsers = ArrayListMultimap.create();
56 58
     /** The manager to use to iterate servers. */
57 59
     private final ConnectionManager connectionManager;
58 60
     /** Provider to use to retrieve the global window. */
@@ -220,7 +222,7 @@ public class CommandManager implements CommandController {
220 222
                     parser.registerCommand(pair.getValue(), pair.getKey());
221 223
                 }
222 224
 
223
-                parsers.add(type, parser);
225
+                parsers.put(type, parser);
224 226
             }
225 227
         }
226 228
     }

+ 5
- 3
src/com/dmdirc/commandparser/commands/server/JoinChannelCommand.java View File

@@ -38,7 +38,9 @@ import com.dmdirc.interfaces.Connection;
38 38
 import com.dmdirc.parser.common.ChannelJoinRequest;
39 39
 import com.dmdirc.ui.input.AdditionalTabTargets;
40 40
 import com.dmdirc.ui.messages.Styliser;
41
-import com.dmdirc.util.collections.MapList;
41
+
42
+import com.google.common.collect.ArrayListMultimap;
43
+import com.google.common.collect.Multimap;
42 44
 
43 45
 import java.util.ArrayList;
44 46
 import java.util.List;
@@ -64,7 +66,7 @@ public class JoinChannelCommand extends Command implements IntelligentCommand {
64 66
             CommandType.TYPE_SERVER);
65 67
     /** A map of channel name mentions. */
66 68
     @GuardedBy("mentionsLock")
67
-    private final MapList<FrameContainer, String> mentions = new MapList<>();
69
+    private final Multimap<FrameContainer, String> mentions = ArrayListMultimap.create();
68 70
     /** Lock to synchronise on when accessing mentions. */
69 71
     private final Object mentionsLock = new Object();
70 72
 
@@ -117,7 +119,7 @@ public class JoinChannelCommand extends Command implements IntelligentCommand {
117 119
         synchronized (mentionsLock) {
118 120
             for (int i = 1; i < parts.length; i += 2) {
119 121
                 // All of the odd parts of the array are channel names
120
-                mentions.add(event.getFrameContainer(), parts[i]);
122
+                mentions.put(event.getFrameContainer(), parts[i]);
121 123
             }
122 124
         }
123 125
     }

+ 7
- 5
src/com/dmdirc/config/ConfigBinder.java View File

@@ -28,7 +28,9 @@ import com.dmdirc.interfaces.config.AggregateConfigProvider;
28 28
 import com.dmdirc.interfaces.config.ConfigChangeListener;
29 29
 import com.dmdirc.interfaces.config.ReadOnlyConfigProvider;
30 30
 import com.dmdirc.logger.ErrorLevel;
31
-import com.dmdirc.util.collections.MapList;
31
+
32
+import com.google.common.collect.ArrayListMultimap;
33
+import com.google.common.collect.Multimap;
32 34
 
33 35
 import java.lang.reflect.AccessibleObject;
34 36
 import java.lang.reflect.Executable;
@@ -48,7 +50,7 @@ import javax.annotation.Nonnull;
48 50
 public class ConfigBinder {
49 51
 
50 52
     /** A map of instances to created listeners. */
51
-    private final MapList<Object, ConfigChangeListener> listeners = new MapList<>();
53
+    private final Multimap<Object, ConfigChangeListener> listeners = ArrayListMultimap.create();
52 54
     /** The default domain to use. */
53 55
     private final Optional<String> defaultDomain;
54 56
     /** The configuration manager to use to retrieve settings. */
@@ -219,7 +221,7 @@ public class ConfigBinder {
219 221
     private void addListeners(final Object instance,
220 222
             final Collection<ConfigChangeListener> newListeners) {
221 223
         synchronized (listeners) {
222
-            listeners.add(instance, newListeners);
224
+            listeners.putAll(instance, newListeners);
223 225
         }
224 226
     }
225 227
 
@@ -230,8 +232,8 @@ public class ConfigBinder {
230 232
      */
231 233
     public void unbind(final Object instance) {
232 234
         synchronized (listeners) {
233
-            listeners.safeGet(instance).forEach(manager::removeListener);
234
-            listeners.remove(instance);
235
+            listeners.get(instance).forEach(manager::removeListener);
236
+            listeners.removeAll(instance);
235 237
         }
236 238
     }
237 239
 

+ 13
- 8
src/com/dmdirc/config/ConfigFileBackedConfigProvider.java View File

@@ -27,15 +27,14 @@ import com.dmdirc.events.UserErrorEvent;
27 27
 import com.dmdirc.interfaces.config.ConfigChangeListener;
28 28
 import com.dmdirc.interfaces.config.ConfigProvider;
29 29
 import com.dmdirc.logger.ErrorLevel;
30
-import com.dmdirc.util.collections.WeakList;
31 30
 import com.dmdirc.util.io.ConfigFile;
32 31
 import com.dmdirc.util.io.InvalidConfigFileException;
33 32
 import com.dmdirc.util.validators.Validator;
34 33
 
35 34
 import java.io.IOException;
36 35
 import java.io.InputStream;
36
+import java.lang.ref.WeakReference;
37 37
 import java.nio.file.Path;
38
-import java.util.ArrayList;
39 38
 import java.util.Collection;
40 39
 import java.util.HashMap;
41 40
 import java.util.HashSet;
@@ -44,6 +43,7 @@ import java.util.List;
44 43
 import java.util.Map;
45 44
 import java.util.Objects;
46 45
 import java.util.Set;
46
+import java.util.concurrent.CopyOnWriteArrayList;
47 47
 
48 48
 import javax.annotation.Nullable;
49 49
 
@@ -70,7 +70,8 @@ public class ConfigFileBackedConfigProvider implements ConfigProvider {
70 70
     /** The global config manager. */
71 71
     protected ConfigManager globalConfig;
72 72
     /** The config change listeners for this source. */
73
-    protected final List<ConfigChangeListener> listeners = new WeakList<>();
73
+    protected final List<WeakReference<ConfigChangeListener>> listeners =
74
+            new CopyOnWriteArrayList<>();
74 75
     /** The event bus to post error events to. */
75 76
     private final DMDircMBassador eventBus;
76 77
     /** Whether this identity needs to be saved. */
@@ -274,9 +275,10 @@ public class ConfigFileBackedConfigProvider implements ConfigProvider {
274 275
      * @since 0.6.3m1
275 276
      */
276 277
     private void fireSettingChange(final String domain, final String key) {
277
-        for (ConfigChangeListener listener : new ArrayList<>(listeners)) {
278
-            listener.configChanged(domain, key);
279
-        }
278
+        listeners.stream()
279
+                .map(WeakReference::get)
280
+                .filter(Objects::nonNull)
281
+                .forEach(l -> l.configChanged(domain, key));
280 282
     }
281 283
 
282 284
     @Override
@@ -518,12 +520,15 @@ public class ConfigFileBackedConfigProvider implements ConfigProvider {
518 520
 
519 521
     @Override
520 522
     public void addListener(final ConfigChangeListener listener) {
521
-        listeners.add(listener);
523
+        listeners.add(new WeakReference<>(listener));
522 524
     }
523 525
 
524 526
     @Override
525 527
     public void removeListener(final ConfigChangeListener listener) {
526
-        listeners.remove(listener);
528
+        listeners.stream().filter(w -> {
529
+            final ConfigChangeListener target = w.get();
530
+            return target == null || target.equals(listener);
531
+        }).forEach(listeners::remove);
527 532
     }
528 533
 
529 534
     /**

+ 7
- 4
src/com/dmdirc/config/ConfigManager.java View File

@@ -29,9 +29,11 @@ import com.dmdirc.interfaces.config.ConfigProvider;
29 29
 import com.dmdirc.interfaces.config.ConfigProviderListener;
30 30
 import com.dmdirc.interfaces.config.ConfigProviderMigrator;
31 31
 import com.dmdirc.util.ClientInfo;
32
-import com.dmdirc.util.collections.MapList;
33 32
 import com.dmdirc.util.validators.Validator;
34 33
 
34
+import com.google.common.collect.ArrayListMultimap;
35
+import com.google.common.collect.Multimap;
36
+
35 37
 import java.util.ArrayList;
36 38
 import java.util.Collection;
37 39
 import java.util.Collections;
@@ -59,7 +61,7 @@ class ConfigManager implements ConfigChangeListener, ConfigProviderListener,
59 61
     /** A list of sources for this config manager. */
60 62
     private final List<ConfigProvider> sources = new ArrayList<>();
61 63
     /** The listeners registered for this manager. */
62
-    private final MapList<String, ConfigChangeListener> listeners = new MapList<>();
64
+    private final Multimap<String, ConfigChangeListener> listeners = ArrayListMultimap.create();
63 65
     /** The config binder to use for this manager. */
64 66
     private final ConfigBinder binder;
65 67
     /** The manager to use to fetch global state. */
@@ -433,7 +435,8 @@ class ConfigManager implements ConfigChangeListener, ConfigProviderListener,
433 435
     @Override
434 436
     public void removeListener(final ConfigChangeListener listener) {
435 437
         synchronized (listeners) {
436
-            listeners.removeFromAll(listener);
438
+            final Iterable<String> keys = new HashSet<>(listeners.keySet());
439
+            keys.forEach(k -> listeners.remove(k, listener));
437 440
         }
438 441
     }
439 442
 
@@ -446,7 +449,7 @@ class ConfigManager implements ConfigChangeListener, ConfigProviderListener,
446 449
     private void addListener(final String key,
447 450
             final ConfigChangeListener listener) {
448 451
         synchronized (listeners) {
449
-            listeners.add(key, listener);
452
+            listeners.put(key, listener);
450 453
         }
451 454
     }
452 455
 

+ 33
- 29
src/com/dmdirc/config/IdentityManager.java View File

@@ -34,13 +34,15 @@ import com.dmdirc.interfaces.config.IdentityController;
34 34
 import com.dmdirc.interfaces.config.IdentityFactory;
35 35
 import com.dmdirc.logger.ErrorLevel;
36 36
 import com.dmdirc.util.ClientInfo;
37
-import com.dmdirc.util.collections.MapList;
38
-import com.dmdirc.util.collections.WeakMapList;
39 37
 import com.dmdirc.util.io.ConfigFile;
40 38
 import com.dmdirc.util.io.FileUtils;
41 39
 import com.dmdirc.util.io.InvalidConfigFileException;
42 40
 
41
+import com.google.common.collect.ArrayListMultimap;
42
+import com.google.common.collect.Multimap;
43
+
43 44
 import java.io.IOException;
45
+import java.lang.ref.WeakReference;
44 46
 import java.net.URISyntaxException;
45 47
 import java.nio.file.DirectoryStream;
46 48
 import java.nio.file.Files;
@@ -49,9 +51,9 @@ import java.util.ArrayList;
49 51
 import java.util.Collection;
50 52
 import java.util.Collections;
51 53
 import java.util.HashMap;
52
-import java.util.LinkedHashSet;
53 54
 import java.util.List;
54 55
 import java.util.Map;
56
+import java.util.Objects;
55 57
 import java.util.concurrent.ConcurrentHashMap;
56 58
 import java.util.stream.Collectors;
57 59
 
@@ -80,7 +82,7 @@ public class IdentityManager implements IdentityFactory, IdentityController {
80 82
      * Standard identities are inserted with a <code>null</code> key, custom identities use their
81 83
      * custom type as the key.
82 84
      */
83
-    private final MapList<String, ConfigProvider> identities = new MapList<>();
85
+    private final Multimap<String, ConfigProvider> identities = ArrayListMultimap.create();
84 86
     /** Map of paths to corresponding config providers, to facilitate reloading. */
85 87
     private final Map<Path, ConfigProvider> configProvidersByPath = new ConcurrentHashMap<>();
86 88
     /** The event bus to post events to. */
@@ -91,7 +93,8 @@ public class IdentityManager implements IdentityFactory, IdentityController {
91 93
      * Listeners for standard identities are inserted with a <code>null</code> key, listeners for a
92 94
      * specific custom type use their type as the key.
93 95
      */
94
-    private final MapList<String, ConfigProviderListener> listeners = new WeakMapList<>();
96
+    private final Multimap<String, WeakReference<ConfigProviderListener>> listeners =
97
+            ArrayListMultimap.create();
95 98
     /** Client info objecty. */
96 99
     private final ClientInfo clientInfo;
97 100
     /** The identity file used for the global config. */
@@ -283,13 +286,7 @@ public class IdentityManager implements IdentityFactory, IdentityController {
283 286
      * @since 0.6.4
284 287
      */
285 288
     private Iterable<ConfigProvider> getAllIdentities() {
286
-        final Collection<ConfigProvider> res = new LinkedHashSet<>();
287
-
288
-        for (Map.Entry<String, List<ConfigProvider>> entry : identities.entrySet()) {
289
-            res.addAll(entry.getValue());
290
-        }
291
-
292
-        return res;
289
+        return identities.values();
293 290
     }
294 291
 
295 292
     /**
@@ -372,20 +369,21 @@ public class IdentityManager implements IdentityFactory, IdentityController {
372 369
 
373 370
         final String target = getGroup(identity);
374 371
 
375
-        if (identities.containsValue(target, identity)) {
372
+        if (identities.containsEntry(target, identity)) {
376 373
             removeConfigProvider(identity);
377 374
         }
378 375
 
379 376
         synchronized (identities) {
380
-            identities.add(target, identity);
377
+            identities.put(target, identity);
381 378
         }
382 379
 
383 380
         LOG.debug("Adding identity: {} (group: {})", new Object[]{identity, target});
384 381
 
385 382
         synchronized (listeners) {
386
-            for (ConfigProviderListener listener : listeners.safeGet(target)) {
387
-                listener.configProviderAdded(identity);
388
-            }
383
+            listeners.get(target).stream()
384
+                    .map(WeakReference::get)
385
+                    .filter(Objects::nonNull)
386
+                    .forEach(l -> l.configProviderAdded(identity));
389 387
         }
390 388
     }
391 389
 
@@ -395,7 +393,7 @@ public class IdentityManager implements IdentityFactory, IdentityController {
395 393
 
396 394
         final String group = getGroup(identity);
397 395
 
398
-        checkArgument(identities.containsValue(group, identity));
396
+        checkArgument(identities.containsEntry(group, identity));
399 397
 
400 398
         Path path = null;
401 399
         for (Map.Entry<Path, ConfigProvider> entry : configProvidersByPath.entrySet()) {
@@ -413,9 +411,10 @@ public class IdentityManager implements IdentityFactory, IdentityController {
413 411
         }
414 412
 
415 413
         synchronized (listeners) {
416
-            for (ConfigProviderListener listener : listeners.safeGet(group)) {
417
-                listener.configProviderRemoved(identity);
418
-            }
414
+            listeners.get(group).stream()
415
+                    .map(WeakReference::get)
416
+                    .filter(Objects::nonNull)
417
+                    .forEach(l -> l.configProviderRemoved(identity));
419 418
         }
420 419
     }
421 420
 
@@ -426,7 +425,12 @@ public class IdentityManager implements IdentityFactory, IdentityController {
426 425
 
427 426
     @Override
428 427
     public void unregisterIdentityListener(final ConfigProviderListener listener) {
429
-        listeners.removeFromAll(listener);
428
+        synchronized (listeners) {
429
+            listeners.entries().stream().filter(e -> {
430
+                final ConfigProviderListener value = e.getValue().get();
431
+                return value == null || value.equals(listener);
432
+            }).forEach(e -> listeners.remove(e.getKey(), e.getValue()));
433
+        }
430 434
     }
431 435
 
432 436
     @Override
@@ -434,13 +438,13 @@ public class IdentityManager implements IdentityFactory, IdentityController {
434 438
         checkNotNull(listener);
435 439
 
436 440
         synchronized (listeners) {
437
-            listeners.add(type, listener);
441
+            listeners.put(type, new WeakReference<>(listener));
438 442
         }
439 443
     }
440 444
 
441 445
     @Override
442
-    public List<ConfigProvider> getProvidersByType(final String type) {
443
-        return Collections.unmodifiableList(identities.safeGet(type));
446
+    public Collection<ConfigProvider> getProvidersByType(final String type) {
447
+        return Collections.unmodifiableCollection(identities.get(type));
444 448
     }
445 449
 
446 450
     /**
@@ -455,7 +459,7 @@ public class IdentityManager implements IdentityFactory, IdentityController {
455 459
         final List<ConfigProvider> sources = new ArrayList<>();
456 460
 
457 461
         synchronized (identities) {
458
-            sources.addAll(identities.safeGet(null).stream()
462
+            sources.addAll(identities.get(null).stream()
459 463
                     .filter(manager::identityApplies)
460 464
                     .collect(Collectors.toList()));
461 465
         }
@@ -491,7 +495,7 @@ public class IdentityManager implements IdentityFactory, IdentityController {
491 495
         final String myTarget = (channel + '@' + network).toLowerCase();
492 496
 
493 497
         synchronized (identities) {
494
-            for (ConfigProvider identity : identities.safeGet(null)) {
498
+            for (ConfigProvider identity : identities.get(null)) {
495 499
                 if (identity.getTarget().getType() == ConfigTarget.TYPE.CHANNEL
496 500
                         && identity.getTarget().getData().equalsIgnoreCase(myTarget)) {
497 501
                     return identity;
@@ -516,7 +520,7 @@ public class IdentityManager implements IdentityFactory, IdentityController {
516 520
         final String myTarget = network.toLowerCase();
517 521
 
518 522
         synchronized (identities) {
519
-            for (ConfigProvider identity : identities.safeGet(null)) {
523
+            for (ConfigProvider identity : identities.get(null)) {
520 524
                 if (identity.getTarget().getType() == ConfigTarget.TYPE.NETWORK
521 525
                         && identity.getTarget().getData().equalsIgnoreCase(myTarget)) {
522 526
                     return identity;
@@ -541,7 +545,7 @@ public class IdentityManager implements IdentityFactory, IdentityController {
541 545
         final String myTarget = server.toLowerCase();
542 546
 
543 547
         synchronized (identities) {
544
-            for (ConfigProvider identity : identities.safeGet(null)) {
548
+            for (ConfigProvider identity : identities.get(null)) {
545 549
                 if (identity.getTarget().getType() == ConfigTarget.TYPE.SERVER
546 550
                         && identity.getTarget().getData().equalsIgnoreCase(myTarget)) {
547 551
                     return identity;

+ 0
- 4
src/com/dmdirc/config/prefs/PreferencesDialogModel.java View File

@@ -185,10 +185,6 @@ public class PreferencesDialogModel {
185 185
                 "ui", "confirmQuit", "Confirm quit",
186 186
                 "Show a confirmation message when you try to close the client",
187 187
                 configManager, identity));
188
-        category.addSetting(new PreferencesSetting(PreferencesType.BOOLEAN,
189
-                "channel", "splitusermodes", "Split user modes",
190
-                "Show individual mode lines for each mode change that affects"
191
-                + " a user (e.g. op, devoice)", configManager, identity));
192 188
         category.addSetting(new PreferencesSetting(PreferencesType.BOOLEAN,
193 189
                 "channel", "showmodeprefix", "Show mode prefix",
194 190
                 "Prefix users' names with their mode (e.g. @) in channels",

+ 0
- 5
src/com/dmdirc/config/prefs/PreferencesManager.java View File

@@ -143,11 +143,6 @@ public class PreferencesManager {
143 143
                 "These settings are specific to this channel on this network,"
144 144
                 + " any settings specified here will overwrite global settings");
145 145
 
146
-        category.addSetting(new PreferencesSetting(PreferencesType.BOOLEAN,
147
-                "channel", "splitusermodes", "Split user modes",
148
-                "Show individual mode lines for each mode change that affects"
149
-                + " a user (e.g. op, devoice)",
150
-                manager, identity));
151 146
         category.addSetting(new PreferencesSetting(PreferencesType.BOOLEAN,
152 147
                 "channel", "showmodeprefix", "Show mode prefix",
153 148
                 "Prefix users' names with their mode (e.g. @) in channels",

+ 8
- 3
src/com/dmdirc/events/DisplayProperty.java View File

@@ -27,11 +27,16 @@ import com.dmdirc.util.colours.Colour;
27 27
 /**
28 28
  * Describes a property that may be set on a {@link DisplayableEvent} to affect its display.
29 29
  */
30
-public final class DisplayProperty<T> {
30
+@SuppressWarnings("UnusedDeclaration") // Generic type used for compile-time validation only
31
+public interface DisplayProperty<T> {
31 32
 
32 33
     /** The foreground colour of text relating to the event. */
33
-    public static final DisplayProperty<Colour> FOREGROUND_COLOUR = new DisplayProperty<>();
34
+    DisplayProperty<Colour> FOREGROUND_COLOUR = new DisplayPropertyImpl<>();
34 35
     /** The background colour of text relating to the event. */
35
-    public static final DisplayProperty<Colour> BACKGROUND_COLOUR = new DisplayProperty<>();
36
+    DisplayProperty<Colour> BACKGROUND_COLOUR = new DisplayPropertyImpl<>();
37
+    /** Whether to suppress display of the event. */
38
+    DisplayProperty<Void> DO_NOT_DISPLAY = new DisplayPropertyImpl<>();
39
+
40
+    final class DisplayPropertyImpl<T> implements DisplayProperty<T> {}
36 41
 
37 42
 }

+ 1
- 1
src/com/dmdirc/events/ServerDisconnectedEvent.java View File

@@ -27,7 +27,7 @@ import com.dmdirc.interfaces.Connection;
27 27
 /**
28 28
  * Fire when a server disconnects.
29 29
  */
30
-public class ServerDisconnectedEvent extends ServerEvent {
30
+public class ServerDisconnectedEvent extends ServerDisplayableEvent {
31 31
 
32 32
     public ServerDisconnectedEvent(final Connection connection) {
33 33
         super(connection);

+ 43
- 0
src/com/dmdirc/events/ServerReconnectScheduledEvent.java View File

@@ -0,0 +1,43 @@
1
+/*
2
+ * Copyright (c) 2006-2015 DMDirc Developers
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.events;
24
+
25
+import com.dmdirc.interfaces.Connection;
26
+
27
+/**
28
+ * Event raised when a reconnection attempt has been scheduled.
29
+ */
30
+public class ServerReconnectScheduledEvent extends ServerDisplayableEvent {
31
+
32
+    private final int seconds;
33
+
34
+    public ServerReconnectScheduledEvent(final Connection connection, final int seconds) {
35
+        super(connection);
36
+        this.seconds = seconds;
37
+    }
38
+
39
+    public int getSeconds() {
40
+        return seconds;
41
+    }
42
+
43
+}

+ 36
- 0
src/com/dmdirc/events/ServerStonedEvent.java View File

@@ -0,0 +1,36 @@
1
+/*
2
+ * Copyright (c) 2006-2015 DMDirc Developers
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.events;
24
+
25
+import com.dmdirc.interfaces.Connection;
26
+
27
+/**
28
+ * Event raised when a server appears to be 'stoned' (i.e., non-responsive).
29
+ */
30
+public class ServerStonedEvent extends ServerDisplayableEvent {
31
+
32
+    public ServerStonedEvent(final Connection connection) {
33
+        super(connection);
34
+    }
35
+
36
+}

+ 2
- 2
src/com/dmdirc/interfaces/config/IdentityController.java View File

@@ -22,7 +22,7 @@
22 22
 
23 23
 package com.dmdirc.interfaces.config;
24 24
 
25
-import java.util.List;
25
+import java.util.Collection;
26 26
 
27 27
 /**
28 28
  * Defines the interface implemented by the object in charge of DMDirc's identities.
@@ -68,7 +68,7 @@ public interface IdentityController {
68 68
      *
69 69
      * @since 0.6.4
70 70
      */
71
-    List<ConfigProvider> getProvidersByType(String type);
71
+    Collection<ConfigProvider> getProvidersByType(String type);
72 72
 
73 73
     /**
74 74
      * Loads user-defined identity files.

+ 6
- 4
src/com/dmdirc/plugins/PluginManager.java View File

@@ -29,7 +29,9 @@ import com.dmdirc.interfaces.config.IdentityController;
29 29
 import com.dmdirc.logger.ErrorLevel;
30 30
 import com.dmdirc.updater.components.PluginComponent;
31 31
 import com.dmdirc.updater.manager.UpdateManager;
32
-import com.dmdirc.util.collections.MapList;
32
+
33
+import com.google.common.collect.ArrayListMultimap;
34
+import com.google.common.collect.Multimap;
33 35
 
34 36
 import java.io.File;
35 37
 import java.net.MalformedURLException;
@@ -366,7 +368,7 @@ public class PluginManager {
366 368
             }
367 369
         }
368 370
 
369
-        final MapList<String, String> newServices = new MapList<>();
371
+        final Multimap<String, String> newServices = ArrayListMultimap.create();
370 372
         final Map<String, PluginMetaData> newPluginsByName = new HashMap<>();
371 373
         final Map<String, PluginMetaData> newPluginsByPath = new HashMap<>();
372 374
 
@@ -389,13 +391,13 @@ public class PluginManager {
389 391
 
390 392
                     for (String service : targetMetaData.getServices()) {
391 393
                         final String[] parts = service.split(" ", 2);
392
-                        newServices.add(parts[1], parts[0]);
394
+                        newServices.put(parts[1], parts[0]);
393 395
                     }
394 396
 
395 397
                     for (String export : targetMetaData.getExports()) {
396 398
                         final String[] parts = export.split(" ");
397 399
                         final String name = parts.length > 4 ? parts[4] : parts[0];
398
-                        newServices.add("export", name);
400
+                        newServices.put("export", name);
399 401
                     }
400 402
                 }
401 403
             } catch (MalformedURLException mue) {

+ 6
- 5
src/com/dmdirc/plugins/PluginMetaDataValidator.java View File

@@ -23,7 +23,8 @@
23 23
 package com.dmdirc.plugins;
24 24
 
25 25
 import com.dmdirc.updater.Version;
26
-import com.dmdirc.util.collections.MapList;
26
+
27
+import com.google.common.collect.Multimap;
27 28
 
28 29
 import java.io.File;
29 30
 import java.util.ArrayList;
@@ -62,7 +63,7 @@ public class PluginMetaDataValidator {
62 63
      * @return A collection of errors that occurred (if any)
63 64
      */
64 65
     public Collection<String> validate(final Map<String, PluginMetaData> plugins,
65
-            final MapList<String, String> services) {
66
+            final Multimap<String, String> services) {
66 67
         errors.clear();
67 68
 
68 69
         checkMetaData();
@@ -100,7 +101,7 @@ public class PluginMetaDataValidator {
100 101
      * @param services A map of known services
101 102
      */
102 103
     protected void checkRequirements(final Map<String, PluginMetaData> plugins,
103
-            final MapList<String, String> services) {
104
+            final Multimap<String, String> services) {
104 105
         checkOS(metadata.getRequirements().get("os"), System.getProperty("os.name"), System.
105 106
                 getProperty("os.version"), System.getProperty("os.arch"));
106 107
         checkFiles(metadata.getRequirements().get("files"));
@@ -114,7 +115,7 @@ public class PluginMetaDataValidator {
114 115
      * @param knownServices A map of known services
115 116
      * @param services      Required services
116 117
      */
117
-    private void checkServices(final MapList<String, String> knownServices,
118
+    private void checkServices(final Multimap<String, String> knownServices,
118 119
             final Collection<String> services) {
119 120
         if (services == null || services.isEmpty()) {
120 121
             return;
@@ -127,7 +128,7 @@ public class PluginMetaDataValidator {
127 128
 
128 129
             if (!knownServices.containsKey(type)
129 130
                     || !"any".equalsIgnoreCase(name)
130
-                    && !knownServices.containsValue(type, name)) {
131
+                    && !knownServices.containsEntry(type, name)) {
131 132
                 errors.add("Service " + name + " of type " + type
132 133
                         + " not available");
133 134
             }

+ 20
- 20
src/com/dmdirc/ui/input/TabCompleter.java View File

@@ -24,9 +24,10 @@ package com.dmdirc.ui.input;
24 24
 
25 25
 import com.dmdirc.interfaces.CommandController;
26 26
 import com.dmdirc.interfaces.config.AggregateConfigProvider;
27
-import com.dmdirc.util.collections.MapList;
28 27
 
29
-import java.util.List;
28
+import com.google.common.collect.ArrayListMultimap;
29
+import com.google.common.collect.Multimap;
30
+
30 31
 import java.util.Locale;
31 32
 import java.util.Map;
32 33
 
@@ -47,7 +48,7 @@ public class TabCompleter {
47 48
     /** The controller to use to retrieve command information. */
48 49
     private final CommandController commandController;
49 50
     /** The entries in this completer. */
50
-    private final MapList<TabCompletionType, String> entries = new MapList<>();
51
+    private final Multimap<TabCompletionType, String> entries = ArrayListMultimap.create();
51 52
 
52 53
     /**
53 54
      * Creates a new instance of {@link TabCompleter}.
@@ -91,7 +92,7 @@ public class TabCompleter {
91 92
             final AdditionalTabTargets additionals) {
92 93
         final TabCompletionMatches result = new TabCompletionMatches();
93 94
 
94
-        final MapList<TabCompletionType, String> targets = new MapList<>(entries);
95
+        final Multimap<TabCompletionType, String> targets = ArrayListMultimap.create(entries);
95 96
 
96 97
         final boolean caseSensitive = configManager.getOptionBool("tabcompletion", "casesensitive");
97 98
         final boolean allowEmpty = configManager.getOptionBool("tabcompletion", "allowempty");
@@ -101,26 +102,25 @@ public class TabCompleter {
101 102
         }
102 103
 
103 104
         if (additionals != null) {
104
-            targets.safeGet(TabCompletionType.ADDITIONAL).addAll(additionals);
105
+            targets.putAll(TabCompletionType.ADDITIONAL, additionals);
105 106
         }
106 107
 
107
-        for (Map.Entry<TabCompletionType, List<String>> typeEntry : targets.entrySet()) {
108
-            if (additionals != null && !additionals.shouldInclude(typeEntry.getKey())) {
108
+        for (Map.Entry<TabCompletionType, String> entry : targets.entries()) {
109
+            // TODO: This can probably be replaced with a stream + filter chain
110
+            if (additionals != null && !additionals.shouldInclude(entry.getKey())) {
109 111
                 // If we're not including this type, skip to the next.
110 112
                 continue;
111 113
             }
112 114
 
113
-            for (String entry : typeEntry.getValue()) {
114
-                // Skip over duplicates
115
-                if (result.hasResult(entry)) {
116
-                    continue;
117
-                }
118
-
119
-                if (caseSensitive && entry.startsWith(partial)
120
-                        || !caseSensitive && entry.toLowerCase(Locale.getDefault())
121
-                                .startsWith(partial.toLowerCase(Locale.getDefault()))) {
122
-                    result.addResult(entry);
123
-                }
115
+            // Skip over duplicates
116
+            if (result.hasResult(entry.getValue())) {
117
+                continue;
118
+            }
119
+
120
+            if (caseSensitive && entry.getValue().startsWith(partial)
121
+                    || !caseSensitive && entry.getValue().toLowerCase(Locale.getDefault())
122
+                            .startsWith(partial.toLowerCase(Locale.getDefault()))) {
123
+                result.addResult(entry.getValue());
124 124
             }
125 125
         }
126 126
 
@@ -142,7 +142,7 @@ public class TabCompleter {
142 142
      * @param entry The new entry to be added
143 143
      */
144 144
     public void addEntry(final TabCompletionType type, final String entry) {
145
-        entries.add(type, entry);
145
+        entries.put(type, entry);
146 146
 
147 147
         if (type == TabCompletionType.COMMAND && entry.length() > 1
148 148
                 && entry.charAt(0) == commandController.getCommandChar()
@@ -193,7 +193,7 @@ public class TabCompleter {
193 193
      * @param type The type of entry to clear
194 194
      */
195 195
     public void clear(final TabCompletionType type) {
196
-        entries.clear(type);
196
+        entries.removeAll(type);
197 197
     }
198 198
 
199 199
 }

+ 17
- 4
src/com/dmdirc/ui/messages/BackBuffer.java View File

@@ -24,7 +24,9 @@ package com.dmdirc.ui.messages;
24 24
 
25 25
 import com.dmdirc.DMDircMBassador;
26 26
 import com.dmdirc.FrameContainer;
27
+import com.dmdirc.events.DisplayProperty;
27 28
 import com.dmdirc.events.DisplayableEvent;
29
+import com.dmdirc.util.EventUtils;
28 30
 
29 31
 import net.engio.mbassy.listener.Handler;
30 32
 
@@ -72,19 +74,30 @@ public class BackBuffer {
72 74
      *
73 75
      * @param event The event to be displayed.
74 76
      */
75
-    @Handler
76
-    public void handleDisplayableEvent(final DisplayableEvent event) {
77
-        if (event.getSource().equals(owner)) {
77
+    @Handler(priority = EventUtils.PRIORITY_DISPLAYABLE_EVENT_HANDLER)
78
+    private void handleDisplayableEvent(final DisplayableEvent event) {
79
+        if (shouldDisplay(event)) {
78 80
             formatter.format(event).map(s -> s.split("\n")).ifPresent(
79 81
                     t -> {
80 82
                         for (String line : t) {
81 83
                             document.addText(event.getTimestamp(), event
82
-                                            .getDisplayProperties(), line);
84
+                                    .getDisplayProperties(), line);
83 85
                         }
84 86
                     });
85 87
         }
86 88
     }
87 89
 
90
+    /**
91
+     * Determines if the specified event should be displayed in this backbuffer.
92
+     *
93
+     * @param event The event to check
94
+     * @return True if the event should be displayed, false otherwise.
95
+     */
96
+    private boolean shouldDisplay(final DisplayableEvent event) {
97
+        return event.getSource().equals(owner)
98
+                && !event.getDisplayProperty(DisplayProperty.DO_NOT_DISPLAY).isPresent();
99
+    }
100
+
88 101
     public IRCDocument getDocument() {
89 102
         return document;
90 103
     }

+ 3
- 3
test/com/dmdirc/config/IdentityManagerTest.java View File

@@ -33,7 +33,7 @@ import java.io.IOException;
33 33
 import java.nio.file.FileSystem;
34 34
 import java.nio.file.Files;
35 35
 import java.nio.file.Path;
36
-import java.util.List;
36
+import java.util.Collection;
37 37
 
38 38
 import org.junit.Before;
39 39
 import org.junit.Test;
@@ -95,9 +95,9 @@ public class IdentityManagerTest {
95 95
                 baseDirectory, identitiesDirectory, eventBus, clientInfo);
96 96
         identityManager.initialise();
97 97
 
98
-        final List<ConfigProvider> profiles = identityManager.getProvidersByType("profile");
98
+        final Collection<ConfigProvider> profiles = identityManager.getProvidersByType("profile");
99 99
         assertEquals(1, profiles.size());
100
-        assertEquals("New Profile", profiles.get(0).getName());
100
+        assertEquals("New Profile", profiles.stream().findAny().get().getName());
101 101
     }
102 102
 
103 103
 }

Loading…
Cancel
Save