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 }