/* Copyright (c) 2010, Carl Burch. License information is located in the
* com.cburch.logisim.Main source code and at www.cburch.com/logisim/. */
package com.cburch.logisim.gui.main;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;
import com.cburch.draw.model.CanvasModelEvent;
import com.cburch.draw.model.CanvasModelListener;
import com.cburch.logisim.circuit.Circuit;
import com.cburch.logisim.circuit.CircuitState;
import com.cburch.logisim.circuit.Simulator;
import com.cburch.logisim.file.LibraryEvent;
import com.cburch.logisim.file.LibraryListener;
import com.cburch.logisim.file.LogisimFile;
import com.cburch.logisim.gui.appear.RevertAppearanceAction;
import com.cburch.logisim.gui.generic.CardPanel;
import com.cburch.logisim.gui.menu.LogisimMenuItem;
import com.cburch.logisim.gui.menu.ProjectCircuitActions;
import com.cburch.logisim.gui.menu.LogisimMenuBar;
import com.cburch.logisim.gui.menu.SimulateListener;
import com.cburch.logisim.proj.Project;
import com.cburch.logisim.proj.ProjectEvent;
import com.cburch.logisim.proj.ProjectListener;
class MenuListener {
interface EnabledListener {
public void menuEnableChanged(MenuListener source);
}
private class FileListener implements ActionListener {
private void register() {
menubar.addActionListener(LogisimMenuBar.EXPORT_IMAGE, this);
menubar.addActionListener(LogisimMenuBar.PRINT, this);
}
@Override
public void actionPerformed(ActionEvent event) {
Object src = event.getSource();
Project proj = frame.getProject();
if (src == LogisimMenuBar.EXPORT_IMAGE) {
ExportImage.doExport(proj);
} else if (src == LogisimMenuBar.PRINT) {
Print.doPrint(proj);
}
}
}
private class EditListener implements ActionListener, EditHandler.Listener {
private EditHandler handler = null;
private void setHandler(EditHandler value) {
handler = value;
value.setListener(this);
handler.computeEnabled();
}
private void register() {
menubar.addActionListener(LogisimMenuBar.CUT, this);
menubar.addActionListener(LogisimMenuBar.COPY, this);
menubar.addActionListener(LogisimMenuBar.PASTE, this);
menubar.addActionListener(LogisimMenuBar.DELETE, this);
menubar.addActionListener(LogisimMenuBar.DUPLICATE, this);
menubar.addActionListener(LogisimMenuBar.SELECT_ALL, this);
menubar.addActionListener(LogisimMenuBar.RAISE, this);
menubar.addActionListener(LogisimMenuBar.LOWER, this);
menubar.addActionListener(LogisimMenuBar.RAISE_TOP, this);
menubar.addActionListener(LogisimMenuBar.LOWER_BOTTOM, this);
menubar.addActionListener(LogisimMenuBar.ADD_CONTROL, this);
menubar.addActionListener(LogisimMenuBar.REMOVE_CONTROL, this);
if (handler != null) {
handler.computeEnabled();
}
}
@Override
public void actionPerformed(ActionEvent e) {
Object src = e.getSource();
EditHandler h = handler;
if (src == LogisimMenuBar.CUT) {
if (h != null) {
h.cut();
}
} else if (src == LogisimMenuBar.COPY) {
if (h != null) {
h.copy();
}
} else if (src == LogisimMenuBar.PASTE) {
if (h != null) {
h.paste();
}
} else if (src == LogisimMenuBar.DELETE) {
if (h != null) {
h.delete();
}
} else if (src == LogisimMenuBar.DUPLICATE) {
if (h != null) {
h.duplicate();
}
} else if (src == LogisimMenuBar.SELECT_ALL) {
if (h != null) {
h.selectAll();
}
} else if (src == LogisimMenuBar.RAISE) {
if (h != null) {
h.raise();
}
} else if (src == LogisimMenuBar.LOWER) {
if (h != null) {
h.lower();
}
} else if (src == LogisimMenuBar.RAISE_TOP) {
if (h != null) {
h.raiseTop();
}
} else if (src == LogisimMenuBar.LOWER_BOTTOM) {
if (h != null) {
h.lowerBottom();
}
} else if (src == LogisimMenuBar.ADD_CONTROL) {
if (h != null) {
h.addControlPoint();
}
} else if (src == LogisimMenuBar.REMOVE_CONTROL) {
if (h != null) {
h.removeControlPoint();
}
}
}
@Override
public void enableChanged(EditHandler handler, LogisimMenuItem action,
boolean value) {
if (handler == this.handler) {
menubar.setEnabled(action, value);
fireEnableChanged();
}
}
}
class ProjectMenuListener implements ProjectListener, LibraryListener,
ActionListener, PropertyChangeListener, CanvasModelListener {
void register() {
Project proj = frame.getProject();
if (proj == null) {
return;
}
proj.addProjectListener(this);
proj.addLibraryListener(this);
frame.addPropertyChangeListener(Frame.EDITOR_VIEW, this);
frame.addPropertyChangeListener(Frame.EXPLORER_VIEW, this);
Circuit circ = proj.getCurrentCircuit();
if (circ != null) {
circ.getAppearance().addCanvasModelListener(this);
}
menubar.addActionListener(LogisimMenuBar.ADD_CIRCUIT, this);
menubar.addActionListener(LogisimMenuBar.MOVE_CIRCUIT_UP, this);
menubar.addActionListener(LogisimMenuBar.MOVE_CIRCUIT_DOWN, this);
menubar.addActionListener(LogisimMenuBar.SET_MAIN_CIRCUIT, this);
menubar.addActionListener(LogisimMenuBar.REMOVE_CIRCUIT, this);
menubar.addActionListener(LogisimMenuBar.EDIT_LAYOUT, this);
menubar.addActionListener(LogisimMenuBar.EDIT_APPEARANCE, this);
menubar.addActionListener(LogisimMenuBar.VIEW_TOOLBOX, this);
menubar.addActionListener(LogisimMenuBar.VIEW_SIMULATION, this);
menubar.addActionListener(LogisimMenuBar.REVERT_APPEARANCE, this);
menubar.addActionListener(LogisimMenuBar.ANALYZE_CIRCUIT, this);
menubar.addActionListener(LogisimMenuBar.CIRCUIT_STATS, this);
computeEnabled();
}
@Override
public void modelChanged(CanvasModelEvent event) {
computeRevertEnabled();
}
@Override
public void projectChanged(ProjectEvent event) {
int action = event.getAction();
if (action == ProjectEvent.ACTION_SET_CURRENT) {
Circuit old = (Circuit) event.getOldData();
if (old != null) {
old.getAppearance().removeCanvasModelListener(this);
}
Circuit circ = (Circuit) event.getData();
if (circ != null) {
circ.getAppearance().addCanvasModelListener(this);
}
computeEnabled();
} else if (action == ProjectEvent.ACTION_SET_FILE) {
computeEnabled();
}
}
@Override
public void libraryChanged(LibraryEvent event) {
computeEnabled();
}
@Override
public void actionPerformed(ActionEvent event) {
Object src = event.getSource();
Project proj = frame.getProject();
Circuit cur = proj == null ? null : proj.getCurrentCircuit();
if (src == LogisimMenuBar.ADD_CIRCUIT) {
ProjectCircuitActions.doAddCircuit(proj);
} else if (src == LogisimMenuBar.MOVE_CIRCUIT_UP) {
ProjectCircuitActions.doMoveCircuit(proj, cur, -1);
} else if (src == LogisimMenuBar.MOVE_CIRCUIT_DOWN) {
ProjectCircuitActions.doMoveCircuit(proj, cur, 1);
} else if (src == LogisimMenuBar.SET_MAIN_CIRCUIT) {
ProjectCircuitActions.doSetAsMainCircuit(proj, cur);
} else if (src == LogisimMenuBar.REMOVE_CIRCUIT) {
ProjectCircuitActions.doRemoveCircuit(proj, cur);
} else if (src == LogisimMenuBar.EDIT_LAYOUT) {
frame.setEditorView(Frame.EDIT_LAYOUT);
} else if (src == LogisimMenuBar.EDIT_APPEARANCE) {
frame.setEditorView(Frame.EDIT_APPEARANCE);
} else if (src == LogisimMenuBar.VIEW_TOOLBOX) {
frame.setExplorerView(Frame.VIEW_TOOLBOX);
} else if (src == LogisimMenuBar.VIEW_SIMULATION) {
frame.setExplorerView(Frame.VIEW_SIMULATION);
} else if (src == LogisimMenuBar.REVERT_APPEARANCE) {
proj.doAction(new RevertAppearanceAction(cur));
} else if (src == LogisimMenuBar.ANALYZE_CIRCUIT) {
ProjectCircuitActions.doAnalyze(proj, cur);
} else if (src == LogisimMenuBar.CIRCUIT_STATS) {
StatisticsDialog.show(frame, proj.getLogisimFile(), cur);
}
}
private void computeEnabled() {
Project proj = frame.getProject();
LogisimFile file = proj.getLogisimFile();
Circuit cur = proj.getCurrentCircuit();
int curIndex = file.getCircuits().indexOf(cur);
boolean isProjectCircuit = curIndex >= 0;
String editorView = frame.getEditorView();
String explorerView = frame.getExplorerView();
boolean canSetMain = false;
boolean canMoveUp = false;
boolean canMoveDown = false;
boolean canRemove = false;
boolean canRevert = false;
boolean viewAppearance = editorView.equals(Frame.EDIT_APPEARANCE);
boolean viewLayout = editorView.equals(Frame.EDIT_LAYOUT);
boolean viewToolbox = explorerView.equals(Frame.VIEW_TOOLBOX);
boolean viewSimulation = explorerView.equals(Frame.VIEW_SIMULATION);
if (isProjectCircuit) {
List<?> tools = proj.getLogisimFile().getTools();
canSetMain = proj.getLogisimFile().getMainCircuit() != cur;
canMoveUp = curIndex > 0;
canMoveDown = curIndex < tools.size() - 1;
canRemove = tools.size() > 1;
canRevert = viewAppearance
&& !cur.getAppearance().isDefaultAppearance();
}
menubar.setEnabled(LogisimMenuBar.ADD_CIRCUIT, true);
menubar.setEnabled(LogisimMenuBar.MOVE_CIRCUIT_UP, canMoveUp);
menubar.setEnabled(LogisimMenuBar.MOVE_CIRCUIT_DOWN, canMoveDown);
menubar.setEnabled(LogisimMenuBar.SET_MAIN_CIRCUIT, canSetMain);
menubar.setEnabled(LogisimMenuBar.REMOVE_CIRCUIT, canRemove);
menubar.setEnabled(LogisimMenuBar.VIEW_TOOLBOX, !viewToolbox);
menubar.setEnabled(LogisimMenuBar.VIEW_SIMULATION, !viewSimulation);
menubar.setEnabled(LogisimMenuBar.EDIT_LAYOUT, !viewLayout);
menubar.setEnabled(LogisimMenuBar.EDIT_APPEARANCE, !viewAppearance);
menubar.setEnabled(LogisimMenuBar.REVERT_APPEARANCE, canRevert);
menubar.setEnabled(LogisimMenuBar.ANALYZE_CIRCUIT, true);
menubar.setEnabled(LogisimMenuBar.CIRCUIT_STATS, true);
fireEnableChanged();
}
private void computeRevertEnabled() {
// do this separately since it can happen rather often
Project proj = frame.getProject();
LogisimFile file = proj.getLogisimFile();
Circuit cur = proj.getCurrentCircuit();
boolean isProjectCircuit = file.contains(cur);
boolean viewAppearance = frame.getEditorView().equals(Frame.EDIT_APPEARANCE);
boolean canRevert = isProjectCircuit && viewAppearance
&& !cur.getAppearance().isDefaultAppearance();
boolean oldValue = menubar.isEnabled(LogisimMenuBar.REVERT_APPEARANCE);
if (canRevert != oldValue) {
menubar.setEnabled(LogisimMenuBar.REVERT_APPEARANCE, canRevert);
fireEnableChanged();
}
}
@Override
public void propertyChange(PropertyChangeEvent e) {
computeEnabled();
}
}
class SimulateMenuListener implements ProjectListener, SimulateListener {
void register() {
Project proj = frame.getProject();
proj.addProjectListener(this);
menubar.setSimulateListener(this);
menubar.setCircuitState(proj.getSimulator(), proj.getCircuitState());
}
@Override
public void projectChanged(ProjectEvent event) {
if (event.getAction() == ProjectEvent.ACTION_SET_STATE) {
menubar.setCircuitState(frame.getProject().getSimulator(),
frame.getProject().getCircuitState());
}
}
@Override
public void stateChangeRequested(Simulator sim, CircuitState state) {
if (state != null) {
frame.getProject().setCircuitState(state);
}
}
}
private Frame frame;
private LogisimMenuBar menubar;
private ArrayList<EnabledListener> listeners;
private FileListener fileListener = new FileListener();
private EditListener editListener = new EditListener();
private ProjectMenuListener projectListener = new ProjectMenuListener();
private SimulateMenuListener simulateListener = new SimulateMenuListener();
public MenuListener(Frame frame, LogisimMenuBar menubar) {
this.frame = frame;
this.menubar = menubar;
this.listeners = new ArrayList<EnabledListener>();
}
LogisimMenuBar getMenuBar() {
return menubar;
}
public void register(CardPanel mainPanel) {
fileListener.register();
editListener.register();
projectListener.register();
simulateListener.register();
}
public void setEditHandler(EditHandler handler) {
editListener.setHandler(handler);
}
public void addEnabledListener(EnabledListener listener) {
listeners.add(listener);
}
public void removeEnabledListener(EnabledListener listener) {
listeners.remove(listener);
}
public void doAction(LogisimMenuItem item) {
menubar.doAction(item);
}
public boolean isEnabled(LogisimMenuItem item) {
return menubar.isEnabled(item);
}
private void fireEnableChanged() {
for (EnabledListener listener : listeners) {
listener.menuEnableChanged(this);
}
}
}