--- /dev/null
+package jalview.io;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A singleton registry of alignment file formats known to Jalview. On startup,
+ * the 'built-in' formats are added (from the FileFormat enum). Additional
+ * formats can be registered (or formats deregistered) programmatically, for
+ * example with a Groovy script.
+ *
+ * @author gmcarstairs
+ *
+ */
+public class FileFormats
+{
+ private static FileFormats instance = new FileFormats();
+
+ /*
+ * A lookup map of file formats by upper-cased name
+ */
+ private static Map<String, FileFormatI> formats;
+
+ /*
+ * Formats in this set are capable of being identified by IdentifyFile
+ */
+ private static Set<FileFormatI> identifiable;
+
+ public static FileFormats getInstance()
+ {
+ return instance;
+ }
+
+ /**
+ * Private constructor registers Jalview's built-in file formats
+ */
+ private FileFormats()
+ {
+ reset();
+ }
+
+ /**
+ * Reset to just the built-in file formats packaged with Jalview. These are
+ * added (and will be shown in menus) in the order of their declaration in the
+ * FileFormat enum.
+ */
+ public synchronized void reset()
+ {
+ formats = new LinkedHashMap<String, FileFormatI>();
+ identifiable = new HashSet<FileFormatI>();
+ for (FileFormat format : FileFormat.values())
+ {
+ registerFileFormat(format, format.isIdentifiable());
+ }
+ }
+
+ /**
+ * Answers true if the format is one that can be identified by IdentifyFile.
+ * Answers false for a null value.
+ */
+ public boolean isIdentifiable(FileFormatI f)
+ {
+ return identifiable.contains(f);
+ }
+
+ /**
+ * Registers a file format for case-insensitive lookup by name
+ *
+ * @param format
+ */
+ public void registerFileFormat(FileFormatI format)
+ {
+ boolean isIdentifiable = format instanceof FileFormat
+ && ((FileFormat) format).isIdentifiable();
+ registerFileFormat(format, isIdentifiable);
+ }
+
+ protected void registerFileFormat(FileFormatI format,
+ boolean isIdentifiable)
+ {
+ String name = format.getName().toUpperCase();
+ if (formats.containsKey(name))
+ {
+ System.err.println("Overwriting file format: " + format.getName());
+ }
+ formats.put(name, format);
+ if (isIdentifiable)
+ {
+ identifiable.add(format);
+ }
+ }
+
+ /**
+ * Deregisters a file format so it is no longer shown in menus
+ *
+ * @param name
+ */
+ public void deregisterFileFormat(String name)
+ {
+ FileFormatI ff = formats.remove(name.toUpperCase());
+ identifiable.remove(ff);
+ }
+
+ /**
+ * Answers a list of writeable file formats (as strings, corresponding to the
+ * getName() and forName() methods)
+ *
+ * @param textOnly
+ * if true, only text (not binary) formats are included
+ * @return
+ */
+ public List<String> getWritableFormats(boolean textOnly)
+ {
+ List<String> l = new ArrayList<String>();
+ for (FileFormatI ff : formats.values())
+ {
+ if (ff.isWritable() && (!textOnly || ff.isTextFormat()))
+ {
+ l.add(ff.getName());
+ }
+ }
+ return l;
+ }
+
+ /**
+ * Answers a list of readable file formats (as strings, corresponding to the
+ * getName() and forName() methods)
+ *
+ * @return
+ */
+ public List<String> getReadableFormats()
+ {
+ List<String> l = new ArrayList<String>();
+ for (FileFormatI ff : formats.values())
+ {
+ if (ff.isReadable())
+ {
+ l.add(ff.getName());
+ }
+ }
+ return l;
+ }
+
+ /**
+ * Returns the file format with the given name, or null if format is null or
+ * invalid. This is not case-sensitive.
+ *
+ * @param format
+ * @return
+ */
+ public FileFormatI forName(String format)
+ {
+ return format == null ? null : formats.get(format.toUpperCase());
+ }
+
+ /**
+ * Returns an iterable collection of registered file formats (in the order in
+ * which they were registered)
+ *
+ * @return
+ */
+ public Iterable<FileFormatI> getFormats()
+ {
+ return formats.values();
+ }
+}