Subversion Repositories HomeAutomation

Rev

Go to most recent revision | Details | Last modification | View Log | SVN | RSS feed

Rev Author Line No. Line
15 arune 1
/**
2
 * File created by Jimmy
3
 * at 2003-dec-23 21:43:41
4
 */
5
package Macbeth;
6
 
7
import Macbeth.System.*;
8
import Macbeth.Utilities.*;
9
import com.jgoodies.plaf.windows.ExtWindowsLookAndFeel;
10
import com.jgoodies.plaf.plastic.PlasticXPLookAndFeel;
11
import com.jgoodies.plaf.plastic.Plastic3DLookAndFeel;
12
import javax.swing.*;
13
import javax.swing.event.*;
14
import java.awt.*;
15
import java.awt.event.*;
16
import java.util.HashMap;
17
import java.util.Iterator;
18
import java.io.IOException;
19
import java.net.URL;
20
 
21
/**
22
 * A full featured kernel with graphical user interface.
23
 * @author Jimmy
24
 */
25
public class GUIKernel extends MbKernel {
26
 
27
    //a list of references to all loaded module GUI windows
28
    private HashMap loadedModuleGUIs;
29
    //the module whose info page we're currently viewing
30
    private MbModule selectedModule;
31
 
32
    /**
33
     * Creates a new instance of GUIKernel.
34
     * @param configFile The XML-configuration file to use.
35
     */
36
    public GUIKernel(String configFile) {
37
        super(configFile);
38
        selectedModule = null;
39
        //create GUI
40
        try {
41
            _debug.println("Loading Swing look and feel");
42
            //UIManager.setLookAndFeel(new ExtWindowsLookAndFeel());
43
            UIManager.setLookAndFeel(new Plastic3DLookAndFeel());
44
        } catch (Exception e) {}
45
        _debug.println("Creating Swing GUI");
46
        GUI g = new GUI();
47
        g.setVisible(true);
48
        try {
49
            startup();
50
        } catch (MbStartupException e) {
51
            _errors.println("Failed to start up kernel! (message: '" + e.getMessage() + "')");
52
            shutdown();
53
        }
54
        g.updateHTMLBar();
55
    }
56
 
57
    /**
58
     * Gets a short description of the kernel.
59
     * @return A short description of the kernel.
60
     */
61
    public String description() {
62
        return "Advanced kernel with graphical user interface";
63
    }
64
 
65
    /**
66
     * Starts up this kernel.
67
     */
68
    public void startup() throws MbStartupException {
69
        //startup MbKernel
70
        super.startup();
71
        loadedModuleGUIs = new HashMap(32);
72
    }
73
 
74
    /**
75
     * Shuts down this kernel.
76
     */
77
    public void shutdown() {
78
        //shut down MbKernel
79
        super.shutdown();
80
    }
81
 
82
    /**
83
     * Finds out whether or not a module has a graphical user interface.
84
     * @param moduleName The classname of the module.
85
     * @return True if this module has a GUI, false otherwise (or if module wasn't found).
86
     */
87
    public boolean moduleHasGUI(String moduleName) {
88
        //get the module
89
        MbModule m = (MbModule)loadedModules.get(moduleName);
90
        if (m!=null) {
91
            //get its interfaces
92
            Class[] interfaces = m.getClass().getInterfaces();
93
            //check whether the module implements the MbModuleGUI interface
94
            for (int i=0; i<interfaces.length; i++) {
95
                if (interfaces[i].getName().equals("Macbeth.System.MbModuleGUI")) {
96
                    return true;
97
                }
98
            }
99
        }
100
        return false;
101
    }
102
 
103
    /**
104
     * Gets the HTML-page from a specified module.
105
     * @param moduleName The classname of the module whose HTML-page you want to get.
106
     * @return Full HTML-code for this modules HTML-page. If the specified module
107
     * doesn't have a HTML-interface, its description is returned instead.
108
     */
109
    public String getHTMLPage(String moduleName) {
110
        //get the module
111
        MbModule mod = (MbModule)loadedModules.get(moduleName);
112
        //get its html-interface
113
        MbHTMLInterface html = mod.getHTMLInterface();
114
        //if this module has a HTML-interface
115
        if (html!=null) {
116
            //then return the HTML-page
117
            return html.getHTMLPage();
118
            //else, if this module doesn't have a html-interface
119
        } else {
120
            //return description instead
121
            return mod.description();
122
        }
123
    }
124
 
125
    /**
126
     * The whole graphical user interface for this kernel.
127
     */
128
    private class GUI extends JFrame implements ActionListener,WindowListener {
129
        //private JSplitPane contentArea;
130
        private JEditorPane htmlBar;
131
        private JScrollPane htmlBarScrolled;
132
        private JTabbedPane tabbedArea;
133
        private JEditorPane tabInfo;
134
        private JScrollPane tabInfoScrolled;
135
        private MDIDesktopPane tabGUI;
136
        private JScrollPane tabGUIScrolled;
137
        //private JTextArea console;
138
        private JEditorPane console;
139
        //private MbHTMLDocument consoleDocument;
140
        private JScrollPane consoleScrolled;
141
        private JMenuBar menuBar;
142
 
143
        public GUI() {
144
            setTitle("Macbeth GUI kernel");
145
 
146
        //create html bar
147
            htmlBar = new JEditorPane();
148
            htmlBar.setEditable(false);
149
            htmlBar.setBorder(BorderFactory.createEmptyBorder());
150
            htmlBar.setContentType("text/html");
151
            htmlBar.addHyperlinkListener(new HyperlinkActionsHTMLBar());
152
            htmlBarScrolled = new JScrollPane(htmlBar);
153
            htmlBarScrolled.setMinimumSize(new Dimension(100,100));
154
            htmlBarScrolled.setBorder(BorderFactory.createEmptyBorder());
155
 
156
        //create info tab
157
            tabInfo = new JEditorPane();
158
            tabInfo.setBorder(BorderFactory.createEmptyBorder());
159
            tabInfo.setContentType("text/html");
160
            tabInfo.addHyperlinkListener(new HyperlinkActionsInfoPage());
161
            tabInfo.setText("<html><h1>Macbeth!</h1></html>");
162
            tabInfo.setEditable(false);
163
            tabInfoScrolled = new JScrollPane(tabInfo);
164
            tabInfoScrolled.setBorder(BorderFactory.createEmptyBorder());
165
 
166
        //create gui tab
167
            tabGUI = new MDIDesktopPane();
168
            tabGUI.setBorder(BorderFactory.createEmptyBorder());
169
            tabGUIScrolled = new JScrollPane(tabGUI);
170
            tabGUIScrolled.setBorder(BorderFactory.createEmptyBorder());
171
 
172
        //create tabbed view
173
            tabbedArea = new JTabbedPane();
174
            tabbedArea.addTab("Info Page", null, tabInfoScrolled, "Module information");
175
            tabbedArea.addTab("GUI Desktop", null, tabGUIScrolled, "Module GUI desktop");
176
            tabbedArea.setPreferredSize(new Dimension(600,500));
177
            tabbedArea.setMinimumSize(new Dimension(100,100));
178
            tabbedArea.setBorder(BorderFactory.createEmptyBorder());
179
 
180
        //create console area
181
            console = new JEditorPane();
182
            console.setEditable(false);
183
            console.setContentType("text/html");
184
            //console = new JTextArea();
185
            //console.setMargin(new Insets(5,5,5,5));
186
            console.setBorder(BorderFactory.createEmptyBorder());
187
            consoleScrolled = new JScrollPane(console);
188
            consoleScrolled.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
189
            consoleScrolled.setPreferredSize(new Dimension(600,80));
190
            consoleScrolled.setMinimumSize(new Dimension(200,50));
191
            consoleScrolled.setBorder(BorderFactory.createEmptyBorder());
192
            consoleScrolled.addComponentListener(
193
                    new ComponentListener(){
194
                        //when console is resized, make sure it scrolls down to bottom
195
                        public void componentResized(ComponentEvent e) {
196
                            //hmm....ugly hack, but it doesn't seem to work without the 0-position
197
                            console.setCaretPosition(0);
198
                            console.setCaretPosition(console.getDocument().getLength());
199
                        }
200
                        public void componentMoved(ComponentEvent e) {}
201
                        public void componentShown(ComponentEvent e) {}
202
                        public void componentHidden(ComponentEvent e) {}
203
                    });
204
 
205
            _errors = new TextFormatterStream(new EditorPaneStream(console));
206
            ((TextFormatterStream)_errors).setPreString("<font size=\"-1\" color=\"red\">");
207
            ((TextFormatterStream)_errors).setPostString("</font>");
208
            _info = new TextFormatterStream(new EditorPaneStream(console));
209
            ((TextFormatterStream)_info).setPreString("<font size=\"-1\" color=\"black\">");
210
            ((TextFormatterStream)_info).setPostString("</font>");
211
            _debug = new TextFormatterStream(new EditorPaneStream(console));
212
            ((TextFormatterStream)_debug).setPreString("<font size=\"-1\" color=\"#777777\">");
213
            ((TextFormatterStream)_debug).setPostString("</font>");
214
 
215
        //create menu bar
216
            menuBar = new JMenuBar();
217
            setJMenuBar(menuBar);
218
            JMenu menu;
219
            JMenuItem menuItem;
220
            menu = new JMenu("System");
221
            menu.getAccessibleContext().setAccessibleDescription("System commands");
222
            menuBar.add(menu);
223
            menuItem = new JMenuItem("Restart modules");
224
            menuItem.getAccessibleContext().setAccessibleDescription("Restart all modules");
225
            menu.add(menuItem);
226
            menuItem = new JMenuItem("Restart kernel");
227
            menu.add(menuItem);
228
            menu.addSeparator();
229
            menuItem = new JMenuItem("Quit");
230
            menu.add(menuItem);
231
 
232
        //create a split pane that holds the HTML bar to the left and the tabview to the right
233
            JSplitPane splitHorizontal = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,new TitledControl(htmlBarScrolled,"Macbeth menu"),tabbedArea);
234
            splitHorizontal.setDividerLocation(130);
235
            splitHorizontal.setDividerSize(6);
236
            //tabbedArea will get all extra space when resizing
237
            splitHorizontal.setResizeWeight(0.0);
238
            //JWindowPane splitHorizontal = new JWindowPane(JWindowPane.HORIZONTAL,"Macbeth components",htmlBarScrolled,"Content",tabbedArea,null);
239
 
240
        //create a split pane that holds the the content at top and the console at bottom
241
            JSplitPane splitVertical = new JSplitPane(JSplitPane.VERTICAL_SPLIT,splitHorizontal,new TitledControl(consoleScrolled,"Console"));
242
            splitVertical.setResizeWeight(0.8);
243
            //JWindowPane splitVertical = new JWindowPane(JWindowPane.VERTICAL,"top",splitHorizontal,"Console",consoleScrolled,null);
244
 
245
        //add everything to main frame
246
            Container content = this.getContentPane();
247
            content.setLayout(new BorderLayout());
248
            content.add(splitVertical,BorderLayout.CENTER);
249
            pack();
250
            setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
251
            addWindowListener(this);
252
        }
253
 
254
        /* EVENT HANDLERS... */
255
        public void actionPerformed(ActionEvent e) {}
256
        public void windowClosing(WindowEvent e) {
257
            //when kernel GUI is closed, it's time to shut down
258
            shutdown();
259
            setVisible(false);
260
            _errors = System.err;
261
            _info = System.out;
262
            _debug = System.out;
263
            _debug.println("GUI has been closed");
264
            _debug.println("Waiting for threads to stop");
265
            dispose();
266
        }
267
        public void windowOpened(WindowEvent e) {}
268
        public void windowClosed(WindowEvent e) {}
269
        public void windowIconified(WindowEvent e) {}
270
        public void windowDeiconified(WindowEvent e) {}
271
        public void windowActivated(WindowEvent e) {}
272
        public void windowDeactivated(WindowEvent e) {}
273
 
274
        /**
275
         * Responds to hyperlink clicks in the left HTML bar.
276
         */
277
        class HyperlinkActionsHTMLBar implements HyperlinkListener {
278
            public void hyperlinkUpdate(HyperlinkEvent e) {
279
                if (e.getEventType()==HyperlinkEvent.EventType.ACTIVATED) {
280
                    URL url = e.getURL();
281
                    String description = e.getDescription();
282
                    //if a valid URL exists for the link
283
                    if (url!=null) {
284
                        //load the page in the main browser
285
                        try {
286
                            tabInfo.setPage(url);
287
                            selectedModule = null;
288
                        } catch (IOException e1) {
289
                            e1.printStackTrace();
290
                        }
291
                    }
292
                    //else, use the description to find out what to do
293
                    else {
294
                        //interprete the description as an internal macbeth command
295
                        String[] cmd = description.split(":");
296
                        if (cmd.length<=0) {
297
                            return;
298
                        }
299
                        //shows information on the specified macbeth component
300
                        if (cmd[0].equalsIgnoreCase("ShowInfo")) {
301
                            tabInfo.setText(getHTMLPage(cmd[1]));
302
                            selectedModule = (MbModule)loadedModules.get(cmd[1]);
303
                        }
304
                        //adds a module GUI to the GUI desktop
305
                        else if (cmd[0].equalsIgnoreCase("ShowGUI")) {
306
                            loadModuleGUI(cmd[1]);
307
                        }
308
                        //unloads a module
309
                        else if (cmd[0].equalsIgnoreCase("Unload")) {
310
                            unloadModule(cmd[1]);
311
                            updateHTMLBar();
312
                        }
313
                        //loads an unloaded module
314
                        else if (cmd[0].equalsIgnoreCase("Load")) {
315
                            try {
316
                                loadModule(cmd[1]);
317
                            } catch (Exception el) {
318
                                _errors.println("Error loading module: " + el);
319
                            }
320
                            updateHTMLBar();
321
                        }
322
                    }
323
 
324
                }
325
            }
326
        }
327
 
328
        /**
329
         * Responds to hyperlink clicks on module info page.
330
         */
331
        class HyperlinkActionsInfoPage implements HyperlinkListener {
332
            public void hyperlinkUpdate(HyperlinkEvent e) {
333
                if (e.getEventType()==HyperlinkEvent.EventType.ACTIVATED) {
334
                    URL url = e.getURL();
335
                    String description = e.getDescription();
336
                    //if a valid URL exists for the link
337
                    if (url!=null) {
338
                        //load the page in the main browser
339
                        try {
340
                            tabInfo.setPage(url);
341
                        } catch (IOException e1) {
342
                            e1.printStackTrace();
343
                        }
344
                    }
345
                    //else, notify the current module about the click
346
                    else {
347
                        if (selectedModule!=null) {
348
                            MbHTMLInterface html = selectedModule.getHTMLInterface();
349
                            if (html!=null) {
350
                                html.linkPressed(description);
351
                            }
352
                        }
353
                    }
354
 
355
                }
356
            }
357
        }
358
 
359
        public void updateHTMLBar() {
360
            String html = "<html>" + MySystem.lineBreak;
361
            html += "<body><b>Loaded modules</b><p>" + MySystem.lineBreak;
362
            //iterate through loaded modules-list
363
            Iterator it = loadedModules.keySet().iterator();
364
            while (it.hasNext()) {
365
                String modname = (String)it.next();
366
                html += "<b>" + modname + "</b><br>" + MySystem.lineBreak;
367
                html += " - [<a href=\"ShowInfo:" + modname + "\">Show Info</a>]<br>" + MySystem.lineBreak;
368
                if (moduleHasGUI(modname)) {
369
                    html += " - [<a href=\"ShowGUI:" + modname + "\">Load GUI</a>]<br>" + MySystem.lineBreak;
370
                }
371
                html += " - [<a href=\"Unload:" + modname + "\">Unload</a>]<br>" + MySystem.lineBreak;
372
            }
373
            html += "</p>" + MySystem.lineBreak;
374
            html += "<b>Unloaded modules</b><p>";
375
            //iterate through module list to find unloaded modules
376
            it = moduleList.keySet().iterator();
377
            while (it.hasNext()) {
378
                String modname = (String)it.next();
379
                //only show unloaded modules
380
                if (!loadedModules.containsKey(modname)) {
381
                    html += "<b>" + modname + "</b><br>" + MySystem.lineBreak;
382
                    html += " - [<a href=\"Load:" + modname + "\">Load</a>]<br>" + MySystem.lineBreak;
383
                }
384
            }
385
            html += "</p>" + MySystem.lineBreak;
386
            html += "</body></html>";
387
            htmlBar.setText(html);
388
        }
389
 
390
 
391
        /**
392
         * Loads the GUI for the specified module.
393
         * @param moduleName The module whose GUI should be loaded.
394
         */
395
        public void loadModuleGUI(String moduleName) {
396
            //if a GUI is already loaded for this module
397
            if (loadedModuleGUIs.containsKey(moduleName)) {
398
                //then bring this GUI to the front
399
                ModuleGUIWindow w = (ModuleGUIWindow)loadedModuleGUIs.get(moduleName);
400
                w.moveToFront();
401
                return;
402
            }
403
            //else, if this module does have a GUI
404
            else if (moduleHasGUI(moduleName)) {
405
                //create a new window for the GUI
406
                MbModuleGUI i = (MbModuleGUI)loadedModules.get(moduleName);
407
                ModuleGUIWindow w = new ModuleGUIWindow(moduleName);
408
                //and render GUI into this window
409
                i.renderGUI(w.getContentPane());
410
                w.setTitle(moduleName);
411
                //pack the contents to minimum possible size and show frame
412
                w.pack();
413
                w.setVisible(true);
414
                tabGUI.add(w);
415
            } else {
416
                //the module doesn't have any GUI
417
            }
418
        }
419
 
420
        /**
421
         * A window for a module GUI. This window will be shown
422
         * on the GUI desktop located inside the tabview.
423
         */
424
        private class ModuleGUIWindow extends JInternalFrame implements InternalFrameListener {
425
            private String moduleName;
426
 
427
            /**
428
             * Creates a new GUI window.
429
             * @param moduleName The name of the module.
430
             */
431
            public ModuleGUIWindow(String moduleName) {
432
                super();
433
                this.moduleName = moduleName;
434
                setDefaultCloseOperation(DISPOSE_ON_CLOSE);
435
                setResizable(true);
436
                setClosable(true);
437
                setMaximizable(false);
438
                addInternalFrameListener(this);
439
            }
440
 
441
            public void internalFrameOpened(InternalFrameEvent e) {
442
                //put a reference to this window into the hashmap
443
                loadedModuleGUIs.put(moduleName,this);
444
            }
445
 
446
            public void internalFrameClosed(InternalFrameEvent e) {
447
                //remove our reference from the hashmap
448
                loadedModuleGUIs.remove(moduleName);
449
            }
450
 
451
            public void internalFrameClosing(InternalFrameEvent e) {}
452
            public void internalFrameIconified(InternalFrameEvent e) {}
453
            public void internalFrameDeiconified(InternalFrameEvent e) {}
454
            public void internalFrameActivated(InternalFrameEvent e) {}
455
            public void internalFrameDeactivated(InternalFrameEvent e) {}
456
        }
457
    }
458
 
459
 
460
    /**
461
     * Program entry point.
462
     * @param args The command line arguments.
463
     */
464
    public static void main(String[] args) {
465
        String configFile = "Config\\Kernel.xml";
466
        //config file can also be specified with command line args
467
        if (args.length>0) {
468
            configFile = args[0];
469
        }
470
        //create new kernel
471
        new GUIKernel(configFile);
472
    }
473
 
474
}