001 /****************************************************************************** 002 * Copyright (C) MActor Developers. All rights reserved. * 003 * ---------------------------------------------------------------------------* 004 * This file is part of MActor. * 005 * * 006 * MActor is free software; you can redistribute it and/or modify * 007 * it under the terms of the GNU General Public License as published by * 008 * the Free Software Foundation; either version 2 of the License, or * 009 * (at your option) any later version. * 010 * * 011 * MActor is distributed in the hope that it will be useful, * 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 014 * GNU General Public License for more details. * 015 * * 016 * You should have received a copy of the GNU General Public License * 017 * along with MActor; if not, write to the Free Software * 018 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * 019 ******************************************************************************/ 020 package org.mactor.ui.gui; 021 022 import java.awt.BorderLayout; 023 import java.awt.CardLayout; 024 import java.awt.Color; 025 import java.awt.Component; 026 import java.awt.Font; 027 import java.awt.Frame; 028 import java.awt.Toolkit; 029 import java.awt.event.ActionEvent; 030 import java.awt.event.ActionListener; 031 import java.io.File; 032 import java.util.LinkedList; 033 034 import javax.swing.AbstractAction; 035 import javax.swing.BorderFactory; 036 import javax.swing.JButton; 037 import javax.swing.JEditorPane; 038 import javax.swing.JFrame; 039 import javax.swing.JLabel; 040 import javax.swing.JMenuBar; 041 import javax.swing.JOptionPane; 042 import javax.swing.JPanel; 043 import javax.swing.JScrollPane; 044 import javax.swing.JSplitPane; 045 import javax.swing.JTabbedPane; 046 import javax.swing.Timer; 047 048 import org.dom4j.Element; 049 import org.mactor.brokers.MessageBrokerManager; 050 import org.mactor.framework.MactorException; 051 import org.mactor.framework.spec.ProjectContext; 052 import org.mactor.ui.gui.project.ProjectControlListener; 053 import org.mactor.ui.gui.project.ProjectExplorerPanel; 054 import org.mactor.ui.gui.project.ProjectNodeType; 055 import org.mactor.ui.gui.project.ProjectTreeNode; 056 import org.mactor.ui.gui.project.editors.NodeEditor; 057 import org.mactor.ui.gui.project.editors.NodeEditorConfig; 058 import org.mactor.ui.gui.project.editors.NodeEditorConfigManager; 059 import org.mactor.ui.gui.testrunner.ChannelRuntimePanel; 060 import org.mactor.ui.gui.testrunner.MockBatteryPanel; 061 import org.mactor.ui.gui.testrunner.SingelTestPanel; 062 import org.mactor.ui.gui.testrunner.TestRunPanel; 063 064 public class MActorGui { 065 JFrame f; 066 TipPanel tipPanel = new TipPanel(); 067 NodeEditor editor; 068 JSplitPane projectPane; 069 JEditorPane introPane; 070 JPanel mainPane = new JPanel(new CardLayout()); 071 JTabbedPane tabbedPane = new JTabbedPane(); 072 JPanel editorContainer = new JPanel(new BorderLayout()); 073 JPanel editorPanel = new JPanel(new BorderLayout()); 074 TabPanel editorTab = new TabPanel(editorPanel, false); 075 EventLogPanel eventLog = new EventLogPanel(); 076 JButton dummyButton = new JButton(""); 077 ProjectExplorerPanel pc; 078 JButton reloadButton = new JButton(new AsyncAction("Reload the Project to Activate the Message Broker Modification", false, new AsyncAction.AsyncRunnable() { 079 public void run() throws MactorException { 080 pc.getProjectController().reloadProject(); 081 }; 082 })); 083 Timer reloadTimer = new Timer(700, new ActionListener() { 084 public void actionPerformed(ActionEvent e) { 085 if (reloadButton.getBackground().equals(Color.RED)) 086 reloadButton.setBackground(dummyButton.getBackground()); 087 else 088 reloadButton.setBackground(Color.RED); 089 } 090 }); 091 private void showEditorForNode(ProjectTreeNode newNode, ProjectTreeNode oldNode) { 092 if (editor != null) { 093 editor.applyChanges(); 094 } 095 if (tabbedPane.getTabCount() > 0) 096 tabbedPane.setSelectedIndex(0); 097 try { 098 if (newNode != null && oldNode != newNode) { 099 editorTab.setHeader(getPath(newNode)); 100 NodeEditorConfig editorConfig = NodeEditorConfigManager.getInstance().getNodeEditorConfig(newNode.getNodeType()); 101 if (oldNode != null && editor != null && editor.isDirty()) 102 oldNode.save(); 103 editorContainer.removeAll(); 104 if (editorConfig != null) { 105 tipPanel.onTip(1, editorConfig.getTip()); 106 editor = editorConfig.createEditor(); 107 editor.setTipListener(tipPanel); 108 editor.setData(newNode); 109 editorContainer.add((Component) editor, BorderLayout.WEST); 110 } else { 111 tipPanel.onTip(1, null); 112 editor = null; 113 } 114 } 115 editorTab.revalidate(); 116 editorTab.repaint(); 117 } catch (MactorException me) { 118 GuiUtil.showGuiError(f, me); 119 } 120 } 121 private String getPath(ProjectTreeNode node) { 122 LinkedList<String> names = new LinkedList<String>(); 123 while (node != null && node.getParentNode() != null) { 124 names.addFirst(node.getCaption()); 125 node = node.getParentNode(); 126 } 127 StringBuffer sb = new StringBuffer(); 128 for (String n : names) { 129 if (sb.length() > 0) 130 sb.append(" > "); 131 sb.append(n); 132 } 133 return sb.toString(); 134 } 135 ProjectControlListener projectControlListener = new ProjectControlListener() { 136 public void onProjectLoaded() { 137 CardLayout cl = (CardLayout) (mainPane.getLayout()); 138 cl.show(mainPane, "PROJECT"); 139 tabbedPane.removeAll(); 140 tabbedPane.addTab("Edit", new JScrollPane(editorTab)); 141 f.setTitle("MActor (" + VersionUtil.getVersion() + ") - " + ProjectContext.getGlobalInstance().getProjectName()); 142 tabbedPane.revalidate(); 143 tabbedPane.repaint(); 144 try { 145 if (MessageBrokerManager.isActive()) 146 MessageBrokerManager.getInstance().terminate(); 147 } catch (MactorException me) { 148 me.printStackTrace(); 149 } 150 reloadButton.setVisible(false); 151 reloadTimer.stop(); 152 }; 153 public void onProjectTreeSelectionChanged(ProjectTreeNode selectedNode, ProjectTreeNode previousSelectedNode) { 154 showEditorForNode(selectedNode, previousSelectedNode); 155 }; 156 public void onRequestGuiAction(ProjectTreeNode node, String action) { 157 if ("run".equals(action) && node != null) 158 openInNewTab(node); 159 if ("open".equals(action) && node != null) 160 openInNewTab(node); 161 return; 162 } 163 public void onProjectDirty() { 164 if (MessageBrokerManager.isActive()) { 165 reloadButton.setVisible(true); 166 reloadTimer.start(); 167 } 168 } 169 }; 170 public void openInNewTab(ProjectTreeNode node) { 171 try { 172 if (node != null) { 173 if (ProjectNodeType.MBC_CHANNEL.equals(node.getNodeType())) { 174 TabPanel tc = new TabPanel(new ChannelRuntimePanel(node.getName(), Boolean.parseBoolean(((Element) node.getModelObject()).attributeValue("requires_response"))), true); 175 tc.setHeader(getPath(node)); 176 tabbedPane.addTab("Channel - " + node.getCaption(), tc); 177 tabbedPane.setSelectedIndex(tabbedPane.getTabCount() - 1); 178 } else if (ProjectNodeType.T_TEST.equals(node.getNodeType())) { 179 TabPanel tc = new TabPanel(new SingelTestPanel(node), true); 180 tc.setHeader(getPath(node)); 181 tabbedPane.addTab("Test - " + node.getCaption(), tc); 182 tabbedPane.setSelectedIndex(tabbedPane.getTabCount() - 1); 183 } else if (ProjectNodeType.TM_MOCK_BATTERY.equals(node.getNodeType())) { 184 TabPanel tc = new TabPanel(new MockBatteryPanel(node), true); 185 tc.setHeader(getPath(node)); 186 tabbedPane.addTab("Mock Battery - " + node.getCaption(), tc); 187 tabbedPane.setSelectedIndex(tabbedPane.getTabCount() - 1); 188 } else if (ProjectNodeType.TR_TEST_RUN.equals(node.getNodeType())) { 189 TabPanel tc = new TabPanel(new TestRunPanel(node), true); 190 tc.setHeader(getPath(node)); 191 tabbedPane.addTab("Test Run - " + node.getCaption(), tc); 192 tabbedPane.setSelectedIndex(tabbedPane.getTabCount() - 1); 193 } 194 } 195 } catch (MactorException me) { 196 GuiUtil.showGuiError(f, me); 197 } 198 } 199 private class TabPanel extends JPanel { 200 JLabel headerLabel = new JLabel(""); 201 JButton closeButton = new JButton(new AbstractAction("X") { 202 public void actionPerformed(ActionEvent e) { 203 tabbedPane.remove(tabbedPane.indexOfComponent(TabPanel.this)); 204 if (containedComponent instanceof Stoppable) 205 ((Stoppable) containedComponent).stop(); 206 } 207 }); 208 Component containedComponent; 209 public TabPanel(Component containedComponent, boolean closeable) { 210 super(new BorderLayout()); 211 this.containedComponent = containedComponent; 212 headerLabel.setBackground(getBackground().darker().darker().darker()); 213 headerLabel.setForeground(getBackground().brighter().brighter()); 214 headerLabel.setOpaque(true); 215 headerLabel.setFont(headerLabel.getFont().deriveFont(Font.BOLD, 12)); 216 headerLabel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); 217 JPanel headerPanel = new JPanel(new BorderLayout()); 218 setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); 219 if (closeable) 220 headerPanel.add(closeButton, BorderLayout.EAST); 221 headerPanel.add(headerLabel, BorderLayout.CENTER); 222 add(headerPanel, BorderLayout.NORTH); 223 add(containedComponent, BorderLayout.CENTER); 224 } 225 public void setHeader(String header) { 226 headerLabel.setText(header); 227 headerLabel.setVisible(header != null && header.trim().length() > 0); 228 } 229 } 230 MActorGui(File projectDir) throws Exception { 231 reloadButton.setVisible(false); 232 f = new JFrame("MActor (" + VersionUtil.getVersion() + ")"); 233 f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 234 JMenuBar bar = new JMenuBar(); 235 pc = new ProjectExplorerPanel(projectControlListener); 236 bar.add(pc.getMenuBuilder().buildMenu("Project")); 237 bar.add(pc.getMenuBuilder().buildMenu("Help")); 238 bar.add(reloadButton); 239 f.setJMenuBar(bar); 240 editorPanel.add(tipPanel, BorderLayout.CENTER); 241 editorPanel.add(editorContainer, BorderLayout.NORTH); 242 projectPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, pc, tabbedPane); 243 projectPane.setDividerLocation(250); 244 introPane = new JEditorPane(Thread.currentThread().getContextClassLoader().getResource("frontpage.html")); 245 introPane.addHyperlinkListener(BrowserUtil.createLinkListener()); 246 introPane.setEditable(false); 247 mainPane.add(new JScrollPane(introPane), "INTRO"); 248 mainPane.add(projectPane, "PROJECT"); 249 JSplitPane allPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, mainPane, eventLog); 250 allPane.setDividerLocation((int) Toolkit.getDefaultToolkit().getScreenSize().getHeight() - 250); 251 f.getContentPane().add(allPane, BorderLayout.CENTER); 252 if (projectDir != null) 253 pc.getProjectController().openProject(projectDir); 254 f.setSize(1024, 800); 255 f.setExtendedState(Frame.MAXIMIZED_BOTH); 256 f.setVisible(true); 257 } 258 public static void main(String[] args) throws Exception { 259 File projectDir = null; 260 if (args != null && args.length > 0) { 261 projectDir = new File(args[0]); 262 if (!projectDir.exists()) { 263 JOptionPane.showMessageDialog(null, "Project directory '" + projectDir.getAbsolutePath() + "' does not exist", "Project not found", JOptionPane.ERROR_MESSAGE); 264 System.exit(1); 265 } else if (projectDir.isFile()) { 266 projectDir = projectDir.getParentFile(); 267 } 268 } 269 Splash s = new Splash(); 270 new MActorGui(projectDir); 271 s.dispose(); 272 } 273 }