Browse Source

Add debug plugin.

Tidy up sevreal classes
Add checkboxmenu item
Change menu bar so plugins can add items.
Add update ID to notifications plugin

Fixes issue CLIENT-80

Change-Id: I289bbf7bcad6d9c528eb353dc8cf49ad48954a65
Reviewed-on: http://gerrit.dmdirc.com/1559
Reviewed-by: Chris Smith <chris@dmdirc.com>
Automatic-Compile: Chris Smith <chris@dmdirc.com>
tags/0.6.5
Greg Holmes 13 years ago
parent
commit
9ad6bc4dd4

+ 4
- 0
src/com/dmdirc/addons/notifications/plugin.config View File

@@ -8,6 +8,7 @@ keysections:
8 8
   version
9 9
   requires
10 10
   defaults
11
+  updates
11 12
 
12 13
 metadata:
13 14
   author=Greg <greg@dmdirc.com>
@@ -16,6 +17,9 @@ metadata:
16 17
   name=notifications
17 18
   nicename=Notification Manager
18 19
 
20
+updates:
21
+  id=61
22
+
19 23
 version:
20 24
   friendly=0.1
21 25
 

+ 85
- 0
src/com/dmdirc/addons/swingdebug/CloseListener.java View File

@@ -0,0 +1,85 @@
1
+/*
2
+ * Copyright (c) 2006-2010 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
+package com.dmdirc.addons.swingdebug;
23
+
24
+import java.awt.Window;
25
+import java.awt.event.ComponentEvent;
26
+import java.awt.event.ComponentListener;
27
+
28
+import javax.swing.ButtonModel;
29
+
30
+/**
31
+ * Updates checkbox state on window close.
32
+ */
33
+public class CloseListener implements ComponentListener {
34
+
35
+    /** Button model to update. */
36
+    private final ButtonModel model;
37
+
38
+    /**
39
+     * Creates a new Close Listener for the specified window and model.
40
+     *
41
+     * @param model Model to keep updated
42
+     * @param window Window to monitor
43
+     */
44
+    public CloseListener(final ButtonModel model, final Window window) {
45
+        super();
46
+
47
+        this.model = model;
48
+        window.addComponentListener(this);
49
+    }
50
+
51
+    /** {@inheritDoc} */
52
+    @Override
53
+    public void componentResized(final ComponentEvent e) {
54
+        //Ignore, don't care
55
+    }
56
+
57
+    /** {@inheritDoc} */
58
+    @Override
59
+    public void componentMoved(final ComponentEvent e) {
60
+        //Ignore, don't care
61
+    }
62
+
63
+    /** {@inheritDoc} */
64
+    @Override
65
+    public void componentShown(final ComponentEvent e) {
66
+        //Ignore, don't care
67
+    }
68
+
69
+    /** {@inheritDoc} */
70
+    @Override
71
+    public void componentHidden(final ComponentEvent e) {
72
+        model.setSelected(false);
73
+    }
74
+
75
+    /**
76
+     * Adds a close listener to the specified window, updating the specified
77
+     * model.
78
+     *
79
+     * @param model Model to update
80
+     * @param window Window to listener to
81
+     */
82
+    public static void add(final ButtonModel model, final Window window) {
83
+        new CloseListener(model, window);
84
+    }
85
+}

+ 152
- 0
src/com/dmdirc/addons/swingdebug/SwingDebugPlugin.java View File

@@ -0,0 +1,152 @@
1
+/*
2
+ * Copyright (c) 2006-2010 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.addons.swingdebug;
24
+
25
+import com.dmdirc.addons.ui_swing.DMDircEventQueue;
26
+import com.dmdirc.addons.ui_swing.SwingController;
27
+import com.dmdirc.addons.ui_swing.components.CheckBoxMenuItem;
28
+import com.dmdirc.addons.ui_swing.components.text.TextLabel;
29
+import com.dmdirc.plugins.Plugin;
30
+import com.dmdirc.plugins.PluginManager;
31
+import java.awt.Toolkit;
32
+import java.awt.event.ActionEvent;
33
+
34
+import java.awt.event.ActionListener;
35
+import java.io.IOException;
36
+import java.io.PrintStream;
37
+
38
+import javax.swing.JCheckBoxMenuItem;
39
+import javax.swing.JDialog;
40
+import javax.swing.JMenu;
41
+import javax.swing.JScrollPane;
42
+import net.miginfocom.swing.MigLayout;
43
+
44
+/**
45
+ * Swing debug plugin. Provides long running EDT task violation detection and
46
+ * a console for System.out and System.err.
47
+ */
48
+public class SwingDebugPlugin extends Plugin implements ActionListener {
49
+
50
+    /** Swing controller. */
51
+    private SwingController controller;
52
+    /** Debug menu. */
53
+    private JMenu debugMenu;
54
+    /** Debug EDT menu item. */
55
+    private JCheckBoxMenuItem debugEDT;
56
+    /** Debug EDT menu item. */
57
+    private JCheckBoxMenuItem showSysOut;
58
+    /** Debug EDT menu item. */
59
+    private JCheckBoxMenuItem showSysErr;
60
+    /** Old System.out. */
61
+    private PrintStream sysout;
62
+    /** Old System.err. */
63
+    private PrintStream syserr;
64
+    /** System.out redirect thread. */
65
+    private SystemStreamRedirectThread out;
66
+    /** System.err redirect thread. */
67
+    private SystemStreamRedirectThread err;
68
+    /** System out frame. */
69
+    private JDialog outFrame;
70
+    /** System error frame. */
71
+    private JDialog errorFrame;
72
+
73
+    /** {@inheritDoc} */
74
+    @Override
75
+    public void onLoad() {
76
+        controller = (SwingController) PluginManager.getPluginManager()
77
+                .getPluginInfoByName("ui_swing").getPlugin();
78
+        try {
79
+            sysout = System.out;
80
+            syserr = System.err;
81
+            final TextLabel outTextArea = new TextLabel();
82
+            final TextLabel errorTextArea = new TextLabel();
83
+            outFrame = new JDialog(controller.getMainFrame());
84
+            errorFrame = new JDialog(controller.getMainFrame());
85
+            outFrame.setTitle("DMDirc: System.out Console");
86
+            errorFrame.setTitle("DMDirc: System.err Console");
87
+            outFrame.setLayout(new MigLayout("ins 0, pack, wmin 20sp, hmin 20sp"));
88
+            errorFrame.setLayout(new MigLayout("ins 0, pack, wmin 20sp, hmin 20sp"));
89
+            outFrame.add(new JScrollPane(outTextArea), "grow, push");
90
+            errorFrame.add(new JScrollPane(errorTextArea), "grow, push");
91
+            outFrame.pack();
92
+            errorFrame.pack();
93
+            out = new SystemStreamRedirectThread(
94
+                    SystemStreamRedirectThread.Stream.OUT,
95
+                    outTextArea.getDocument());
96
+            err = new SystemStreamRedirectThread(
97
+                    SystemStreamRedirectThread.Stream.IN,
98
+                    errorTextArea.getDocument());
99
+            out.start();
100
+            err.start();
101
+            debugMenu = new JMenu("Debug");
102
+            debugEDT = new CheckBoxMenuItem("Check EDT task length");
103
+            showSysOut = new CheckBoxMenuItem("Show System.out Console");
104
+            showSysErr = new CheckBoxMenuItem("Show System.err Console");
105
+            debugEDT.addActionListener(this);
106
+            showSysErr.addActionListener(this);
107
+            showSysOut.addActionListener(this);
108
+            controller.getMainFrame().getJMenuBar().add(debugMenu);
109
+            debugMenu.add(debugEDT);
110
+            debugMenu.add(showSysOut);
111
+            debugMenu.add(showSysErr);
112
+            CloseListener.add(showSysOut.getModel(), outFrame);
113
+            CloseListener.add(showSysErr.getModel(), outFrame);
114
+        } catch (IOException ex) {
115
+            onUnload();
116
+        }
117
+    }
118
+
119
+    /** {@inheritDoc} */
120
+    @Override
121
+    public void onUnload() {
122
+        out.cancel();
123
+        err.cancel();
124
+        System.setOut(sysout);
125
+        System.setErr(syserr);
126
+        outFrame = null;
127
+        errorFrame = null;
128
+        controller.getMainFrame().getJMenuBar().remove(debugMenu);
129
+        controller = null;
130
+    }
131
+
132
+    /** {@inheritDoc} */
133
+    @Override
134
+    public void actionPerformed(final ActionEvent e) {
135
+        if (e.getSource() == debugEDT) {
136
+            if (debugEDT.getState()) {
137
+                Toolkit.getDefaultToolkit().getSystemEventQueue().
138
+                        push(new TracingEventQueue(this, controller));
139
+            } else {
140
+                Toolkit.getDefaultToolkit().getSystemEventQueue().
141
+                        push(new DMDircEventQueue(controller));
142
+            }
143
+        }
144
+        if (e.getSource() == showSysOut) {
145
+            outFrame.setVisible(showSysOut.getState());
146
+        }
147
+        if (e.getSource() == showSysErr) {
148
+            errorFrame.setVisible(showSysErr.getState());
149
+        }
150
+    }
151
+
152
+}

+ 133
- 0
src/com/dmdirc/addons/swingdebug/SystemStreamRedirectThread.java View File

@@ -0,0 +1,133 @@
1
+/*
2
+ * Copyright (c) 2006-2010 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.addons.swingdebug;
24
+
25
+import java.io.BufferedReader;
26
+import java.io.IOException;
27
+import java.io.InputStreamReader;
28
+import java.io.PipedInputStream;
29
+import java.io.PipedOutputStream;
30
+import java.io.PrintStream;
31
+
32
+import javax.swing.text.BadLocationException;
33
+import javax.swing.text.Document;
34
+
35
+/**
36
+ * Simple utility class to redirect System streams to the specified Document.
37
+ */
38
+public class SystemStreamRedirectThread implements Runnable {
39
+
40
+    /**
41
+     * Enum to identify System streams.
42
+     */
43
+    public enum Stream {
44
+        /** System.out. */
45
+        OUT,
46
+        /** System.in. */
47
+        IN;
48
+    }
49
+
50
+    /** Is this thread running? */
51
+    private boolean running = false;
52
+    /** Reader to for the system stream. */
53
+    private final BufferedReader rar;
54
+    /** Stream identifier. */
55
+    private final Stream stream;
56
+    /** Document to output stream into. */
57
+    private final Document document;
58
+
59
+    /**
60
+     * Constructs a new redirection thread.
61
+     *
62
+     * @param stream System stream to redirect
63
+     * @param document Document to redirect stream into
64
+     *
65
+     * @throws IOException On error redirecting stream
66
+     */
67
+    public SystemStreamRedirectThread(final Stream stream,
68
+            final Document document) throws IOException {
69
+        super();
70
+        this.stream = stream;
71
+        this.document = document;
72
+
73
+        final PipedInputStream in = new PipedInputStream();
74
+        final PipedOutputStream out = new PipedOutputStream(in);
75
+        rar = new BufferedReader(new InputStreamReader(in));
76
+        switch (stream) {
77
+            case OUT:
78
+                System.setOut(new PrintStream(out));
79
+                break;
80
+            case IN:
81
+                System.setErr(new PrintStream(out));
82
+                break;
83
+            default:
84
+                throw new IllegalArgumentException("Unknown stream type: "
85
+                        + stream);
86
+        }
87
+    }
88
+
89
+    /** {@inheritDoc} */
90
+    @Override
91
+    public void run() {
92
+        running = true;
93
+        while (running) {
94
+            try {
95
+                if (rar.ready()) {
96
+                    document.insertString(document.getLength(), rar.readLine(),
97
+                            null);
98
+                    document.insertString(document.getLength(), "\n", null);
99
+                }
100
+            } catch (BadLocationException ex) {
101
+                running = false;
102
+            } catch (IOException ex) {
103
+                running = false;
104
+            }
105
+        }
106
+    }
107
+
108
+    /**
109
+     * Starts the thread adding text to the document.
110
+     */
111
+    public void start() {
112
+        final Thread thread = new Thread(this,
113
+                "System stream redirector (" + stream + ")");
114
+        thread.setDaemon(true);
115
+        thread.start();
116
+    }
117
+
118
+    /**
119
+     * Cancels the thread adding text to the document.
120
+     */
121
+    public void cancel() {
122
+        running = false;
123
+    }
124
+
125
+    /**
126
+     * Is this thread running?
127
+     *
128
+     * @return true iif running
129
+     */
130
+    public boolean isRunning() {
131
+        return running;
132
+    }
133
+}

src/com/dmdirc/addons/ui_swing/TracingEventQueueThread.java → src/com/dmdirc/addons/swingdebug/TracingEventQueue.java View File

@@ -24,12 +24,19 @@
24 24
  * POSSIBILITY OF SUCH DAMAGE.
25 25
  */
26 26
 
27
-package com.dmdirc.addons.ui_swing;
27
+package com.dmdirc.addons.swingdebug;
28
+
29
+import com.dmdirc.addons.ui_swing.DMDircEventQueue;
30
+import com.dmdirc.addons.ui_swing.SwingController;
31
+import com.dmdirc.config.IdentityManager;
32
+import com.dmdirc.interfaces.ConfigChangeListener;
33
+import com.dmdirc.plugins.Plugin;
28 34
 
29 35
 import java.awt.AWTEvent;
30 36
 import java.lang.management.ManagementFactory;
31 37
 import java.lang.management.ThreadInfo;
32 38
 import java.lang.management.ThreadMXBean;
39
+import java.util.Collections;
33 40
 import java.util.HashMap;
34 41
 import java.util.Map;
35 42
 import java.util.Set;
@@ -38,33 +45,52 @@ import javax.management.MBeanServer;
38 45
 import javax.management.ObjectName;
39 46
 
40 47
 /**
41
- * Event queue extention to monitor long running tasks on the EDT. Found at
42
- * http://today.java.net/lpt/a/433
48
+ * Event queue extention to monitor long running tasks on the EDT. Original
49
+ * code found at http://today.java.net/lpt/a/433 modified to work as a DMDirc
50
+ * plugin.
43 51
  */
44
-public class TracingEventQueueThread extends Thread {
52
+public class TracingEventQueue extends DMDircEventQueue implements
53
+        Runnable, ConfigChangeListener {
45 54
 
46
-    private final long thresholdDelay;
55
+    /** Threshold before event is considered long running. */
56
+    private long thresholdDelay;
57
+    /** Map of event to time started. */
47 58
     private final Map<AWTEvent, Long> eventTimeMap;
59
+    /** Thread bean, used to get thread info. */
48 60
     private ThreadMXBean threadBean;
61
+    /** boolean to end thread. */
49 62
     private boolean running = false;
63
+    /** Parent plugin. */
64
+    private final Plugin parentPlugin;
65
+    /** Tracing thread. */
66
+    private Thread tracingThread;
50 67
 
51 68
     /**
52 69
      * Instantiates a new tracing thread.
53
-     * 
54
-     * @param thresholdDelay
55
-     *            Length to consider a long running task
70
+     *
71
+     * @param parentPlugin Parent plugin
72
+     * @param controller Swing controller
56 73
      */
57
-    public TracingEventQueueThread(final long thresholdDelay) {
58
-        this.thresholdDelay = thresholdDelay;
59
-        eventTimeMap = new HashMap<AWTEvent, Long>();
74
+    public TracingEventQueue(final Plugin parentPlugin,
75
+            final SwingController controller) {
76
+        super(controller);
77
+        this.parentPlugin = parentPlugin;
78
+
79
+        eventTimeMap = Collections.synchronizedMap(
80
+                new HashMap<AWTEvent, Long>());
81
+        IdentityManager.getGlobalConfig().addChangeListener(
82
+                parentPlugin.getDomain(), "debugEDT", this);
83
+        IdentityManager.getGlobalConfig().addChangeListener(
84
+                parentPlugin.getDomain(), "slowedttaskthreshold", this);
85
+        checkTracing();
60 86
 
61 87
         try {
62 88
             final MBeanServer mbeanServer = ManagementFactory
63 89
                     .getPlatformMBeanServer();
64 90
             final ObjectName objName = new ObjectName(
65 91
                     ManagementFactory.THREAD_MXBEAN_NAME);
66
-            final Set<ObjectName> mbeans = mbeanServer
67
-                    .queryNames(objName, null);
92
+            final Set<ObjectName> mbeans = mbeanServer.queryNames(objName,
93
+                    null);
68 94
             for (final ObjectName name : mbeans) {
69 95
                 threadBean = ManagementFactory.newPlatformMXBeanProxy(
70 96
                         mbeanServer, name.toString(), ThreadMXBean.class);
@@ -74,28 +100,47 @@ public class TracingEventQueueThread extends Thread {
74 100
         }
75 101
     }
76 102
 
103
+    /** {@inheritDoc} */
104
+    @Override
105
+    protected void preDispatchEvent(final AWTEvent event) {
106
+        eventDispatched(event);
107
+    }
108
+
109
+    /** {@inheritDoc} */
110
+    @Override
111
+    protected void postDispatchEvent(final AWTEvent event) {
112
+        eventProcessed(event);
113
+    }
114
+
115
+
116
+
77 117
     /**
78 118
      * Marks the start time for the specified event.
79
-     * 
80
-     * @param event
81
-     *            Event to monitor
119
+     *
120
+     * @param event Event to monitor
82 121
      */
83
-    public synchronized void eventDispatched(final AWTEvent event) {
122
+    public void eventDispatched(final AWTEvent event) {
84 123
         eventTimeMap.put(event, System.currentTimeMillis());
85 124
     }
86 125
 
87 126
     /**
88 127
      * Marks the end time for the specified event.
89
-     * 
90
-     * @param event
91
-     *            Event to finish monitoring.
128
+     *
129
+     * @param event Event to finish monitoring.
92 130
      */
93
-    public synchronized void eventProcessed(final AWTEvent event) {
94
-        checkEventTime(event, System.currentTimeMillis(), eventTimeMap
95
-                .get(event));
131
+    public void eventProcessed(final AWTEvent event) {
132
+        checkEventTime(event, System.currentTimeMillis(),
133
+                eventTimeMap.get(event));
96 134
         eventTimeMap.put(event, null);
97 135
     }
98 136
 
137
+    /**
138
+     * Check how long an event took, if over threshold notify user.
139
+     *
140
+     * @param event Event to check
141
+     * @param currTime Current time
142
+     * @param startTime Start time
143
+     */
99 144
     private void checkEventTime(final AWTEvent event, final long currTime,
100 145
             final long startTime) {
101 146
         final long currProcessingTime = currTime - startTime;
@@ -112,11 +157,10 @@ public class TracingEventQueueThread extends Thread {
112 157
                             threadId, Integer.MAX_VALUE);
113 158
                     if (threadInfo != null
114 159
                             && threadInfo.getThreadName().startsWith(
115
-                                    "AWT-EventQueue")) {
160
+                            "AWT-EventQueue")) {
116 161
                         System.out.println(threadInfo.getThreadName() + " / "
117 162
                                 + threadInfo.getThreadState());
118
-                        final StackTraceElement[] stack = threadInfo
119
-                                .getStackTrace();
163
+                        final StackTraceElement[] stack = threadInfo.getStackTrace();
120 164
                         for (final StackTraceElement stackEntry : stack) {
121 165
                             System.out.println("\t" + stackEntry.getClassName()
122 166
                                     + "." + stackEntry.getMethodName() + " ["
@@ -125,8 +169,7 @@ public class TracingEventQueueThread extends Thread {
125 169
                     }
126 170
                 }
127 171
 
128
-                final long[] deadlockedThreads = threadBean
129
-                        .findDeadlockedThreads();
172
+                final long[] deadlockedThreads = threadBean.findDeadlockedThreads();
130 173
                 if (deadlockedThreads != null && deadlockedThreads.length > 0) {
131 174
                     System.out.println("Deadlocked threads:");
132 175
                     for (final long threadId : deadlockedThreads) {
@@ -134,8 +177,7 @@ public class TracingEventQueueThread extends Thread {
134 177
                                 threadId, Integer.MAX_VALUE);
135 178
                         System.out.println(threadInfo.getThreadName() + " / "
136 179
                                 + threadInfo.getThreadState());
137
-                        final StackTraceElement[] stack = threadInfo
138
-                                .getStackTrace();
180
+                        final StackTraceElement[] stack = threadInfo.getStackTrace();
139 181
                         for (final StackTraceElement stackEntry : stack) {
140 182
                             System.out.println("\t" + stackEntry.getClassName()
141 183
                                     + "." + stackEntry.getMethodName() + " ["
@@ -153,7 +195,7 @@ public class TracingEventQueueThread extends Thread {
153 195
         running = true;
154 196
         while (running) {
155 197
             final long currTime = System.currentTimeMillis();
156
-            synchronized (this) {
198
+            synchronized (eventTimeMap) {
157 199
                 for (final Map.Entry<AWTEvent, Long> entry : eventTimeMap
158 200
                         .entrySet()) {
159 201
                     final AWTEvent event = entry.getKey();
@@ -165,7 +207,7 @@ public class TracingEventQueueThread extends Thread {
165 207
                 }
166 208
             }
167 209
             try {
168
-                Thread.sleep(100);
210
+                Thread.sleep(thresholdDelay);
169 211
             } catch (final InterruptedException ie) {
170 212
                 // Ignore
171 213
             }
@@ -178,4 +220,24 @@ public class TracingEventQueueThread extends Thread {
178 220
     public void cancel() {
179 221
         running = false;
180 222
     }
181
-}
223
+
224
+    private void checkTracing() {
225
+        final boolean tracing = IdentityManager.getGlobalConfig().
226
+                getOptionBool(parentPlugin.getDomain(), "debugEDT");
227
+        thresholdDelay = IdentityManager.getGlobalConfig().
228
+                getOptionInt(parentPlugin.getDomain(), "slowedttaskthreshold");
229
+        if (tracing) {
230
+            running = true;
231
+            tracingThread = new Thread(this);
232
+            tracingThread.start();
233
+        } else {
234
+            running = false;
235
+        }
236
+    }
237
+
238
+    /** {@inheritDoc} */
239
+    @Override
240
+    public void configChanged(final String domain, final String key) {
241
+        checkTracing();
242
+    }
243
+}

+ 35
- 0
src/com/dmdirc/addons/swingdebug/plugin.config View File

@@ -0,0 +1,35 @@
1
+# This is a DMDirc configuration file.
2
+
3
+# This section indicates which sections below take key/value
4
+# pairs, rather than a simple list. It should be placed above
5
+# any sections that take key/values.
6
+keysections:
7
+  metadata
8
+  updates
9
+  version
10
+  defaults
11
+  requires
12
+
13
+metadata:
14
+  author=Greg <greg@dmdirc.com>
15
+  mainclass=com.dmdirc.addons.swingdebug.SwingDebugPlugin
16
+  description=Debugging plugin for DMDirc.
17
+  name=swingdebug
18
+  nicename=Swing debug
19
+  unloadable=yes
20
+
21
+updates:
22
+  id=60
23
+
24
+version:
25
+  friendly=0.1
26
+
27
+requires:
28
+    parent=ui_swing
29
+
30
+required-services:
31
+    swing ui
32
+
33
+defaults:
34
+    debugEDT=false
35
+    slowedttaskthreshold=100

+ 40
- 128
src/com/dmdirc/addons/ui_swing/DMDircEventQueue.java View File

@@ -28,8 +28,6 @@ import com.dmdirc.addons.ui_swing.actions.CopyAction;
28 28
 import com.dmdirc.addons.ui_swing.actions.CutAction;
29 29
 import com.dmdirc.addons.ui_swing.actions.PasteAction;
30 30
 
31
-import com.dmdirc.config.IdentityManager;
32
-import com.dmdirc.interfaces.ConfigChangeListener;
33 31
 import java.awt.AWTEvent;
34 32
 import java.awt.Component;
35 33
 import java.awt.EventQueue;
@@ -46,47 +44,27 @@ import javax.swing.SwingUtilities;
46 44
 import javax.swing.text.JTextComponent;
47 45
 
48 46
 /**
49
- * Custom event queue to add common functionality to certain components and 
50
- * monitor the EDT for long running tasks.  The monitoring code was taken from
51
- * TracingEventQueue by Kirill Grouchnikov (http://today.java.net/lpt/a/433).
47
+ * Custom event queue to add common functionality to certain components.
52 48
  */
53
-public final class DMDircEventQueue extends EventQueue implements
54
-        ConfigChangeListener {
49
+public class DMDircEventQueue extends EventQueue {
55 50
 
56 51
     /** Swing Controller. */
57
-    private SwingController controller;
58
-    /** Tracing thread. */
59
-    private TracingEventQueueThread tracingThread;
52
+    private final SwingController controller;
60 53
 
61
-    /** 
62
-     * Instantiates the DMDircEventQueue. 
63
-     * 
54
+    /**
55
+     * Instantiates the DMDircEventQueue.
56
+     *
64 57
      * @param controller Swing controller
65 58
      */
66 59
     public DMDircEventQueue(final SwingController controller) {
67 60
         super();
68 61
 
69 62
         this.controller = controller;
70
-        checkTracing();
71
-        IdentityManager.getGlobalConfig().addChangeListener(
72
-                controller.getDomain(), "debugEDT", this);
73 63
     }
74 64
 
75 65
     /** {@inheritDoc} */
76 66
     @Override
77 67
     protected void dispatchEvent(final AWTEvent event) {
78
-        if (tracingThread == null) {
79
-            super.dispatchEvent(event);
80
-        } else {
81
-            if (tracingThread != null) {
82
-                tracingThread.eventDispatched(event);
83
-            }
84
-            super.dispatchEvent(event);
85
-            if (tracingThread != null) {
86
-                tracingThread.eventProcessed(event);
87
-            }
88
-        }
89
-
90 68
         if (event instanceof MouseEvent) {
91 69
             handleMouseEvent((MouseEvent) event);
92 70
         } else if (event instanceof KeyEvent) {
@@ -94,112 +72,54 @@ public final class DMDircEventQueue extends EventQueue implements
94 72
         } else if (event instanceof WindowEvent) {
95 73
             handleWindowEvent((WindowEvent) event);
96 74
         }
75
+        preDispatchEvent(event);
76
+        super.dispatchEvent(event);
77
+        postDispatchEvent(event);
97 78
     }
98 79
 
99
-    private void checkTracing() {
100
-        final boolean tracing = IdentityManager.getGlobalConfig().
101
-                getOptionBool(controller.getDomain(), "debugEDT");
102
-        if (tracing) {
103
-            tracingThread = new TracingEventQueueThread(100);
104
-            tracingThread.start();
105
-        } else {
106
-            if (tracingThread != null) {
107
-                tracingThread.cancel();
108
-                tracingThread = null;
109
-            }
110
-        }
80
+    /**
81
+     * Triggered before the event is dispatched to AWT.
82
+     *
83
+     * @param event Event about to be dispatched
84
+     */
85
+    protected void preDispatchEvent(final AWTEvent event) {
86
+        //Do nothing
87
+    }
88
+
89
+    /**
90
+     * Called just after an event is dispatched to AWT.
91
+     *
92
+     * @param event Event that has been dispatched
93
+     */
94
+    protected void postDispatchEvent(final AWTEvent event) {
95
+        //Do nothing
111 96
     }
112 97
 
113 98
     /**
114 99
      * Handles key events.
115
-     * 
100
+     *
116 101
      * @param ke Key event
117 102
      */
118 103
     private void handleKeyEvent(final KeyEvent ke) {
119
-        switch (ke.getKeyChar()) {
120
-            case KeyEvent.VK_F1:
121
-            //Fallthrough
122
-            case KeyEvent.VK_F2:
123
-            //Fallthrough
124
-            case KeyEvent.VK_F3:
125
-            //Fallthrough
126
-            case KeyEvent.VK_F4:
127
-            //Fallthrough
128
-            case KeyEvent.VK_F5:
129
-            //Fallthrough
130
-            case KeyEvent.VK_F6:
131
-            //Fallthrough
132
-            case KeyEvent.VK_F7:
133
-            //Fallthrough
134
-            case KeyEvent.VK_F8:
135
-            //Fallthrough
136
-            case KeyEvent.VK_F9:
137
-            //Fallthrough
138
-            case KeyEvent.VK_F10:
139
-            //Fallthrough
140
-            case KeyEvent.VK_F11:
141
-            //Fallthrough
142
-            case KeyEvent.VK_F12:
143
-            //Fallthrough
144
-            case KeyEvent.VK_F13:
145
-            //Fallthrough
146
-            case KeyEvent.VK_F14:
147
-            //Fallthrough
148
-            case KeyEvent.VK_F15:
149
-            //Fallthrough
150
-            case KeyEvent.VK_F16:
151
-            //Fallthrough
152
-            case KeyEvent.VK_F17:
153
-            //Fallthrough
154
-            case KeyEvent.VK_F18:
155
-            //Fallthrough
156
-            case KeyEvent.VK_F19:
157
-            //Fallthrough
158
-            case KeyEvent.VK_F20:
159
-            //Fallthrough
160
-            case KeyEvent.VK_F21:
161
-            //Fallthrough
162
-            case KeyEvent.VK_F22:
163
-            //Fallthrough
164
-            case KeyEvent.VK_F23:
165
-            //Fallthrough
166
-            case KeyEvent.VK_F24:
167
-                ActionManager.processEvent(CoreActionType.CLIENT_KEY_PRESSED,
168
-                        null, KeyStroke.getKeyStroke(ke.getKeyChar(),
169
-                        ke.getModifiers()));
170
-                break;
171
-            default:
172
-                if (ke.getModifiers() != 0) {
173
-                    ActionManager.processEvent(CoreActionType.CLIENT_KEY_PRESSED,
174
-                            null, KeyStroke.getKeyStroke(ke.getKeyChar(),
175
-                            ke.getModifiers()));
176
-                }
177
-                break;
178
-        }
104
+        ActionManager.processEvent(CoreActionType.CLIENT_KEY_PRESSED, null,
105
+                KeyStroke.getKeyStroke(ke.getKeyChar(), ke.getModifiers()));
179 106
     }
180 107
 
181 108
     /**
182 109
      * Handles mouse events.
183
-     * 
110
+     *
184 111
      * @param me Mouse event
185 112
      */
186 113
     private void handleMouseEvent(final MouseEvent me) {
187
-        if (!me.isPopupTrigger()) {
188
-            return;
189
-        }
190
-
191
-        if (me.getComponent() == null) {
114
+        if (!me.isPopupTrigger() || me.getComponent() == null) {
192 115
             return;
193 116
         }
194 117
 
195 118
         final Component comp = SwingUtilities.getDeepestComponentAt(
196 119
                 me.getComponent(), me.getX(), me.getY());
197 120
 
198
-        if (!(comp instanceof JTextComponent)) {
199
-            return;
200
-        }
201
-
202
-        if (MenuSelectionManager.defaultManager().getSelectedPath().length > 0) {
121
+        if (!(comp instanceof JTextComponent) || MenuSelectionManager
122
+                .defaultManager().getSelectedPath().length > 0) {
203 123
             return;
204 124
         }
205 125
 
@@ -215,25 +135,17 @@ public final class DMDircEventQueue extends EventQueue implements
215 135
     }
216 136
 
217 137
     /**
218
-     * Handles window events
219
-     * 
220
-     * @param windowEvent Window event
138
+     * Handles window events.
139
+     *
140
+     * @param we Window event
221 141
      */
222 142
     private void handleWindowEvent(final WindowEvent we) {
223
-        if (we.getSource() instanceof Window) {
224
-            if (controller.hasMainFrame()) {
225
-                if (we.getID() == WindowEvent.WINDOW_OPENED) {
226
-                    controller.addTopLevelWindow((Window) we.getSource());
227
-                } else if (we.getID() == WindowEvent.WINDOW_CLOSED) {
228
-                    controller.delTopLevelWindow((Window) we.getSource());
229
-                }
143
+        if ((we.getSource() instanceof Window) && controller.hasMainFrame()) {
144
+            if (we.getID() == WindowEvent.WINDOW_OPENED) {
145
+                controller.addTopLevelWindow((Window) we.getSource());
146
+            } else if (we.getID() == WindowEvent.WINDOW_CLOSED) {
147
+                controller.delTopLevelWindow((Window) we.getSource());
230 148
             }
231 149
         }
232 150
     }
233
-
234
-    /** {@inheritDoc} */
235
-    @Override
236
-    public void configChanged(final String domain, final String key) {
237
-        checkTracing();
238
-    }
239 151
 }

+ 0
- 1
src/com/dmdirc/addons/ui_swing/MainFrame.java View File

@@ -53,7 +53,6 @@ import java.awt.event.WindowListener;
53 53
 import java.lang.reflect.InvocationTargetException;
54 54
 
55 55
 import javax.swing.ImageIcon;
56
-import javax.swing.JDesktopPane;
57 56
 import javax.swing.JFrame;
58 57
 import javax.swing.JPanel;
59 58
 import javax.swing.JSplitPane;

+ 154
- 0
src/com/dmdirc/addons/ui_swing/components/CheckBoxMenuItem.java View File

@@ -0,0 +1,154 @@
1
+/*
2
+ * Copyright (c) 2006-2010 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.addons.ui_swing.components;
24
+
25
+import javax.swing.Action;
26
+import javax.swing.Icon;
27
+import javax.swing.JCheckBoxMenuItem;
28
+import javax.swing.MenuElement;
29
+import javax.swing.MenuSelectionManager;
30
+import javax.swing.event.ChangeEvent;
31
+import javax.swing.event.ChangeListener;
32
+
33
+/**
34
+ * Extention of a normal JCheckboxMenuItem that stays open when clicked.
35
+ */
36
+public class CheckBoxMenuItem extends JCheckBoxMenuItem {
37
+
38
+    /** Menu path to use when clicked. */
39
+    private static MenuElement[] path;
40
+
41
+    /**
42
+     * Constructs a new checkbox menu item.
43
+     *
44
+     * @see JCheckBoxMenuItem#JCheckBoxMenuItem()
45
+     */
46
+    public CheckBoxMenuItem() {
47
+        super();
48
+        getModel().addChangeListener(new StayOpenListener());
49
+    }
50
+
51
+    /**
52
+     * Constructs a new checkbox menu item with the specified action.
53
+     *
54
+     * @param a Action to use
55
+     *
56
+     * @see JCheckBoxMenuItem#JCheckBoxMenuItem(Action)
57
+     */
58
+    public CheckBoxMenuItem(final Action a) {
59
+        super(a);
60
+        getModel().addChangeListener(new StayOpenListener());
61
+    }
62
+
63
+    /**
64
+     * Constructs a new checkbox menu item with the specified action.
65
+     *
66
+     * @param icon Icon to use
67
+     *
68
+     * @see JCheckBoxMenuItem#JCheckBoxMenuItem(Icon)
69
+     */
70
+    public CheckBoxMenuItem(final Icon icon) {
71
+        super(icon);
72
+        getModel().addChangeListener(new StayOpenListener());
73
+    }
74
+
75
+    /**
76
+     * Constructs a new checkbox menu item with the specified text.
77
+     *
78
+     * @param text Text to use
79
+     *
80
+     * @see JCheckBoxMenuItem#JCheckBoxMenuItem(String)
81
+     */
82
+    public CheckBoxMenuItem(final String text) {
83
+        super(text);
84
+        getModel().addChangeListener(new StayOpenListener());
85
+    }
86
+
87
+    /**
88
+     * Constructs a new checkbox menu item with the specified text and selected
89
+     * state.
90
+     *
91
+     * @param text Text to use
92
+     * @param selected Initial selection state
93
+     *
94
+     * @see JCheckBoxMenuItem#JCheckBoxMenuItem(String, boolean)
95
+     */
96
+    public CheckBoxMenuItem(final String text, final boolean selected) {
97
+        super(text, selected);
98
+        getModel().addChangeListener(new StayOpenListener());
99
+    }
100
+
101
+    /**
102
+     * Constructs a new checkbox menu item with the specified text and icon.
103
+     *
104
+     * @param text Text to use
105
+     * @param icon Icon to use
106
+     *
107
+     * @see JCheckBoxMenuItem#JCheckBoxMenuItem(String, Icon)
108
+     */
109
+    public CheckBoxMenuItem(final String text, final Icon icon) {
110
+        super(text, icon);
111
+        getModel().addChangeListener(new StayOpenListener());
112
+    }
113
+
114
+    /**
115
+     * Constructs a new checkbox menu item with the specified text icon and
116
+     * initial selected state.
117
+     *
118
+     * @param text Text to use
119
+     * @param icon Icon to use
120
+     * @param selected Initial selection state
121
+     *
122
+     * @see JCheckBoxMenuItem#JCheckBoxMenuItem(String, Icon, boolean)
123
+     */
124
+    public CheckBoxMenuItem(final String text, final Icon icon,
125
+            final boolean selected) {
126
+        super(text, icon, selected);
127
+        getModel().addChangeListener(new StayOpenListener());
128
+    }
129
+
130
+    /**
131
+     * Overridden to reopen the menu.
132
+     *
133
+     * @param pressTime the time to "hold down" the button, in milliseconds
134
+     */
135
+    @Override
136
+    public void doClick(final int pressTime) {
137
+        super.doClick(pressTime);
138
+        MenuSelectionManager.defaultManager().setSelectedPath(path);
139
+    }
140
+
141
+    /**
142
+     * Listener to restore the saved path when clicked.
143
+     */
144
+    private class StayOpenListener implements ChangeListener {
145
+
146
+        /** {@inheritDoc} */
147
+        @Override
148
+        public void stateChanged(final ChangeEvent e) {
149
+            if (getModel().isArmed() && isShowing()) {
150
+                path = MenuSelectionManager.defaultManager().getSelectedPath();
151
+            }
152
+        }
153
+    }
154
+}

+ 13
- 3
src/com/dmdirc/addons/ui_swing/components/MenuBar.java View File

@@ -77,6 +77,8 @@ public class MenuBar extends JMenuBar implements ActionListener, MenuListener {
77 77
     private final SwingController controller;
78 78
     /** Main frame. */
79 79
     private final MainFrame mainFrame;
80
+    /** Normal menu count. */
81
+    private int menuItemCount = 0;
80 82
 
81 83
     /**
82 84
      * Instantiates a new menu bar.
@@ -97,16 +99,24 @@ public class MenuBar extends JMenuBar implements ActionListener, MenuListener {
97 99
         initSettingsMenu();
98 100
         add(new WindowMenuFrameManager(controller));
99 101
         initHelpMenu();
100
-        add(Box.createHorizontalGlue(), "growx, pushx");
101
-        add(new MDIBar(controller, mainFrame));
102
-        add(Box.createHorizontalStrut(PlatformDefaults.getPanelInsets(1)
102
+        menuItemCount = getComponentCount();
103
+        super.add(Box.createHorizontalGlue(), "growx, pushx");
104
+        super.add(new MDIBar(controller, mainFrame));
105
+        super.add(Box.createHorizontalStrut(PlatformDefaults.getPanelInsets(1)
103 106
                 .getUnit()));
107
+        menuItemCount = getComponentCount() - menuItemCount;
104 108
 
105 109
         getActionMap().setParent(null);
106 110
         getActionMap().clear();
107 111
         menuSelected(null);
108 112
     }
109 113
 
114
+    /** {@inheritDoc} */
115
+    @Override
116
+    public JMenu add(final JMenu c) {
117
+        return (JMenu) super.add(c, getComponentCount() - menuItemCount);
118
+    }
119
+
110 120
     /**
111 121
      * Initialises the server menu.
112 122
      */

+ 0
- 1
src/com/dmdirc/addons/ui_swing/plugin.config View File

@@ -27,7 +27,6 @@ provides:
27 27
   swing ui
28 28
 
29 29
 defaults:
30
-    debugEDT=false
31 30
     windowMenuItems=30
32 31
     windowMenuScrollInterval=250
33 32
     showtopicbar=true

Loading…
Cancel
Save