/*******************************************************************************
* 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.gui.menu;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.WindowEvent;
import java.awt.event.WindowFocusListener;
import java.util.ArrayList;
import java.util.Map;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import com.bfh.logisim.designrulecheck.CorrectLabel;
import com.cburch.logisim.analyze.gui.Analyzer;
import com.cburch.logisim.analyze.gui.AnalyzerManager;
import com.cburch.logisim.analyze.model.AnalyzerModel;
import com.cburch.logisim.circuit.Analyze;
import com.cburch.logisim.circuit.AnalyzeException;
import com.cburch.logisim.circuit.Circuit;
import com.cburch.logisim.file.LogisimFileActions;
import com.cburch.logisim.instance.Instance;
import com.cburch.logisim.instance.StdAttr;
import com.cburch.logisim.proj.Project;
import com.cburch.logisim.std.wiring.Pin;
import com.cburch.logisim.tools.AddTool;
import com.cburch.logisim.tools.Library;
import com.cburch.logisim.tools.Tool;
import com.cburch.logisim.util.StringUtil;
import com.cburch.logisim.util.SyntaxChecker;
public class ProjectCircuitActions {
private static void analyzeError(Project proj, String message) {
JOptionPane.showMessageDialog(proj.getFrame(), message,
Strings.get("analyzeErrorTitle"), JOptionPane.ERROR_MESSAGE);
return;
}
private static void configureAnalyzer(Project proj, Circuit circuit,
Analyzer analyzer, Map<Instance, String> pinNames,
ArrayList<String> inputNames, ArrayList<String> outputNames) {
analyzer.getModel().setVariables(inputNames, outputNames);
// If there are no inputs, we stop with that tab selected
if (inputNames.size() == 0) {
analyzer.setSelectedTab(Analyzer.INPUTS_TAB);
return;
}
// If there are no outputs, we stop with that tab selected
if (outputNames.size() == 0) {
analyzer.setSelectedTab(Analyzer.OUTPUTS_TAB);
return;
}
// Attempt to show the corresponding expression
try {
Analyze.computeExpression(analyzer.getModel(), circuit, pinNames);
analyzer.setSelectedTab(Analyzer.EXPRESSION_TAB);
return;
} catch (AnalyzeException ex) {
JOptionPane.showMessageDialog(proj.getFrame(), ex.getMessage(),
Strings.get("analyzeNoExpressionTitle"),
JOptionPane.INFORMATION_MESSAGE);
}
// As a backup measure, we compute a truth table.
Analyze.computeTable(analyzer.getModel(), proj, circuit, pinNames);
analyzer.setSelectedTab(Analyzer.TABLE_TAB);
}
public static void doAddCircuit(Project proj) {
String name = promptForCircuitName(proj.getFrame(),
proj.getLogisimFile(), "");
if (name != null) {
JLabel error = null;
/* Checking for valid names */
if (name.isEmpty()) {
error = new JLabel(Strings.get("circuitNameMissingError"));
} else
if (!SyntaxChecker.isVariableNameAcceptable(name,false)) {
error = new JLabel("\""+name+"\": "+Strings.get("circuitNameInvalidName"));
} else
if (CorrectLabel.IsKeyword(name,false)) {
error = new JLabel("\""+name+"\": "+Strings.get("circuitNameKeyword"));
} else
if (NameIsInUse(proj,name)) {
error = new JLabel("\""+name+"\": "+Strings.get("circuitNameExists"));
}
if (error != null) {
JOptionPane.showMessageDialog(proj.getFrame(), error,
Strings.get("circuitCreateTitle"), JOptionPane.ERROR_MESSAGE);
} else {
Circuit circuit = new Circuit(name, proj.getLogisimFile(),proj);
proj.doAction(LogisimFileActions.addCircuit(circuit));
proj.setCurrentCircuit(circuit);
}
}
}
private static boolean NameIsInUse(Project proj, String Name) {
for (Library mylib : proj.getLogisimFile().getLibraries()) {
if (NameIsInLibraries(mylib,Name))
return true;
}
for (AddTool mytool : proj.getLogisimFile().getTools()) {
if (Name.toUpperCase().equals(mytool.getName().toUpperCase()))
return true;
}
return false;
}
private static boolean NameIsInLibraries(Library lib, String Name) {
for (Library mylib : lib.getLibraries()) {
if (NameIsInLibraries(mylib,Name))
return true;
}
for (Tool mytool : lib.getTools()) {
if (Name.toUpperCase().equals(mytool.getName().toUpperCase()))
return true;
}
return false;
}
public static void doAnalyze(Project proj, Circuit circuit) {
Map<Instance, String> pinNames = Analyze.getPinLabels(circuit);
ArrayList<String> inputNames = new ArrayList<String>();
ArrayList<String> outputNames = new ArrayList<String>();
for (Map.Entry<Instance, String> entry : pinNames.entrySet()) {
Instance pin = entry.getKey();
boolean isInput = Pin.FACTORY.isInputPin(pin);
if (isInput) {
inputNames.add(entry.getValue());
} else {
outputNames.add(entry.getValue());
}
if (pin.getAttributeValue(StdAttr.WIDTH).getWidth() > 1) {
if (isInput) {
analyzeError(proj, Strings.get("analyzeMultibitInputError"));
} else {
analyzeError(proj,
Strings.get("analyzeMultibitOutputError"));
}
return;
}
}
if (inputNames.size() > AnalyzerModel.MAX_INPUTS) {
analyzeError(proj, StringUtil.format(
Strings.get("analyzeTooManyInputsError"), ""
+ AnalyzerModel.MAX_INPUTS));
return;
}
if (outputNames.size() > AnalyzerModel.MAX_OUTPUTS) {
analyzeError(proj, StringUtil.format(
Strings.get("analyzeTooManyOutputsError"), ""
+ AnalyzerModel.MAX_OUTPUTS));
return;
}
Analyzer analyzer = AnalyzerManager.getAnalyzer();
analyzer.getModel().setCurrentCircuit(proj, circuit);
configureAnalyzer(proj, circuit, analyzer, pinNames, inputNames,
outputNames);
analyzer.setVisible(true);
analyzer.toFront();
}
public static void doMoveCircuit(Project proj, Circuit cur, int delta) {
AddTool tool = proj.getLogisimFile().getAddTool(cur);
if (tool != null) {
int oldPos = proj.getLogisimFile().getCircuits().indexOf(cur);
int newPos = oldPos + delta;
int toolsCount = proj.getLogisimFile().getTools().size();
if (newPos >= 0 && newPos < toolsCount) {
proj.doAction(LogisimFileActions.moveCircuit(tool, newPos));
}
}
}
public static void doRemoveCircuit(Project proj, Circuit circuit) {
if (proj.getLogisimFile().getTools().size() == 1) {
JOptionPane.showMessageDialog(proj.getFrame(),
Strings.get("circuitRemoveLastError"),
Strings.get("circuitRemoveErrorTitle"),
JOptionPane.ERROR_MESSAGE);
} else if (!proj.getDependencies().canRemove(circuit)) {
JOptionPane.showMessageDialog(proj.getFrame(),
Strings.get("circuitRemoveUsedError"),
Strings.get("circuitRemoveErrorTitle"),
JOptionPane.ERROR_MESSAGE);
} else {
proj.doAction(LogisimFileActions.removeCircuit(circuit));
}
}
public static void doSetAsMainCircuit(Project proj, Circuit circuit) {
proj.doAction(LogisimFileActions.setMainCircuit(circuit));
}
/**
* Ask the user for the name of the new circuit to create. If the name is
* valid, then it returns it, otherwise it displays an error message and
* returns null.
*
* @param frame
* Project's frame
* @param lib
* Project's logisim file
* @param initialValue
* Default suggested value (can be empty if no initial value)
*/
private static String promptForCircuitName(JFrame frame, Library lib,
String initialValue) {
JLabel label = new JLabel(Strings.get("circuitNamePrompt"));
final JTextField field = new JTextField(15);
field.setText(initialValue);
JLabel error = new JLabel(" ");
GridBagLayout gb = new GridBagLayout();
GridBagConstraints gc = new GridBagConstraints();
JPanel strut = new JPanel(null);
strut.setPreferredSize(new Dimension(
3 * field.getPreferredSize().width / 2, 0));
JPanel panel = new JPanel(gb);
gc.gridx = 0;
gc.gridy = GridBagConstraints.RELATIVE;
gc.weightx = 1.0;
gc.fill = GridBagConstraints.NONE;
gc.anchor = GridBagConstraints.LINE_START;
gb.setConstraints(label, gc);
panel.add(label);
gb.setConstraints(field, gc);
panel.add(field);
gb.setConstraints(error, gc);
panel.add(error);
gb.setConstraints(strut, gc);
panel.add(strut);
JOptionPane pane = new JOptionPane(panel, JOptionPane.QUESTION_MESSAGE,
JOptionPane.OK_CANCEL_OPTION);
pane.setInitialValue(field);
JDialog dlog = pane.createDialog(frame,
Strings.get("circuitNameDialogTitle"));
dlog.addWindowFocusListener(new WindowFocusListener() {
public void windowGainedFocus(WindowEvent arg0) {
field.requestFocus();
}
public void windowLostFocus(WindowEvent arg0) {
}
});
field.selectAll();
dlog.pack();
dlog.setVisible(true);
field.requestFocusInWindow();
Object action = pane.getValue();
if (action == null || !(action instanceof Integer)
|| ((Integer) action).intValue() != JOptionPane.OK_OPTION) {
return null;
}
return field.getText().trim();
}
private ProjectCircuitActions() {
}
}