diff --git a/CHANGES.md b/CHANGES.md index 436d1bb897..5412edf03f 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -6,6 +6,7 @@ * Fixed bug preventing TTL 7442, 7443 and 7444 from being placed on the circuit canvas. * Sub-circuit can now be deleted with `DELETE` key, along with `BACKSPACE` used so far. * Fixed `Simulate` -> `Timing Diagram` not opening when using "Nimbus" look and feel. + * New take on project export/import a zip-file is generated which can include a user provided "README.md". * v3.7.2 (2021-11-09) * Fixed Preferences/Window "Reset window layout to defaults" not doing much. @@ -39,6 +40,7 @@ * Added a setting to select lower- or upper-case VHDL keywords. * Added project export feature. * Cleaned-up the written .circ file. + * Cleaned-up the library tree of loaded projects. * v3.6.1 (2021-09-27) * Fixed bug in LED-array diff --git a/build.gradle.kts b/build.gradle.kts index e5d942785a..dcf536b9fc 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -35,10 +35,11 @@ dependencies { implementation("org.drjekyll:colorpicker:1.3") implementation("at.swimmesberger:swingx-core:1.6.8") implementation("org.scijava:swing-checkbox-tree:1.0.2") - implementation("org.slf4j:slf4j-api:1.7.32") - implementation("org.slf4j:slf4j-simple:1.7.32") - implementation("com.formdev:flatlaf:1.6.4") - implementation("commons-cli:commons-cli:1.5.0") + implementation("org.slf4j:slf4j-api:1.7.30") + implementation("org.slf4j:slf4j-simple:1.7.30") + implementation("com.formdev:flatlaf:1.2") + implementation("commons-cli:commons-cli:1.4") + implementation("com.vladsch.flexmark:flexmark-all:0.62.2") implementation("org.apache.commons:commons-text:1.9") // NOTE: Do not upgrade the jflex version. Later versions do not work. diff --git a/src/main/java/com/cburch/logisim/file/LibraryManager.java b/src/main/java/com/cburch/logisim/file/LibraryManager.java index 363ca5d8cc..815d56bbc3 100644 --- a/src/main/java/com/cburch/logisim/file/LibraryManager.java +++ b/src/main/java/com/cburch/logisim/file/LibraryManager.java @@ -281,6 +281,16 @@ public Library loadLibrary(Loader loader, String desc) { } } + public static boolean isJarLibrary(Loader loader, String desc) { + final var sep = desc.indexOf(DESC_SEP); + if (sep < 0) { + loader.showError(S.get("fileDescriptorError", desc)); + return false; + } + final var type = desc.substring(0, sep); + return "jar".equals(type); + } + public static String getLibraryFilePath(Loader loader, String desc) { final var sep = desc.indexOf(DESC_SEP); if (sep < 0) { diff --git a/src/main/java/com/cburch/logisim/file/Loader.java b/src/main/java/com/cburch/logisim/file/Loader.java index 5be5afda2d..6044f85480 100644 --- a/src/main/java/com/cburch/logisim/file/Loader.java +++ b/src/main/java/com/cburch/logisim/file/Loader.java @@ -15,7 +15,6 @@ import com.cburch.logisim.std.Builtin; import com.cburch.logisim.tools.Library; import com.cburch.logisim.util.JFileChoosers; -import com.cburch.logisim.util.LineBuffer; import com.cburch.logisim.util.ZipClassLoader; import com.cburch.logisim.vhdl.file.HdlFile; import java.awt.Component; @@ -28,6 +27,8 @@ import java.util.HashMap; import java.util.Map; import java.util.Stack; +import java.util.zip.ZipOutputStream; + import javax.swing.JFileChooser; import javax.swing.JScrollPane; import javax.swing.JTextArea; @@ -82,6 +83,18 @@ public String getDescription() { } } + private static class LogisimProjectBundleFilter extends FileFilter { + @Override + public boolean accept(File f) { + return f.isDirectory() || f.getName().endsWith(LOGISIM_PROJECT_BUNDLE_EXTENSION); + } + + @Override + public String getDescription() { + return S.get("logisimProjectBundleFilter"); + } + } + private static class LogisimDirectoryFilter extends FileFilter { @Override public boolean accept(File f) { @@ -107,9 +120,11 @@ public String getDescription() { } public static final String LOGISIM_EXTENSION = ".circ"; - public static final String LOGISIM_LIBRARY_DIR = "library"; - public static final String LOGISIM_CIRCUIT_DIR = "circuit"; + public static final String LOGISIM_PROJECT_BUNDLE_EXTENSION = ".lsebdl"; + public static final String LOGISIM_LIBRARY_DIR = "libraries"; + public static final String LOGISIM_PROJECT_BUNDLE_INFO_FILE = "LogisimEvolutionBundle.info"; public static final FileFilter LOGISIM_FILTER = new LogisimFileFilter(); + public static final FileFilter LOGISIM_BUNDLE_FILTER = new LogisimProjectBundleFilter(); public static final FileFilter LOGISIM_DIRECTORY = new LogisimDirectoryFilter(); public static final FileFilter JAR_FILTER = new JarFileFilter(); public static final FileFilter TXT_FILTER = new TxtFileFilter(); @@ -122,6 +137,7 @@ public String getDescription() { private File mainFile = null; private final Stack filesOpening = new Stack<>(); private Map substitutions = new HashMap<>(); + private ZipOutputStream zipFile; public Loader(Component parent) { this.parent = parent; @@ -326,21 +342,21 @@ public void reload(LoadedLibrary lib) { LibraryManager.instance.reload(this, lib); } - public boolean export(LogisimFile file, String homeDirectory) { - try { - final var mainCircFile = LineBuffer.format("{{1}}{{2}}{{3}}{{2}}{{4}}", homeDirectory, File.separator, - LOGISIM_CIRCUIT_DIR, getMainFile().getName()); - final var libraryHome = String.format("%s%s%s", homeDirectory, File.separator, LOGISIM_LIBRARY_DIR); - final var fwrite = new FileOutputStream(mainCircFile); - file.write(fwrite, this, libraryHome); - } catch (IOException e) { - //TODO: give an error message to the user #1136 - System.err.println("Unable to export file"); - return false; - } + public boolean export(LogisimFile file, ZipOutputStream zipFile, String mainFileName) { + this.zipFile = zipFile; + file.write(zipFile, this, mainFileName); + this.zipFile = null; return true; } + public ZipOutputStream getZipFile() { + return zipFile; + } + + public void setZipFile(ZipOutputStream file) { + zipFile = file; + } + public boolean save(LogisimFile file, File dest) { final var reference = LibraryManager.instance.findReference(file, dest); if (reference != null) { diff --git a/src/main/java/com/cburch/logisim/file/LogisimFile.java b/src/main/java/com/cburch/logisim/file/LogisimFile.java index 6fe212c7da..d6ebb83530 100644 --- a/src/main/java/com/cburch/logisim/file/LogisimFile.java +++ b/src/main/java/com/cburch/logisim/file/LogisimFile.java @@ -591,16 +591,24 @@ public void setName(String name) { // other methods // void write(OutputStream out, LibraryLoader loader) { - write(out, loader, null, null); + write(out, loader, null, null, false); } - void write(OutputStream out, LibraryLoader loader, String libraryHome) { - write(out, loader, null, libraryHome); + void write(OutputStream out, LibraryLoader loader, String mainCircFile) { + write(out, loader, null, mainCircFile, false); } - void write(OutputStream out, LibraryLoader loader, File dest, String libraryHome) { + void write(OutputStream out, LibraryLoader loader, String mainCircFile, boolean recurse) { + write(out, loader, null, mainCircFile, recurse); + } + + void write(OutputStream out, LibraryLoader loader, File dest, String mainCircFile) { + write(out, loader, dest, mainCircFile, false); + } + + void write(OutputStream out, LibraryLoader loader, File dest, String mainCircFile, boolean recurse) { try { - XmlWriter.write(this, out, loader, dest, libraryHome); + XmlWriter.write(this, out, loader, dest, mainCircFile, recurse); } catch (TransformerConfigurationException e) { loader.showError("internal error configuring transformer"); } catch (ParserConfigurationException e) { @@ -610,6 +618,10 @@ void write(OutputStream out, LibraryLoader loader, File dest, String libraryHome var err = S.get("xmlConversionError"); if (msg == null) err += ": " + msg; loader.showError(err); + } catch (IOException e) { + loader.showError("Unable to create zip file"); + } catch (LoadFailedException e) { + loader.showError("Unable to create zip file"); } } diff --git a/src/main/java/com/cburch/logisim/file/XmlWriter.java b/src/main/java/com/cburch/logisim/file/XmlWriter.java index 4b6b8dbe0e..8b1dde9871 100644 --- a/src/main/java/com/cburch/logisim/file/XmlWriter.java +++ b/src/main/java/com/cburch/logisim/file/XmlWriter.java @@ -32,16 +32,17 @@ import com.cburch.logisim.util.XmlUtil; import com.cburch.logisim.vhdl.base.VhdlContent; import java.io.File; +import java.io.FileInputStream; import java.io.IOException; import java.io.OutputStream; -import java.nio.file.Files; import java.nio.file.Paths; -import java.nio.file.StandardCopyOption; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; import java.util.regex.Pattern; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.OutputKeys; @@ -65,29 +66,31 @@ final class XmlWriter { * Path of the file which is being written on disk -- used to relativize components stored in it. */ private final String outFilePath; - private final String librariesPath; private final boolean isProjectExport; private final LibraryLoader loader; private final HashMap libs = new HashMap<>(); + private final boolean isRecursiveCall; private XmlWriter(LogisimFile file, Document doc, LibraryLoader loader) { - this(file, doc, loader, null, null); + this(file, doc, loader, null, null, false); } private XmlWriter(LogisimFile file, Document doc, LibraryLoader loader, String outFilePath) { - this(file, doc, loader, outFilePath, null); + this(file, doc, loader, outFilePath, null, false); } - private XmlWriter(LogisimFile file, Document doc, LibraryLoader loader, String outFilePath, String librariesPath) { + private XmlWriter(LogisimFile file, Document doc, LibraryLoader loader, String outFilePath, + String mainCircFile, boolean recursiveCall) { this.file = file; this.doc = doc; this.loader = loader; this.outFilePath = outFilePath; - this.librariesPath = librariesPath; - isProjectExport = StringUtil.isNotEmpty(librariesPath); + isProjectExport = StringUtil.isNotEmpty(mainCircFile); + isRecursiveCall = recursiveCall; } + /* We sort some parts of the xml tree, to help with reproducibility and to * ease testing (e.g. diff a circuit file). Attribute name=value pairs seem * to be sorted already, so we don't worry about those. The code below sorts @@ -173,8 +176,8 @@ static void sort(Node top) { } } - static void write(LogisimFile file, OutputStream out, LibraryLoader loader, File destFile, String libraryHome) - throws ParserConfigurationException, TransformerException { + static void write(LogisimFile file, OutputStream out, LibraryLoader loader, File destFile, String mainCircFile, boolean recurse) + throws ParserConfigurationException, TransformerException, IOException, LoadFailedException { final var docFactory = XmlUtil.getHardenedBuilderFactory(); final var docBuilder = docFactory.newDocumentBuilder(); @@ -185,11 +188,9 @@ static void write(LogisimFile file, OutputStream out, LibraryLoader loader, File var dstFilePath = destFile.getAbsolutePath(); dstFilePath = dstFilePath.substring(0, dstFilePath.lastIndexOf(File.separator)); context = new XmlWriter(file, doc, loader, dstFilePath); - } else if (libraryHome != null) { - context = new XmlWriter(file, doc, loader, null, libraryHome); - } else { - context = new XmlWriter(file, doc, loader); - } + } else if (mainCircFile != null) { + context = new XmlWriter(file, doc, loader, null, mainCircFile, recurse); + } else context = new XmlWriter(file, doc, loader); context.fromLogisimFile(); @@ -208,6 +209,9 @@ static void write(LogisimFile file, OutputStream out, LibraryLoader loader, File // Do nothing } + if ((mainCircFile != null) && (out instanceof ZipOutputStream zipFile)) { + zipFile.putNextEntry(new ZipEntry(mainCircFile)); + } doc.normalize(); sort(doc); Source src = new DOMSource(doc); @@ -367,7 +371,7 @@ Element fromComponent(Component comp) { return ret; } - Element fromLibrary(Library lib) { + Element fromLibrary(Library lib) throws IOException, LoadFailedException { final var ret = doc.createElement("lib"); if (libs.containsKey(lib)) return null; final var name = Integer.toString(libs.size()); @@ -377,7 +381,7 @@ Element fromLibrary(Library lib) { return null; } libs.put(lib, name); - if (isProjectExport || AppPreferences.REMOVE_UNUSED_LIBRARIES.getBoolean()) { + if (AppPreferences.REMOVE_UNUSED_LIBRARIES.getBoolean()) { // first we check if the library is used and if this is not the case we do not add it var isUsed = false; final var tools = lib.getTools(); @@ -399,18 +403,22 @@ Element fromLibrary(Library lib) { if (isProjectExport) { if (lib instanceof LoadedLibrary) { final var origFile = LibraryManager.getLibraryFilePath(file.getLoader(), desc); + final var isJarLibrary = LibraryManager.isJarLibrary(file.getLoader(), desc); if (origFile != null) { final var names = origFile.split(Pattern.quote(File.separator)); final var filename = names[names.length - 1]; - final var newFile = String.format("%s%s%s", librariesPath, File.separator, filename); - try { - Files.copy(Paths.get(origFile), Paths.get(newFile), StandardCopyOption.REPLACE_EXISTING); - } catch (IOException e) { - //TODO: error message to user - return null; + final var newFile = LineBuffer.format("{{1}}{{2}}{{3}}", Loader.LOGISIM_LIBRARY_DIR, File.separator, filename); + final var zipFile = file.getLoader().getZipFile(); + if (zipFile != null) { + if (isJarLibrary) { + writeJarToZip(zipFile, origFile, newFile); + } else { + writeLogisimFileToZip(zipFile, origFile, newFile); + } + desc = LibraryManager.getReplacementDescriptor(file.getLoader(), desc, isRecursiveCall + ? LineBuffer.format(".{{1}}{{2}}", File.separator, filename) + : LineBuffer.format(".{{1}}{{2}}{{1}}{{3}}", File.separator, Loader.LOGISIM_LIBRARY_DIR, filename)); } - final var newFilePath = LineBuffer.format("..{{1}}{{2}}{{1}}{{3}}", File.separator, Loader.LOGISIM_LIBRARY_DIR, filename); - desc = LibraryManager.getReplacementDescriptor(file.getLoader(), desc, newFilePath); } } } @@ -430,7 +438,7 @@ Element fromLibrary(Library lib) { return ret; } - Element fromLogisimFile() { + Element fromLogisimFile() throws IOException, LoadFailedException { final var ret = doc.createElement("project"); doc.appendChild(ret); ret.appendChild( @@ -537,4 +545,23 @@ boolean libraryContains(Library lib, Tool query) { } return false; } + + private void writeJarToZip(ZipOutputStream zipFile, String inputFileName, String outputFileName) throws IOException { + final var fileToRead = new File(inputFileName); + final var fileReader = new FileInputStream(fileToRead); + zipFile.putNextEntry(new ZipEntry(outputFileName)); + final var bytes = new byte[1024]; + var length = 0; + while ((length = fileReader.read(bytes)) >= 0) { + zipFile.write(bytes, 0, length); + } + fileReader.close(); + } + + private void writeLogisimFileToZip(ZipOutputStream zipFile, String inputFileName, String outputFileName) throws IOException, LoadFailedException { + final var newLoader = new Loader(null); + newLoader.setZipFile(zipFile); + final var library = newLoader.openLogisimFile(new File(inputFileName).getCanonicalFile()); + library.write(zipFile, newLoader, outputFileName, true); + } } diff --git a/src/main/java/com/cburch/logisim/gui/menu/MenuFile.java b/src/main/java/com/cburch/logisim/gui/menu/MenuFile.java index 0d220f7882..a6d93b3a04 100644 --- a/src/main/java/com/cburch/logisim/gui/menu/MenuFile.java +++ b/src/main/java/com/cburch/logisim/gui/menu/MenuFile.java @@ -34,6 +34,7 @@ class MenuFile extends Menu implements ActionListener { private final JMenuItem save = new JMenuItem(); private final JMenuItem saveAs = new JMenuItem(); private final JMenuItem exportProj = new JMenuItem(); + private final JMenuItem extractRunProj = new JMenuItem(); private final MenuItemImpl print = new MenuItemImpl(this, LogisimMenuBar.PRINT); private final MenuItemImpl exportImage = new MenuItemImpl(this, LogisimMenuBar.EXPORT_IMAGE); private final JMenuItem prefs = new JMenuItem(); @@ -63,6 +64,8 @@ public MenuFile(LogisimMenuBar menubar) { add(close); add(save); add(saveAs); + addSeparator(); + add(extractRunProj); add(exportProj); addSeparator(); add(exportImage); @@ -85,12 +88,14 @@ public MenuFile(LogisimMenuBar menubar) { save.setEnabled(false); saveAs.setEnabled(false); exportProj.setEnabled(false); + extractRunProj.setEnabled(false); } else { merge.addActionListener(this); close.addActionListener(this); save.addActionListener(this); saveAs.addActionListener(this); exportProj.addActionListener(this); + extractRunProj.addActionListener(this); } menubar.registerItem(LogisimMenuBar.EXPORT_IMAGE, exportImage); menubar.registerItem(LogisimMenuBar.PRINT, print); @@ -163,6 +168,8 @@ public void actionPerformed(ActionEvent e) { ProjectActions.doSaveAs(proj); } else if (src == exportProj) { ProjectActions.doExportProject(proj); + } else if (src == extractRunProj) { + ProjectActions.doExtractAndRunProject(proj); } } } @@ -183,6 +190,7 @@ public void localeChanged() { save.setText(S.get("fileSaveItem")); saveAs.setText(S.get("fileSaveAsItem")); exportProj.setText(S.get("fileExportProject")); + extractRunProj.setText(S.get("fileExtractRunProject")); exportImage.setText(S.get("fileExportImageItem")); print.setText(S.get("filePrintItem")); prefs.setText(S.get("filePreferencesItem")); diff --git a/src/main/java/com/cburch/logisim/proj/ProjectActions.java b/src/main/java/com/cburch/logisim/proj/ProjectActions.java index 056d7eaeed..99bb39d073 100644 --- a/src/main/java/com/cburch/logisim/proj/ProjectActions.java +++ b/src/main/java/com/cburch/logisim/proj/ProjectActions.java @@ -17,6 +17,7 @@ import com.cburch.logisim.file.Loader; import com.cburch.logisim.file.LogisimFile; import com.cburch.logisim.file.LogisimFileActions; +import com.cburch.logisim.generated.BuildInfo; import com.cburch.logisim.gui.generic.OptionPane; import com.cburch.logisim.gui.main.Frame; import com.cburch.logisim.gui.start.SplashScreen; @@ -26,6 +27,7 @@ import com.cburch.logisim.util.JFileChoosers; import java.awt.Component; import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; @@ -37,6 +39,10 @@ import java.util.HashSet; import java.util.Map; import java.util.regex.Pattern; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import java.util.zip.ZipOutputStream; + import javax.swing.JFileChooser; import javax.swing.JOptionPane; import javax.swing.SwingUtilities; @@ -396,59 +402,182 @@ public static boolean doSave(Project proj, File f) { } /** - * Exports a Logisim project in a seperate directory + * Imports a Logisim project in a zip file * - *

It is the action listener for the File->Export project... menu option. + *

It is the action listener for the File->Import project bundle... menu option. * - * @param proj Project to be exported - * @return true if success, false otherwise + * @param proj the current project to perform the file->open action afterwards + * @return true if success, false otherwise */ - public static boolean doExportProject(Project proj) { - var ret = proj.isFileDirty() ? doSave(proj) : true; - if (ret) { - final var loader = proj.getLogisimFile().getLoader(); - final var oldTool = proj.getTool(); - proj.setTool(null); - final var chooser = loader.createChooser(); - chooser.setFileFilter(Loader.LOGISIM_DIRECTORY); - chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + public static boolean doExtractAndRunProject(Project proj) { + var ret = true; + final var loader = proj.getLogisimFile().getLoader(); + final var chooser = loader.createChooser(); + var isCorrectFile = true; + do { + chooser.setFileFilter(Loader.LOGISIM_BUNDLE_FILTER); chooser.setAcceptAllFileFilterUsed(false); - var isCorrectDirectory = false; - var exportRootDir = ""; - do { - ret &= chooser.showSaveDialog(proj.getFrame()) == JFileChooser.APPROVE_OPTION; - if (!ret) { - proj.setTool(oldTool); - return false; - } - final var exportHome = chooser.getSelectedFile(); - final var exportRoot = loader.getMainFile().getName().replace(".circ", ""); - exportRootDir = String.format("%s%s%s", exportHome, File.separator, exportRoot); - final var exportLibDir = String.format("%s%s%s", exportRootDir, File.separator, Loader.LOGISIM_LIBRARY_DIR); - final var exportCircDir = String.format("%s%s%s", exportRootDir, File.separator, Loader.LOGISIM_CIRCUIT_DIR); + chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); + chooser.setDialogTitle(S.get("projImportBundle")); + ret &= chooser.showOpenDialog(proj.getFrame()) == JFileChooser.APPROVE_OPTION; + if (!ret) return ret; + final var zipFileName = chooser.getSelectedFile().getAbsolutePath(); + isCorrectFile = Files.exists(Paths.get(zipFileName)); + if (isCorrectFile) { try { - final var path = Paths.get(exportRootDir); - if (Files.exists(path)) { - OptionPane.showMessageDialog(proj.getFrame(), S.get("ProjExistsUnableToCreate", exportRoot)); - } else { - isCorrectDirectory = true; + final var zipFile = new ZipFile(zipFileName); + final var bundleInfo = ProjectBundleManifest.getManifestInfo(zipFile, proj.getFrame()); + if (bundleInfo == null) return false; + final var mainFileEntry = zipFile.getEntry(bundleInfo.getMainLogisimFilename()); + if (mainFileEntry == null) { + OptionPane.showMessageDialog(proj.getFrame(), S.fmt("projBundleReadError", S.get("projBundleMainNotFound"))); + return false; } - if (isCorrectDirectory) { - Files.createDirectories(Paths.get(exportLibDir)); - Files.createDirectories(Paths.get(exportCircDir)); + final var readmeFileEntry = zipFile.getEntry(ProjectBundleReadme.README_FILE_NAME); + if (readmeFileEntry != null) { + final var readmeInStream = zipFile.getInputStream(readmeFileEntry); + final var dialog = new ProjectBundleReadme(proj, ""); + dialog.showReadme(readmeInStream); + readmeInStream.close(); } + chooser.setFileFilter(Loader.LOGISIM_DIRECTORY); + chooser.setAcceptAllFileFilterUsed(false); + chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + chooser.setDialogTitle(S.get("projBundleDirectory")); + var isCorrectDirectory = true; + do { + ret &= chooser.showOpenDialog(proj.getFrame()) == JFileChooser.APPROVE_OPTION; + if (!ret) return ret; + final var exportDirectory = chooser.getSelectedFile().getAbsolutePath(); + final var mainProjectFileName = String.format("%s%s%s", exportDirectory, File.separator, bundleInfo.getMainLogisimFilename()); + var filename = mainProjectFileName; + if (Files.exists(Paths.get(filename)) + || Files.exists(Paths.get(String.format("%s%s%s", exportDirectory, File.separator, Loader.LOGISIM_LIBRARY_DIR)))) { + isCorrectDirectory = false; + OptionPane.showMessageDialog(proj.getFrame(), S.fmt("projContainsFileDir", bundleInfo.getMainLogisimFilename(), Loader.LOGISIM_LIBRARY_DIR)); + } else { + isCorrectDirectory = true; + // extract the main file + var zipInput = zipFile.getInputStream(mainFileEntry); + var fileOutput = new FileOutputStream(filename); + var data = zipInput.read(); + while (data > 0) { + fileOutput.write(data); + data = zipInput.read(); + } + zipInput.close(); + fileOutput.close(); + final var zipFileEntries = zipFile.entries(); + final var libDir = String.format("%s%s%s", exportDirectory, File.separator, Loader.LOGISIM_LIBRARY_DIR); + while (zipFileEntries.hasMoreElements()) { + final var entry = zipFileEntries.nextElement(); + if (entry.isDirectory()) { + final var dirName = entry.getName(); + if (!dirName.equals(Loader.LOGISIM_LIBRARY_DIR)) continue; + new File(String.format("%s%s%s", exportDirectory, File.separator, dirName)).mkdirs(); + } else { + final var entryName = entry.getName(); + if (!entryName.startsWith(String.format("%s%s", Loader.LOGISIM_LIBRARY_DIR, File.separator))) continue; + if (entryName.lastIndexOf(File.separator) != entryName.indexOf(File.separator)) continue; + if (!entryName.endsWith(Loader.LOGISIM_EXTENSION) + && !entryName.toLowerCase().endsWith(".jar")) { + continue; + } + // make sure the library dir exists + if (!Files.exists(Paths.get(libDir))) new File(libDir).mkdirs(); + filename = String.format("%s%s%s", exportDirectory, File.separator, entry.getName()); + zipInput = zipFile.getInputStream(entry); + fileOutput = new FileOutputStream(filename); + final var bytes = new byte[1024]; + var length = 0; + while (((length = zipInput.read(bytes)) >= 0)) { + fileOutput.write(bytes, 0, length); + } + fileOutput.close(); + zipInput.close(); + } + } + ProjectActions.doOpen(proj.getFrame().getCanvas(), proj, new File(mainProjectFileName)); + } + } while (!isCorrectDirectory); + zipFile.close(); } catch (IOException e) { - OptionPane.showMessageDialog(proj.getFrame(), S.get("ProjUnableToCreate", e.getMessage())); - proj.setTool(oldTool); - return false; + isCorrectFile = false; + OptionPane.showMessageDialog(proj.getFrame(), S.fmt("fileOpenError", + String.format("%s\n%s", zipFileName, e.getMessage()))); } - } while (!isCorrectDirectory); - ret &= loader.export(proj.getLogisimFile(), exportRootDir); - proj.setTool(oldTool); - } + } else { + OptionPane.showMessageDialog(proj.getFrame(), S.fmt("fileOpenError", zipFileName)); + } + } while (!isCorrectFile); + return ret; + } + + /** + * Exports a Logisim project in a zip file + * + *

It is the action listener for the File->Export project bundle... menu option. + * + * @param proj Project to be exported + * @return true if success, false otherwise + */ + public static boolean doExportProject(Project proj) { + var ret = true; + final var loader = proj.getLogisimFile().getLoader(); + final var oldTool = proj.getTool(); + proj.setTool(null); + var mainFileName = loader.getMainFile() == null ? "Untitled.circ" : loader.getMainFile().getName(); + var zipFile = mainFileName.replace(Loader.LOGISIM_EXTENSION, Loader.LOGISIM_PROJECT_BUNDLE_EXTENSION); + final var chooser = loader.createChooser(); + chooser.setFileFilter(Loader.LOGISIM_BUNDLE_FILTER); + chooser.setAcceptAllFileFilterUsed(false); + chooser.setSelectedFile(new File(zipFile)); + chooser.setDialogTitle(S.get("projExportBundle")); + var isCorrectFile = true; + do { + ret &= chooser.showSaveDialog(proj.getFrame()) == JFileChooser.APPROVE_OPTION; + if (!ret) { + proj.setTool(oldTool); + return false; + } + try { + zipFile = chooser.getSelectedFile().getAbsolutePath(); + if (!zipFile.endsWith(Loader.LOGISIM_PROJECT_BUNDLE_EXTENSION)) { + zipFile = zipFile.concat(Loader.LOGISIM_PROJECT_BUNDLE_EXTENSION); + } + final var path = Paths.get(zipFile); + if (Files.exists(path)) { + isCorrectFile = OptionPane.showConfirmDialog(proj.getFrame(), S.fmt("projExistsOverwrite", + new File(zipFile).getName()), S.get("projExportBundle"), OptionPane.YES_NO_OPTION) == OptionPane.YES_OPTION; + } else { + isCorrectFile = true; + } + if (isCorrectFile) { + final var dialog = new ProjectBundleReadme(proj, mainFileName.replace(Loader.LOGISIM_EXTENSION, "")); + final var readmeInfo = dialog.getReadmeInfo(); + if (readmeInfo == null) return false; + final var projectFile = new FileOutputStream(zipFile); + final var projectZipFile = new ZipOutputStream(projectFile); + ProjectBundleReadme.writeReadmeFile(projectZipFile, readmeInfo); + projectZipFile.putNextEntry(new ZipEntry(String.format("%s%s", Loader.LOGISIM_LIBRARY_DIR, File.separator))); + mainFileName = chooser.getSelectedFile().getName().replace(Loader.LOGISIM_PROJECT_BUNDLE_EXTENSION, "").concat(Loader.LOGISIM_EXTENSION); + ret &= loader.export(proj.getLogisimFile(), projectZipFile, mainFileName); + final var info = ProjectBundleManifest.getInfoContainer(BuildInfo.displayName, mainFileName); + ProjectBundleManifest.writeManifest(projectZipFile, info); + projectZipFile.close(); + projectFile.close(); + } + } catch (IOException e) { + OptionPane.showMessageDialog(proj.getFrame(), S.get("ProjUnableToCreate", e.getMessage())); + proj.setTool(oldTool); + return false; + } + } while (!isCorrectFile); + proj.setTool(oldTool); return ret; } + /** * Saves a Logisim project in a .circ file. * diff --git a/src/main/java/com/cburch/logisim/proj/ProjectBundleManifest.java b/src/main/java/com/cburch/logisim/proj/ProjectBundleManifest.java new file mode 100644 index 0000000000..4919a1a9a0 --- /dev/null +++ b/src/main/java/com/cburch/logisim/proj/ProjectBundleManifest.java @@ -0,0 +1,203 @@ +/* + * Logisim-evolution - digital logic design tool and simulator + * Copyright by the Logisim-evolution developers + * + * https://github.com/logisim-evolution/ + * + * This is free software released under GNU GPLv3 license + */ + +package com.cburch.logisim.proj; + +import static com.cburch.logisim.proj.Strings.S; + +import java.io.IOException; +import java.io.StringWriter; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import java.util.zip.ZipOutputStream; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +import org.w3c.dom.Text; +import org.xml.sax.SAXException; + +import com.cburch.logisim.gui.generic.OptionPane; +import com.cburch.logisim.gui.main.Frame; +import com.cburch.logisim.util.XmlUtil; + +public class ProjectBundleManifest { + + public static class infofileInformation { + private final String logisimVersion; + private final String mainCircuitFile; + + public infofileInformation(String logisimVersion, String mainCircuitFile) { + this.logisimVersion = logisimVersion; + this.mainCircuitFile = mainCircuitFile; + } + + public String getBundleLogisimVersion() { + return logisimVersion; + } + + public String getMainLogisimFilename() { + return mainCircuitFile; + } + } + + public static infofileInformation getInfoContainer(String logisimVersion, String mainCircuitFile) { + return new infofileInformation(logisimVersion, mainCircuitFile); + } + + /** + * This function writes the manifest file to a given zip-file + * + * @param zipfile Zipfile to write to + * @param info Logisim version with which this manifest was created and main-circuit-file + * @throws IOException + */ + public static void writeManifest(ZipOutputStream zipfile, infofileInformation info) throws IOException { + if (zipfile == null) return; + try { + final var factory = XmlUtil.getHardenedBuilderFactory(); + final var parser = factory.newDocumentBuilder(); + final var boardInfo = parser.newDocument(); + final var manifest = boardInfo.createElement("logisim"); + boardInfo.appendChild(manifest); + manifest.setAttribute("type", "bundle"); + manifest.setAttribute("version", "1"); + final var meta = boardInfo.createElement("meta"); + manifest.appendChild(meta); + final var progInfo = boardInfo.createElement("tool"); + meta.appendChild(progInfo); + final var parts = info.logisimVersion.split(" "); + progInfo.setAttribute("name", parts[0]); + if (parts.length > 1) { + progInfo.setAttribute("version", parts[1]); + } + final var project = boardInfo.createElement("project"); + manifest.appendChild(project); + final var files = boardInfo.createElement("files"); + project.appendChild(files); + final var mainFile = boardInfo.createElement("file"); + files.appendChild(mainFile); + mainFile.setAttribute("main", "true"); + final var fileName = boardInfo.createTextNode(info.mainCircuitFile); + mainFile.appendChild(fileName); + final var tranFactory = TransformerFactory.newInstance(); + final var aTransformer = tranFactory.newTransformer(); + aTransformer.setOutputProperty(OutputKeys.INDENT, "yes"); + final var src = new DOMSource(boardInfo); + final var dest = new StreamResult(new StringWriter()); + aTransformer.transform(src, dest); + zipfile.putNextEntry(new ZipEntry("manifest.xml")); + zipfile.write(dest.getWriter().toString().getBytes()); + } catch (ParserConfigurationException e) { + System.err.println(e.getMessage()); + } catch (TransformerConfigurationException e) { + System.err.println(e.getMessage()); + } catch (TransformerException e) { + System.err.println(e.getMessage()); + } + } + + /** + * This function reads the contents of the manifest-file from a given zip-file + * + * @param zipFile zipfile to read from + * @param frame parrent frame of the caller + * @return Information contained in the manifest-file + * @throws IOException + */ + public static infofileInformation getManifestInfo(ZipFile zipFile, Frame frame) throws IOException { + try { + final var factory = XmlUtil.getHardenedBuilderFactory(); + final var parser = factory.newDocumentBuilder(); + final var projInfoEntry = zipFile.getEntry("manifest.xml"); + if (projInfoEntry == null) { + OptionPane.showMessageDialog(frame, S.fmt("projBundleReadError", S.get("projBundleNoInfo"))); + return null; + } + final var projInfoStream = zipFile.getInputStream(projInfoEntry); + final var docInfo = parser.parse(projInfoStream); + final var manifestNodes = docInfo.getElementsByTagName("logisim"); + if (manifestNodes.getLength() != 1) { + OptionPane.showMessageDialog(frame, S.fmt("projBundleReadError", S.get("projBundleMisformatted"))); + return null; + } + final var manifestNode = manifestNodes.item(0); + final var manifestInfo = manifestNode.getChildNodes(); + // first we find the version of the manifest to check if we can process + final var nodeAttr = manifestNode.getAttributes(); + if (nodeAttr.getLength() != 2) { + OptionPane.showMessageDialog(frame, S.fmt("projBundleReadError", S.get("projBundleMisformatted"))); + return null; + } + final var attr0 = nodeAttr.item(0); + final var attr1 = nodeAttr.item(1); + if (!"type".equals(attr0.getNodeName()) || !"bundle".equals(attr0.getNodeValue()) + || !"version".equals(attr1.getNodeName()) || !"1".equals(attr1.getNodeValue())) { + OptionPane.showMessageDialog(frame, S.fmt("projBundleReadError", S.get("projBundleMisformatted"))); + return null; + } + // now we find the info of the main file + var main = ""; + var creator = ""; + for (var nodeId = 0; nodeId < manifestInfo.getLength(); nodeId++) { + final var node = manifestInfo.item(nodeId); + if ("project".equals(node.getNodeName())) { + final var projectChilds = node.getChildNodes(); + for (var childId = 0; childId < projectChilds.getLength(); childId++) { + final var childNode = projectChilds.item(childId); + if ("files".equals(childNode.getNodeName())) { + final var fileNodes = childNode.getChildNodes(); + for (var fileId = 0; fileId < fileNodes.getLength(); fileId++) { + final var fileNode = fileNodes.item(fileId); + if ("file".equals(fileNode.getNodeName())) { + final var fileAttrs = fileNode.getAttributes(); + if (fileAttrs.getLength() == 1 && "main".equals(fileAttrs.item(0).getNodeName()) + && "true".equals(fileAttrs.item(0).getNodeValue())) { + final var mainNodes = fileNode.getChildNodes(); + if ((mainNodes.getLength() == 1) && (mainNodes.item(0) instanceof Text filename)) { + main = filename.getNodeValue(); + } + } + } + } + } + } + } else if ("meta".equals(node.getNodeName())) { + final var metaChilds = node.getChildNodes(); + for (var metaId = 0; metaId < metaChilds.getLength(); metaId++) { + final var metaNode = metaChilds.item(metaId); + if ("tool".equals(metaNode.getNodeName())) { + final var metaAttrs = metaNode.getAttributes(); + if (metaAttrs.getLength() == 2) { + final var metaAttr1 = metaAttrs.item(0); + final var metaAttr2 = metaAttrs.item(1); + if ("name".equals(metaAttr1.getNodeName()) && "version".equals(metaAttr2.getNodeName())) { + creator = String.format("%s %s", metaAttr1.getNodeValue(), metaAttr2.getNodeValue()); + } + } + } + } + } + } + if (!main.isEmpty() && !creator.isEmpty()) { + return new infofileInformation(creator, main); + } + } catch (ParserConfigurationException e) { + System.err.println(e.getMessage()); + } catch (SAXException e) { + System.err.println(e.getMessage()); + } + return null; + } +} diff --git a/src/main/java/com/cburch/logisim/proj/ProjectBundleReadme.java b/src/main/java/com/cburch/logisim/proj/ProjectBundleReadme.java new file mode 100644 index 0000000000..775b62000e --- /dev/null +++ b/src/main/java/com/cburch/logisim/proj/ProjectBundleReadme.java @@ -0,0 +1,228 @@ +/* + * Logisim-evolution - digital logic design tool and simulator + * Copyright by the Logisim-evolution developers + * + * https://github.com/logisim-evolution/ + * + * This is free software released under GNU GPLv3 license + */ + +package com.cburch.logisim.proj; + +import static com.cburch.logisim.proj.Strings.S; + +import java.io.IOException; +import java.io.InputStream; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JEditorPane; +import javax.swing.JLabel; +import javax.swing.JScrollPane; +import javax.swing.JTextField; +import javax.swing.SwingConstants; + +import java.awt.BorderLayout; +import java.awt.GridBagLayout; +import java.awt.GridBagConstraints; +import java.awt.Dimension; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import com.cburch.logisim.generated.BuildInfo; +import com.cburch.logisim.gui.main.Frame; +import com.cburch.logisim.prefs.AppPreferences; +import com.cburch.logisim.util.StringUtil; +import com.vladsch.flexmark.html.HtmlRenderer; +import com.vladsch.flexmark.parser.Parser; +import com.vladsch.flexmark.util.data.MutableDataSet; + +public class ProjectBundleReadme extends JDialog implements ActionListener { + + public static final String README_FILE_NAME = "README.md"; + + private JButton closeButton = new JButton(); + private JButton writeButton = new JButton(); + private JTextField projectName = new JTextField(20); + private JTextField projectAuthor = new JTextField(20); + private JTextField projectKeywords = new JTextField(20); + private JEditorPane projectDescription = new JEditorPane(); + private ReadmeInfo projectReadmeInfo; + private final Frame parrent; + + public class ReadmeInfo { + private String projectName; + private String projectAuthor; + private String projectKeywords; + private String projectDescription; + + public ReadmeInfo(String name, String author, String keyword, String description) { + projectName = name; + projectAuthor = author; + projectKeywords = keyword; + projectDescription = description; + } + } + + public ProjectBundleReadme(Project project, String projName) { + super(project.getFrame(), S.get("projBundleReadmeWindow")); + setModal(true); + setDefaultCloseOperation(DISPOSE_ON_CLOSE); + setAlwaysOnTop(true); + setVisible(false); + closeButton.addActionListener(this); + writeButton.addActionListener(this); + projectName.setText(projName); + parrent = project.getFrame(); + } + + public void showReadme(InputStream file) throws IOException { + final var lines = new StringBuilder(); + var kar = 0; + do { + kar = file.read(); + if (kar >= 0) lines.append((char) kar); + } while (kar >= 0); + final var options = new MutableDataSet(); + final var parser = Parser.builder(options).build(); + final var renderer = HtmlRenderer.builder(options).build(); + final var readme = parser.parse(lines.toString()); + final var text = renderer.render(readme); + final var dialog = new JEditorPane("text/html", text); + dialog.setEditable(false); + dialog.setCaretPosition(0); + final var scroller = new JScrollPane(dialog); + setLayout(new BorderLayout()); + add(scroller, BorderLayout.CENTER); + closeButton.setText(S.get("projCloseReadme")); + add(closeButton, BorderLayout.SOUTH); + pack(); + setLocationRelativeTo(parrent); + setVisible(true); + } + + public ReadmeInfo getReadmeInfo() { + setLayout(new GridBagLayout()); + setResizable(false); + final var gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 0; + gbc.fill = GridBagConstraints.HORIZONTAL; + add(new JLabel(S.get("projName")), gbc); + gbc.gridx = 1; + add(projectName, gbc); + gbc.gridx = 0; + gbc.gridy++; + add(new JLabel(S.get("projAuthor")), gbc); + gbc.gridx = 1; + add(projectAuthor, gbc); + gbc.gridx = 0; + gbc.gridy++; + add(new JLabel(S.get("projKeywords")), gbc); + gbc.gridx = 1; + add(projectKeywords, gbc); + gbc.gridx = 0; + gbc.gridy++; + gbc.gridwidth = 2; + add(new JLabel(S.get("projDescription"), SwingConstants.CENTER), gbc); + gbc.gridy++; + final var scroller = new JScrollPane(projectDescription); + scroller.setPreferredSize(new Dimension(AppPreferences.getScaled(500), AppPreferences.getScaled(300))); + add(scroller, gbc); + gbc.gridx = 0; + gbc.gridy++; + gbc.gridwidth = 1; + closeButton.setText(S.get("projCancel")); + gbc.gridx = 1; + add(closeButton, gbc); + writeButton.setText(S.get("projWriteReadme")); + gbc.gridx = 0; + add(writeButton, gbc); + pack(); + setLocationRelativeTo(parrent); + setVisible(true); + return projectReadmeInfo; + } + + @Override + public void actionPerformed(ActionEvent e) { + if (closeButton.equals(e.getSource())) { + setVisible(false); + dispose(); + } else if (writeButton.equals(e.getSource())) { + projectReadmeInfo = new ReadmeInfo(projectName.getText(), projectAuthor.getText(), + projectKeywords.getText(), projectDescription.getText()); + setVisible(false); + dispose(); + } + } + + public static void writeReadmeFile(ZipOutputStream zipfile, ReadmeInfo info) { + if ((zipfile == null) || (StringUtil.isNullOrEmpty(info.projectAuthor) + && StringUtil.isNullOrEmpty(info.projectDescription) && StringUtil.isNullOrEmpty(info.projectKeywords))) return; + try { + final var seperator = "---\n\n"; + var wroteheader1 = false; + zipfile.putNextEntry(new ZipEntry(README_FILE_NAME)); + zipfile.write(S.get("projHeader").concat("\n\n").getBytes()); + final var projName = info.projectName; + if (StringUtil.isNotEmpty(projName)) { + zipfile.write(S.get("projHeader1").concat("\n\n").getBytes()); + wroteheader1 = true; + zipfile.write(S.fmt("projIntro", projName).concat("\n\n").getBytes()); + } + final var projAuthor = info.projectAuthor; + if (StringUtil.isNotEmpty(projAuthor)) { + final var authors = projAuthor.split(","); + if (authors.length > 0) { + if (!wroteheader1) { + zipfile.write(S.get("projHeader1").concat("\n\n").getBytes()); + wroteheader1 = true; + } + zipfile.write(S.get("projAuthor").getBytes()); + for (var authorId = 0; authorId < authors.length; authorId++) { + if (authorId > 0) { + var authSep = authorId == (authors.length - 1) ? authors.length == 2 ? " and " : ", and " : ", "; + zipfile.write(authSep.getBytes()); + } + zipfile.write(String.format("`%s`", authors[authorId]).getBytes()); + } + zipfile.write("\n\n".getBytes()); + } + } + final var projKeywords = info.projectKeywords; + if (StringUtil.isNotEmpty(projKeywords)) { + final var keywords = projKeywords.split(","); + if (keywords.length > 0) { + if (!wroteheader1) { + zipfile.write(S.get("projHeader1").concat("\n\n").getBytes()); + wroteheader1 = true; + } else { + zipfile.write(seperator.getBytes()); + } + for (var keywordId = 0; keywordId < keywords.length; keywordId++) { + if (keywordId > 0) zipfile.write(", ".getBytes()); + zipfile.write(String.format("`%s`", keywords[keywordId]).getBytes()); + } + zipfile.write("\n\n".getBytes()); + } + } + final var projDescription = info.projectDescription; + if (StringUtil.isNotEmpty(projDescription)) { + zipfile.write(S.get("projHeader2").concat("\n\n").getBytes()); + zipfile.write(projDescription.getBytes()); + zipfile.write("\n".getBytes()); + } + final var dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss"); + final var now = LocalDateTime.now(); + zipfile.write(S.get("projHeader3").concat("\n\n").getBytes()); + zipfile.write(S.fmt("projGenerateInfo", BuildInfo.displayName, BuildInfo.url, dtf.format(now)).concat("\n\n").getBytes()); + } catch (IOException e) { + System.err.println(e.getMessage()); + } + } +} diff --git a/src/main/resources/resources/logisim/strings/file/file.properties b/src/main/resources/resources/logisim/strings/file/file.properties index 90b7818217..b9a044d9e7 100644 --- a/src/main/resources/resources/logisim/strings/file/file.properties +++ b/src/main/resources/resources/logisim/strings/file/file.properties @@ -28,6 +28,7 @@ jarFileFilter = Java Archive (*.jar) jarLibraryNotCreatedError = The %s library could not be instantiated. logisimCircularError = The file %s contains within it a reference to itself. logisimFileFilter = Logisim project (*.circ) +logisimProjectBundleFilter = Logisim project bundle (*.lsebdl) logisimDirectoryFilter = Logisim project directory logisimLoadError = Error encountered opening %s: %s tclFileFilter = TCL files (*.tcl) diff --git a/src/main/resources/resources/logisim/strings/file/file_de.properties b/src/main/resources/resources/logisim/strings/file/file_de.properties index ffb7f258ac..47b4d78fe6 100644 --- a/src/main/resources/resources/logisim/strings/file/file_de.properties +++ b/src/main/resources/resources/logisim/strings/file/file_de.properties @@ -28,6 +28,7 @@ jarFileFilter = Java-Archiv (*.jar) jarLibraryNotCreatedError = Die Bibliothek %s konnte nicht instanziiert werden. logisimCircularError = Die Datei %s enthält einen Verweis auf sich selbst. logisimFileFilter = Logisim-Projekt (*.circ) +# == > logisimProjectBundleFilter = logisimDirectoryFilter = Logisim Projektverzeichniss logisimLoadError = Fehler beim Öffnen von %s: %s tclFileFilter = TCL-Dateien (*.tcl) diff --git a/src/main/resources/resources/logisim/strings/file/file_el.properties b/src/main/resources/resources/logisim/strings/file/file_el.properties index 5a9a955a64..8e698bf1be 100644 --- a/src/main/resources/resources/logisim/strings/file/file_el.properties +++ b/src/main/resources/resources/logisim/strings/file/file_el.properties @@ -28,6 +28,7 @@ jarFileFilter = Java Archive (*.jar) jarLibraryNotCreatedError = Η βιβλιοθήκη %s δεν ήταν δυνατόν να αρχικοποιηθεί. logisimCircularError = Το αρχείο %s περιέχει μέσα του μια αναφορά στο ίδιο (αυτοαναφορά). logisimFileFilter = Έργο Logisim (*.circ) +# == > logisimProjectBundleFilter = # ==> logisimDirectoryFilter = logisimLoadError = Σφάλμα παρουσιάστηκε κατά το άνοιγμα %s: %s # ==> tclFileFilter = diff --git a/src/main/resources/resources/logisim/strings/file/file_es.properties b/src/main/resources/resources/logisim/strings/file/file_es.properties index 394339b6cb..34068e3eee 100644 --- a/src/main/resources/resources/logisim/strings/file/file_es.properties +++ b/src/main/resources/resources/logisim/strings/file/file_es.properties @@ -28,6 +28,7 @@ jarFileFilter = Archivo Java (*.jar) jarLibraryNotCreatedError = La librería %s no ha podido ser instanciada. logisimCircularError = El archivo %s contiene una referencia a sí mismo. logisimFileFilter = Proyecto Logisim (*.circ) +# == > logisimProjectBundleFilter = # ==> logisimDirectoryFilter = logisimLoadError = Error encontrado al abrir %s: %s tclFileFilter = Archivos TCL (*.tcl) diff --git a/src/main/resources/resources/logisim/strings/file/file_fr.properties b/src/main/resources/resources/logisim/strings/file/file_fr.properties index a322f39c5f..d97d34e181 100644 --- a/src/main/resources/resources/logisim/strings/file/file_fr.properties +++ b/src/main/resources/resources/logisim/strings/file/file_fr.properties @@ -28,6 +28,7 @@ jarFileFilter = Archives Java (*.jar) jarLibraryNotCreatedError = La librairie %s n'a pas pu être installée. logisimCircularError = Le fichier %s contient une référence à lui-même. logisimFileFilter = Projets Logisim (*.circ) +# == > logisimProjectBundleFilter = # ==> logisimDirectoryFilter = logisimLoadError = Erreur rencontrée à l'ouverture de %s : %s tclFileFilter = Fichiers TCL (*.tcl) diff --git a/src/main/resources/resources/logisim/strings/file/file_it.properties b/src/main/resources/resources/logisim/strings/file/file_it.properties index c3299d5b9b..15a091b37c 100644 --- a/src/main/resources/resources/logisim/strings/file/file_it.properties +++ b/src/main/resources/resources/logisim/strings/file/file_it.properties @@ -28,6 +28,7 @@ jarFileFilter = Archivio Java (*.jar) jarLibraryNotCreatedError = La libreria %s non può essere istanziata. logisimCircularError = Il file %s contiene al suo interno un riferimento a se stesso. logisimFileFilter = Progetto Logisim (*.circ) +# == > logisimProjectBundleFilter = # ==> logisimDirectoryFilter = logisimLoadError = Errore incontrato aprendo %s: %s tclFileFilter = File TCL (*.tcl) diff --git a/src/main/resources/resources/logisim/strings/file/file_ja.properties b/src/main/resources/resources/logisim/strings/file/file_ja.properties index 6f52b62418..aca354843e 100644 --- a/src/main/resources/resources/logisim/strings/file/file_ja.properties +++ b/src/main/resources/resources/logisim/strings/file/file_ja.properties @@ -28,6 +28,7 @@ jarFileFilter = Java Archive (*.jar) jarLibraryNotCreatedError = %s ライブラリをインスタンス化できませんでした。 logisimCircularError = ファイル %s にはそれ自身への参照が含まれています。 logisimFileFilter = Logisim プロジェクト (*.circ) +# == > logisimProjectBundleFilter = # ==> logisimDirectoryFilter = logisimLoadError = エラーが発生しました。 tclFileFilter = TCL ファイル (*.tcl) diff --git a/src/main/resources/resources/logisim/strings/file/file_nl.properties b/src/main/resources/resources/logisim/strings/file/file_nl.properties index 04bc171e17..1c8c3b3c67 100644 --- a/src/main/resources/resources/logisim/strings/file/file_nl.properties +++ b/src/main/resources/resources/logisim/strings/file/file_nl.properties @@ -28,6 +28,7 @@ jarFileFilter = Java-archief (*.jar) jarLibraryNotCreatedError = De %s bibliotheek kon niet worden geïnstrueerd. logisimCircularError = Het bestand %s bevat een verwijzing naar zichzelf. logisimFileFilter = Logisim Project (*.circ) +# == > logisimProjectBundleFilter = # ==> logisimDirectoryFilter = logisimLoadError = Fout bij het openen %s: %s tclFileFilter = TCL bestanden (*.tcl) diff --git a/src/main/resources/resources/logisim/strings/file/file_pl.properties b/src/main/resources/resources/logisim/strings/file/file_pl.properties index d046d29221..dfb80724ad 100644 --- a/src/main/resources/resources/logisim/strings/file/file_pl.properties +++ b/src/main/resources/resources/logisim/strings/file/file_pl.properties @@ -28,6 +28,7 @@ jarFileFilter = Archiwum Java (*.jar) jarLibraryNotCreatedError = Biblioteka %s nie może zostać utworzona. logisimCircularError = Plik %s zawiera odniesienia do siebie samego. logisimFileFilter = Projekt Logisim (*.circ) +# == > logisimProjectBundleFilter = logisimDirectoryFilter = Katalog z projektem Logisim logisimLoadError = Napotkano błąd poczas otwierania %s: %s tclFileFilter = Pliki TCL (*.tcl) diff --git a/src/main/resources/resources/logisim/strings/file/file_pt.properties b/src/main/resources/resources/logisim/strings/file/file_pt.properties index b1e0ebc891..da3b76d898 100644 --- a/src/main/resources/resources/logisim/strings/file/file_pt.properties +++ b/src/main/resources/resources/logisim/strings/file/file_pt.properties @@ -28,6 +28,7 @@ jarFileFilter = Arquivo compactado Java (*.jar) jarLibraryNotCreatedError = Impossível instanciar a biblioteca %s. logisimCircularError = O arquivo %s contém uma referência circular. logisimFileFilter = Projeto do Logisim (*.circ) +# == > logisimProjectBundleFilter = # ==> logisimDirectoryFilter = logisimLoadError = Erro encontrado ao abrir %s: %s tclFileFilter = Arquivos TCL (*.tcl) diff --git a/src/main/resources/resources/logisim/strings/file/file_ru.properties b/src/main/resources/resources/logisim/strings/file/file_ru.properties index 40d4382d13..3c6b456530 100644 --- a/src/main/resources/resources/logisim/strings/file/file_ru.properties +++ b/src/main/resources/resources/logisim/strings/file/file_ru.properties @@ -28,6 +28,7 @@ jarFileFilter = Архив Java (*.jar) jarLibraryNotCreatedError = Невозможно создать экземпляр библиотеки %s. logisimCircularError = Файл %s содержит ссылку на себя. logisimFileFilter = Проект Logisim (*.circ) +# == > logisimProjectBundleFilter = # ==> logisimDirectoryFilter = logisimLoadError = Произошла ошибка открытия %s: %s tclFileFilter = TCL файлы (*.tcl) diff --git a/src/main/resources/resources/logisim/strings/gui/gui.properties b/src/main/resources/resources/logisim/strings/gui/gui.properties index 712b00c099..313422406c 100644 --- a/src/main/resources/resources/logisim/strings/gui/gui.properties +++ b/src/main/resources/resources/logisim/strings/gui/gui.properties @@ -339,7 +339,8 @@ filePrintItem = Print... fileQuitItem = Exit fileSaveAsItem = Save As... fileSaveItem = Save -fileExportProject = Export project +fileExportProject = Export project bundle... +fileExtractRunProject = Extract and open project bundle... # # menu/MenuHelp.java # diff --git a/src/main/resources/resources/logisim/strings/gui/gui_de.properties b/src/main/resources/resources/logisim/strings/gui/gui_de.properties index abe7990e2a..16998ed1ec 100644 --- a/src/main/resources/resources/logisim/strings/gui/gui_de.properties +++ b/src/main/resources/resources/logisim/strings/gui/gui_de.properties @@ -340,6 +340,7 @@ fileQuitItem = Beenden fileSaveAsItem = Speichern unter... fileSaveItem = Speichern # ==> fileExportProject = +# ==> fileExtractRunProject = # # menu/MenuHelp.java # diff --git a/src/main/resources/resources/logisim/strings/gui/gui_el.properties b/src/main/resources/resources/logisim/strings/gui/gui_el.properties index faa27b1586..eb16614728 100644 --- a/src/main/resources/resources/logisim/strings/gui/gui_el.properties +++ b/src/main/resources/resources/logisim/strings/gui/gui_el.properties @@ -340,6 +340,7 @@ fileQuitItem = Έξοδος fileSaveAsItem = Αποθήκευση ως... fileSaveItem = Αποθήκευση # ==> fileExportProject = +# ==> fileExtractRunProject = # # menu/MenuHelp.java # diff --git a/src/main/resources/resources/logisim/strings/gui/gui_es.properties b/src/main/resources/resources/logisim/strings/gui/gui_es.properties index b9a277c9b9..f51ce764c9 100644 --- a/src/main/resources/resources/logisim/strings/gui/gui_es.properties +++ b/src/main/resources/resources/logisim/strings/gui/gui_es.properties @@ -340,6 +340,7 @@ fileQuitItem = Salir fileSaveAsItem = Guardar como... fileSaveItem = Guardar # ==> fileExportProject = +# ==> fileExtractRunProject = # # menu/MenuHelp.java # diff --git a/src/main/resources/resources/logisim/strings/gui/gui_fr.properties b/src/main/resources/resources/logisim/strings/gui/gui_fr.properties index a5ee3fab1b..82dd7fb10d 100644 --- a/src/main/resources/resources/logisim/strings/gui/gui_fr.properties +++ b/src/main/resources/resources/logisim/strings/gui/gui_fr.properties @@ -340,6 +340,7 @@ fileQuitItem = Sortir fileSaveAsItem = Enregistrer sous... fileSaveItem = Enregistrer # ==> fileExportProject = +# ==> fileExtractRunProject = # # menu/MenuHelp.java # diff --git a/src/main/resources/resources/logisim/strings/gui/gui_it.properties b/src/main/resources/resources/logisim/strings/gui/gui_it.properties index 9f5347b8dc..55aed5b089 100644 --- a/src/main/resources/resources/logisim/strings/gui/gui_it.properties +++ b/src/main/resources/resources/logisim/strings/gui/gui_it.properties @@ -340,6 +340,7 @@ fileQuitItem = Esci fileSaveAsItem = Salva Come... fileSaveItem = Salva # ==> fileExportProject = +# ==> fileExtractRunProject = # # menu/MenuHelp.java # diff --git a/src/main/resources/resources/logisim/strings/gui/gui_ja.properties b/src/main/resources/resources/logisim/strings/gui/gui_ja.properties index 8e463c004e..c1619349a0 100644 --- a/src/main/resources/resources/logisim/strings/gui/gui_ja.properties +++ b/src/main/resources/resources/logisim/strings/gui/gui_ja.properties @@ -340,6 +340,7 @@ fileQuitItem = 終了する fileSaveAsItem = 新規ファイルで保存... fileSaveItem = 保存 # ==> fileExportProject = +# ==> fileExtractRunProject = # # menu/MenuHelp.java # diff --git a/src/main/resources/resources/logisim/strings/gui/gui_nl.properties b/src/main/resources/resources/logisim/strings/gui/gui_nl.properties index 0f98705b6d..e6f35883b0 100644 --- a/src/main/resources/resources/logisim/strings/gui/gui_nl.properties +++ b/src/main/resources/resources/logisim/strings/gui/gui_nl.properties @@ -339,7 +339,8 @@ filePrintItem = Afdrukken.... fileQuitItem = Afsluiten fileSaveAsItem = Opslaan als... fileSaveItem = Opslaan -fileExportProject = Projekt exporteren +fileExportProject = Projekt bundel exporteren... +fileExtractRunProject = Projekt bundel uitpakken en openen... # # menu/MenuHelp.java # diff --git a/src/main/resources/resources/logisim/strings/gui/gui_pl.properties b/src/main/resources/resources/logisim/strings/gui/gui_pl.properties index 730cdc6c31..d3f33db674 100644 --- a/src/main/resources/resources/logisim/strings/gui/gui_pl.properties +++ b/src/main/resources/resources/logisim/strings/gui/gui_pl.properties @@ -387,7 +387,8 @@ filePrintItem = Drukuj... fileQuitItem = Zakończ... fileSaveAsItem = Zapisz jako... fileSaveItem = Zapisz... -fileExportProject = Eksportuj projekt +# == > fileExportProject = +# ==> fileExtractRunProject = # # menu/MenuHelp.java # diff --git a/src/main/resources/resources/logisim/strings/gui/gui_pt.properties b/src/main/resources/resources/logisim/strings/gui/gui_pt.properties index d429d7c1a5..600a422e56 100644 --- a/src/main/resources/resources/logisim/strings/gui/gui_pt.properties +++ b/src/main/resources/resources/logisim/strings/gui/gui_pt.properties @@ -340,6 +340,7 @@ fileQuitItem = Sair fileSaveAsItem = Salvar como... fileSaveItem = Salvar # ==> fileExportProject = +# ==> fileExtractRunProject = # # menu/MenuHelp.java # diff --git a/src/main/resources/resources/logisim/strings/gui/gui_ru.properties b/src/main/resources/resources/logisim/strings/gui/gui_ru.properties index 682fcda730..0bf62f89a4 100644 --- a/src/main/resources/resources/logisim/strings/gui/gui_ru.properties +++ b/src/main/resources/resources/logisim/strings/gui/gui_ru.properties @@ -340,6 +340,7 @@ fileQuitItem = Выход fileSaveAsItem = Сохранить как... fileSaveItem = Сохранить # ==> fileExportProject = +# ==> fileExtractRunProject = # # menu/MenuHelp.java # diff --git a/src/main/resources/resources/logisim/strings/proj/proj.properties b/src/main/resources/resources/logisim/strings/proj/proj.properties index a606428506..62abdc9b26 100644 --- a/src/main/resources/resources/logisim/strings/proj/proj.properties +++ b/src/main/resources/resources/logisim/strings/proj/proj.properties @@ -37,7 +37,30 @@ templateOpenError = Could not open template: %s templateOpenErrorTitle = Error Loading Template UsedLibraryToolnameError = The filename may not be equal to a circuit name, tool name, or library name used in your project.\n The specified filename equals to one of these names. ProjUnableToCreate = Failed to create project: %s -ProjExistsUnableToCreate = Folder named "%s" already exists in selected directory. Please select another location. +projExportBundle = Exporting a project bundle +projBundleDirectory = Choose directory to extract project bundle: +projExistsOverwrite = Project bundle "%s" already exists, overwrite it? +projBundleReadError = Error reading project bundle: %s +projBundleNoInfo = Bundle does not contain info-file, aborting import! +projBundleMisformatted = Bundle info-file is not correctly formatted, aborting import! +projBundleMainNotFound = Bundle does not contain the main file, aborting import! +projContainsFileDir = Selected directory contains either the file "%s" or a sub-directory called "%s".\nPlease select a directory that does not contain these elements! +projImportBundle = Importing a project bundle +projBundleReadmeWindow = Project bundle README.md information +projCloseReadme = Close project bundle README.md +projCancel = Cancel +projWriteReadme = Save +projName = Project name: +projAuthor = Author(s) (comma seperated): +projKeywords = Keywords (comma seperated): +projDescription = Project description: +projHeader = # Logisim-evolution project bundle # +projHeader1 = ## Project information: ## +projHeader2 = ## Project description: ## +projHeader3 = ## Project bundle file information: ## +projGenerateInfo = This project bundle was generated by %s (%s) at %s +projIntro = This project bundle contains the required Logisim-evolution-files for the project `%s`. +projAuthor = Project author(s): # # Template.java # diff --git a/src/main/resources/resources/logisim/strings/proj/proj_de.properties b/src/main/resources/resources/logisim/strings/proj/proj_de.properties index 19ae12191e..ca011efd43 100644 --- a/src/main/resources/resources/logisim/strings/proj/proj_de.properties +++ b/src/main/resources/resources/logisim/strings/proj/proj_de.properties @@ -37,7 +37,30 @@ templateOpenError = Konnte Vorlage %s nicht öffnen templateOpenErrorTitle = Fehler beim Laden der Vorlage UsedLibraryToolnameError = Der Dateiname muss sich von den Schaltkreisnamen, Werkzeugnamen oder Bibliotheksnamen, die in Ihrem Projekt verwendet werden, unterscheiden.\n Der angegebene Dateiname entspricht einem dieser Namen. # ==> ProjUnableToCreate = -# ==> ProjExistsUnableToCreate = +# ==> projExportBundle = +# ==> projExistsOverwrite = +# ==> projBundleReadError = +# ==> projBundleNoInfo = +# ==> projBundleMisformatted = +# ==> projBundleMainNotFound = +# ==> projBundleDirectory = +# ==> projContainsFileDir = +# ==> projImportBundle = +# ==> projBundleReadmeWindow = +# ==> projCloseReadme = +# ==> projCancel = +# ==> projWriteReadme = +# ==> projName = +# ==> projAuthor = +# ==> projKeywords = +# ==> projDescription = +# ==> projHeader = +# ==> projHeader1 = +# ==> projIntro = +# ==> projAuthor = +# ==> projHeader2 = +# ==> projHeader3 = +# ==> projGenerateInfo = # # Template.java # diff --git a/src/main/resources/resources/logisim/strings/proj/proj_el.properties b/src/main/resources/resources/logisim/strings/proj/proj_el.properties index 718f151df5..fbd50518b8 100644 --- a/src/main/resources/resources/logisim/strings/proj/proj_el.properties +++ b/src/main/resources/resources/logisim/strings/proj/proj_el.properties @@ -37,7 +37,30 @@ templateOpenError = Δεν είναι δυνατό το άνοιγμα του π templateOpenErrorTitle = Σφάλμα στο Άνοιγμα Προτύπου # ==> UsedLibraryToolnameError = # ==> ProjUnableToCreate = -# ==> ProjExistsUnableToCreate = +# ==> projExportBundle = +# ==> projExistsOverwrite = +# ==> projBundleReadError = +# ==> projBundleNoInfo = +# ==> projBundleMisformatted = +# ==> projBundleMainNotFound = +# ==> projBundleDirectory = +# ==> projContainsFileDir = +# ==> projImportBundle = +# ==> projBundleReadmeWindow = +# ==> projCloseReadme = +# ==> projCancel = +# ==> projWriteReadme = +# ==> projName = +# ==> projAuthor = +# ==> projKeywords = +# ==> projDescription = +# ==> projHeader = +# ==> projHeader1 = +# ==> projIntro = +# ==> projAuthor = +# ==> projHeader2 = +# ==> projHeader3 = +# ==> projGenerateInfo = # # Template.java # diff --git a/src/main/resources/resources/logisim/strings/proj/proj_es.properties b/src/main/resources/resources/logisim/strings/proj/proj_es.properties index 44c07532b2..7e856d068a 100644 --- a/src/main/resources/resources/logisim/strings/proj/proj_es.properties +++ b/src/main/resources/resources/logisim/strings/proj/proj_es.properties @@ -37,7 +37,30 @@ templateOpenError = No se pudo abrir la plantilla: %s templateOpenErrorTitle = Error al cargar plantilla UsedLibraryToolnameError = El nombre de archivo no debe coincidir con el nombre de un circuito, herramienta o librería de tu proyecto.\n El nombre especificado coincide con uno de ellos. # ==> ProjUnableToCreate = -# ==> ProjExistsUnableToCreate = +# ==> projExportBundle = +# ==> projExistsOverwrite = +# ==> projBundleReadError = +# ==> projBundleNoInfo = +# ==> projBundleMisformatted = +# ==> projBundleMainNotFound = +# ==> projBundleDirectory = +# ==> projContainsFileDir = +# ==> projImportBundle = +# ==> projBundleReadmeWindow = +# ==> projCloseReadme = +# ==> projCancel = +# ==> projWriteReadme = +# ==> projName = +# ==> projAuthor = +# ==> projKeywords = +# ==> projDescription = +# ==> projHeader = +# ==> projHeader1 = +# ==> projIntro = +# ==> projAuthor = +# ==> projHeader2 = +# ==> projHeader3 = +# ==> projGenerateInfo = # # Template.java # diff --git a/src/main/resources/resources/logisim/strings/proj/proj_fr.properties b/src/main/resources/resources/logisim/strings/proj/proj_fr.properties index 42b8c18437..eb3dad71be 100644 --- a/src/main/resources/resources/logisim/strings/proj/proj_fr.properties +++ b/src/main/resources/resources/logisim/strings/proj/proj_fr.properties @@ -37,7 +37,30 @@ templateOpenError = Impossible d'ouvrir le modèle : %s templateOpenErrorTitle = Impossible de charger le modèle UsedLibraryToolnameError = Le nom de fichier ne doit pas correspondre à un nom de circuit, à un nom d'outil ou à un nom de bibliothèque utilisé dans votre projet. # ==> ProjUnableToCreate = -# ==> ProjExistsUnableToCreate = +# ==> projExportBundle = +# ==> projExistsOverwrite = +# ==> projBundleReadError = +# ==> projBundleNoInfo = +# ==> projBundleMisformatted = +# ==> projBundleMainNotFound = +# ==> projBundleDirectory = +# ==> projContainsFileDir = +# ==> projImportBundle = +# ==> projBundleReadmeWindow = +# ==> projCloseReadme = +# ==> projCancel = +# ==> projWriteReadme = +# ==> projName = +# ==> projAuthor = +# ==> projKeywords = +# ==> projDescription = +# ==> projHeader = +# ==> projHeader1 = +# ==> projIntro = +# ==> projAuthor = +# ==> projHeader2 = +# ==> projHeader3 = +# ==> projGenerateInfo = # # Template.java # diff --git a/src/main/resources/resources/logisim/strings/proj/proj_it.properties b/src/main/resources/resources/logisim/strings/proj/proj_it.properties index 928de40b90..643134dab2 100644 --- a/src/main/resources/resources/logisim/strings/proj/proj_it.properties +++ b/src/main/resources/resources/logisim/strings/proj/proj_it.properties @@ -37,7 +37,30 @@ templateOpenError = Impossibile aprire il modello: %s templateOpenErrorTitle = Errore caricamento modello UsedLibraryToolnameError = Il nome del file potrebbe non essere uguale al nome del circuito, del tool o della libreria utilizzati nel progetto.\n Il nome del file specificato equivale a uno di questi nomi. # ==> ProjUnableToCreate = -# ==> ProjExistsUnableToCreate = +# ==> projExportBundle = +# ==> projExistsOverwrite = +# ==> projBundleReadError = +# ==> projBundleNoInfo = +# ==> projBundleMisformatted = +# ==> projBundleMainNotFound = +# ==> projBundleDirectory = +# ==> projContainsFileDir = +# ==> projImportBundle = +# ==> projBundleReadmeWindow = +# ==> projCloseReadme = +# ==> projCancel = +# ==> projWriteReadme = +# ==> projName = +# ==> projAuthor = +# ==> projKeywords = +# ==> projDescription = +# ==> projHeader = +# ==> projHeader1 = +# ==> projIntro = +# ==> projAuthor = +# ==> projHeader2 = +# ==> projHeader3 = +# ==> projGenerateInfo = # # Template.java # diff --git a/src/main/resources/resources/logisim/strings/proj/proj_ja.properties b/src/main/resources/resources/logisim/strings/proj/proj_ja.properties index 5c5a4629de..53dfc983b6 100644 --- a/src/main/resources/resources/logisim/strings/proj/proj_ja.properties +++ b/src/main/resources/resources/logisim/strings/proj/proj_ja.properties @@ -37,7 +37,30 @@ templateOpenError = テンプレートを開けませんでした: %s templateOpenErrorTitle = テンプレートの読み込みエラー UsedLibraryToolnameError = ファイル名は、プロジェクトで使用されている回路名、ツール名、ライブラリ名と一致しない場合があります。\n 指定されたファイル名は、これらの名前のいずれかに等しくなります。 # ==> ProjUnableToCreate = -# ==> ProjExistsUnableToCreate = +# ==> projExportBundle = +# ==> projExistsOverwrite = +# ==> projBundleReadError = +# ==> projBundleNoInfo = +# ==> projBundleMisformatted = +# ==> projBundleMainNotFound = +# ==> projBundleDirectory = +# ==> projContainsFileDir = +# ==> projImportBundle = +# ==> projBundleReadmeWindow = +# ==> projCloseReadme = +# ==> projCancel = +# ==> projWriteReadme = +# ==> projName = +# ==> projAuthor = +# ==> projKeywords = +# ==> projDescription = +# ==> projHeader = +# ==> projHeader1 = +# ==> projIntro = +# ==> projAuthor = +# ==> projHeader2 = +# ==> projHeader3 = +# ==> projGenerateInfo = # # Template.java # diff --git a/src/main/resources/resources/logisim/strings/proj/proj_nl.properties b/src/main/resources/resources/logisim/strings/proj/proj_nl.properties index 7f26add804..007f98f6e2 100644 --- a/src/main/resources/resources/logisim/strings/proj/proj_nl.properties +++ b/src/main/resources/resources/logisim/strings/proj/proj_nl.properties @@ -37,7 +37,30 @@ templateOpenError = Kon sjabloon niet openen: %s templateOpenErrorTitle = Fout Laden van de sjabloon UsedLibraryToolnameError = De bestandsnaam mag niet gelijk zijn aan de naam van een circuit, gereedschapsnaam of bibliotheeknaam die in uw project wordt gebruikt.\n De opgegeven bestandsnaam is gelijk aan een van deze namen. # ==> ProjUnableToCreate = -# ==> ProjExistsUnableToCreate = +# ==> projExportBundle = +# ==> projExistsOverwrite = +# ==> projBundleReadError = +# ==> projBundleNoInfo = +# ==> projBundleMisformatted = +# ==> projBundleMainNotFound = +# ==> projBundleDirectory = +# ==> projContainsFileDir = +# ==> projImportBundle = +# ==> projBundleReadmeWindow = +# ==> projCloseReadme = +# ==> projCancel = +# ==> projWriteReadme = +# ==> projName = +# ==> projAuthor = +# ==> projKeywords = +# ==> projDescription = +# ==> projHeader = +# ==> projHeader1 = +# ==> projIntro = +# ==> projAuthor = +# ==> projHeader2 = +# ==> projHeader3 = +# ==> projGenerateInfo = # # Template.java # diff --git a/src/main/resources/resources/logisim/strings/proj/proj_pl.properties b/src/main/resources/resources/logisim/strings/proj/proj_pl.properties index 8535fbcaef..ff5a5afc9c 100644 --- a/src/main/resources/resources/logisim/strings/proj/proj_pl.properties +++ b/src/main/resources/resources/logisim/strings/proj/proj_pl.properties @@ -40,7 +40,30 @@ templateOpenError = Nie można otworzyć szablonu: %s templateOpenErrorTitle = Błąd ładowania szablonu UsedLibraryToolnameError = Nazwa pliku nie może być taka sama jak nazwa obwodu, narzędzia lub biblioteki użytej w projekcie.\n Podana nazwa pliku jest taka sama jak nazwa jednego z wymienionych elementów. ProjUnableToCreate = Utworzenie projektu nie powiodło się: %s -ProjExistsUnableToCreate = Katalog o nazwie "%s" już istnieje. Proszę wybierz inny katalog. +# ==> projExportBundle = +# ==> projExistsOverwrite = +# ==> projBundleReadError = +# ==> projBundleNoInfo = +# ==> projBundleMisformatted = +# ==> projBundleMainNotFound = +# ==> projBundleDirectory = +# ==> projContainsFileDir = +# ==> projImportBundle = +# ==> projBundleReadmeWindow = +# ==> projCloseReadme = +# ==> projCancel = +# ==> projWriteReadme = +# ==> projName = +# ==> projAuthor = +# ==> projKeywords = +# ==> projDescription = +# ==> projHeader = +# ==> projHeader1 = +# ==> projIntro = +# ==> projAuthor = +# ==> projHeader2 = +# ==> projHeader3 = +# ==> projGenerateInfo = # # Template.java # diff --git a/src/main/resources/resources/logisim/strings/proj/proj_pt.properties b/src/main/resources/resources/logisim/strings/proj/proj_pt.properties index aa1f89caff..4308226bfc 100644 --- a/src/main/resources/resources/logisim/strings/proj/proj_pt.properties +++ b/src/main/resources/resources/logisim/strings/proj/proj_pt.properties @@ -37,7 +37,30 @@ templateOpenError = Impossível abrir gabarito: %s templateOpenErrorTitle = Erro ao carregar gabarito UsedLibraryToolnameError = O nome do arquivo não pode ser igual a um nome de circuito, nome de ferramenta ou nome de biblioteca usado em seu projeto.\n O nome de arquivo especificado é igual a um desses nomes. # ==> ProjUnableToCreate = -# ==> ProjExistsUnableToCreate = +# ==> projExportBundle = +# ==> projExistsOverwrite = +# ==> projBundleReadError = +# ==> projBundleNoInfo = +# ==> projBundleMisformatted = +# ==> projBundleMainNotFound = +# ==> projBundleDirectory = +# ==> projContainsFileDir = +# ==> projImportBundle = +# ==> projBundleReadmeWindow = +# ==> projCloseReadme = +# ==> projCancel = +# ==> projWriteReadme = +# ==> projName = +# ==> projAuthor = +# ==> projKeywords = +# ==> projDescription = +# ==> projHeader = +# ==> projHeader1 = +# ==> projIntro = +# ==> projAuthor = +# ==> projHeader2 = +# ==> projHeader3 = +# ==> projGenerateInfo = # # Template.java # diff --git a/src/main/resources/resources/logisim/strings/proj/proj_ru.properties b/src/main/resources/resources/logisim/strings/proj/proj_ru.properties index 305c1fb4b9..bc8bed7869 100644 --- a/src/main/resources/resources/logisim/strings/proj/proj_ru.properties +++ b/src/main/resources/resources/logisim/strings/proj/proj_ru.properties @@ -37,7 +37,30 @@ templateOpenError = Невозможно открыть шаблон: %s templateOpenErrorTitle = Ошибка при загрузке шаблона UsedLibraryToolnameError = Имя файла может не совпадать с именем схемы, инструмента или библиотеки, используемой в вашем проекте.\n Указанное имя файла равно одному из этих имен. # ==> ProjUnableToCreate = -# ==> ProjExistsUnableToCreate = +# ==> projExportBundle = +# ==> projExistsOverwrite = +# ==> projBundleReadError = +# ==> projBundleNoInfo = +# ==> projBundleMisformatted = +# ==> projBundleMainNotFound = +# ==> projBundleDirectory = +# ==> projContainsFileDir = +# ==> projImportBundle = +# ==> projBundleReadmeWindow = +# ==> projCloseReadme = +# ==> projCancel = +# ==> projWriteReadme = +# ==> projName = +# ==> projAuthor = +# ==> projKeywords = +# ==> projDescription = +# ==> projHeader = +# ==> projHeader1 = +# ==> projIntro = +# ==> projAuthor = +# ==> projHeader2 = +# ==> projHeader3 = +# ==> projGenerateInfo = # # Template.java #