Improved the SingleValueDialog to enter multi bit values

This commit is contained in:
hneemann 2017-03-07 12:50:12 +01:00
parent 5a27cf916f
commit 7fc84db1f1
3 changed files with 214 additions and 38 deletions

View File

@ -5,54 +5,204 @@ import de.neemann.digital.gui.sync.Sync;
import de.neemann.digital.lang.Lang;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.Arrays;
/**
* Dialog to edit a single value.
* Used to enter a multi bit input value
* Used to enter a multi bit input value.
*
* @author hneemann
* @author Rüdiger Heintz
*/
public final class SingleValueDialog extends JDialog {
private String returnText;
private enum InMode {
HEX(Lang.get("attr_dialogHex")),
DECIMAL(Lang.get("attr_dialogDecimal")),
OCTAL(Lang.get("attr_dialogOctal")),
ASCII(Lang.get("attr_dialogAscii")),
HIGHZ(Lang.get("attr_dialogHighz"));
/**
* Creates a new instance
*
* @param pos the position to show the dialog
* @param text the text to edit
*/
private SingleValueDialog(Point pos, String text) {
private String langText;
InMode(String langKey) {
this.langText = langKey;
}
@Override
public String toString() {
return langText;
}
public static InMode[] values(boolean supportsHighZ) {
if (supportsHighZ) {
return values();
} else {
return Arrays.copyOf(values(), values().length - 1);
}
}
}
private final JTextField textField;
private final boolean supportsHighZ;
private final JComboBox<InMode> formatComboBox;
private JCheckBox[] checkBoxes;
private boolean programmaticModifyingFormat = false;
private long editValue;
private boolean ok = false;
private SingleValueDialog(Point pos, ObservableValue value) {
super((Frame) null, Lang.get("attr_dialogTitle"), true);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
JTextField textField = new JTextField(30);
textField.setText(text);
getContentPane().add(textField);
editValue = value.getValue();
supportsHighZ = value.supportsHighZ();
textField.addActionListener(new ActionListener() {
textField = new JTextField(10);
textField.setHorizontalAlignment(JTextField.RIGHT);
formatComboBox = new JComboBox<>(InMode.values(supportsHighZ));
formatComboBox.addActionListener(actionEvent -> {
if (!programmaticModifyingFormat)
setLongToDialog(editValue);
});
JPanel panel = new JPanel(new DialogLayout());
panel.add(formatComboBox, DialogLayout.LABEL);
panel.add(textField, DialogLayout.INPUT);
panel.add(new JLabel(Lang.get("attr_dialogBinary")), DialogLayout.LABEL);
panel.add(createCheckBoxPanel(value.getBits(), editValue), DialogLayout.INPUT);
getContentPane().add(panel);
textField.getDocument().addDocumentListener(new MyDocumentListener(() -> setStringToDialog(textField.getText())));
if (value.isHighZ())
formatComboBox.setSelectedItem(InMode.HIGHZ);
else
setLongToDialog(editValue);
JButton okButton = new JButton(new AbstractAction(Lang.get("ok")) {
@Override
public void actionPerformed(ActionEvent e) {
returnText = textField.getText();
public void actionPerformed(ActionEvent actionEvent) {
ok = true;
dispose();
}
});
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
buttonPanel.add(okButton);
getContentPane().add(buttonPanel, BorderLayout.EAST);
getRootPane().setDefaultButton(okButton);
getRootPane().registerKeyboardAction(actionEvent -> dispose(),
KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0),
JComponent.WHEN_IN_FOCUSED_WINDOW);
pack();
setLocation(pos.x, pos.y);
textField.requestFocus();
textField.select(0, Integer.MAX_VALUE);
}
/**
* edits the given value
*
* @return result or null if dialog closed without something entered
*/
private String showDialog() {
private JPanel createCheckBoxPanel(int bits, long value) {
JPanel p = new JPanel();
p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS));
checkBoxes = new JCheckBox[bits];
for (int i = bits - 1; i >= 0; i--) {
final int bit = i;
checkBoxes[bit] = new JCheckBox("", (value & (1L << bit)) != 0);
checkBoxes[bit].setBorder(null);
checkBoxes[bit].addActionListener(actionEvent -> setBit(bit, checkBoxes[bit].isSelected()));
p.add(checkBoxes[bit]);
}
return p;
}
private void setBit(int bitNum, boolean set) {
if (set)
editValue |= 1L << bitNum;
else
editValue &= ~(1L << bitNum);
if (getSelectedFormat().equals(InMode.HIGHZ))
setSelectedFormat(InMode.HEX);
setLongToDialog(editValue);
}
private void setLongToDialog(long editValue) {
switch (getSelectedFormat()) {
case ASCII:
char val = (char) (editValue);
textField.setText("\'" + val + "\'");
textField.setCaretPosition(1);
break;
case DECIMAL:
textField.setText(Long.toString(editValue));
break;
case HEX:
textField.setText("0x" + Long.toHexString(editValue));
break;
case OCTAL:
textField.setText("0" + Long.toOctalString(editValue));
break;
case HIGHZ:
textField.setText("?");
break;
default:
}
textField.requestFocus();
}
private InMode getSelectedFormat() {
return (InMode) formatComboBox.getSelectedItem();
}
private void setSelectedFormat(InMode format) {
if (!getSelectedFormat().equals(format)) {
programmaticModifyingFormat = true;
formatComboBox.setSelectedItem(format);
programmaticModifyingFormat = false;
}
}
private void setStringToDialog(String text) {
text = text.trim();
if (text.length() > 0) {
if (text.contains("?") && supportsHighZ) {
setSelectedFormat(InMode.HIGHZ);
editValue = 0;
} else if (text.charAt(0) == '\'') {
setSelectedFormat(InMode.ASCII);
if (text.length() > 1) {
editValue = text.charAt(1);
} else {
editValue = 0;
}
} else {
if (text.startsWith("0x"))
setSelectedFormat(InMode.HEX);
else if (text.startsWith("0"))
setSelectedFormat(InMode.OCTAL);
else
setSelectedFormat(InMode.DECIMAL);
try {
editValue = Long.decode(text);
} catch (NumberFormatException e) {
// do nothing on error
}
}
for (int i = 0; i < checkBoxes.length; i++)
checkBoxes[i].setSelected((editValue & (1L << i)) != 0);
}
}
private boolean showDialog() {
setVisible(true);
return returnText;
return ok;
}
/**
@ -62,23 +212,37 @@ public final class SingleValueDialog extends JDialog {
* @param value the value to edit
*/
public static void editValue(Point pos, ObservableValue value, Sync modelSync) {
String ret = new SingleValueDialog(pos, value.getValueString()).showDialog();
if (ret != null) {
ret = ret.trim();
if (ret.equals("?") && value.supportsHighZ()) {
modelSync.access(() -> {
value.setHighZ(true);
});
SingleValueDialog svd = new SingleValueDialog(pos, value);
if (svd.showDialog()) {
if (svd.getSelectedFormat().equals(InMode.HIGHZ)) {
modelSync.access(() -> value.setHighZ(true));
} else {
try {
long l = Long.decode(ret);
modelSync.access(() -> {
value.set(l, false);
});
} catch (NumberFormatException e) {
}
modelSync.access(() -> value.set(svd.editValue, false));
}
}
}
private static final class MyDocumentListener implements DocumentListener {
private final Runnable runnable;
private MyDocumentListener(Runnable runnable) {
this.runnable = runnable;
}
@Override
public void insertUpdate(DocumentEvent documentEvent) {
runnable.run();
}
@Override
public void removeUpdate(DocumentEvent documentEvent) {
runnable.run();
}
@Override
public void changedUpdate(DocumentEvent documentEvent) {
runnable.run();
}
}
}

View File

@ -13,6 +13,12 @@
<string name="attr_openCircuit_tt">Öffnet die Schaltung in einem neuen Fenster.</string>
<string name="attr_help">Hilfe</string>
<string name="attr_help_tt">Zeigt eine Beschreibung dieses Elements.</string>
<string name="attr_dialogHex">Hex</string>
<string name="attr_dialogDecimal">Dezimal</string>
<string name="attr_dialogAscii">Ascii</string>
<string name="attr_dialogHighz">HighZ</string>
<string name="attr_dialogOctal">Oktal</string>
<string name="attr_dialogBinary">Binär</string>
<string name="btn_discard">Verwerfen</string>
<string name="btn_edit">Bearbeiten</string>
<string name="btn_editFurther">Weiter bearbeiten</string>

View File

@ -13,6 +13,12 @@
<string name="attr_openCircuit_tt">Opens the circuit in a new window.</string>
<string name="attr_help">Help</string>
<string name="attr_help_tt">Shows a short description of this element.</string>
<string name="attr_dialogHex">Hex</string>
<string name="attr_dialogDecimal">Decimal</string>
<string name="attr_dialogAscii">Ascii</string>
<string name="attr_dialogHighz">HighZ</string>
<string name="attr_dialogOctal">Octal</string>
<string name="attr_dialogBinary">Binary</string>
<string name="btn_discard">Discard Changes</string>
<string name="btn_edit">Edit</string>
<string name="btn_editFurther">Continue editing</string>