/** * Copyright (c) 2009-2011, The HATS Consortium. All rights reserved. * This file is licensed under the terms of the Modified BSD License. */ package abs.backend.java.debugging; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.net.JarURLConnection; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.jar.JarEntry; import javax.swing.AbstractCellEditor; import javax.swing.BorderFactory; import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSplitPane; import javax.swing.JTabbedPane; import javax.swing.JTable; import javax.swing.JTextArea; import javax.swing.JTree; import javax.swing.SwingUtilities; import javax.swing.WindowConstants; import javax.swing.table.AbstractTableModel; import javax.swing.table.TableCellEditor; import javax.swing.table.TableCellRenderer; import javax.swing.text.BadLocationException; import javax.swing.text.DefaultHighlighter; import javax.swing.text.DefaultHighlighter.DefaultHighlightPainter; import javax.swing.text.Highlighter; import javax.swing.text.Highlighter.HighlightPainter; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreeCellRenderer; import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; import abs.backend.java.lib.runtime.ABSException; import abs.backend.java.lib.runtime.ABSRuntime; import abs.backend.java.observing.COGView; import abs.backend.java.observing.FutView; import abs.backend.java.observing.ObjectCreationObserver; import abs.backend.java.observing.ObjectView; import abs.backend.java.observing.SystemObserver; import abs.backend.java.utils.ColorUtils; import abs.backend.java.utils.StringUtil; public class GraphicalDebugger implements SystemObserver { final DebugWindow window; final DebugModel model; public GraphicalDebugger() { model = new DebugModel(); window = new DebugWindow(model); } // only for ad-hoc testing public static void main(String[] args) { new GraphicalDebugger(); } @Override public void systemStarted() { } @Override public void newCOGCreated(COGView cog, ObjectView initialObject) { model.cogCreated(cog, initialObject); } @Override public void systemFinished() { // TODO Auto-generated method stub } public static Color getColor(TaskState ts) { switch(ts) { case READY: return (ColorUtils.setSaturation(Color.YELLOW, 0.5f)); case SUSPENDED: return (ColorUtils.setSaturation(Color.ORANGE, 0.5f)); case RUNNING: return ColorUtils.setSaturation(Color.GREEN, 0.5f); case FINISHED: return (Color.LIGHT_GRAY); case DEADLOCKED: return (Color.red); case ASSERTION_FAILED: return (ColorUtils.PSYCHEDELIC_PURPLE); case EXCEPTION: return (ColorUtils.PSYCHEDELIC_PURPLE); case BLOCKED: return ColorUtils.setSaturation(Color.RED, 0.5f); default: throw new IllegalArgumentException("Unknown Taskstate " + ts); } } @Override public void systemError(final ABSException e) { /*SwingUtilities.invokeLater(new Runnable() { @Override public void run() { e.getMessage(); // TODO Auto-generated method stub } });*/ JOptionPane.showMessageDialog(window.frame, e.getMessage(), e.getName(), JOptionPane.ERROR_MESSAGE); } } class SourceView extends JPanel implements DebugModelListener { private static final long serialVersionUID = 1L; private final DebugModel model; final Highlighter highlighter; final Highlighter.HighlightPainter highlightPainter; final Highlighter taskHighlighter; JTextArea textArea; JTextArea lineArea; JTextArea taskArea; File file; private final Map<TaskState, DefaultHighlightPainter> highlightPainters = new HashMap<TaskState, DefaultHighlightPainter>(); private final String fileName; SourceView(DebugModel model, String fileName) { this.file = getFileFromName(fileName); this.fileName = fileName; this.model = model; JPanel content = new JPanel(); this.setLayout(new BorderLayout()); this.add(new JScrollPane(content), BorderLayout.CENTER); content.setLayout(new BorderLayout()); JPanel leftContent = new JPanel(); leftContent.setLayout(new BorderLayout()); content.add(leftContent, BorderLayout.WEST); createHighlightPainters(); textArea = new JTextArea(); lineArea = new JTextArea(); taskArea = new JTextArea(); lineArea.setBorder(BorderFactory.createLineBorder(Color.gray)); textArea.setBorder(BorderFactory.createLineBorder(Color.gray)); taskArea.setBorder(BorderFactory.createLineBorder(Color.gray)); textArea.setSelectionColor(Color.LIGHT_GRAY); highlighter = new DefaultHighlighter(); highlightPainter = new DefaultHighlighter.DefaultHighlightPainter(ColorUtils.setSatAndBright(Color.BLUE, 0.5f, 1f)); textArea.setHighlighter(highlighter); taskHighlighter = new DefaultHighlighter(); taskArea.setHighlighter(taskHighlighter); content.add(textArea, BorderLayout.CENTER); leftContent.add(lineArea, BorderLayout.EAST); leftContent.add(taskArea, BorderLayout.WEST); fillArea(); model.registerListener(this); } /** * Creates a {@link File} that has the file content referred by the * input file name. If the input file name points to an existing file this * method just returns a {@link File} for this file, otherwise this * method checks if the file name conforms to a {@link JarURLConnection} that * points to a package. If so, this method extract that particular * ABS file from that package to a temporary file and returns a {@link File} * to that temporary file. * * @param fileName * @return */ private File getFileFromName(String fileName) { File file = new File(fileName); if (file.exists()) { return file; } try { final URL jarURL = new URL(fileName); final JarURLConnection connection = (JarURLConnection) jarURL.openConnection(); final JarEntry entry = connection.getJarEntry(); final InputStream input = connection.getJarFile().getInputStream(entry); final File tmp = File.createTempFile(entry.getName(),null); tmp.deleteOnExit(); final OutputStream output = new FileOutputStream(tmp); int read = 0; byte[] bytes = new byte[1024]; while ((read = input.read(bytes)) != -1) { output.write(bytes, 0, read); } input.close(); output.flush(); output.close(); return tmp; } catch (Exception e) { throw new IllegalStateException(e); } } private void createHighlightPainters() { for (TaskState s : TaskState.values()) { highlightPainters.put(s, new DefaultHighlightPainter(GraphicalDebugger.getColor(s))); } } private void fillArea() { try { int lineNo = 1; BufferedReader reader = new BufferedReader(new FileReader(file)); while (reader.ready()) { String line = reader.readLine(); if (line == null) break; textArea.append(line + "\n"); lineArea.append(lineNo + " \n"); taskArea.append(" \n"); taskLineInfo.add(new ArrayList<TaskInfo>(0)); lineNo++; } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } textArea.setCaretPosition(0); textArea.moveCaretPosition(1); textArea.setEditable(false); } List<List<TaskInfo>> taskLineInfo = new ArrayList<List<TaskInfo>>(); Map<TaskInfo, Object> highlightTags = new HashMap<TaskInfo, Object>(); class Highlight { TaskInfo info; int start; int end; } public void updateTaskLine(int line) { highlighter.removeAllHighlights(); // taskHighlighter.removeAllHighlights(); String string = ""; boolean first = true; List<TaskInfo> tasks = taskLineInfo.get(line - 1); List<Highlight> highlights = new ArrayList<Highlight>(); try { int start = taskArea.getLineStartOffset(line - 1); for (TaskInfo info : tasks) { Object tag = highlightTags.remove(info); if (tag != null) taskHighlighter.removeHighlight(tag); Highlight highlight = new Highlight(); highlight.info = info; highlight.start = start; if (first) first = false; else { string += ", "; highlight.start += 2; } String taskString = "T" + info.task.getID(); string += taskString; highlight.end = highlight.start + taskString.length(); highlights.add(highlight); start = highlight.end; } if (tasks.isEmpty()) string = " "; else string += " ->"; setTaskLine(string, line); for (Highlight h : highlights) { highlightTags.put(h.info, taskHighlighter.addHighlight(h.start, h.end, getHighlighterPainter(h.info))); } } catch (BadLocationException e) { e.printStackTrace(); } } private HighlightPainter getHighlighterPainter(TaskInfo info) { return highlightPainters.get(info.state); } private void highlightLine(TaskInfo line) { try { int start = textArea.getLineStartOffset(line.currentLine - 1); int end = textArea.getLineEndOffset(line.currentLine - 1); highlighter.addHighlight(start, end, highlightPainter); textArea.setCaretPosition(end); } catch (BadLocationException e) { e.printStackTrace(); } } private void setTaskLine(String string, int line) { try { int start = taskArea.getLineStartOffset(line - 1); int end = taskArea.getLineEndOffset(line - 1); taskArea.replaceRange(string + " \n", start, end); } catch (BadLocationException e) { e.printStackTrace(); } } @Override public void taskInfoChanged(TaskInfo infoLine) { if (infoLine.previousLine > 0 && infoLine.previousFile == fileName) { taskLineInfo.get(infoLine.previousLine - 1).remove(infoLine); updateTaskLine(infoLine.previousLine); } if (infoLine.state == TaskState.FINISHED) { taskInfoRemoved(infoLine); textArea.select(0, 0); return; } if (infoLine.currentLine > 0 && infoLine.currentFile == fileName) { if (!taskLineInfo.get(infoLine.currentLine - 1).contains(infoLine)) { taskLineInfo.get(infoLine.currentLine - 1).add(infoLine); } updateTaskLine(infoLine.currentLine); highlightLine(infoLine); } } @Override public void taskInfoAdded(TaskInfo line) { } @Override public void taskInfoRemoved(TaskInfo line) { if (line.currentFile == fileName) { taskLineInfo.get(line.currentLine - 1).remove(line); updateTaskLine(line.currentLine); } } @Override public void cogCreated(COGInfo cog) { } @Override public void cogChanged(COGInfo info) { } } class TaskTable extends JPanel { private static final long serialVersionUID = 1L; private static final int STEP_COLUMN = 9; private static int[] INITIAL_COLUMN_WIDTHS = { 15, 50, 50, 50, 50, 50, 10, 70, 10 }; final JTable table; final TableModel tableModel; final DebugModel debugModel; private JScrollPane scrollPane; TaskTable(DebugModel debugModel) { this.tableModel = new TableModel(); this.debugModel = debugModel; setLayout(new BorderLayout()); table = new JTable(tableModel); for (int c = 0; c < tableModel.getColumnCount(); c++) { table.getColumnModel().getColumn(c).setCellRenderer(new StringRenderer()); table.getColumnModel().getColumn(c).setPreferredWidth(INITIAL_COLUMN_WIDTHS[c]); } /* * StepBtnCellEditor e = new StepBtnCellEditor(); * table.getColumnModel().getColumn(STEP_COLUMN).setCellEditor(e); * table.getColumnModel().getColumn(STEP_COLUMN).setCellRenderer(e); */ scrollPane = new JScrollPane(table); add(scrollPane, BorderLayout.CENTER); setBorder(BorderFactory.createTitledBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5), "Tasks")); setPreferredSize(new Dimension(200, 200)); debugModel.registerListener(SwingWrapperProxy.newInstance(tableModel, DebugModelListener.class)); } class StringRenderer extends JLabel implements TableCellRenderer { public StringRenderer() { setOpaque(true); setFont(getFont().deriveFont(Font.PLAIN)); } @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { TaskInfo info = tableModel.rows.get(row); setBackground(GraphicalDebugger.getColor(info.state)); setText((String) value); return this; } } class StepBtnCellEditor extends AbstractCellEditor implements TableCellRenderer, TableCellEditor { class BtnPanel extends JPanel { JButton stepBtn; JButton runBtn; BtnPanel(final TaskInfo task) { stepBtn = new JButton("step"); stepBtn.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { System.out.println("Clicked Step Task " + task.task.getID()); stopCellEditing(); debugModel.stepTask(task.task); } }); runBtn = new JButton("run"); runBtn.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { System.out.println("Clicked Run Task " + task.task.getID()); stopCellEditing(); debugModel.runTask(task.task); } }); setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS)); add(runBtn); add(stepBtn); } @Override public void setEnabled(boolean enabled) { super.setEnabled(enabled); runBtn.setEnabled(enabled); stepBtn.setEnabled(enabled); } } private List<BtnPanel> btns = new ArrayList<BtnPanel>(); private BtnPanel getBtns(final int row) { final TaskInfo task = tableModel.rows.get(row); if (row >= btns.size()) { BtnPanel pnl = new BtnPanel(task); btns.add(pnl); } BtnPanel pnl = btns.get(row); pnl.setEnabled(task.state == TaskState.RUNNING); return pnl; } @Override public Object getCellEditorValue() { return "NOTHING"; } @Override public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { return getBtns(row); } @Override public Component getTableCellRendererComponent(JTable arg0, Object value, boolean isSelected, boolean hasFocus, int row, int column) { return getBtns(row); } } class TableModel extends AbstractTableModel implements DebugModelListener { private static final long serialVersionUID = 1L; final List<TaskInfo> rows = new ArrayList<TaskInfo>(); protected final String[] columnNames = new String[] { "Task ID", "Source", "Target", "Method", "State", "Condition", "COG", "Future" }; @Override public boolean isCellEditable(int rowIndex, int columnIndex) { if (columnIndex != STEP_COLUMN) return false; TaskInfo info = rows.get(rowIndex); return info.state == TaskState.RUNNING; } @Override public String getColumnName(int column) { return columnNames[column]; } @Override public int getColumnCount() { return columnNames.length; } @Override public int getRowCount() { return rows.size(); } @Override public Class<?> getColumnClass(int columnIndex) { return String.class; } @Override public Object getValueAt(int row, int col) { TaskInfo line = rows.get(row); switch (col) { case 0: { return "" + line.task.getID(); } case 1: { ObjectView source = line.task.getSource(); if (source != null) { return source.toString(); } return ""; } case 2: { return line.task.getTarget().toString(); } case 3: { StringBuilder sb = new StringBuilder(); sb.append(line.task.getMethodName()); sb.append("("); sb.append(StringUtil.iterableToString(line.task.getArgs(), ", ")); sb.append(")"); return sb.toString(); } case 4: { String res = line.state.toString(); if (line.state == TaskState.EXCEPTION) { res += " (" + line.task.getException().getName() + ")"; } return res; } case 5: if (line.state == TaskState.SUSPENDED) { if (line.waitingOnGuard != null) { return line.waitingOnGuard.toABSString(); } } else if (line.blockedOnFuture != null) { return "Fut " + line.blockedOnFuture.getID() + "?"; } return ""; case 6: return "" + line.task.getCOG().getID(); case 7: { FutView fut = line.task.getFuture(); if (fut.isResolved()) return "" + fut.getValue(); else return "<unresolved>"; } case 8: return "NOTHING"; } return "ERROR"; } @Override public void taskInfoChanged(TaskInfo task) { int row = rows.indexOf(task); fireTableRowsUpdated(row, row); fireTableDataChanged(); } @Override public void taskInfoAdded(TaskInfo task) { rows.add(task); fireTableRowsInserted(rows.size() - 1, rows.size() - 1); fireTableDataChanged(); } @Override public void taskInfoRemoved(TaskInfo task) { int row = rows.indexOf(task); rows.remove(task); fireTableRowsDeleted(row, row); } @Override public void cogCreated(COGInfo cog) { } @Override public void cogChanged(COGInfo info) { } } } class COGTree extends JPanel { private final JTree tree; private final DebugModel debugModel; private final DefaultTreeModel treeModel; private final RootNode rootNode; COGTree(DebugModel model) { this.debugModel = model; this.rootNode = new RootNode(); this.treeModel = new DefaultTreeModel(rootNode); setLayout(new BorderLayout()); tree = new JTree(treeModel); tree.setCellRenderer(new COGNodeRenderer()); tree.setRootVisible(false); tree.setShowsRootHandles(true); JScrollPane scrollPane = new JScrollPane(tree); add(scrollPane, BorderLayout.CENTER); setBorder(BorderFactory.createTitledBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5), "Concurrent Object Groups (COGs)")); setPreferredSize(new Dimension(400, 500)); model.registerListener(SwingWrapperProxy.newInstance(rootNode, DebugModelListener.class)); } private static final String OBJECTS = "Objects"; private static final String TASKS = "Tasks"; private static final String COGS = "COGs"; class COGNodeRenderer implements TreeCellRenderer { @Override public Component getTreeCellRendererComponent(JTree tree, Object node, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode) node; Object value = treeNode.getUserObject(); JLabel lbl; if (value instanceof COGInfo) { COGInfo cogInfo = (COGInfo) value; lbl = new JLabel("COG " + cogInfo.cog.getID() + " [" + cogInfo.initialObject + "]"); } else if (value instanceof TaskInfo) { TaskInfo taskInfo = (TaskInfo) value; lbl = new JLabel("Task " + taskInfo.task.getID() + " (" + taskInfo.task.getTarget() + "." + taskInfo.task.getMethodName() + ")"); lbl.setBackground(GraphicalDebugger.getColor(taskInfo.state)); lbl.setOpaque(true); } else if (value == OBJECTS || value == TASKS || value == COGS) { lbl = new JLabel(value + " (" + treeNode.getChildCount() + ")"); } else if (value instanceof ObjectView) { ObjectView ov = (ObjectView) value; lbl = new JLabel(ov.toString()); } else if (value instanceof String) { String fieldName = (String) value; DefaultMutableTreeNode objNode = (DefaultMutableTreeNode) treeNode.getParent(); ObjectView v = (ObjectView) objNode.getUserObject(); String fieldValue; try { fieldValue = "" + v.getFieldValue(fieldName); } catch (NoSuchFieldException e) { fieldValue = "ERROR"; } lbl = new JLabel(fieldName + ":" + fieldValue); } else { lbl = new JLabel("???"); } lbl.setFont(lbl.getFont().deriveFont(Font.PLAIN)); return lbl; } } class RootNode extends DefaultMutableTreeNode implements DebugModelListener, ObjectCreationObserver { Map<COGView, DefaultMutableTreeNode> cogs = new HashMap<COGView, DefaultMutableTreeNode>(); Map<TaskInfo, DefaultMutableTreeNode> tasks = new HashMap<TaskInfo, DefaultMutableTreeNode>(); Map<ObjectView, DefaultMutableTreeNode> objects = new HashMap<ObjectView, DefaultMutableTreeNode>(); @Override public void taskInfoChanged(TaskInfo line) { TreeNode node = tasks.get(line); treeModel.nodeChanged(node); DefaultMutableTreeNode cogNode = cogs.get(line.task.getCOG()); TreeNode objectsNode = cogNode.getChildAt(0); for (int i = 0; i < objectsNode.getChildCount(); i++) { TreeNode objectNode = objectsNode.getChildAt(i); for (int j = 0; j < objectNode.getChildCount(); j++) { treeModel.nodeChanged(objectNode.getChildAt(j)); } } } @Override public void taskInfoAdded(TaskInfo line) { DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(line); tasks.put(line, newNode); DefaultMutableTreeNode tasksNode = (DefaultMutableTreeNode) cogs.get( debugModel.getCOGInfo(line.task.getCOG()).cog).getChildAt(1); treeModel.insertNodeInto(newNode, tasksNode, tasksNode.getChildCount()); tree.scrollPathToVisible(new TreePath(newNode.getPath())); } @Override public void taskInfoRemoved(TaskInfo line) { // TODO Auto-generated method stub } @Override public void cogCreated(COGInfo info) { DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(info); cogs.put(info.cog, newNode); this.add(newNode); treeModel.nodesWereInserted(this, new int[] { this.getChildCount() - 1 }); treeModel.insertNodeInto(new DefaultMutableTreeNode(OBJECTS), newNode, 0); treeModel.insertNodeInto(new DefaultMutableTreeNode(TASKS), newNode, 1); addObjectNode(info.initialObject); info.cog.registerObjectCreationListener(SwingWrapperProxy.newInstance(this, ObjectCreationObserver.class)); } @Override public void cogChanged(COGInfo info) { } @Override public void objectCreated(ObjectView o) { addObjectNode(o); } @Override public void objectInitialized(ObjectView o) { // nothing } private void addObjectNode(ObjectView o) { DefaultMutableTreeNode objectsNode = (DefaultMutableTreeNode) cogs.get(o.getCOG()).getChildAt(0); DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(o); treeModel.insertNodeInto(newNode, objectsNode, objectsNode.getChildCount()); createFieldNodes(o, newNode); } private void createFieldNodes(ObjectView o, DefaultMutableTreeNode objectNode) { for (String fieldName : o.getFieldNames()) { DefaultMutableTreeNode fieldNode = new DefaultMutableTreeNode(fieldName); treeModel.insertNodeInto(fieldNode, objectNode, objectNode.getChildCount()); } } } } class COGTable extends JPanel { private final DebugModel model; private final TableModel tableModel; private JTable table; private JScrollPane scrollPane; COGTable(DebugModel model) { this.model = model; this.tableModel = new TableModel(); setLayout(new BorderLayout()); table = new JTable(tableModel); scrollPane = new JScrollPane(table); add(scrollPane, BorderLayout.CENTER); setBorder(BorderFactory.createTitledBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5), "Concurrent Object Groups (COGs)")); setPreferredSize(new Dimension(500, 400)); model.registerListener(tableModel); } class TableModel extends AbstractTableModel implements DebugModelListener { final List<COGInfo> rows = new ArrayList<COGInfo>(); protected final String[] columnNames = new String[] { "COG ID", "Class", "Tasks" }; protected final Class<?>[] columnClasses = new Class<?>[] { String.class, String.class, String.class }; @Override public String getColumnName(int column) { return columnNames[column]; } @Override public int getColumnCount() { return columnNames.length; } @Override public int getRowCount() { return rows.size(); } @Override public Class<?> getColumnClass(int columnIndex) { return columnClasses[columnIndex]; } @Override public Object getValueAt(int row, int col) { COGInfo line = rows.get(row); switch (col) { case 0: return line.cog.getID(); case 1: return line.initialObject.getClassName(); case 2: { boolean first = true; StringBuilder sb = new StringBuilder(); for (TaskInfo t : line.tasks) { if (first) first = false; else sb.append(", "); sb.append(t.task.getID()); } return sb.toString(); } } return "ERROR"; } @Override public void taskInfoChanged(TaskInfo line) { } @Override public void taskInfoAdded(TaskInfo line) { } @Override public void taskInfoRemoved(TaskInfo line) { } @Override public void cogCreated(COGInfo info) { rows.add(info); fireTableRowsInserted(rows.size() - 1, rows.size() - 1); } @Override public void cogChanged(COGInfo info) { int row = rows.indexOf(info); fireTableRowsUpdated(row, row); } } } class DebugWindow implements DebugModelListener { final JFrame frame; final JTabbedPane tabs; // final JButton nextStepBtn; final TaskTable controls; final COGTree cogTree; final DebugModel model; final Map<String, SourceView> windows = new HashMap<String, SourceView>(); // private COGTable cogTable; DebugWindow(final DebugModel model) { this.model = model; frame = new JFrame("ABS Graphical Debugger"); frame.setLayout(new BorderLayout()); if (ABSRuntime.runsInOwnProcess()) frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); else frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); tabs = new JTabbedPane(); JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); frame.add(splitPane, BorderLayout.CENTER); splitPane.setRightComponent(tabs); /* * nextStepBtn = new JButton("Step Arbitrary Task"); * * nextStepBtn.addActionListener(new ActionListener() { * * @Override public void actionPerformed(ActionEvent arg0) { * model.stepRandom(); } }); * * frame.add(nextStepBtn,BorderLayout.NORTH); */ /* * cogTable = new COGTable(model); * leftSide.add(cogTable,BorderLayout.NORTH); */ cogTree = new COGTree(model); splitPane.setLeftComponent(cogTree); controls = new TaskTable(model); frame.add(new JSplitPane(JSplitPane.VERTICAL_SPLIT, splitPane, controls)); splitPane.setSize(new Dimension(1000, 600)); frame.setBounds(350, 0, 930, 800); frame.setVisible(true); model.registerListener(this); } private SourceView getSourceView(String fileName) { SourceView c = windows.get(fileName); if (c == null) { c = new SourceView(model, fileName); windows.put(fileName, c); tabs.addTab(new File(fileName).getName(), c); } return c; } @Override public void taskInfoChanged(TaskInfo line) { if (line.currentFile != null) { SourceView view = getSourceView(line.currentFile); tabs.setSelectedComponent(view); } } @Override public void taskInfoAdded(TaskInfo line) { } @Override public void taskInfoRemoved(TaskInfo line) { } @Override public void cogCreated(COGInfo cog) { } @Override public void cogChanged(COGInfo info) { } } class SwingWrapperProxy implements InvocationHandler { final Object target; public SwingWrapperProxy(Object target) { this.target = target; } @Override public synchronized Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { try { method.invoke(target, args); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } }); return null; } public static <V> V newInstance(V target, Class<?> interfce) { return (V) Proxy.newProxyInstance(SwingWrapperProxy.class.getClassLoader(), new Class[] { interfce }, new SwingWrapperProxy(target)); } }