Improved and documented the file import strategy.

This commit is contained in:
hneemann 2017-02-26 13:01:36 +01:00
parent c7b550a010
commit 8281f4dc61
9 changed files with 129 additions and 6 deletions

View File

@ -7,6 +7,7 @@ planned as v0.10
- With the right mouse button you can now select and move/delete wires.
- Added a real bidirectional switch and a relay.
- Added N and P channel FETs and some CMOS examples
- Improved and documented the file import strategy.
v0.9, released on 03. Feb 2017
- improved documentation

View File

@ -160,7 +160,7 @@ public class ElementLibrary implements Iterable<ElementLibrary.ElementContainer>
try {
description = elementNotFoundNotification.elementNotFound(file);
} catch (IOException e) {
throw new ElementNotFoundException(Lang.get("msg_errorImportingModel", elementName));
throw new ElementNotFoundException(Lang.get("msg_errorImportingModel", elementName), e);
}
if (description != null)

View File

@ -7,11 +7,21 @@ package de.neemann.digital.draw.library;
*/
public class ElementNotFoundException extends Exception {
/**
* Creates a new Iistance
* Creates a new Instance
*
* @param message the error message
*/
public ElementNotFoundException(String message) {
super(message);
}
/**
* Creates a new Instance
*
* @param message the error message
* @param cause the errors cause
*/
public ElementNotFoundException(String message, Exception cause) {
super(message, cause);
}
}

View File

@ -28,7 +28,14 @@ public class MissingShape implements Shape {
*/
public MissingShape(String elementName, Exception cause) {
this.message = Lang.get("msg_missingShape_N", elementName);
this.cause = cause.getMessage();
this.cause = getMessage(cause);
}
private String getMessage(Throwable e) {
String message = e.getMessage();
if (e.getCause() != null)
message += "; " + getMessage(e.getCause());
return message;
}
@Override

View File

@ -22,6 +22,7 @@ import java.awt.event.ActionEvent;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
/**
* The LibrarySelector is responsible for building the menu used to select items for adding them to the circuit.
@ -38,6 +39,7 @@ public class LibrarySelector implements ElementNotFoundNotification {
private InsertHistory insertHistory;
private CircuitComponent circuitComponent;
private ArrayList<ImportedItem> importedElements;
private HashMap<String, File> treeFileMap;
/**
* Creates a new library selector.
@ -138,6 +140,7 @@ public class LibrarySelector implements ElementNotFoundNotification {
* @param filePath the file path
*/
public void setFilePath(File filePath) {
treeFileMap = null;
this.filePath = filePath;
}
@ -149,7 +152,47 @@ public class LibrarySelector implements ElementNotFoundNotification {
if (primary.exists())
file = primary;
return importElement(file).description;
// check if there is a file with the given name below the current directory
// if so, load this file!
File f = getFileFromTree(file.getName());
if (f != null)
return importElement(f).description;
// than check if the exact given file exists
if (file.exists())
return importElement(file).description;
// could not find the given file
throw new IOException(Lang.get("err_couldNotFindIncludedFile_N0", file));
}
private File getFileFromTree(String name) throws IOException {
if (treeFileMap == null) {
treeFileMap = new HashMap<>();
populateTreeFileMap(treeFileMap, filePath);
} else {
if (!treeFileMap.containsKey(name)) { // if file not in map rescan folder
treeFileMap.clear();
populateTreeFileMap(treeFileMap, filePath);
}
}
return treeFileMap.get(name);
}
private void populateTreeFileMap(HashMap<String, File> map, File path) throws IOException {
File[] list = path.listFiles();
if (list != null) {
for (File f : list) {
final String name = f.getName();
if (f.isFile() && name.endsWith(".dig")) {
if (map.containsKey(name))
throw new IOException(Lang.get("err_file_N0_ExistsTwiceBelow_N1", name, filePath));
map.put(name, f);
}
if (f.isDirectory())
populateTreeFileMap(map, f);
}
}
}
private static String getActionName(ElementTypeDescription typeDescription) {

View File

@ -420,6 +420,8 @@ Zur Analyse können Sie die Schaltung im Gatterschrittmodus ausführen.</string>
<string name="err_splitterAllowsOnlyOneHighZInput">Ein Splitter der hochohmige Eingänge erlaubt, kann nur einen Eingang haben!</string>
<string name="err_couldNotCreateFolder_N0">Konnte den Order '{0}' nicht erzeugen!</string>
<string name="err_switchHasNoNet">Ein Schalter kann nicht nur mit Eingängen verbunden werden.</string>
<string name="err_file_N0_ExistsTwiceBelow_N1">Die Datei {0} existiert mehrfach unter {1}</string>
<string name="err_couldNotFindIncludedFile_N0">Die Datei {0} konnte nicht gefunden werden.</string>
<string name="key_AddrBits">Adress-Bits</string>
<string name="key_AddrBits_tt">Anzahl der Adress-Bits die verwendet werden.</string>

View File

@ -406,6 +406,8 @@ To analyse you can run the circuit in single gate step mode.</string>
<string name="err_splitterAllowsOnlyOneHighZInput">A splitter which allows high z inputs can only have one input!</string>
<string name="err_couldNotCreateFolder_N0">Could not create folder '{0}'!</string>
<string name="err_switchHasNoNet">It is not allowed to connect only inputs to a switch.</string>
<string name="err_file_N0_ExistsTwiceBelow_N1">The file {0} exists multiple times below {1}.</string>
<string name="err_couldNotFindIncludedFile_N0">Could not find the file {0}.</string>
<string name="key_AddrBits">Address Bits</string>
<string name="key_AddrBits_tt">Number of address bits used.</string>

View File

@ -99,6 +99,37 @@
erzeugt wird.
</par>
</chapter>
<chapter name="Dateinamen">
<par>
Um eine Schaltung in mehrere Teile zu zerlegen, die auch unabhängig z.B. in einem VCS abgelegt und verfolgt
werden können, wird jede eingebundenen Schaltung in einer eigenen Datei gespeichert. Das hat zu Folge, dass in einer
Schaltung nur die Dateinamen der Teilschaltungen gespeichert sind, und diese Dateien zur Laufzeit im Dateisystem
gefunden werden müssen. Um die verschiedenen Arbeitsweisen der Nutzer bestmöglich zu unterstützen und dennoch
auf eine komplexe Verwaltung von Importpfaden usw. zu verzichten, ist eine etwas ungewöhnliche Import-Strategie
implementiert.
</par>
<par>
In einer Schaltung sind die absoluten Pfade der eingebetteten Schaltungen gespeichert. Wenn diese Datei eingelesen
werden soll, wird jedoch zunächst geprüft, ob sich eine Datei des gleichen Namens im Ordner der einbindenden Datei befindet.
Ist das der Fall, wird diese Datei verwendet.
</par>
<par>
Ist das nicht der Fall, werden alle Unterordner nach einer Datei des entsprechenden Namens durchsucht. Wird
eine passende Datei gefunden, wird diese importiert. Dabei kommt es nur auf den Dateinamen der einzulesenden
Datei an, nicht auf dessen Pfad. Entsprechend wird eine Fehlermeldung erzeugt, wenn sich in verschiedenen
Unterordneren mehrere Dateien gleichen Namens befinden, da dann Mehrdeutigkeiten entstehen.
</par>
<par>
Erst wenn bisher keine Datei gefunden wurde, wird der komplette absolute Pfad verwendet und es wird versucht,
diese Datei zu importieren. Gelingt auch das nicht, wird eine Fehlermeldung erzeugt.
</par>
<par>
Eine geeignete Projektstruktur sieht daher wie folgt aus: In einem eigenen Ordner befindet sich die Wurzelschaltung.
Alle importierten Schaltungen sollte sin im selben Ordner oder in Unterordnern befinden. Alle Schaltungen sollten
unterschiedliche Namen haben, es sollte also nicht vorkommen, dass sich in verschiedenen Ordnern Schaltungen
gleichen Namens befinden.
</par>
</chapter>
<chapter name="Häufig gestellte Fragen">
<faq>
<question>Wie kann ich eine Leitung verschieben?</question>

View File

@ -42,7 +42,6 @@
circuit behave in exact the same way as if all components had been inserted at the same circuit level.
</par>
</chapter>
<chapter name="Wires">
<par>
All components must be connected via wires. It is not possible to connect two components to each other by
@ -97,7 +96,35 @@
circuit is not analyzed correctly, which means that an incorrect state transition table is generated.
</par>
</chapter>
<chapter name="File Names">
<par>
In order to decompose a circuit into several parts which are independent, e.g. can be stored and tracked in
a VCS, each embedded circuit is stored in its own file. The result is that in a circuit only the file names
of the subcircuits are stored, and these files must be found in the file system at runtime.
In order to support the various work methods of the users as best as possible and still to avoid a complex
administration of import paths, etc., a somewhat unusual import strategy is implemented.
</par>
<par>
The absolute paths of the embedded circuits are stored in a circuits file. If a file is to be imported,
however, it is first checked whether a file with the same name is located in the folder of the including
file. If this is the case, this file is used.
</par>
<par>
If this is not the case, all subfolders are searched for a file of the corresponding name.
If a suitable file is found, it is imported. This process only depends on the file name of the file to be
read, not on its path. Correspondingly, an error message is generated if there are several files of the
same name in different subfolders, since ambiguities then arise.
</par>
<par>
Only if no file has been found yet, the complete absolute path is used and an attempt is made to import
this file. If this is not successful, an error message is generated.
</par>
<par>
A suitable project structure therefore looks as follows: The root circuit is located in a separate folder.
All imported circuits should be in the same folder or subfolders. All circuits should have different names,
so it should not happen that there are circuits of the same name in different folders.
</par>
</chapter>
<chapter name="Frequently asked Questions">
<faq>
<question>How to move a wire?</question>