/*******************************************************************************
* 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.file;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import com.cburch.logisim.circuit.Circuit;
import com.cburch.logisim.circuit.CircuitMutation;
import com.cburch.logisim.circuit.SubcircuitFactory;
import com.cburch.logisim.comp.Component;
import com.cburch.logisim.comp.ComponentFactory;
import com.cburch.logisim.data.Attribute;
import com.cburch.logisim.data.AttributeSet;
import com.cburch.logisim.proj.Project;
import com.cburch.logisim.proj.Projects;
import com.cburch.logisim.tools.AddTool;
import com.cburch.logisim.tools.Library;
import com.cburch.logisim.tools.Tool;
import com.cburch.logisim.util.EventSourceWeakSupport;
public class LoadedLibrary extends Library implements LibraryEventSource {
private class MyListener implements LibraryListener {
public void libraryChanged(LibraryEvent event) {
fireLibraryEvent(event);
}
}
static void copyAttributes(AttributeSet dest, AttributeSet src) {
for (Attribute<?> destAttr : dest.getAttributes()) {
Attribute<?> srcAttr = src.getAttribute(destAttr.getName());
if (srcAttr != null) {
@SuppressWarnings("unchecked")
Attribute<Object> destAttr2 = (Attribute<Object>) destAttr;
dest.setValue(destAttr2, src.getValue(srcAttr));
}
}
}
private static AttributeSet createAttributes(ComponentFactory factory,
AttributeSet src) {
AttributeSet dest = factory.createAttributeSet();
copyAttributes(dest, src);
return dest;
}
private static void replaceAll(Circuit circuit,
Map<ComponentFactory, ComponentFactory> compMap) {
ArrayList<Component> toReplace = null;
for (Component comp : circuit.getNonWires()) {
if (compMap.containsKey(comp.getFactory())) {
if (toReplace == null)
toReplace = new ArrayList<Component>();
toReplace.add(comp);
}
}
if (toReplace != null) {
CircuitMutation xn = new CircuitMutation(circuit);
for (Component comp : toReplace) {
xn.remove(comp);
ComponentFactory factory = compMap.get(comp.getFactory());
if (factory != null) {
AttributeSet newAttrs = createAttributes(factory,
comp.getAttributeSet());
xn.add(factory.createComponent(comp.getLocation(), newAttrs));
}
}
xn.execute();
}
}
private static void replaceAll(LogisimFile file,
Map<ComponentFactory, ComponentFactory> compMap,
Map<Tool, Tool> toolMap) {
file.getOptions().getToolbarData().replaceAll(toolMap);
file.getOptions().getMouseMappings().replaceAll(toolMap);
for (Circuit circuit : file.getCircuits()) {
replaceAll(circuit, compMap);
}
}
private static void replaceAll(
Map<ComponentFactory, ComponentFactory> compMap,
Map<Tool, Tool> toolMap) {
for (Project proj : Projects.getOpenProjects()) {
Tool oldTool = proj.getTool();
Circuit oldCircuit = proj.getCurrentCircuit();
if (toolMap.containsKey(oldTool)) {
proj.setTool(toolMap.get(oldTool));
}
SubcircuitFactory oldFactory = oldCircuit.getSubcircuitFactory();
if (compMap.containsKey(oldFactory)) {
SubcircuitFactory newFactory;
newFactory = (SubcircuitFactory) compMap.get(oldFactory);
proj.setCurrentCircuit(newFactory.getSubcircuit());
}
replaceAll(proj.getLogisimFile(), compMap, toolMap);
}
for (LogisimFile file : LibraryManager.instance.getLogisimLibraries()) {
replaceAll(file, compMap, toolMap);
}
}
private Library base;
private boolean dirty;
private MyListener myListener;
private EventSourceWeakSupport<LibraryListener> listeners;
LoadedLibrary(Library base) {
dirty = false;
myListener = new MyListener();
listeners = new EventSourceWeakSupport<LibraryListener>();
while (base instanceof LoadedLibrary)
base = ((LoadedLibrary) base).base;
this.base = base;
if (base instanceof LibraryEventSource) {
((LibraryEventSource) base).addLibraryListener(myListener);
}
}
public void addLibraryListener(LibraryListener l) {
listeners.add(l);
}
private void fireLibraryEvent(int action, Object data) {
fireLibraryEvent(new LibraryEvent(this, action, data));
}
private void fireLibraryEvent(LibraryEvent event) {
if (event.getSource() != this) {
event = new LibraryEvent(this, event.getAction(), event.getData());
}
for (LibraryListener l : listeners) {
l.libraryChanged(event);
}
}
public Library getBase() {
return base;
}
@Override
public String getDisplayName() {
return base.getDisplayName();
}
@Override
public List<Library> getLibraries() {
return base.getLibraries();
}
public boolean removeLibrary(String Name) {
return base.removeLibrary(Name);
}
@Override
public String getName() {
return base.getName();
}
@Override
public List<? extends Tool> getTools() {
return base.getTools();
}
@Override
public boolean isDirty() {
return dirty || base.isDirty();
}
public void removeLibraryListener(LibraryListener l) {
listeners.remove(l);
}
private void resolveChanges(Library old) {
if (listeners.isEmpty())
return;
if (!base.getDisplayName().equals(old.getDisplayName())) {
fireLibraryEvent(LibraryEvent.SET_NAME, base.getDisplayName());
}
HashSet<Library> changes = new HashSet<Library>(old.getLibraries());
changes.removeAll(base.getLibraries());
for (Library lib : changes) {
fireLibraryEvent(LibraryEvent.REMOVE_LIBRARY, lib);
}
changes.clear();
changes.addAll(base.getLibraries());
changes.removeAll(old.getLibraries());
for (Library lib : changes) {
fireLibraryEvent(LibraryEvent.ADD_LIBRARY, lib);
}
HashMap<ComponentFactory, ComponentFactory> componentMap;
HashMap<Tool, Tool> toolMap;
componentMap = new HashMap<ComponentFactory, ComponentFactory>();
toolMap = new HashMap<Tool, Tool>();
for (Tool oldTool : old.getTools()) {
Tool newTool = base.getTool(oldTool.getName());
toolMap.put(oldTool, newTool);
if (oldTool instanceof AddTool) {
ComponentFactory oldFactory = ((AddTool) oldTool).getFactory();
if (newTool != null && newTool instanceof AddTool) {
ComponentFactory newFactory = ((AddTool) newTool)
.getFactory();
componentMap.put(oldFactory, newFactory);
} else {
componentMap.put(oldFactory, null);
}
}
}
replaceAll(componentMap, toolMap);
HashSet<Tool> toolChanges = new HashSet<Tool>(old.getTools());
toolChanges.removeAll(toolMap.keySet());
for (Tool tool : toolChanges) {
fireLibraryEvent(LibraryEvent.REMOVE_TOOL, tool);
}
toolChanges = new HashSet<Tool>(base.getTools());
toolChanges.removeAll(toolMap.values());
for (Tool tool : toolChanges) {
fireLibraryEvent(LibraryEvent.ADD_TOOL, tool);
}
}
void setBase(Library value) {
if (base instanceof LibraryEventSource) {
((LibraryEventSource) base).removeLibraryListener(myListener);
}
Library old = base;
base = value;
resolveChanges(old);
if (base instanceof LibraryEventSource) {
((LibraryEventSource) base).addLibraryListener(myListener);
}
}
void setDirty(boolean value) {
if (dirty != value) {
dirty = value;
fireLibraryEvent(LibraryEvent.DIRTY_STATE, isDirty() ? Boolean.TRUE
: Boolean.FALSE);
}
}
}