Merge branch 'tableUndo'

This commit is contained in:
hneemann 2019-09-28 09:25:56 +02:00
commit a5ec767176
22 changed files with 382 additions and 212 deletions

View File

@ -16,14 +16,17 @@ import de.neemann.digital.analyse.quinemc.BoolTable;
import de.neemann.digital.analyse.quinemc.BoolTableByteArray;
import de.neemann.digital.analyse.quinemc.ThreeStateValue;
import de.neemann.digital.lang.Lang;
import de.neemann.digital.undo.Copyable;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
/**
* The description of a truth table.
*/
public class TruthTable {
public class TruthTable implements Copyable<TruthTable> {
private final ArrayList<Variable> variables;
private final ArrayList<Result> results;
@ -52,7 +55,7 @@ public class TruthTable {
*/
public void save(File filename) throws IOException {
XStream xStream = getxStream();
try (Writer out = new OutputStreamWriter(new FileOutputStream(filename), "utf-8")) {
try (Writer out = new OutputStreamWriter(new FileOutputStream(filename), StandardCharsets.UTF_8)) {
out.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
xStream.marshal(this, new PrettyPrintWriter(out));
}
@ -68,7 +71,7 @@ public class TruthTable {
if (results.size() > 63)
throw new IOException(Lang.get("err_tableHasToManyResultColumns"));
try (Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(filename), "utf-8"))) {
try (Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(filename), StandardCharsets.UTF_8))) {
saveHex(out);
}
}
@ -147,6 +150,29 @@ public class TruthTable {
}
}
private TruthTable(TruthTable truthTable) {
variables = new ArrayList<>(truthTable.variables.size());
for (Variable v : truthTable.variables)
variables.add(new Variable(v.getIdentifier()));
results = new ArrayList<>();
for (int i = 0; i < truthTable.getResultCount(); i++) {
Result result = truthTable.results.get(i);
addResult(result.getName(), new BoolTableByteArray(result.values));
}
this.modelAnalyzerInfo = truthTable.modelAnalyzerInfo;
}
/**
* Clears the table and sets the given variables
*
* @param vars the variables to use
*/
public void clear(Collection<? extends Variable> vars) {
variables.clear();
variables.addAll(vars);
results.clear();
}
/**
* Returns the number of rows
*
@ -456,30 +482,18 @@ public class TruthTable {
}
/**
* Sets the don't cares to a given value
* Modifies all column in the table
*
* @param b the value to set
* @param m the modifier to use
* @return this for chained calls
*/
public void setXto(boolean b) {
public TruthTable modifyValues(BoolTableByteArray.TableModifier m) {
for (Result r : results) {
BoolTable bt = r.getValues();
if (bt instanceof BoolTableByteArray)
((BoolTableByteArray) bt).setXTo(b ? 1 : 0);
}
}
/**
* Set all table entries to the given value.
* Zero and one behave as expected. All other values represent "don't care"
*
* @param value the value to set
*/
public void setAllTo(int value) {
for (Result r : results) {
BoolTable bt = r.getValues();
if (bt instanceof BoolTableByteArray)
((BoolTableByteArray) bt).setAllTo(value);
((BoolTableByteArray) bt).modify(m);
}
return this;
}
/**
@ -500,6 +514,31 @@ public class TruthTable {
return modelAnalyzerInfo;
}
@Override
public TruthTable createDeepCopy() {
return new TruthTable(this);
}
/**
* @return the names of all input variables
*/
public ArrayList<String> getVarNames() {
ArrayList<String> names = new ArrayList<>();
for (Variable v : variables)
names.add(v.getIdentifier());
return names;
}
/**
* @return the names of al result variables
*/
public ArrayList<String> getResultNames() {
ArrayList<String> names = new ArrayList<>();
for (Result r : results)
names.add(r.getName());
return names;
}
/**
* A single result column
*/

View File

@ -6,6 +6,8 @@
package de.neemann.digital.analyse;
import de.neemann.digital.analyse.quinemc.BoolTable;
import de.neemann.digital.undo.ModifyException;
import de.neemann.digital.undo.UndoManager;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
@ -23,31 +25,31 @@ public class TruthTableTableModel implements TableModel {
*/
public static final String[] STATENAMES = new String[]{"0", "1", "x"};
private final TruthTable truthTable;
private final ArrayList<TableModelListener> listeners = new ArrayList<>();
private final UndoManager<TruthTable> undoManager;
/**
* Creates a new instance
*
* @param truthTable the truthTable which is to visualize
* @param undoManager the undoManager
*/
public TruthTableTableModel(TruthTable truthTable) {
this.truthTable = truthTable;
public TruthTableTableModel(UndoManager<TruthTable> undoManager) {
this.undoManager = undoManager;
}
@Override
public int getRowCount() {
return truthTable.getRows();
return undoManager.getActual().getRows();
}
@Override
public int getColumnCount() {
return truthTable.getCols();
return undoManager.getActual().getCols();
}
@Override
public String getColumnName(int columnIndex) {
return truthTable.getColumnName(columnIndex);
return undoManager.getActual().getColumnName(columnIndex);
}
@Override
@ -57,27 +59,38 @@ public class TruthTableTableModel implements TableModel {
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return truthTable.isEditable(columnIndex);
return undoManager.getActual().isEditable(columnIndex);
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
return truthTable.getValue(rowIndex, columnIndex);
return undoManager.getActual().getValue(rowIndex, columnIndex);
}
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
if (aValue instanceof Integer)
truthTable.setValue(rowIndex, columnIndex, (Integer) aValue);
setValue(rowIndex, columnIndex, (Integer) aValue);
if (aValue instanceof String) {
if (aValue.toString().equals("0"))
truthTable.setValue(rowIndex, columnIndex, 0);
setValue(rowIndex, columnIndex, 0);
else if (aValue.toString().equals("1"))
truthTable.setValue(rowIndex, columnIndex, 1);
setValue(rowIndex, columnIndex, 1);
else
truthTable.setValue(rowIndex, columnIndex, 2);
setValue(rowIndex, columnIndex, 2);
}
}
private void setValue(int rowIndex, int columnIndex, int val) {
int actVal = undoManager.getActual().getValue(rowIndex, columnIndex);
if (actVal != val) {
try {
undoManager.apply(truthTable -> truthTable.setValue(rowIndex, columnIndex, val));
} catch (ModifyException e) {
e.printStackTrace();
}
fireModelEvent(rowIndex);
}
fireModelEvent(rowIndex);
}
private void fireModelEvent(int rowIndex) {
@ -86,6 +99,15 @@ public class TruthTableTableModel implements TableModel {
l.tableChanged(e);
}
/**
* Fires a structural table change
*/
public void fireTableChanged() {
TableModelEvent e = new TableModelEvent(this, HEADER_ROW);
for (TableModelListener l : listeners)
l.tableChanged(e);
}
@Override
public void addTableModelListener(TableModelListener l) {
listeners.add(l);
@ -95,13 +117,6 @@ public class TruthTableTableModel implements TableModel {
public void removeTableModelListener(TableModelListener l) {
}
/**
* @return the truth table used by this model
*/
public TruthTable getTable() {
return truthTable;
}
/**
* Sets the column name
*
@ -109,7 +124,11 @@ public class TruthTableTableModel implements TableModel {
* @param name the new name
*/
public void setColumnName(int columnIndex, String name) {
truthTable.setColumnName(columnIndex, name);
try {
undoManager.apply(truthTable -> truthTable.setColumnName(columnIndex, name));
} catch (ModifyException e) {
e.printStackTrace();
}
fireModelEvent(HEADER_ROW);
}
@ -121,18 +140,26 @@ public class TruthTableTableModel implements TableModel {
*/
public void incValue(BoolTable boolTable, int row) {
int col = -1;
for (int i = 0; i < truthTable.getResultCount(); i++) {
if (truthTable.getResult(i) == boolTable) {
TruthTable tt = undoManager.getActual();
for (int i = 0; i < tt.getResultCount(); i++) {
if (tt.getResult(i) == boolTable) {
col = i;
break;
}
}
if (col >= 0) {
col += truthTable.getVars().size();
int value = truthTable.getValue(row, col);
col += tt.getVars().size();
int value = tt.getValue(row, col);
if (value == 2) value = 0;
else value++;
setValueAt(value, row, col);
}
}
/**
* @return the truth table shown
*/
public TruthTable getTable() {
return undoManager.getActual();
}
}

View File

@ -32,6 +32,17 @@ public class BoolTableByteArray implements BoolTable {
this.table = table;
}
/**
* Creates a new instance
*
* @param values the values to initialize the table
*/
public BoolTableByteArray(BoolTable values) {
table = new byte[values.size()];
for (int i = 0; i < values.size(); i++)
table[i] = (byte) values.get(i).asInt();
}
@Override
public int size() {
return table.length;
@ -79,23 +90,25 @@ public class BoolTableByteArray implements BoolTable {
}
/**
* Sets the don't cares to the given value
* Modifies all the table elements using the given modifier.
*
* @param value the value
* @param m the modifier
*/
public void setXTo(int value) {
public void modify(TableModifier m) {
for (int i = 0; i < table.length; i++)
if (table[i] > 1)
table[i] = (byte) value;
table[i] = m.modify(table[i]);
}
/**
* Sets all entries to the given value
*
* @param value the value
* Modifier to modify the table
*/
public void setAllTo(int value) {
for (int i = 0; i < table.length; i++)
table[i] = (byte) value;
public interface TableModifier {
/**
* Creates the modified value
*
* @param b the original value
* @return the modified value
*/
byte modify(byte b);
}
}

View File

@ -83,7 +83,7 @@ public class TransitionTableCreator {
// create state variables
ArrayList<Variable> vars = new ArrayList<>();
for (int i = stateBits - 1; i >= 0; i--) {
final Variable var = new Variable(STATE_VAR+"_" + i + "^n");
final Variable var = new Variable(STATE_VAR + "_" + i + "^n");
vars.add(var);
boolean initVal = (initState & (1 << i)) != 0;
modelAnalyserInfo.setSequentialInitValue(var.getIdentifier(), initVal ? 1 : 0);
@ -93,7 +93,7 @@ public class TransitionTableCreator {
// create the next state result variables
for (int i = stateBits - 1; i >= 0; i--)
truthTable.addResult(STATE_VAR+"_" + i + "^{n+1}");
truthTable.addResult(STATE_VAR + "_" + i + "^{n+1}");
// add the output variables
TreeSet<String> results = new TreeSet<>();
@ -108,7 +108,7 @@ public class TransitionTableCreator {
}
// set all to dc
truthTable.setAllTo(2);
truthTable.modifyValues(v -> (byte) 2);
// set state output variables
for (State s : states) {

View File

@ -5,7 +5,7 @@
*/
package de.neemann.digital.gui.components.table;
import de.neemann.digital.analyse.TruthTableTableModel;
import de.neemann.digital.analyse.TruthTable;
import de.neemann.digital.analyse.expression.Expression;
import de.neemann.digital.analyse.expression.ExpressionException;
import de.neemann.digital.analyse.expression.NamedExpression;
@ -15,10 +15,10 @@ import de.neemann.digital.draw.graphics.text.formatter.LaTeXFormatter;
final class LaTeXExpressionListener implements ExpressionListener {
private final StringBuilder sb;
LaTeXExpressionListener(TruthTableTableModel model) throws ExpressionException {
LaTeXExpressionListener(TruthTable truthTable) throws ExpressionException {
sb = new StringBuilder();
if (model.getTable().getRows() <= 256) {
String text = new TruthTableFormatterLaTeX().format(model.getTable());
if (truthTable.getRows() <= 256) {
String text = new TruthTableFormatterLaTeX().format(truthTable);
sb.append(text);
}
sb.append("\\begin{eqnarray*}\n");

View File

@ -27,7 +27,7 @@ public class ProgressDialog extends JDialog implements ExpressionCreator.Progres
super(tableDialog, false);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
bar = new JProgressBar(0, tableDialog.getModel().getTable().getResultCount());
bar = new JProgressBar(0, tableDialog.getUndoManager().getActual().getResultCount());
int b = Screen.getInstance().getFontSize();
bar.setBorder(BorderFactory.createEmptyBorder(b, b, b, b));
final JLabel label = new JLabel(Lang.get("msg_optimizationInProgress"));

View File

@ -55,10 +55,9 @@ public class ReorderInputs {
/**
* Creates a new table matching the actual state of the items
*
* @return the new table
* @throws ExpressionException ExpressionException
*/
public TruthTable reorder() throws ExpressionException {
public void reorder() throws ExpressionException {
ArrayList<Variable> newVars = new ArrayList<>();
ArrayList<Variable> deletedVars = new ArrayList<>(table.getVars());
@ -79,21 +78,20 @@ public class ReorderInputs {
if (newVars.size() < 2)
throw new ExpressionException(Lang.get("err_tableBecomesToSmall"));
TruthTable newTable = new TruthTable(newVars);
newTable.setModelAnalyzerInfo(table.getModelAnalyzerInfo());
for (int j = 0; j < table.getResultCount(); j++)
newTable.addResult(table.getResultName(j));
TruthTable oldTable = this.table.createDeepCopy();
ContextFiller fc = new ContextFiller(newTable.getVars());
table.clear(newVars);
for (int j = 0; j < oldTable.getResultCount(); j++)
table.addResult(oldTable.getResultName(j));
ContextFiller fc = new ContextFiller(table.getVars());
for (Variable v : deletedVars)
fc.set(v, false);
for (int row = 0; row < newTable.getRows(); row++) {
for (int row = 0; row < table.getRows(); row++) {
fc.setContextTo(row);
for (int t = 0; t < newTable.getResultCount(); t++)
newTable.setByContext(t, fc, table.getByContext(t, fc));
for (int t = 0; t < table.getResultCount(); t++)
table.setByContext(t, fc, oldTable.getByContext(t, fc));
}
return newTable;
}
}

View File

@ -53,23 +53,20 @@ public class ReorderOutputs {
/**
* Creates a new table matching the actual state of the items
*
* @return the new table
* @throws ExpressionException ExpressionException
*/
public TruthTable reorder() throws ExpressionException {
TruthTable newTable = new TruthTable(table.getVars());
newTable.setModelAnalyzerInfo(table.getModelAnalyzerInfo());
public void reorder() throws ExpressionException {
TruthTable oldTable = table.createDeepCopy();
table.clear(oldTable.getVars());
for (String name : names) {
for (int i = 0; i < table.getResultCount(); i++)
if (table.getResultName(i).equals(name)) {
newTable.addResult(table.getResultName(i), table.getResult(i));
for (int i = 0; i < oldTable.getResultCount(); i++)
if (oldTable.getResultName(i).equals(name)) {
table.addResult(oldTable.getResultName(i), oldTable.getResult(i));
break;
}
}
if (newTable.getResultCount() < 1)
if (table.getResultCount() < 1)
throw new ExpressionException(Lang.get("err_oneResultIsRequired"));
return newTable;
}
}

View File

@ -41,6 +41,8 @@ import de.neemann.digital.gui.components.table.hardware.GenerateCUPL;
import de.neemann.digital.gui.components.table.hardware.GenerateFile;
import de.neemann.digital.gui.components.table.hardware.HardwareDescriptionGenerator;
import de.neemann.digital.lang.Lang;
import de.neemann.digital.undo.ModifyException;
import de.neemann.digital.undo.UndoManager;
import de.neemann.gui.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -66,7 +68,7 @@ import java.util.prefs.Preferences;
import static de.neemann.digital.analyse.ModelAnalyser.addOne;
/**
*
* The dialog used to show the truth table.
*/
public class TableDialog extends JDialog {
private static final Logger LOGGER = LoggerFactory.getLogger(TableDialog.class);
@ -102,15 +104,16 @@ public class TableDialog extends JDialog {
private final ToolTipAction karnaughMenuAction;
private final HashMap<String, HardwareDescriptionGenerator> availGenerators = new HashMap<>();
private final JMenu hardwareMenu;
private final TruthTableTableModel model;
private JCheckBoxMenuItem createJK;
private File filename;
private TruthTableTableModel model;
private int columnIndex;
private AllSolutionsDialog allSolutionsDialog;
private ExpressionListenerStore lastGeneratedExpressions;
private KarnaughMapDialog kvMap;
private JMenuItem lastUsedGenratorMenuItem;
private Mouse mouse = Mouse.getMouse();
private UndoManager<TruthTable> undoManager;
/**
* Creates a new instance
@ -122,10 +125,15 @@ public class TableDialog extends JDialog {
*/
public TableDialog(Window parent, TruthTable truthTable, ElementLibrary library, File filename) {
super(parent, Lang.get("win_table"));
undoManager = new UndoManager<>(truthTable);
this.library = library;
this.shapeFactory = library.getShapeFactory();
this.filename = filename;
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
model = new TruthTableTableModel(undoManager);
model.addTableModelListener(new CalculationTableModelListener());
kvMap = new KarnaughMapDialog(this, (boolTable, row) -> model.incValue(boolTable, row));
statusBar = new ExpressionComponent();
@ -182,63 +190,90 @@ public class TableDialog extends JDialog {
}
bar.add(sizeMenu);
JMenu columnsMenu = new JMenu(Lang.get("menu_table_columns"));
bar.add(columnsMenu);
columnsMenu.add(new ToolTipAction(Lang.get("menu_table_reorder_inputs")) {
JMenu edit = new JMenu(Lang.get("menu_edit"));
bar.add(edit);
addUndoRedo(edit);
edit.addSeparator();
edit.add(new ToolTipAction(Lang.get("menu_table_reorder_inputs")) {
@Override
public void actionPerformed(ActionEvent e) {
ReorderInputs ri = new ReorderInputs(model.getTable());
if (new ElementOrderer<>(TableDialog.this, Lang.get("menu_table_reorder_inputs"), ri.getItems())
ArrayList<String> varNames = undoManager.getActual().getVarNames();
if (new ElementOrderer<>(TableDialog.this, Lang.get("menu_table_reorder_inputs"), new ElementOrderer.ListOrder<>(varNames))
.addDeleteButton()
.addOkButton()
.showDialog()) {
try {
setModel(new TruthTableTableModel(ri.reorder()));
} catch (ExpressionException e1) {
undoManager.apply(tt -> {
try {
new ReorderInputs(tt, varNames).reorder();
tableChanged();
} catch (ExpressionException ex) {
throw new ModifyException("failed to reorder", ex);
}
});
} catch (ModifyException e1) {
new ErrorMessage().addCause(e1).show(TableDialog.this);
}
}
}
}.createJMenuItem());
columnsMenu.add(new ToolTipAction(Lang.get("menu_table_columnsAddVariable")) {
edit.add(new ToolTipAction(Lang.get("menu_table_columnsAddVariable")) {
@Override
public void actionPerformed(ActionEvent actionEvent) {
TruthTable t = model.getTable();
t.addVariable();
setModel(new TruthTableTableModel(t));
try {
undoManager.apply(TruthTable::addVariable);
tableChanged();
} catch (ModifyException e) {
new ErrorMessage().addCause(e).show(TableDialog.this);
}
}
}.setToolTip(Lang.get("menu_table_columnsAddVariable_tt")).createJMenuItem());
columnsMenu.add(new ToolTipAction(Lang.get("menu_table_reorder_outputs")) {
edit.add(new ToolTipAction(Lang.get("menu_table_reorder_outputs")) {
@Override
public void actionPerformed(ActionEvent e) {
ReorderOutputs ro = new ReorderOutputs(model.getTable());
if (new ElementOrderer<>(TableDialog.this, Lang.get("menu_table_reorder_outputs"), ro.getItems())
ArrayList<String> resultNames = undoManager.getActual().getResultNames();
if (new ElementOrderer<>(TableDialog.this, Lang.get("menu_table_reorder_outputs"), new ElementOrderer.ListOrder<>(resultNames))
.addDeleteButton()
.addOkButton()
.showDialog()) {
try {
setModel(new TruthTableTableModel(ro.reorder()));
} catch (ExpressionException e1) {
undoManager.apply(tt -> {
try {
new ReorderOutputs(tt, resultNames).reorder();
tableChanged();
} catch (ExpressionException ex) {
throw new ModifyException("failed to reorder", ex);
}
});
} catch (ModifyException e1) {
new ErrorMessage().addCause(e1).show(TableDialog.this);
}
}
}
}.createJMenuItem());
columnsMenu.add(new ToolTipAction(Lang.get("menu_table_columnsAdd")) {
edit.add(new ToolTipAction(Lang.get("menu_table_columnsAdd")) {
@Override
public void actionPerformed(ActionEvent actionEvent) {
TruthTable t = model.getTable();
t.addResult();
setModel(new TruthTableTableModel(t));
try {
undoManager.apply(TruthTable::addResult);
tableChanged();
} catch (ModifyException e) {
new ErrorMessage().addCause(e).show(TableDialog.this);
}
}
}.setToolTip(Lang.get("menu_table_columnsAdd_tt")).createJMenuItem());
bar.add(columnsMenu);
edit.addSeparator();
bar.add(createSetMenu());
createSetMenuEntries(edit);
hardwareMenu = createCreateMenu();
bar.add(hardwareMenu);
@ -256,7 +291,8 @@ public class TableDialog extends JDialog {
setJMenuBar(bar);
setModel(new TruthTableTableModel(truthTable));
karnaughMenuAction.setEnabled(undoManager.getActual().getVars().size() <= 4);
calculateExpressions();
getContentPane().add(new JScrollPane(table));
getContentPane().add(statusBar, BorderLayout.SOUTH);
@ -264,6 +300,55 @@ public class TableDialog extends JDialog {
setLocationRelativeTo(parent);
}
private void addUndoRedo(JMenu edit) {
final ToolTipAction undo = new ToolTipAction(Lang.get("menu_undo")) {
@Override
public void actionPerformed(ActionEvent actionEvent) {
if (undoManager.undoAvailable()) {
try {
undoManager.undo();
tableChanged();
} catch (ModifyException e) {
new ErrorMessage().addCause(e).show(TableDialog.this);
}
}
}
}.setAcceleratorCTRLplus("Z");
final ToolTipAction redo = new ToolTipAction(Lang.get("menu_redo")) {
@Override
public void actionPerformed(ActionEvent actionEvent) {
if (undoManager.redoAvailable()) {
try {
undoManager.redo();
tableChanged();
} catch (ModifyException e) {
new ErrorMessage().addCause(e).show(TableDialog.this);
}
}
}
}.setAcceleratorCTRLplus("Y");
edit.add(undo.createJMenuItem());
edit.add(redo.createJMenuItem());
undoManager.addListener(() -> {
undo.setEnabled(undoManager.undoAvailable());
redo.setEnabled(undoManager.redoAvailable());
if (undoManager.isModified())
setTitle("*" + Lang.get("win_table"));
else
setTitle(Lang.get("win_table"));
}).hasChanged();
}
/**
* Called if table was modified.
*/
public void tableChanged() {
karnaughMenuAction.setEnabled(undoManager.getActual().getVars().size() <= 4);
calculateExpressions();
model.fireTableChanged();
}
private void editColumnName(int columnIndex, Point pos) {
ElementAttributes attr = new ElementAttributes();
final String name = model.getColumnName(columnIndex);
@ -290,7 +375,8 @@ public class TableDialog extends JDialog {
try {
File file = fc.getSelectedFile();
TruthTable truthTable = TruthTable.readFromFile(file);
setModel(new TruthTableTableModel(truthTable));
undoManager.setInitial(truthTable);
tableChanged();
TableDialog.this.filename = file;
} catch (IOException e1) {
new ErrorMessage().addCause(e1).show(TableDialog.this);
@ -308,7 +394,7 @@ public class TableDialog extends JDialog {
fc.setFileFilter(new FileNameExtensionFilter(Lang.get("msg_truthTable"), "tru"));
new SaveAsHelper(TableDialog.this, fc, "tru").checkOverwrite(
file -> {
model.getTable().save(file);
undoManager.getActual().save(file);
TableDialog.this.filename = file;
}
);
@ -320,7 +406,7 @@ public class TableDialog extends JDialog {
@Override
public void actionPerformed(ActionEvent e) {
try {
final LaTeXExpressionListener laTeXExpressionListener = new LaTeXExpressionListener(model);
final LaTeXExpressionListener laTeXExpressionListener = new LaTeXExpressionListener(undoManager.getActual());
ExpressionListener expressionListener = laTeXExpressionListener;
if (createJK.isSelected())
expressionListener = new ExpressionListenerJK(expressionListener);
@ -339,14 +425,14 @@ public class TableDialog extends JDialog {
@Override
public void actionPerformed(ActionEvent e) {
int res = JOptionPane.OK_OPTION;
if (model.getTable().getVars().size() > 20)
if (undoManager.getActual().getVars().size() > 20)
res = JOptionPane.showConfirmDialog(TableDialog.this, Lang.get("msg_tableHasManyRowsConfirm"));
if (res == JOptionPane.OK_OPTION) {
JFileChooser fc = new MyFileChooser();
if (TableDialog.this.filename != null)
fc.setSelectedFile(SaveAsHelper.checkSuffix(TableDialog.this.filename, "hex"));
new SaveAsHelper(TableDialog.this, fc, "hex")
.checkOverwrite(file -> model.getTable().saveHex(file));
.checkOverwrite(file -> undoManager.getActual().saveHex(file));
}
}
}.setToolTip(Lang.get("menu_table_exportHex_tt")).createJMenuItem());
@ -361,49 +447,53 @@ public class TableDialog extends JDialog {
return fileMenu;
}
private JMenu createSetMenu() {
JMenu setMenu = new JMenu(Lang.get("menu_table_set"));
setMenu.add(new ToolTipAction(Lang.get("menu_table_setXTo0")) {
private void createSetMenuEntries(JMenu edit) {
edit.add(new ToolTipAction(Lang.get("menu_table_setXTo0")) {
@Override
public void actionPerformed(ActionEvent e) {
TruthTable t = model.getTable();
t.setXto(false);
setModel(new TruthTableTableModel(t));
modifyTable(v -> v > 1 ? 0 : v);
}
}.setToolTip(Lang.get("menu_table_setXTo0_tt")).createJMenuItem());
setMenu.add(new ToolTipAction(Lang.get("menu_table_setXTo1")) {
edit.add(new ToolTipAction(Lang.get("menu_table_setXTo1")) {
@Override
public void actionPerformed(ActionEvent e) {
TruthTable t = model.getTable();
t.setXto(true);
setModel(new TruthTableTableModel(t));
modifyTable(v -> v > 1 ? 1 : v);
}
}.setToolTip(Lang.get("menu_table_setXTo1_tt")).createJMenuItem());
setMenu.add(new ToolTipAction(Lang.get("menu_table_setAllToX")) {
edit.add(new ToolTipAction(Lang.get("menu_table_setAllToX")) {
@Override
public void actionPerformed(ActionEvent e) {
setAllValuesTo(2);
modifyTable(v -> (byte) 2);
}
}.setToolTip(Lang.get("menu_table_setAllToX_tt")).createJMenuItem());
setMenu.add(new ToolTipAction(Lang.get("menu_table_setAllTo0")) {
edit.add(new ToolTipAction(Lang.get("menu_table_setAllTo0")) {
@Override
public void actionPerformed(ActionEvent e) {
setAllValuesTo(0);
modifyTable(v -> (byte) 0);
}
}.setToolTip(Lang.get("menu_table_setAllTo0_tt")).createJMenuItem());
setMenu.add(new ToolTipAction(Lang.get("menu_table_setAllTo1")) {
edit.add(new ToolTipAction(Lang.get("menu_table_setAllTo1")) {
@Override
public void actionPerformed(ActionEvent e) {
setAllValuesTo(1);
modifyTable(v -> (byte) 1);
}
}.setToolTip(Lang.get("menu_table_setAllTo1_tt")).createJMenuItem());
return setMenu;
edit.add(new ToolTipAction(Lang.get("menu_table_invert")) {
@Override
public void actionPerformed(ActionEvent e) {
modifyTable(v -> v > 1 ? v : (byte) (1 - v));
}
}.setToolTip(Lang.get("menu_table_invert_tt")).createJMenuItem());
}
private void setAllValuesTo(int value) {
TruthTable t = model.getTable();
t.setAllTo(value);
setModel(new TruthTableTableModel(t));
private void modifyTable(BoolTableByteArray.TableModifier m) {
try {
undoManager.apply(truthTable -> truthTable.modifyValues(m));
tableChanged();
} catch (ModifyException e) {
e.printStackTrace();
new ErrorMessage().addCause(e).show(TableDialog.this);
}
}
private JMenu createCreateMenu() {
@ -527,8 +617,8 @@ public class TableDialog extends JDialog {
private void createCircuit(boolean useJKff, boolean useLUTs, ExpressionModifier... modifier) {
try {
final ModelAnalyserInfo modelAnalyzerInfo = model.getTable().getModelAnalyzerInfo();
CircuitBuilder circuitBuilder = new CircuitBuilder(shapeFactory, model.getTable().getVars())
final ModelAnalyserInfo modelAnalyzerInfo = undoManager.getActual().getModelAnalyzerInfo();
CircuitBuilder circuitBuilder = new CircuitBuilder(shapeFactory, undoManager.getActual().getVars())
.setUseJK(useJKff)
.setUseLUTs(useLUTs)
.setModelAnalyzerInfo(modelAnalyzerInfo);
@ -555,19 +645,6 @@ public class TableDialog extends JDialog {
return model;
}
/**
* Sets the table model
*
* @param model the model to use
*/
public void setModel(TruthTableTableModel model) {
this.model = model;
model.addTableModelListener(new CalculationTableModelListener());
table.setModel(model);
karnaughMenuAction.setEnabled(model.getTable().getVars().size() <= 4);
calculateExpressions();
}
private String getProjectName() {
if (filename == null)
return "unknown";
@ -598,6 +675,13 @@ public class TableDialog extends JDialog {
}
}
/**
* @return the undoManager
*/
public UndoManager<TruthTable> getUndoManager() {
return undoManager;
}
private class CalculationTableModelListener implements TableModelListener {
@Override
public void tableChanged(TableModelEvent tableModelEvent) {
@ -613,7 +697,7 @@ public class TableDialog extends JDialog {
if (createJK.isSelected())
expressionListener = new ExpressionListenerJK(expressionListener);
final TruthTable table = model.getTable();
final TruthTable table = undoManager.getActual();
if (table.getVars().size() >= 8) {
ProgressDialog progress = new ProgressDialog(this);
@ -674,7 +758,8 @@ public class TableDialog extends JDialog {
@Override
public void actionPerformed(ActionEvent actionEvent) {
setModel(new TruthTableTableModel(new TruthTable(n).addResult()));
undoManager.setInitial(new TruthTable(n).addResult());
tableChanged();
}
}
@ -702,7 +787,8 @@ public class TableDialog extends JDialog {
i--;
}
setModel(new TruthTableTableModel(truthTable));
undoManager.setInitial(truthTable);
tableChanged();
}
}
@ -735,7 +821,8 @@ public class TableDialog extends JDialog {
i--;
}
setModel(new TruthTableTableModel(truthTable));
undoManager.setInitial(truthTable);
tableChanged();
}
}
@ -746,7 +833,7 @@ public class TableDialog extends JDialog {
JLabel label = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
label.setHorizontalAlignment(SwingConstants.CENTER);
label.setFont(font);
if (column < model.getTable().getVars().size())
if (column < undoManager.getActual().getVars().size())
label.setBackground(MYGRAY);
else
label.setBackground(Color.WHITE);
@ -761,7 +848,7 @@ public class TableDialog extends JDialog {
}
}
private final class StringDefaultTableCellRenderer extends DefaultTableCellRenderer {
private static final class StringDefaultTableCellRenderer extends DefaultTableCellRenderer {
private StringDefaultTableCellRenderer() {
setHorizontalAlignment(SwingConstants.CENTER);
}
@ -832,13 +919,13 @@ public class TableDialog extends JDialog {
int c = table.getSelectedColumn();
if (r < 0 || c < 0) {
r = 0;
c = model.getTable().getVars().size();
c = undoManager.getActual().getVars().size();
}
model.setValueAt(value, r, c);
c++;
if (c >= table.getColumnCount()) {
c = model.getTable().getVars().size();
c = undoManager.getActual().getVars().size();
r++;
if (r >= model.getRowCount())
r = 0;
@ -859,7 +946,7 @@ public class TableDialog extends JDialog {
@Override
public void actionPerformed(ActionEvent e) {
try {
generator.generate(TableDialog.this, filename, model.getTable(), lastGeneratedExpressions);
generator.generate(TableDialog.this, filename, undoManager.getActual(), lastGeneratedExpressions);
setLastUsedGenerator(generator);
} catch (Exception e1) {
new ErrorMessage(Lang.get("msg_errorDuringHardwareExport")).addCause(e1).show(TableDialog.this);

View File

@ -10,6 +10,7 @@ import de.neemann.digital.analyse.TruthTableTableModel;
import de.neemann.digital.analyse.expression.ExpressionException;
import de.neemann.digital.analyse.expression.Variable;
import de.neemann.digital.analyse.quinemc.BoolTable;
import de.neemann.digital.undo.ModifyException;
import javax.swing.*;
import javax.swing.table.TableModel;
@ -20,7 +21,7 @@ import java.util.ArrayList;
/**
* Handles reordering of the table columns by mouse drag and drop
*/
public class TableReorderManager {
class TableReorderManager {
private final TableDialog tableDialog;
private final JTable table;
@ -31,7 +32,7 @@ public class TableReorderManager {
* @param tableDialog the TableDialog instance
* @param table the table which is reordered
*/
public TableReorderManager(TableDialog tableDialog, JTable table) {
TableReorderManager(TableDialog tableDialog, JTable table) {
this.tableDialog = tableDialog;
this.table = table;
table.getTableHeader().addMouseListener(new MouseAdapter() {
@ -64,24 +65,32 @@ public class TableReorderManager {
}
if (wasChange) {
if (isVarChange(varList, vars)) {
try {
TruthTable tt = new ReorderInputs(model.getTable(), vars).reorder();
tableDialog.setModel(new TruthTableTableModel(tt));
} catch (ExpressionException e) {
// can't happen because no columns are removed
e.printStackTrace();
}
} else if (isResultChange(model.getTable(), results)) {
try {
TruthTable tt = new ReorderOutputs(model.getTable(), results).reorder();
tableDialog.setModel(new TruthTableTableModel(tt));
} catch (ExpressionException e) {
// can't happen because no columns are removed
e.printStackTrace();
}
} else
tableDialog.setModel(new TruthTableTableModel(model.getTable()));
try {
if (isVarChange(varList, vars)) {
tableDialog.getUndoManager().apply(tt -> {
try {
new ReorderInputs(tt, vars).reorder();
} catch (ExpressionException e) {
// can't happen because no columns are removed
e.printStackTrace();
}
});
tableDialog.tableChanged();
} else if (isResultChange(model.getTable(), results)) {
tableDialog.getUndoManager().apply(tt -> {
try {
new ReorderOutputs(tt, results).reorder();
} catch (ExpressionException e) {
// can't happen because no columns are removed
e.printStackTrace();
}
});
tableDialog.tableChanged();
} else
tableDialog.tableChanged();
} catch (ModifyException e) {
e.printStackTrace();
}
}
}

View File

@ -45,6 +45,7 @@ public class UndoManager<A extends Copyable<A>> {
modifications = new ArrayList<>();
modificationCounter = 0;
savedCounter = 0;
fireChangedEvent();
}
@ -187,9 +188,11 @@ public class UndoManager<A extends Copyable<A>> {
* Adds a listener
*
* @param listener the listener to add
* @return the given listener for chained calls.
*/
public void addListener(ChangedListener listener) {
public ChangedListener addListener(ChangedListener listener) {
listeners.add(listener);
return listener;
}
/**

View File

@ -1546,14 +1546,12 @@ Sind evtl. die Namen der Variablen nicht eindeutig?</string>
<string name="menu_table_new_combinatorial">Kombinatorisch</string>
<string name="menu_table_new_sequential">Automat</string>
<string name="menu_table_new_sequential_bidir">Automat bidirektional</string>
<string name="menu_table_columns">Spalten</string>
<string name="menu_table_reorder_inputs">Eingangsvariablen umsortieren/löschen</string>
<string name="menu_table_reorder_outputs">Ergebnisspalten umsortieren/löschen</string>
<string name="menu_table_columnsAdd">Ergebnisspalte hinzufügen</string>
<string name="menu_table_columnsAdd_tt">Fügt der Tabelle eine Ergebnisspalte hinzu.</string>
<string name="menu_table_columnsAddVariable">Eingangsvariable hinzufügen</string>
<string name="menu_table_columnsAddVariable_tt">Fügt der Tabelle eine Variablenspalte hinzu.</string>
<string name="menu_table_set">Setzen</string>
<string name="menu_table_setXTo0">Setze X auf 0</string>
<string name="menu_table_setXTo0_tt">Setzt die Don't Cares auf 0.</string>
<string name="menu_table_setXTo1">Setze X auf 1</string>
@ -1565,6 +1563,9 @@ Sind evtl. die Namen der Variablen nicht eindeutig?</string>
<string name="menu_table_setAllTo0_tt">Setzt alle Werte auf Null.</string>
<string name="menu_table_setAllTo1">Alles auf 1 setzen</string>
<string name="menu_table_setAllTo1_tt">Setzt alle Werte auf Eins.</string>
<string name="menu_table_invert">Alle Bits invertieren</string>
<string name="menu_table_invert_tt">Aus einer "1" wird eine "0" und umgekehrt. Don't Cares bleiben unverändert.
</string>
<string name="menu_table_showAllSolutions">Lösungsdialog anzeigen</string>
<string name="menu_table_showAllSolutions_tt">Zeigt den Lösungsdialog wieder an, wenn er manuell geschlossen wurde.</string>
<string name="menu_terminalDelete">Löschen</string>

View File

@ -1529,14 +1529,12 @@
<string name="menu_table_new_combinatorial">Combinatorial</string>
<string name="menu_table_new_sequential">Sequential</string>
<string name="menu_table_new_sequential_bidir">Sequential bidirectional</string>
<string name="menu_table_columns">Columns</string>
<string name="menu_table_reorder_inputs">Reorder/Delete Input Variables</string>
<string name="menu_table_columnsAddVariable">Add Input Variable</string>
<string name="menu_table_columnsAddVariable_tt">Adds a new input variable to the table.</string>
<string name="menu_table_reorder_outputs">Reorder/Delete Output Columns</string>
<string name="menu_table_columnsAdd">Add Output Column</string>
<string name="menu_table_columnsAdd_tt">Adds a new result column to the table.</string>
<string name="menu_table_set">Set</string>
<string name="menu_table_setXTo0">Set X to 0</string>
<string name="menu_table_setXTo0_tt">Sets the Don't Cares to 0.</string>
<string name="menu_table_setXTo1">Set X to 1</string>
@ -1548,6 +1546,8 @@
<string name="menu_table_setAllTo0_tt">Set all values to zero.</string>
<string name="menu_table_setAllTo1">Set all to 1</string>
<string name="menu_table_setAllTo1_tt">Set all values to one.</string>
<string name="menu_table_invert">Invert all bits</string>
<string name="menu_table_invert_tt">A "1" becomes a "0" and vice versa. Don't cares remain unchanged.</string>
<string name="menu_table_showAllSolutions">Show results dialog</string>
<string name="menu_table_showAllSolutions_tt">Shows the results dialog again if it was closed manually.</string>
<string name="menu_terminalDelete">Delete</string>

View File

@ -1293,14 +1293,12 @@
<string name="menu_table_new_combinatorial">Combinacional</string>
<string name="menu_table_new_sequential">Secuencial</string>
<string name="menu_table_new_sequential_bidir">Secuencial bidireccional</string>
<string name="menu_table_columns">Columnas</string>
<string name="menu_table_reorder_inputs">Reordena/Borra variables de entrada</string>
<string name="menu_table_reorder_outputs">Reordena/Borra columnas de salida</string>
<string name="menu_table_columnsAdd">Añade columna de salida</string>
<string name="menu_table_columnsAdd_tt">Añade una nueva columna de resultado a la tabla.</string>
<string name="menu_table_columnsAddVariable">Añade variable de entrada</string>
<string name="menu_table_columnsAddVariable_tt">Añade una nueva variable de entrada a la tabla.</string>
<string name="menu_table_set">Fijar</string>
<string name="menu_table_setXTo0">Fijar X a 0</string>
<string name="menu_table_setXTo0_tt">Convierte los "indiferentes" a 0.</string>
<string name="menu_table_setXTo1">Poner X a 1</string>

View File

@ -1306,14 +1306,12 @@
<string name="menu_table_new_combinatorial">Combinatorial</string>
<string name="menu_table_new_sequential">Sequential</string>
<string name="menu_table_new_sequential_bidir">Sequential bidirectional</string>
<string name="menu_table_columns">Columns</string>
<string name="menu_table_reorder_inputs">Reorder/Delete Input Variables</string>
<string name="menu_table_reorder_outputs">Reorder/Delete Output Columns</string>
<string name="menu_table_columnsAdd">Add Output Column</string>
<string name="menu_table_columnsAdd_tt">Adds a new result column to the table.</string>
<string name="menu_table_columnsAddVariable">Add Input Variable</string>
<string name="menu_table_columnsAddVariable_tt">Adds a new input variable to the table.</string>
<string name="menu_table_set">Set</string>
<string name="menu_table_setXTo0">Set X to 0</string>
<string name="menu_table_setXTo0_tt">Sets the Don't Cares to 0.</string>
<string name="menu_table_setXTo1">Set X to 1</string>

View File

@ -1362,14 +1362,12 @@
<string name="menu_table_new_combinatorial">Combinacional</string>
<string name="menu_table_new_sequential">Sequencial</string>
<string name="menu_table_new_sequential_bidir">Sequencial bidirecional</string>
<string name="menu_table_columns">Colunas</string>
<string name="menu_table_reorder_inputs">Reordenar/remover variáveis de entrada</string>
<string name="menu_table_columnsAddVariable">Adicionar variável de entrada</string>
<string name="menu_table_columnsAddVariable_tt">Adicionar uma nova variável de entrada à tabela.</string>
<string name="menu_table_reorder_outputs">Reordenar/remover colunas de saída</string>
<string name="menu_table_columnsAdd">Adicionar coluna de saída</string>
<string name="menu_table_columnsAdd_tt">Adicionar uma nova coluna de resultado à tabela.</string>
<string name="menu_table_set">Definir</string>
<string name="menu_table_setXTo0">Definir X como 0</string>
<string name="menu_table_setXTo0_tt">Definir "don't cares" como 0.</string>
<string name="menu_table_setXTo1">Definir X como 1</string>

View File

@ -1373,14 +1373,12 @@
<string name="menu_table_new_combinatorial">Combinatorial</string>
<string name="menu_table_new_sequential">Sequential</string>
<string name="menu_table_new_sequential_bidir">Sequential bidirectional</string>
<string name="menu_table_columns">Columns</string>
<string name="menu_table_reorder_inputs">Reorder/Delete Input Variables</string>
<string name="menu_table_columnsAddVariable">Add Input Variable</string>
<string name="menu_table_columnsAddVariable_tt">Adds a new input variable to the table.</string>
<string name="menu_table_reorder_outputs">Reorder/Delete Output Columns</string>
<string name="menu_table_columnsAdd">Add Output Column</string>
<string name="menu_table_columnsAdd_tt">Adds a new result column to the table.</string>
<string name="menu_table_set">Set</string>
<string name="menu_table_setXTo0">Set X to 0</string>
<string name="menu_table_setXTo0_tt">Sets the Don't Cares to 0.</string>
<string name="menu_table_setXTo1">Set X to 1</string>

View File

@ -115,6 +115,7 @@ public class ScreenShots {
.press("F1")
.add(new MainScreenShot("distribution/screenshot.png"))
.execute(); /**/
new GuiTester()
.press("F10")
.press("RIGHT", 4)
@ -157,8 +158,8 @@ public class ScreenShots {
.add(new GuiTester.CloseTopMost())
.add(new GuiTester.CloseTopMost())
.add(new GuiTester.CloseTopMost())
.execute();
.execute();/**/
File trafficLight = new File(Resources.getRoot(), "../../main/fsm/trafficLightBlink.fsm");
new GuiTester()
.press("F10")
@ -179,13 +180,14 @@ public class ScreenShots {
ReorderOutputs ro = new ReorderOutputs(tt);
ro.getItems().swap(3, 4);
ro.getItems().swap(4, 5);
tableDialog.setModel(new TruthTableTableModel(ro.reorder()));
ro.reorder();
tableDialog.tableChanged();
}))
.delay(500)
.add(closeAllSolutionsDialog())
.delay(500)
.press("F10")
.press("RIGHT", 4)
.press("RIGHT", 3)
.press("DOWN", 2)
.press("ENTER")
.delay(500)
@ -217,7 +219,7 @@ public class ScreenShots {
.add(new GuiTester.CloseTopMost())
.add(new GuiTester.CloseTopMost())
.add(new GuiTester.CloseTopMost())
.execute();/**/
.execute();
}
private static GuiTester.WindowCheck<Window> closeAllSolutionsDialog() {

View File

@ -21,8 +21,7 @@ public class LaTeXExpressionListenerTest extends TestCase {
.addVariable("A")
.addVariable("B")
.addResult("Y", new BoolTableBoolArray(new boolean[]{false, false, true, false}));
TruthTableTableModel model = new TruthTableTableModel(tt);
LaTeXExpressionListener l = new LaTeXExpressionListener(model);
LaTeXExpressionListener l = new LaTeXExpressionListener(tt);
l.resultFound("Y", Operation.and(new Variable("A"), new Not(new Variable("B"))));
l.close();

View File

@ -21,9 +21,10 @@ public class TestReorderInputs extends TestCase {
col.set(i, i + 1);
ReorderInputs reorderInputs = new ReorderInputs(t);
TruthTable newTable = t.createDeepCopy();
ReorderInputs reorderInputs = new ReorderInputs(newTable);
reorderInputs.getItems().swap(1, 2);
TruthTable newTable = reorderInputs.reorder();
reorderInputs.reorder();
ContextFiller cf = new ContextFiller(t.getVars());
@ -39,9 +40,10 @@ public class TestReorderInputs extends TestCase {
for (int i = 0; i < t.getRows(); i++)
col.set(i, i + 1);
ReorderInputs reorderInputs = new ReorderInputs(t);
TruthTable newTable = t.createDeepCopy();
ReorderInputs reorderInputs = new ReorderInputs(newTable);
reorderInputs.getItems().delete(2);
TruthTable newTable = reorderInputs.reorder();
reorderInputs.reorder();
assertEquals(2, newTable.getVars().size());
assertEquals(1, newTable.getResultCount());

View File

@ -19,9 +19,10 @@ public class TestReorderOutputs extends TestCase {
for (int i = 0; i < t.getRows(); i++)
col.set(i, i + 1);
ReorderOutputs reorderOutputs = new ReorderOutputs(t);
TruthTable newTable = t.createDeepCopy();
ReorderOutputs reorderOutputs = new ReorderOutputs(newTable);
reorderOutputs.getItems().delete(1);
TruthTable newTable = reorderOutputs.reorder();
reorderOutputs.reorder();
assertEquals(3, newTable.getVars().size());
assertEquals(1, newTable.getResultCount());

View File

@ -332,7 +332,7 @@ public class TestInGUI extends TestCase {
new GuiTester()
.use(create4BitCounterTruthTable)
.press("F10")
.press("RIGHT", 4)
.press("RIGHT", 3)
.press("DOWN", 2)
.press("ENTER")
.delay(500)
@ -424,7 +424,7 @@ public class TestInGUI extends TestCase {
}))
.delay(500)
.press("F10")
.press("RIGHT", 4)
.press("RIGHT", 3)
.press("DOWN", 7)
.press("RIGHT")
.press("DOWN", 2)
@ -947,7 +947,7 @@ public class TestInGUI extends TestCase {
assertEquals(4, model.getRowCount());
for (int i = 0; i < 4; i++) {
final Object valueAt = model.getValueAt(i, 1);
assertEquals("0x0", valueAt.toString());
assertEquals("0", valueAt.toString());
}
found();
}