Package com.cburch.logisim.file

Source Code of com.cburch.logisim.file.Loader

/* 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.awt.Component;
import java.awt.Dimension;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Stack;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.filechooser.FileFilter;

import com.cburch.logisim.std.Builtin;
import com.cburch.logisim.tools.Library;
import com.cburch.logisim.util.JFileChoosers;
import com.cburch.logisim.util.MacCompatibility;
import com.cburch.logisim.util.StringUtil;
import com.cburch.logisim.util.ZipClassLoader;

public class Loader implements LibraryLoader {
  public static final String LOGISIM_EXTENSION = ".circ";
  public static final FileFilter LOGISIM_FILTER = new LogisimFileFilter();
  public static final FileFilter JAR_FILTER = new JarFileFilter();

  private static class LogisimFileFilter extends FileFilter {
    @Override
    public boolean accept(File f) {
      return f.isDirectory()
        || f.getName().endsWith(LOGISIM_EXTENSION);
    }

    @Override
    public String getDescription() {
      return Strings.get("logisimFileFilter");
    }
  }

  private static class JarFileFilter extends FileFilter {
    @Override
    public boolean accept(File f) {
      return f.isDirectory()
        || f.getName().endsWith(".jar");
    }

    @Override
    public String getDescription() {
      return Strings.get("jarFileFilter");
    }
  }
 
  // fixed
  private Component parent;
  private Builtin builtin = new Builtin();

  // to be cleared with each new file
  private File mainFile = null;
  private Stack<File> filesOpening = new Stack<File>();
  private Map<File,File> substitutions = new HashMap<File,File>();

  public Loader(Component parent) {
    this.parent = parent;
    clear();
  }
 
  public Builtin getBuiltin() {
    return builtin;
  }
 
  public void setParent(Component value) {
    parent = value;
  }
 
  private File getSubstitution(File source) {
    File ret = substitutions.get(source);
    return ret == null ? source : ret;
  }

  //
  // file chooser related methods
  //
  public File getMainFile() {
    return mainFile;
  }

  public JFileChooser createChooser() {
    return JFileChoosers.createAt(getCurrentDirectory());
  }

  // used here and in LibraryManager only
  File getCurrentDirectory() {
    File ref;
    if (!filesOpening.empty()) {
      ref = filesOpening.peek();
    } else {
      ref = mainFile;
    }
    return ref == null ? null : ref.getParentFile();
  }

  private void setMainFile(File value) {
    mainFile = value;
  }

  //
  // more substantive methods accessed from outside this package
  //
  public void clear() {
    filesOpening.clear();
    mainFile = null;
  }
 
  public LogisimFile openLogisimFile(File file, Map<File,File> substitutions)
      throws LoadFailedException {
    this.substitutions = substitutions;
    try {
      return openLogisimFile(file);
    } finally {
      this.substitutions = Collections.emptyMap();
    }
  }

  public LogisimFile openLogisimFile(File file) throws LoadFailedException {
    try {
      LogisimFile ret = loadLogisimFile(file);
      if (ret != null) setMainFile(file);
      showMessages(ret);
      return ret;
    } catch (LoaderException e) {
      throw new LoadFailedException(e.getMessage(), e.isShown());
    }
  }
 
  public LogisimFile openLogisimFile(InputStream reader)
      throws LoadFailedException, IOException {
    LogisimFile ret = null;
    try {
      ret = LogisimFile.load(reader, this);
    } catch (LoaderException e) {
      return null;
    }
    showMessages(ret);
    return ret;
  }

  public Library loadLogisimLibrary(File file) {
    File actual = getSubstitution(file);
    LoadedLibrary ret = LibraryManager.instance.loadLogisimLibrary(this, actual);
    if (ret != null) {
      LogisimFile retBase = (LogisimFile) ret.getBase();
      showMessages(retBase);
    }
    return ret;
  }
 
  public Library loadJarLibrary(File file, String className) {
    File actual = getSubstitution(file);
    return LibraryManager.instance.loadJarLibrary(this, actual, className);
  }
 
  public void reload(LoadedLibrary lib) {
    LibraryManager.instance.reload(this, lib);
  }
 
  public boolean save(LogisimFile file, File dest) {
    Library reference = LibraryManager.instance.findReference(file, dest);
    if (reference != null) {
      JOptionPane.showMessageDialog(parent,
          StringUtil.format(Strings.get("fileCircularError"), reference.getDisplayName()),
          Strings.get("fileSaveErrorTitle"),
          JOptionPane.ERROR_MESSAGE);
      return false;
    }
   
    File backup = determineBackupName(dest);
    boolean backupCreated = backup != null && dest.renameTo(backup);
   
    FileOutputStream fwrite = null;
    try {
      try {
        MacCompatibility.setFileCreatorAndType(dest, "LGSM", "circ");
      } catch (IOException e) { }
      fwrite = new FileOutputStream(dest);
      file.write(fwrite, this);
      file.setName(toProjectName(dest));

      File oldFile = getMainFile();
      setMainFile(dest);
      LibraryManager.instance.fileSaved(this, dest, oldFile, file);
    } catch (IOException e) {
      if (backupCreated) recoverBackup(backup, dest);
      if (dest.exists() && dest.length() == 0) dest.delete();
      JOptionPane.showMessageDialog(parent,
        StringUtil.format(Strings.get("fileSaveError"),
          e.toString()),
        Strings.get("fileSaveErrorTitle"),
        JOptionPane.ERROR_MESSAGE);
      return false;
    } finally {
      if (fwrite != null) {
        try {
          fwrite.close();
        } catch (IOException e) {
          if (backupCreated) recoverBackup(backup, dest);
          if (dest.exists() && dest.length() == 0) dest.delete();
          JOptionPane.showMessageDialog(parent,
            StringUtil.format(Strings.get("fileSaveCloseError"),
              e.toString()),
            Strings.get("fileSaveErrorTitle"),
            JOptionPane.ERROR_MESSAGE);
          return false;
        }
      }
    }
   
    if (!dest.exists() || dest.length() == 0) {
      if (backupCreated && backup != null && backup.exists()) {
        recoverBackup(backup, dest);
      } else {
        dest.delete();
      }
      JOptionPane.showMessageDialog(parent,
          Strings.get("fileSaveZeroError"),
          Strings.get("fileSaveErrorTitle"),
          JOptionPane.ERROR_MESSAGE);
      return false;
    }
   
    if (backupCreated && backup.exists()) {
      backup.delete();
    }
    return true;
  }
 
  private static File determineBackupName(File base) {
    File dir = base.getParentFile();
    String name = base.getName();
    if (name.endsWith(LOGISIM_EXTENSION)) {
      name = name.substring(0, name.length() - LOGISIM_EXTENSION.length());
    }
    for (int i = 1; i <= 20; i++) {
      String ext = i == 1 ? ".bak" : (".bak" + i);
      File candidate = new File(dir, name + ext);
      if (!candidate.exists()) return candidate;
    }
    return null;
  }
 
  private static void recoverBackup(File backup, File dest) {
    if (backup != null && backup.exists()) {
      if (dest.exists()) dest.delete();
      backup.renameTo(dest);
    }
  }

  //
  // methods for LibraryManager
  // 
  LogisimFile loadLogisimFile(File request) throws LoadFailedException {
    File actual = getSubstitution(request);
    for (File fileOpening : filesOpening) {
      if (fileOpening.equals(actual)) {
        throw new LoadFailedException(StringUtil.format(Strings.get("logisimCircularError"),
            toProjectName(actual)));
      }
    }

    LogisimFile ret = null;
    filesOpening.push(actual);
    try {
      ret = LogisimFile.load(actual, this);
    } catch (IOException e) {
      throw new LoadFailedException(StringUtil.format(Strings.get("logisimLoadError"),
          toProjectName(actual), e.toString()));
    } finally {
      filesOpening.pop();
    }
    ret.setName(toProjectName(actual));
    return ret;
  }

  Library loadJarFile(File request, String className) throws LoadFailedException {
    File actual = getSubstitution(request);
    // Up until 2.1.8, this was written to use a URLClassLoader, which
    // worked pretty well, except that the class never releases its file
    // handles. For this reason, with 2.2.0, it's been switched to use
    // a custom-written class ZipClassLoader instead. The ZipClassLoader
    // is based on something downloaded off a forum, and I'm not as sure
    // that it works as well. It certainly does more file accesses.
   
    // Anyway, here's the line for this new version:
    ZipClassLoader loader = new ZipClassLoader(actual);
   
    // And here's the code that was present up until 2.1.8, and which I
    // know to work well except for the closing-files bit. If necessary, we
    // can revert by deleting the above declaration and reinstating the below.
    /*
    URL url;
    try {
      url = new URL("file", "localhost", file.getCanonicalPath());
    } catch (MalformedURLException e1) {
      throw new LoadFailedException("Internal error: Malformed URL");
    } catch (IOException e1) {
      throw new LoadFailedException(Strings.get("jarNotOpenedError"));
    }
    URLClassLoader loader = new URLClassLoader(new URL[] { url });
    */
   
    // load library class from loader
    Class<?> retClass;
    try {
      retClass = loader.loadClass(className);
    } catch (ClassNotFoundException e) {
      throw new LoadFailedException(StringUtil.format(Strings.get("jarClassNotFoundError"), className));
    }
    if (!(Library.class.isAssignableFrom(retClass))) {
      throw new LoadFailedException(StringUtil.format(Strings.get("jarClassNotLibraryError"), className));
    }
   
    // instantiate library
    Library ret;
    try {
      ret = (Library) retClass.newInstance();
    } catch (Exception e) {
      throw new LoadFailedException(StringUtil.format(Strings.get("jarLibraryNotCreatedError"), className));
    }
    return ret;
  }

  //
  // Library methods
  //
  public Library loadLibrary(String desc) {
    return LibraryManager.instance.loadLibrary(this, desc);
  }

  public String getDescriptor(Library lib) {
    return LibraryManager.instance.getDescriptor(this, lib);
  }

  public void showError(String description) {
    if (!filesOpening.empty()) {
      File top = filesOpening.peek();
      String init = toProjectName(top) + ":";
      if (description.contains("\n")) {
        description = init + "\n" + description;
      } else {
        description = init + " " + description;
      }
    }
   
    if (description.contains("\n") || description.length() > 60) {
      int lines = 1;
      for (int pos = description.indexOf('\n'); pos >= 0;
          pos = description.indexOf('\n', pos + 1)) {
        lines++;
      }
      lines = Math.max(4, Math.min(lines, 7));

      JTextArea textArea = new JTextArea(lines, 60);
      textArea.setEditable(false);
      textArea.setText(description);
      textArea.setCaretPosition(0);
     
      JScrollPane scrollPane = new JScrollPane(textArea);   
      scrollPane.setPreferredSize(new Dimension(350, 150));
      JOptionPane.showMessageDialog(parent, scrollPane,
          Strings.get("fileErrorTitle"), JOptionPane.ERROR_MESSAGE);
    } else {
      JOptionPane.showMessageDialog(parent, description,
          Strings.get("fileErrorTitle"), JOptionPane.ERROR_MESSAGE);
    }
  }

  private void showMessages(LogisimFile source) {
    if (source == null) return;
    String message = source.getMessage();
    while (message != null) {
      JOptionPane.showMessageDialog(parent,
        message, Strings.get("fileMessageTitle"),
        JOptionPane.INFORMATION_MESSAGE);
      message = source.getMessage();
    }
  }

  //
  // helper methods
  //
  File getFileFor(String name, FileFilter filter) {
    // Determine the actual file name.
    File file = new File(name);
    if (!file.isAbsolute()) {
      File currentDirectory = getCurrentDirectory();
      if (currentDirectory != null) file = new File(currentDirectory, name);
    }
    while (!file.canRead()) {
      // It doesn't exist. Figure it out from the user.
      JOptionPane.showMessageDialog(parent,
        StringUtil.format(Strings.get("fileLibraryMissingError"),
          file.getName()));
      JFileChooser chooser = createChooser();
      chooser.setFileFilter(filter);
      chooser.setDialogTitle(StringUtil.format(Strings.get("fileLibraryMissingTitle"), file.getName()));
      int action = chooser.showDialog(parent, Strings.get("fileLibraryMissingButton"));
      if (action != JFileChooser.APPROVE_OPTION) {
        throw new LoaderException(Strings.get("fileLoadCanceledError"));
      }
      file = chooser.getSelectedFile();
    }
    return file;
  }

  private String toProjectName(File file) {
    String ret = file.getName();
    if (ret.endsWith(LOGISIM_EXTENSION)) {
      return ret.substring(0, ret.length() - LOGISIM_EXTENSION.length());
    } else {
      return ret;
    }
  }

}
TOP

Related Classes of com.cburch.logisim.file.Loader

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.