Package com.cburch.logisim.file

Source Code of com.cburch.logisim.file.LogisimFile$WritingThread

/* 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.file;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;

import org.xml.sax.SAXException;

import com.cburch.logisim.circuit.Circuit;
import com.cburch.logisim.circuit.SubcircuitFactory;
import com.cburch.logisim.comp.Component;
import com.cburch.logisim.comp.ComponentFactory;
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;
import com.cburch.logisim.util.ListUtil;
import com.cburch.logisim.util.StringUtil;

public class LogisimFile extends Library implements LibraryEventSource {
  private static class WritingThread extends Thread {
    OutputStream out;
    LogisimFile file;

    WritingThread(OutputStream out, LogisimFile file) {
      this.out = out;
      this.file = file;
    }

    @Override
    public void run() {
      try {
        file.write(out, file.loader);
      } catch (IOException e) {
        file.loader.showError(StringUtil.format(
          Strings.get("fileDuplicateError"), e.toString()));
      }
      try {
        out.close();
      } catch (IOException e) {
        file.loader.showError(StringUtil.format(
          Strings.get("fileDuplicateError"), e.toString()));
      }
    }
  }

  private EventSourceWeakSupport<LibraryListener> listeners
    = new EventSourceWeakSupport<LibraryListener>();
  private Loader loader;
  private LinkedList<String> messages = new LinkedList<String>();
  private Options options = new Options();
  private LinkedList<AddTool> tools = new LinkedList<AddTool>();
  private LinkedList<Library> libraries = new LinkedList<Library>();
  private Circuit main = null;
  private String name;
  private boolean dirty = false;

  LogisimFile(Loader loader) {
    this.loader = loader;
   
    name = Strings.get("defaultProjectName");
    if (Projects.windowNamed(name)) {
      for (int i = 2; true; i++) {
        if (!Projects.windowNamed(name + " " + i)) {
          name += " " + i;
          break;
        }
      }
    }

  }

  //
  // access methods
  //
  @Override
  public String getName() { return name; }
 
  @Override
  public boolean isDirty() { return dirty; }

  public String getMessage() {
    if (messages.size() == 0) return null;
    return messages.removeFirst();
  }

  public Loader getLoader() {
    return loader;
  }

  public Options getOptions() {
    return options;
  }

  @Override
  public List<AddTool> getTools() {
    return tools;
  }

  @Override
  public List<Library> getLibraries() {
    return libraries;
  }

  @Override
  public List<?> getElements() {
    return ListUtil.joinImmutableLists(tools, libraries);
  }

  public Circuit getCircuit(String name) {
    if (name == null) return null;
    for (AddTool tool : tools) {
      SubcircuitFactory factory = (SubcircuitFactory) tool.getFactory();
      if (name.equals(factory.getName())) return factory.getSubcircuit();
    }
    return null;
  }
 
  public boolean contains(Circuit circ) {
    for (AddTool tool : tools) {
      SubcircuitFactory factory = (SubcircuitFactory) tool.getFactory();
      if (factory.getSubcircuit() == circ) return true;
    }
    return false;
  }
 
  public List<Circuit> getCircuits() {
    List<Circuit> ret = new ArrayList<Circuit>(tools.size());
    for (AddTool tool : tools) {
      SubcircuitFactory factory = (SubcircuitFactory) tool.getFactory();
      ret.add(factory.getSubcircuit());
    }
    return ret;
  }
 
  public AddTool getAddTool(Circuit circ) {
    for (AddTool tool : tools) {
      SubcircuitFactory factory = (SubcircuitFactory) tool.getFactory();
      if (factory.getSubcircuit() == circ) {
        return tool;
      }
    }
    return null;
  }

  public Circuit getMainCircuit() {
    return main;
  }

  public int getCircuitCount() {
    return tools.size();
  }

  //
  // listener methods
  //
  public void addLibraryListener(LibraryListener what) {
    listeners.add(what);
  }

  public void removeLibraryListener(LibraryListener what) {
    listeners.remove(what);
  }

  private void fireEvent(int action, Object data) {
    LibraryEvent e = new LibraryEvent(this, action, data);
    for (LibraryListener l : listeners) {
      l.libraryChanged(e);
    }
  }


  //
  // modification actions
  //
  public void addMessage(String msg) {
    messages.addLast(msg);
  }
 
  public void setDirty(boolean value) {
    if (dirty != value) {
      dirty = value;
      fireEvent(LibraryEvent.DIRTY_STATE, value ? Boolean.TRUE : Boolean.FALSE);
    }
  }

  public void setName(String name) {
    this.name = name;
    fireEvent(LibraryEvent.SET_NAME, name);
  }

  public void addCircuit(Circuit circuit) {
    addCircuit(circuit, tools.size());
  }
 
  public void addCircuit(Circuit circuit, int index) {
    AddTool tool = new AddTool(circuit.getSubcircuitFactory());
    tools.add(index, tool);
    if (tools.size() == 1) setMainCircuit(circuit);
    fireEvent(LibraryEvent.ADD_TOOL, tool);
  }

  public void removeCircuit(Circuit circuit) {
    if (tools.size() <= 1) {
      throw new RuntimeException("Cannot remove last circuit");
    }

    int index = getCircuits().indexOf(circuit);
    if (index >= 0) {
      Tool circuitTool = tools.remove(index);

      if (main == circuit) {
        AddTool dflt_tool = tools.get(0);
        SubcircuitFactory factory = (SubcircuitFactory) dflt_tool.getFactory();
        setMainCircuit(factory.getSubcircuit());
      }
      fireEvent(LibraryEvent.REMOVE_TOOL, circuitTool);
    }
  }
 
  public void moveCircuit(AddTool tool, int index) {
    int oldIndex = tools.indexOf(tool);
    if (oldIndex < 0) {
      tools.add(index, tool);
      fireEvent(LibraryEvent.ADD_TOOL, tool);
    } else {
      AddTool value = tools.remove(oldIndex);
      tools.add(index, value);
      fireEvent(LibraryEvent.MOVE_TOOL, tool);
    }
  }

  public void addLibrary(Library lib) {
    libraries.add(lib);
    fireEvent(LibraryEvent.ADD_LIBRARY, lib);
  }

  public void removeLibrary(Library lib) {
    libraries.remove(lib);
    fireEvent(LibraryEvent.REMOVE_LIBRARY, lib);
  }
 
  public String getUnloadLibraryMessage(Library lib) {
    HashSet<ComponentFactory> factories = new HashSet<ComponentFactory>();
    for (Tool tool : lib.getTools()) {
      if (tool instanceof AddTool) {
        factories.add(((AddTool) tool).getFactory());
      }
    }
   
    for (Circuit circuit : getCircuits()) {
      for (Component comp : circuit.getNonWires()) {
        if (factories.contains(comp.getFactory())) {
          return StringUtil.format(Strings.get("unloadUsedError"),
              circuit.getName());
        }
      }
    }
   
    ToolbarData tb = options.getToolbarData();
    MouseMappings mm = options.getMouseMappings();
    for (Tool t : lib.getTools()) {
      if (tb.usesToolFromSource(t)) {
        return Strings.get("unloadToolbarError");
      }
      if (mm.usesToolFromSource(t)) {
        return Strings.get("unloadMappingError");
      }
    }
   
    return null;
  }

  public void setMainCircuit(Circuit circuit) {
    if (circuit == null) return;
    this.main = circuit;
    fireEvent(LibraryEvent.SET_MAIN, circuit);
  }

  //
  // other methods
  //
  void write(OutputStream out, LibraryLoader loader) throws IOException {
    try {
      XmlWriter.write(this, out, loader);
    } catch (TransformerConfigurationException e) {
      loader.showError("internal error configuring transformer");
    } catch (ParserConfigurationException e) {
      loader.showError("internal error configuring parser");
    } catch (TransformerException e) {
      String msg = e.getMessage();
      String err = Strings.get("xmlConversionError");
      if (msg == null) err += ": " + msg;
      loader.showError(err);
    }
  }

  public LogisimFile cloneLogisimFile(Loader newloader) {
    PipedInputStream reader = new PipedInputStream();
    PipedOutputStream writer = new PipedOutputStream();
    try {
      reader.connect(writer);
    } catch (IOException e) {
      newloader.showError(StringUtil.format(
        Strings.get("fileDuplicateError"), e.toString()));
      return null;
    }
    new WritingThread(writer, this).start();
    try {
      return LogisimFile.load(reader, newloader);
    } catch (IOException e) {
      newloader.showError(StringUtil.format(
        Strings.get("fileDuplicateError"), e.toString()));
      return null;
    }
  }
 
  Tool findTool(Tool query) {
    for (Library lib : getLibraries()) {
      Tool ret = findTool(lib, query);
      if (ret != null) return ret;
    }
    return null;
  }
 
  private Tool findTool(Library lib, Tool query) {
    for (Tool tool : lib.getTools()) {
      if (tool.equals(query)) return tool;
    }
    return null;
  }

  //
  // creation methods
  //
  public static LogisimFile createNew(Loader loader) {
    LogisimFile ret = new LogisimFile(loader);
    ret.main = new Circuit("main");
    // The name will be changed in LogisimPreferences
    ret.tools.add(new AddTool(ret.main.getSubcircuitFactory()));
    return ret;
  }

  public static LogisimFile load(File file, Loader loader)
      throws IOException {
    InputStream in = new FileInputStream(file);
    SAXException firstExcept = null;
    try {
      return loadSub(in, loader);
    } catch (SAXException e) {
      firstExcept = e;
    } finally {
      in.close();
    }
   
    if (firstExcept != null) {
      // We'll now try to do it using a reader. This is to work around
      // Logisim versions prior to 2.5.1, when files were not saved using
      // UTF-8 as the encoding (though the XML file reported otherwise).
      try {
        in = new ReaderInputStream(new FileReader(file), "UTF8");
        return loadSub(in, loader);
      } catch (Throwable t) {
        loader.showError(StringUtil.format(
            Strings.get("xmlFormatError"), firstExcept.toString()));
      } finally {
        try {
          in.close();
        } catch (Throwable t) { }
      }
    }
   
    return null;
  }
 
  public static LogisimFile load(InputStream in, Loader loader)
      throws IOException {
    try {
      return loadSub(in, loader);
    } catch (SAXException e) {
      loader.showError(StringUtil.format(
        Strings.get("xmlFormatError"), e.toString()));
      return null;
    }
  }

  public static LogisimFile loadSub(InputStream in, Loader loader)
      throws IOException, SAXException {
    // fetch first line and then reset
    BufferedInputStream inBuffered = new BufferedInputStream(in);
    String firstLine = getFirstLine(inBuffered);

    if (firstLine == null) {
      throw new IOException("File is empty");
    } else if (firstLine.equals("Logisim v1.0")) {
      // if this is a 1.0 file, then set up a pipe to translate to
      // 2.0 and then interpret as a 2.0 file
      throw new IOException("Version 1.0 files no longer supported");
    }

    XmlReader xmlReader = new XmlReader(loader);
    LogisimFile ret = xmlReader.readLibrary(inBuffered);
    ret.loader = loader;
    return ret;
  }

  private static String getFirstLine(BufferedInputStream in)
      throws IOException {
    byte[] first = new byte[512];
    in.mark(first.length - 1);
    in.read(first);
    in.reset();
   
    int lineBreak = first.length;
    for (int i = 0; i < lineBreak; i++) {
      if (first[i] == '\n') {
        lineBreak = i;
      }
    }
    return new String(first, 0, lineBreak, "UTF-8");
  }
}
TOP

Related Classes of com.cburch.logisim.file.LogisimFile$WritingThread

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.