Skip to content

Commit 3ea9342

Browse files
committed
InterpreterPane: add a left-hand variables pane
It shows the REPL's active language and variables, and allows you to switch the language.
1 parent e6c7b48 commit 3ea9342

File tree

3 files changed

+212
-6
lines changed

3 files changed

+212
-6
lines changed

src/main/java/org/scijava/ui/swing/script/InterpreterPane.java

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import javax.swing.JPanel;
4545
import javax.swing.JScrollPane;
4646
import javax.swing.JSplitPane;
47+
import javax.swing.border.EmptyBorder;
4748

4849
import net.miginfocom.swing.MigLayout;
4950

@@ -63,9 +64,11 @@ public class InterpreterPane implements UIComponent<JComponent> {
6364

6465
private final ScriptREPL repl;
6566

66-
private final JSplitPane splitPane;
67+
private final JSplitPane mainPane;
68+
6769
private final OutputPane output;
6870
private final PromptPane prompt;
71+
private final VarsPane vars;
6972

7073
@Parameter(required = false)
7174
private LogService log;
@@ -89,7 +92,10 @@ public InterpreterPane(final Context context) {
8992
ctx.setErrorWriter(writer);
9093
ctx.setWriter(writer);
9194

92-
prompt = new PromptPane(repl, output) {
95+
vars = new VarsPane(context, repl);
96+
vars.setBorder(new EmptyBorder(0, 0, 8, 0));
97+
98+
prompt = new PromptPane(repl, vars, output) {
9399
@Override
94100
public void quit() {
95101
dispose();
@@ -135,9 +141,13 @@ public void actionPerformed(final ActionEvent e) {
135141
bottomPane.add(autoImportButton, "w pref!, h pref!, wrap");
136142
}
137143

138-
splitPane =
144+
final JSplitPane outputAndPromptPane =
139145
new JSplitPane(JSplitPane.VERTICAL_SPLIT, outputScroll, bottomPane);
140-
splitPane.setResizeWeight(1);
146+
outputAndPromptPane.setResizeWeight(1);
147+
148+
mainPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, vars,
149+
outputAndPromptPane);
150+
mainPane.setDividerLocation(300);
141151
}
142152

143153
// -- InterpreterPane methods --
@@ -166,7 +176,7 @@ public void dispose() {
166176

167177
@Override
168178
public JComponent getComponent() {
169-
return splitPane;
179+
return mainPane;
170180
}
171181

172182
@Override

src/main/java/org/scijava/ui/swing/script/PromptPane.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,9 @@ public abstract class PromptPane implements UIComponent<JTextArea> {
5757
private final TextArea textArea;
5858
private final OutputPane output;
5959

60-
public PromptPane(final ScriptREPL repl, final OutputPane output) {
60+
public PromptPane(final ScriptREPL repl, final VarsPane vars,
61+
final OutputPane output)
62+
{
6163
textArea = new TextArea(3, 2);
6264
textArea.setLineWrap(true);
6365
this.repl = repl;
@@ -77,6 +79,7 @@ public void keyPressed(final KeyEvent event) {
7779
final boolean result = execute();
7880
event.consume();
7981
if (!result) quit();
82+
vars.update();
8083
}
8184
break;
8285
case VK_DOWN:
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
/*
2+
* #%L
3+
* SciJava UI components for Java Swing.
4+
* %%
5+
* Copyright (C) 2010 - 2016 Board of Regents of the University of
6+
* Wisconsin-Madison.
7+
* %%
8+
* Redistribution and use in source and binary forms, with or without
9+
* modification, are permitted provided that the following conditions are met:
10+
*
11+
* 1. Redistributions of source code must retain the above copyright notice,
12+
* this list of conditions and the following disclaimer.
13+
* 2. Redistributions in binary form must reproduce the above copyright notice,
14+
* this list of conditions and the following disclaimer in the documentation
15+
* and/or other materials provided with the distribution.
16+
*
17+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
21+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27+
* POSSIBILITY OF SUCH DAMAGE.
28+
* #L%
29+
*/
30+
31+
package org.scijava.ui.swing.script;
32+
33+
import java.awt.BorderLayout;
34+
import java.awt.event.ActionEvent;
35+
import java.awt.event.ActionListener;
36+
import java.util.ArrayList;
37+
import java.util.Collections;
38+
import java.util.List;
39+
40+
import javax.swing.JCheckBox;
41+
import javax.swing.JComboBox;
42+
import javax.swing.JPanel;
43+
import javax.swing.JScrollPane;
44+
import javax.swing.JTable;
45+
import javax.swing.table.AbstractTableModel;
46+
47+
import org.scijava.Context;
48+
import org.scijava.script.ScriptLanguage;
49+
import org.scijava.script.ScriptREPL;
50+
import org.scijava.script.ScriptService;
51+
52+
/**
53+
* A side pane with information about available languages and variables.
54+
*
55+
* @author Curtis Rueden
56+
*/
57+
public class VarsPane extends JPanel {
58+
59+
private final ScriptREPL repl;
60+
private final JComboBox langBox;
61+
private final VarsTableModel varsTableModel;
62+
63+
public VarsPane(final Context context, final ScriptREPL repl) {
64+
this.repl = repl;
65+
66+
setLayout(new BorderLayout());
67+
68+
final ScriptService scriptService = context.service(ScriptService.class);
69+
final List<ScriptLanguage> langList = scriptService.getLanguages();
70+
final ScriptLanguage[] langs = langList.toArray(new ScriptLanguage[0]);
71+
langBox = new JComboBox(langs);
72+
langBox.setMaximumRowCount(25);
73+
langBox.addActionListener(new ActionListener() {
74+
75+
@Override
76+
public void actionPerformed(final ActionEvent e) {
77+
final ScriptLanguage lang = (ScriptLanguage) langBox.getSelectedItem();
78+
if (lang == repl.getInterpreter().getLanguage()) return; // no change
79+
repl.lang(lang.getLanguageName());
80+
update();
81+
}
82+
});
83+
add(langBox, BorderLayout.NORTH);
84+
85+
varsTableModel = new VarsTableModel();
86+
final JTable varsTable = new JTable(varsTableModel);
87+
varsTable.getColumnModel().getColumn(0).setMinWidth(120);
88+
varsTable.getColumnModel().getColumn(0).setMaxWidth(120);
89+
varsTable.getColumnModel().getColumn(1).setPreferredWidth(120);
90+
add(new JScrollPane(varsTable), BorderLayout.CENTER);
91+
varsTable.setAutoResizeMode(JTable.AUTO_RESIZE_NEXT_COLUMN);
92+
93+
final JCheckBox showTypes = new JCheckBox("Show variable types");
94+
showTypes.addActionListener(new ActionListener() {
95+
96+
@Override
97+
public void actionPerformed(final ActionEvent e) {
98+
varsTableModel.setShowTypes(showTypes.isSelected());
99+
}
100+
101+
});
102+
add(showTypes, BorderLayout.SOUTH);
103+
104+
update();
105+
}
106+
107+
// -- VarsPane methods --
108+
109+
public void update() {
110+
langBox.setSelectedItem(repl.getInterpreter().getLanguage());
111+
varsTableModel.update();
112+
}
113+
114+
// -- Helper classes --
115+
116+
/** Helper class for the table of variables. */
117+
private class VarsTableModel extends AbstractTableModel {
118+
119+
private final ArrayList<String> varNames = new ArrayList<String>();
120+
121+
private boolean showTypes;
122+
123+
// -- InterpreterTableModel methods --
124+
125+
public void update() {
126+
varNames.clear();
127+
varNames.addAll(repl.getInterpreter().getBindings().keySet());
128+
Collections.sort(varNames);
129+
fireTableDataChanged();
130+
}
131+
132+
public void setShowTypes(final boolean showTypes) {
133+
this.showTypes = showTypes;
134+
VarsPane.this.update();
135+
}
136+
137+
// -- TableModel methods --
138+
139+
@Override
140+
public int getColumnCount() {
141+
return 2;
142+
}
143+
144+
@Override
145+
public String getColumnName(final int columnIndex) {
146+
switch (columnIndex) {
147+
case 0:
148+
return "Name";
149+
case 1:
150+
return "Value";
151+
default:
152+
throw invalidColumnException(columnIndex);
153+
}
154+
}
155+
156+
@Override
157+
public int getRowCount() {
158+
return repl.getInterpreter().getBindings().size();
159+
}
160+
161+
@Override
162+
public Object getValueAt(final int rowIndex, final int columnIndex) {
163+
final String varName = varNames.get(rowIndex);
164+
switch (columnIndex) {
165+
case 0:
166+
return varName;
167+
case 1:
168+
return value(varName);
169+
default:
170+
throw invalidColumnException(columnIndex);
171+
}
172+
}
173+
174+
// -- Helper methods --
175+
176+
private String value(final String varName) {
177+
final Object value = repl.getInterpreter().getBindings().get(varName);
178+
if (value == null) return "<null>";
179+
final String vs = value.toString();
180+
final String type = value.getClass().getName();
181+
return vs.startsWith(type) || !showTypes ? vs : vs + " [" + type + "]";
182+
}
183+
184+
private ArrayIndexOutOfBoundsException invalidColumnException(
185+
final int columnIndex)
186+
{
187+
return new ArrayIndexOutOfBoundsException("Invalid column index: " +
188+
columnIndex);
189+
}
190+
191+
}
192+
193+
}

0 commit comments

Comments
 (0)