/*
* Open Source Physics software is free software as described near the bottom of this code file.
*
* For additional information and documentation on Open Source Physics please see:
* <http://www.opensourcephysics.org/>
*/
package org.opensourcephysics.tools;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Set;
import java.util.TreeSet;
import org.opensourcephysics.controls.XML;
import org.opensourcephysics.controls.XMLControl;
import org.opensourcephysics.controls.XMLControlElement;
/**
* A Library for a LibraryBrowser. Maintains lists of collection paths and imported sub-libraries.
*
* @author Douglas Brown
*/
public class Library {
protected String name; // name of the library
protected ArrayList<String> pathList = new ArrayList<String>();
protected HashMap<String, String> pathToNameMap = new HashMap<String, String>();
protected ArrayList<String> comPADREPathList = new ArrayList<String>();
protected HashMap<String, String> comPADREPathToNameMap = new HashMap<String, String>();
protected ArrayList<String> ospPathList = new ArrayList<String>();
protected HashMap<String, Library> ospPathToLibraryMap = new HashMap<String, Library>();
protected ArrayList<String> importedPathList = new ArrayList<String>();
protected HashMap<String, Library> importedPathToLibraryMap = new HashMap<String, Library>();
protected ArrayList<String> subPathList = new ArrayList<String>();
protected HashMap<String, Library> subPathToLibraryMap = new HashMap<String, Library>();
protected HashMap<String, String> allPathsToNameMap = new HashMap<String, String>();
protected Set<String> noSearchSet = new TreeSet<String>();
protected String[] openTabPaths;
protected ArrayList<String> recentTabs = new ArrayList<String>();
protected int maxRecentTabCount = 6;
protected String chooserDir;
protected LibraryBrowser browser;
/**
* Adds an OSP-sponsored library. OSP libraries are not under user control.
*
* @param path the library path
* @return true if successfully added
*/
public boolean addOSPLibrary(String path) {
if (ospPathList.contains(path))
return false;
synchronized (ospPathList) {
XMLControl control = new XMLControlElement(path);
if (control.failedToRead() || control.getObjectClass() != Library.class) {
return false;
}
Library library = new Library();
control.loadObject(library);
library.browser = this.browser;
ospPathList.add(path);
ospPathToLibraryMap.put(path, library);
}
return true;
}
/**
* Imports a library. Imported libraries are managed by the user.
*
* @param path the library path
* @return true if successfully imported
*/
public boolean importLibrary(String path) {
if (importedPathList.contains(path))
return false;
XMLControl control = new XMLControlElement(path);
if (control.failedToRead() || control.getObjectClass()!=Library.class)
return false;
Library library = new Library();
library.browser = this.browser;
control.loadObject(library);
return importLibrary(path, library);
}
/**
* Adds a comPADRE collection. ComPADRE collections are not under user control.
*
* @param path the comPADRE query
* @param name the name of the collection
* @return true if successfully added
*/
public boolean addComPADRECollection(String path, String name) {
path = path.trim();
// don't add duplicate paths
if (comPADREPathList.contains(path))
return false;
comPADREPathList.add(path);
comPADREPathToNameMap.put(path, name.trim());
allPathsToNameMap.put(path, name.trim());
return true;
}
/**
* Adds a sublibrary. Sublibraries are shown as submenus in a Library's Collections menu.
* Sublibraries are not under user control.
*
* @param path the path to the sublibrary
* @return true if successfully added
*/
public boolean addSubLibrary(String path) {
if (subPathList.contains(path))
return false;
synchronized (subPathList) {
XMLControl control = new XMLControlElement(path);
if (control.failedToRead() || control.getObjectClass() != Library.class)
return false;
Library library = new Library();
library.browser = this.browser;
control.loadObject(library);
subPathList.add(path);
subPathToLibraryMap.put(path, library);
}
return true;
}
/**
* Returns a string representation of this library.
*
* @return the name of the library
*/
@Override
public String toString() {
return getName();
}
/**
* Sets the cache path.
*
* @param cachePath the cache path
*/
protected void setCache(String cachePath) {
File cacheDir = cachePath==null? ResourceLoader.getDefaultOSPCache(): new File(cachePath);
ResourceLoader.setOSPCache(cacheDir);
}
//_____________________ protected and private methods _________________________
/**
* Sets the name of this library.
*
* @param name the name
*/
protected void setName(String name) {
if (name==null) {
name = System.getProperty("user.home").replace('\\', '/'); //$NON-NLS-1$
if(name.endsWith("/")) { //$NON-NLS-1$
name = name.substring(0, name.length()-1);
}
name = XML.getName(name)+" "+ToolsRes.getString("Library.Name"); //$NON-NLS-1$//$NON-NLS-2$
}
this.name = name;
}
/**
* Gets the name of this library.
*
* @return the name
*/
protected String getName() {
return name;
}
/**
* Saves this library in an xml file.
*
* @param path the path to the saved file
*/
protected void save(String path) {
if (path==null) return;
XMLControl control = new XMLControlElement(this);
control.write(path);
}
/**
* Loads this library from an xml file.
*
* @param path the path to the file
*/
protected void load(String path) {
if (path==null) return;
XMLControl control = new XMLControlElement(path);
control.loadObject(this);
}
/**
* Gets the names of all collections maintained by this library.
*
* @return a collection of names
*/
protected Collection<String> getNames() {
return pathToNameMap.values();
}
/**
* Returns true if this library has no collections.
*
* @return true if empty
*/
protected boolean isEmpty() {
return pathList.isEmpty();
}
/**
* Returns true if this library contains a collection path.
*
* @param path the collection path
* @param allLists true to search in all collection lists
* @return true if this contains the path
*/
protected boolean containsPath(String path, boolean allLists) {
path = path.trim();
int n = path.indexOf(LibraryComPADRE.PRIMARY_ONLY);
if (n>-1)
path = path.substring(0, n);
boolean containsPath = pathList.contains(path);
if (allLists) {
containsPath = containsPath
|| comPADREPathList.contains(path)
|| ospPathList.contains(path);
}
return containsPath;
}
/**
* Adds a collection to this library.
*
* @param path the path to the collection
* @param name the menu item name for the collection
*/
protected void addCollection(String path, String name) {
path = path.trim();
// don't add duplicate paths
if (pathList.contains(path))
return;
pathList.add(path);
pathToNameMap.put(path, name.trim());
allPathsToNameMap.put(path, name.trim());
}
/**
* Renames a collection.
*
* @param path the path to the collection
* @param newName the new name
*/
protected void renameCollection(String path, String newName) {
path = path.trim();
// change only paths that have already been added
if (!pathList.contains(path))
return;
pathToNameMap.put(path, newName.trim());
allPathsToNameMap.put(path, newName.trim());
}
/**
* Returns all collection paths in this Library and sublibraries.
*
* @return array of paths
*/
protected TreeSet<String> getAllPaths() {
TreeSet<String> paths = new TreeSet<String>();
paths.addAll(pathList);
paths.addAll(comPADREPathList);
paths.addAll(ospPathList);
if (!subPathList.isEmpty()) {
for (String path: subPathList) {
Library library = subPathToLibraryMap.get(path);
paths.addAll(library.getAllPaths());
}
}
for (String path: ospPathList) {
Library library = ospPathToLibraryMap.get(path);
paths.addAll(library.getAllPaths());
}
return paths;
}
/**
* Returns a Map of path-to-tab name.
*
* @return path-to-name map
*/
protected HashMap<String, String> getNameMap() {
return allPathsToNameMap;
}
/**
* Gets a clone of this library that is suitable for exporting. The exported
* library has no OSP libraries, ComPADRE collections or imported libraries.
*
* @return a Library for export
*/
protected Library getCloneForExport() {
Library lib = new Library();
lib.pathList = pathList;
lib.pathToNameMap = pathToNameMap;
lib.name = name;
return lib;
}
/**
* Imports a Library if not already imported.
*
* @param path the path to the library
* @param library the library
* @return true if imported
*/
protected boolean importLibrary(String path, Library library) {
if (importedPathList.contains(path))
return false;
importedPathList.add(path);
importedPathToLibraryMap.put(path, library);
return true;
}
/**
* Adds a path to the list of recently opened tabs.
*
* @param filename the absolute path to a recently opened or saved file.
* @param atEnd true to add at end of the list
*/
protected void addRecent(String filename, boolean atEnd) {
if (filename==null) return;
synchronized(recentTabs) {
while (recentTabs.contains(filename))
recentTabs.remove(filename);
if (atEnd)
recentTabs.add(filename);
else
recentTabs.add(0, filename);
while (recentTabs.size()>maxRecentTabCount) {
recentTabs.remove(recentTabs.size()-1);
}
}
}
/**
* Removes a path from the list of recently opened tabs.
*
* @param filename the path to remove.
*/
protected void removeRecent(String filename) {
if (filename==null) return;
synchronized(recentTabs) {
while (recentTabs.contains(filename))
recentTabs.remove(filename);
}
}
/**
* Returns an ObjectLoader to save and load data for this class.
*
* @return the object loader
*/
public static XML.ObjectLoader getLoader() {
return new Loader();
}
/**
* A class to save and load data for this class.
*/
static class Loader implements XML.ObjectLoader {
/**
* Saves an object's data to an XMLControl.
*
* @param control the control to save to
* @param obj the object to save
*/
public void saveObject(XMLControl control, Object obj) {
Library library = (Library)obj;
control.setValue("name", library.getName()); //$NON-NLS-1$
if (!library.pathList.isEmpty()) {
String[] paths = library.pathList.toArray(new String[0]);
control.setValue("collection_paths", paths); //$NON-NLS-1$
String[] names = new String[paths.length];
for (int i=0; i< paths.length; i++) {
names[i] = library.pathToNameMap.get(paths[i]);
}
control.setValue("collection_names", names); //$NON-NLS-1$
}
if (!library.subPathList.isEmpty()) {
String[] paths = library.subPathList.toArray(new String[0]);
control.setValue("sublibrary_paths", paths); //$NON-NLS-1$
}
if (!library.importedPathList.isEmpty()) {
String[] paths = library.importedPathList.toArray(new String[0]);
control.setValue("imported_library_paths", paths); //$NON-NLS-1$
}
control.setValue("open_tabs", library.openTabPaths); //$NON-NLS-1$
control.setValue("chooser_directory", library.chooserDir); //$NON-NLS-1$
if (!library.recentTabs.isEmpty()) {
String[] paths = library.recentTabs.toArray(new String[0]);
control.setValue("recently_opened", paths); //$NON-NLS-1$
String[] names = new String[paths.length];
for (int i=0; i<names.length; i++) {
names[i] = library.getNameMap().get(paths[i]);
if (names[i]==null) names[i] = XML.getName(paths[i]);
}
control.setValue("recently_opened_names", names); //$NON-NLS-1$
}
if (!library.noSearchSet.isEmpty()) {
String[] paths = library.noSearchSet.toArray(new String[0]);
control.setValue("no_search_paths", paths); //$NON-NLS-1$
}
if (ResourceLoader.getOSPCache()!=null) {
File cache = ResourceLoader.getOSPCache();
control.setValue("cache", cache.getPath()); //$NON-NLS-1$
}
}
/**
* Creates a new object.
*
* @param control the XMLControl with the object data
* @return the newly created object
*/
public Object createObject(XMLControl control) {
return new Library();
}
/**
* Loads an object with data from an XMLControl.
*
* @param control the control
* @param obj the object
* @return the loaded object
*/
public Object loadObject(XMLControl control, Object obj) {
final Library library = (Library)obj;
library.setName(control.getString("name")); //$NON-NLS-1$
String[] paths = (String[])control.getObject("collection_paths"); //$NON-NLS-1$
if (paths!=null) {
String[] names = (String[])control.getObject("collection_names"); //$NON-NLS-1$
library.pathList.clear();
library.pathToNameMap.clear();
for (int i=0; i<paths.length; i++) {
if (paths[i]==null || names[i]==null) continue;
library.pathList.add(paths[i]);
library.pathToNameMap.put(paths[i], names[i]);
library.allPathsToNameMap.put(paths[i], names[i]);
}
}
paths = (String[])control.getObject("sublibrary_paths"); //$NON-NLS-1$
if (paths!=null) {
for (String path: paths) {
library.addSubLibrary(path);
}
}
paths = (String[])control.getObject("imported_library_paths"); //$NON-NLS-1$
if (paths!=null) {
for (String path: paths) {
library.importLibrary(path);
}
}
paths = (String[])control.getObject("recently_opened"); //$NON-NLS-1$
String[] names = (String[])control.getObject("recently_opened_names"); //$NON-NLS-1$
if (paths!=null) {
for (String path: paths) {
library.addRecent(path, true); // add at end
}
if (names!=null) {
for (int i=0; i<names.length; i++) {
library.getNameMap().put(paths[i], names[i]);
}
}
}
paths = (String[])control.getObject("no_search_paths"); //$NON-NLS-1$
if (paths!=null) {
for (String path: paths) {
library.noSearchSet.add(path);
}
}
library.openTabPaths = (String[])control.getObject("open_tabs"); //$NON-NLS-1$
library.chooserDir = control.getString("chooser_directory"); //$NON-NLS-1$
// set cache only if it has not yet been set
if (ResourceLoader.getOSPCache()==null) {
library.setCache(control.getString("cache")); //$NON-NLS-1$
}
return obj;
}
}
}