Subversion Repositories HomeAutomation

Rev

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

  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. }
  475.