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

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

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

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

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
  * POSSIBILITY OF SUCH DAMAGE.
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
 import java.awt.AWTEvent;
35
 import java.awt.AWTEvent;
30
 import java.lang.management.ManagementFactory;
36
 import java.lang.management.ManagementFactory;
31
 import java.lang.management.ThreadInfo;
37
 import java.lang.management.ThreadInfo;
32
 import java.lang.management.ThreadMXBean;
38
 import java.lang.management.ThreadMXBean;
39
+import java.util.Collections;
33
 import java.util.HashMap;
40
 import java.util.HashMap;
34
 import java.util.Map;
41
 import java.util.Map;
35
 import java.util.Set;
42
 import java.util.Set;
38
 import javax.management.ObjectName;
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
     private final Map<AWTEvent, Long> eventTimeMap;
58
     private final Map<AWTEvent, Long> eventTimeMap;
59
+    /** Thread bean, used to get thread info. */
48
     private ThreadMXBean threadBean;
60
     private ThreadMXBean threadBean;
61
+    /** boolean to end thread. */
49
     private boolean running = false;
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
      * Instantiates a new tracing thread.
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
         try {
87
         try {
62
             final MBeanServer mbeanServer = ManagementFactory
88
             final MBeanServer mbeanServer = ManagementFactory
63
                     .getPlatformMBeanServer();
89
                     .getPlatformMBeanServer();
64
             final ObjectName objName = new ObjectName(
90
             final ObjectName objName = new ObjectName(
65
                     ManagementFactory.THREAD_MXBEAN_NAME);
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
             for (final ObjectName name : mbeans) {
94
             for (final ObjectName name : mbeans) {
69
                 threadBean = ManagementFactory.newPlatformMXBeanProxy(
95
                 threadBean = ManagementFactory.newPlatformMXBeanProxy(
70
                         mbeanServer, name.toString(), ThreadMXBean.class);
96
                         mbeanServer, name.toString(), ThreadMXBean.class);
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
      * Marks the start time for the specified event.
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
         eventTimeMap.put(event, System.currentTimeMillis());
123
         eventTimeMap.put(event, System.currentTimeMillis());
85
     }
124
     }
86
 
125
 
87
     /**
126
     /**
88
      * Marks the end time for the specified event.
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
         eventTimeMap.put(event, null);
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
     private void checkEventTime(final AWTEvent event, final long currTime,
144
     private void checkEventTime(final AWTEvent event, final long currTime,
100
             final long startTime) {
145
             final long startTime) {
101
         final long currProcessingTime = currTime - startTime;
146
         final long currProcessingTime = currTime - startTime;
112
                             threadId, Integer.MAX_VALUE);
157
                             threadId, Integer.MAX_VALUE);
113
                     if (threadInfo != null
158
                     if (threadInfo != null
114
                             && threadInfo.getThreadName().startsWith(
159
                             && threadInfo.getThreadName().startsWith(
115
-                                    "AWT-EventQueue")) {
160
+                            "AWT-EventQueue")) {
116
                         System.out.println(threadInfo.getThreadName() + " / "
161
                         System.out.println(threadInfo.getThreadName() + " / "
117
                                 + threadInfo.getThreadState());
162
                                 + threadInfo.getThreadState());
118
-                        final StackTraceElement[] stack = threadInfo
119
-                                .getStackTrace();
163
+                        final StackTraceElement[] stack = threadInfo.getStackTrace();
120
                         for (final StackTraceElement stackEntry : stack) {
164
                         for (final StackTraceElement stackEntry : stack) {
121
                             System.out.println("\t" + stackEntry.getClassName()
165
                             System.out.println("\t" + stackEntry.getClassName()
122
                                     + "." + stackEntry.getMethodName() + " ["
166
                                     + "." + stackEntry.getMethodName() + " ["
125
                     }
169
                     }
126
                 }
170
                 }
127
 
171
 
128
-                final long[] deadlockedThreads = threadBean
129
-                        .findDeadlockedThreads();
172
+                final long[] deadlockedThreads = threadBean.findDeadlockedThreads();
130
                 if (deadlockedThreads != null && deadlockedThreads.length > 0) {
173
                 if (deadlockedThreads != null && deadlockedThreads.length > 0) {
131
                     System.out.println("Deadlocked threads:");
174
                     System.out.println("Deadlocked threads:");
132
                     for (final long threadId : deadlockedThreads) {
175
                     for (final long threadId : deadlockedThreads) {
134
                                 threadId, Integer.MAX_VALUE);
177
                                 threadId, Integer.MAX_VALUE);
135
                         System.out.println(threadInfo.getThreadName() + " / "
178
                         System.out.println(threadInfo.getThreadName() + " / "
136
                                 + threadInfo.getThreadState());
179
                                 + threadInfo.getThreadState());
137
-                        final StackTraceElement[] stack = threadInfo
138
-                                .getStackTrace();
180
+                        final StackTraceElement[] stack = threadInfo.getStackTrace();
139
                         for (final StackTraceElement stackEntry : stack) {
181
                         for (final StackTraceElement stackEntry : stack) {
140
                             System.out.println("\t" + stackEntry.getClassName()
182
                             System.out.println("\t" + stackEntry.getClassName()
141
                                     + "." + stackEntry.getMethodName() + " ["
183
                                     + "." + stackEntry.getMethodName() + " ["
153
         running = true;
195
         running = true;
154
         while (running) {
196
         while (running) {
155
             final long currTime = System.currentTimeMillis();
197
             final long currTime = System.currentTimeMillis();
156
-            synchronized (this) {
198
+            synchronized (eventTimeMap) {
157
                 for (final Map.Entry<AWTEvent, Long> entry : eventTimeMap
199
                 for (final Map.Entry<AWTEvent, Long> entry : eventTimeMap
158
                         .entrySet()) {
200
                         .entrySet()) {
159
                     final AWTEvent event = entry.getKey();
201
                     final AWTEvent event = entry.getKey();
165
                 }
207
                 }
166
             }
208
             }
167
             try {
209
             try {
168
-                Thread.sleep(100);
210
+                Thread.sleep(thresholdDelay);
169
             } catch (final InterruptedException ie) {
211
             } catch (final InterruptedException ie) {
170
                 // Ignore
212
                 // Ignore
171
             }
213
             }
178
     public void cancel() {
220
     public void cancel() {
179
         running = false;
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

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
 import com.dmdirc.addons.ui_swing.actions.CutAction;
28
 import com.dmdirc.addons.ui_swing.actions.CutAction;
29
 import com.dmdirc.addons.ui_swing.actions.PasteAction;
29
 import com.dmdirc.addons.ui_swing.actions.PasteAction;
30
 
30
 
31
-import com.dmdirc.config.IdentityManager;
32
-import com.dmdirc.interfaces.ConfigChangeListener;
33
 import java.awt.AWTEvent;
31
 import java.awt.AWTEvent;
34
 import java.awt.Component;
32
 import java.awt.Component;
35
 import java.awt.EventQueue;
33
 import java.awt.EventQueue;
46
 import javax.swing.text.JTextComponent;
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
     /** Swing Controller. */
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
      * @param controller Swing controller
57
      * @param controller Swing controller
65
      */
58
      */
66
     public DMDircEventQueue(final SwingController controller) {
59
     public DMDircEventQueue(final SwingController controller) {
67
         super();
60
         super();
68
 
61
 
69
         this.controller = controller;
62
         this.controller = controller;
70
-        checkTracing();
71
-        IdentityManager.getGlobalConfig().addChangeListener(
72
-                controller.getDomain(), "debugEDT", this);
73
     }
63
     }
74
 
64
 
75
     /** {@inheritDoc} */
65
     /** {@inheritDoc} */
76
     @Override
66
     @Override
77
     protected void dispatchEvent(final AWTEvent event) {
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
         if (event instanceof MouseEvent) {
68
         if (event instanceof MouseEvent) {
91
             handleMouseEvent((MouseEvent) event);
69
             handleMouseEvent((MouseEvent) event);
92
         } else if (event instanceof KeyEvent) {
70
         } else if (event instanceof KeyEvent) {
94
         } else if (event instanceof WindowEvent) {
72
         } else if (event instanceof WindowEvent) {
95
             handleWindowEvent((WindowEvent) event);
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
      * Handles key events.
99
      * Handles key events.
115
-     * 
100
+     *
116
      * @param ke Key event
101
      * @param ke Key event
117
      */
102
      */
118
     private void handleKeyEvent(final KeyEvent ke) {
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
      * Handles mouse events.
109
      * Handles mouse events.
183
-     * 
110
+     *
184
      * @param me Mouse event
111
      * @param me Mouse event
185
      */
112
      */
186
     private void handleMouseEvent(final MouseEvent me) {
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
             return;
115
             return;
193
         }
116
         }
194
 
117
 
195
         final Component comp = SwingUtilities.getDeepestComponentAt(
118
         final Component comp = SwingUtilities.getDeepestComponentAt(
196
                 me.getComponent(), me.getX(), me.getY());
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
             return;
123
             return;
204
         }
124
         }
205
 
125
 
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
     private void handleWindowEvent(final WindowEvent we) {
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
 import java.lang.reflect.InvocationTargetException;
53
 import java.lang.reflect.InvocationTargetException;
54
 
54
 
55
 import javax.swing.ImageIcon;
55
 import javax.swing.ImageIcon;
56
-import javax.swing.JDesktopPane;
57
 import javax.swing.JFrame;
56
 import javax.swing.JFrame;
58
 import javax.swing.JPanel;
57
 import javax.swing.JPanel;
59
 import javax.swing.JSplitPane;
58
 import javax.swing.JSplitPane;

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

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
     private final SwingController controller;
77
     private final SwingController controller;
78
     /** Main frame. */
78
     /** Main frame. */
79
     private final MainFrame mainFrame;
79
     private final MainFrame mainFrame;
80
+    /** Normal menu count. */
81
+    private int menuItemCount = 0;
80
 
82
 
81
     /**
83
     /**
82
      * Instantiates a new menu bar.
84
      * Instantiates a new menu bar.
97
         initSettingsMenu();
99
         initSettingsMenu();
98
         add(new WindowMenuFrameManager(controller));
100
         add(new WindowMenuFrameManager(controller));
99
         initHelpMenu();
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
                 .getUnit()));
106
                 .getUnit()));
107
+        menuItemCount = getComponentCount() - menuItemCount;
104
 
108
 
105
         getActionMap().setParent(null);
109
         getActionMap().setParent(null);
106
         getActionMap().clear();
110
         getActionMap().clear();
107
         menuSelected(null);
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
      * Initialises the server menu.
121
      * Initialises the server menu.
112
      */
122
      */

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

27
   swing ui
27
   swing ui
28
 
28
 
29
 defaults:
29
 defaults:
30
-    debugEDT=false
31
     windowMenuItems=30
30
     windowMenuItems=30
32
     windowMenuScrollInterval=250
31
     windowMenuScrollInterval=250
33
     showtopicbar=true
32
     showtopicbar=true

Loading…
Cancel
Save