/*******************************************************************************
* This file is part of logisim-evolution.
*
* logisim-evolution is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* logisim-evolution is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with logisim-evolution. If not, see <http://www.gnu.org/licenses/>.
*
* Original code by Carl Burch (http://www.cburch.com), 2011.
* Subsequent modifications by :
* + Haute École Spécialisée Bernoise
* http://www.bfh.ch
* + Haute École du paysage, d'ingénierie et d'architecture de Genève
* http://hepia.hesge.ch/
* + Haute École d'Ingénierie et de Gestion du Canton de Vaud
* http://www.heig-vd.ch/
* The project is currently maintained by :
* + REDS Institute - HEIG-VD
* Yverdon-les-Bains, Switzerland
* http://reds.heig-vd.ch
*******************************************************************************/
package com.cburch.logisim.analyze.gui;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.AbstractListModel;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.ScrollPaneConstants;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import com.cburch.logisim.analyze.model.VariableList;
import com.cburch.logisim.analyze.model.VariableListEvent;
import com.cburch.logisim.analyze.model.VariableListListener;
import com.cburch.logisim.util.StringUtil;
class VariableTab extends AnalyzerTab implements TabInterface {
private class MyListener implements ActionListener, DocumentListener,
ListSelectionListener {
public void actionPerformed(ActionEvent event) {
Object src = event.getSource();
if ((src == add || src == field) && add.isEnabled()) {
String name = field.getText().trim();
if (!name.equals("")) {
data.add(name);
if (data.contains(name)) {
list.setSelectedValue(name, true);
}
field.setText("");
field.grabFocus();
}
} else if (src == rename) {
String oldName = (String) list.getSelectedValue();
String newName = field.getText().trim();
if (oldName != null && !newName.equals("")) {
data.replace(oldName, newName);
field.setText("");
field.grabFocus();
}
} else if (src == remove) {
String name = (String) list.getSelectedValue();
if (name != null)
data.remove(name);
} else if (src == moveUp) {
String name = (String) list.getSelectedValue();
if (name != null) {
data.move(name, -1);
list.setSelectedValue(name, true);
}
} else if (src == moveDown) {
String name = (String) list.getSelectedValue();
if (name != null) {
data.move(name, 1);
list.setSelectedValue(name, true);
}
}
}
public void changedUpdate(DocumentEvent event) {
insertUpdate(event);
}
public void insertUpdate(DocumentEvent event) {
computeEnabled();
}
public void removeUpdate(DocumentEvent event) {
insertUpdate(event);
}
public void valueChanged(ListSelectionEvent event) {
computeEnabled();
}
/*
* public void listChanged(VariableListEvent event) { switch
* (event.getType()) { case VariableListEvent.ALL_REPLACED:
* list.setSelectedIndices(new int[0]); break; case
* VariableListEvent.REMOVE: if
* (event.getVariable().equals(list.getSelectedValue())) { int index =
* ((Integer) event.getData()).intValue(); if (index >= data.size()) {
* if (data.isEmpty()) { list.setSelectedIndices(new int[0]); } index =
* data.size() - 1; } list.setSelectedValue(data.get(index), true); }
* break; case VariableListEvent.ADD: case VariableListEvent.MOVE: case
* VariableListEvent.REPLACE: break; } list.validate(); }
*/
}
@SuppressWarnings("rawtypes")
private static class VariableListModel extends AbstractListModel implements
VariableListListener {
private static final long serialVersionUID = 1L;
private VariableList list;
private String[] listCopy;
public VariableListModel(VariableList list) {
this.list = list;
updateCopy();
list.addVariableListListener(this);
}
public Object getElementAt(int index) {
return index >= 0 && index < listCopy.length ? listCopy[index]
: null;
}
public int getSize() {
return listCopy.length;
}
public void listChanged(VariableListEvent event) {
String[] oldCopy = listCopy;
updateCopy();
int index;
switch (event.getType()) {
case VariableListEvent.ALL_REPLACED:
fireContentsChanged(this, 0, oldCopy.length);
return;
case VariableListEvent.ADD:
index = list.indexOf(event.getVariable());
fireIntervalAdded(this, index, index);
return;
case VariableListEvent.REMOVE:
index = ((Integer) event.getData()).intValue();
fireIntervalRemoved(this, index, index);
return;
case VariableListEvent.MOVE:
fireContentsChanged(this, 0, getSize());
return;
case VariableListEvent.REPLACE:
index = ((Integer) event.getData()).intValue();
fireContentsChanged(this, index, index);
return;
}
}
private void update() {
String[] oldCopy = listCopy;
updateCopy();
fireContentsChanged(this, 0, oldCopy.length);
}
private void updateCopy() {
listCopy = list.toArray(new String[list.size()]);
}
}
private static final long serialVersionUID = 1L;
private VariableList data;
private MyListener myListener = new MyListener();
@SuppressWarnings("rawtypes")
private JList list = new JList();
private JTextField field = new JTextField();
private JButton remove = new JButton();
private JButton moveUp = new JButton();
private JButton moveDown = new JButton();
private JButton add = new JButton();
private JButton rename = new JButton();
private JLabel error = new JLabel(" ");
@SuppressWarnings("unchecked")
VariableTab(VariableList data) {
this.data = data;
list.setModel(new VariableListModel(data));
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
list.addListSelectionListener(myListener);
remove.addActionListener(myListener);
moveUp.addActionListener(myListener);
moveDown.addActionListener(myListener);
add.addActionListener(myListener);
rename.addActionListener(myListener);
field.addActionListener(myListener);
field.getDocument().addDocumentListener(myListener);
JScrollPane listPane = new JScrollPane(list,
ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
listPane.setPreferredSize(new Dimension(100, 100));
JPanel topPanel = new JPanel(new GridLayout(3, 1));
topPanel.add(remove);
topPanel.add(moveUp);
topPanel.add(moveDown);
JPanel fieldPanel = new JPanel();
fieldPanel.add(rename);
fieldPanel.add(add);
GridBagLayout gb = new GridBagLayout();
GridBagConstraints gc = new GridBagConstraints();
setLayout(gb);
Insets oldInsets = gc.insets;
gc.insets = new Insets(10, 10, 0, 0);
gc.fill = GridBagConstraints.BOTH;
gc.weightx = 1.0;
gb.setConstraints(listPane, gc);
add(listPane);
gc.fill = GridBagConstraints.NONE;
gc.anchor = GridBagConstraints.PAGE_START;
gc.weightx = 0.0;
gb.setConstraints(topPanel, gc);
add(topPanel);
gc.insets = new Insets(10, 10, 0, 10);
gc.gridwidth = GridBagConstraints.REMAINDER;
gc.gridx = 0;
gc.gridy = GridBagConstraints.RELATIVE;
gc.fill = GridBagConstraints.HORIZONTAL;
gb.setConstraints(field, gc);
add(field);
gc.insets = oldInsets;
gc.fill = GridBagConstraints.NONE;
gc.anchor = GridBagConstraints.LINE_END;
gb.setConstraints(fieldPanel, gc);
add(fieldPanel);
gc.fill = GridBagConstraints.HORIZONTAL;
gb.setConstraints(error, gc);
add(error);
if (!data.isEmpty())
list.setSelectedValue(data.get(0), true);
computeEnabled();
}
private void computeEnabled() {
int index = list.getSelectedIndex();
int max = list.getModel().getSize();
boolean selected = index >= 0 && index < max;
remove.setEnabled(selected);
moveUp.setEnabled(selected && index > 0);
moveDown.setEnabled(selected && index < max);
boolean ok = validateInput();
add.setEnabled(ok && data.size() < data.getMaximumSize());
rename.setEnabled(ok && selected);
}
public void copy() {
field.requestFocus();
field.copy();
}
public void delete() {
field.requestFocus();
field.replaceSelection("");
}
@Override
void localeChanged() {
remove.setText(Strings.get("variableRemoveButton"));
moveUp.setText(Strings.get("variableMoveUpButton"));
moveDown.setText(Strings.get("variableMoveDownButton"));
add.setText(Strings.get("variableAddButton"));
rename.setText(Strings.get("variableRenameButton"));
validateInput();
}
public void paste() {
field.requestFocus();
field.paste();
}
void registerDefaultButtons(DefaultRegistry registry) {
registry.registerDefaultButton(field, add);
}
public void selectAll() {
field.requestFocus();
field.selectAll();
}
@Override
void updateTab() {
VariableListModel model = (VariableListModel) list.getModel();
model.update();
}
private boolean validateInput() {
String text = field.getText().trim();
boolean ok = true;
boolean errorShown = true;
if (text.length() == 0) {
errorShown = false;
ok = false;
} else if (!Character.isJavaIdentifierStart(text.charAt(0))) {
error.setText(Strings.get("variableStartError"));
ok = false;
} else {
for (int i = 1; i < text.length() && ok; i++) {
char c = text.charAt(i);
if (!Character.isJavaIdentifierPart(c)) {
error.setText(StringUtil.format(
Strings.get("variablePartError"), "" + c));
ok = false;
}
}
}
if (ok) {
for (int i = 0, n = data.size(); i < n && ok; i++) {
String other = data.get(i);
if (text.equals(other)) {
error.setText(Strings.get("variableDuplicateError"));
ok = false;
}
}
}
if (ok || !errorShown) {
if (data.size() >= data.getMaximumSize()) {
error.setText(StringUtil.format(
Strings.get("variableMaximumError"),
"" + data.getMaximumSize()));
} else {
error.setText(" ");
}
}
return ok;
}
}