package com.revolsys.swing.tree.node.file;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.AccessDeniedException;
import java.nio.file.DirectoryStream;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Vector;
import javax.swing.Icon;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import com.revolsys.datatype.DataType;
import com.revolsys.elevation.cloud.PointCloudReaderFactory;
import com.revolsys.elevation.gridded.GriddedElevationModelReadFactory;
import com.revolsys.elevation.tin.TriangulatedIrregularNetworkReadFactory;
import com.revolsys.io.FileUtil;
import com.revolsys.io.IoFactory;
import com.revolsys.io.file.FileConnectionManager;
import com.revolsys.io.file.FolderConnectionRegistry;
import com.revolsys.io.file.Paths;
import com.revolsys.logging.Logs;
import com.revolsys.raster.GeoreferencedImage;
import com.revolsys.raster.GeoreferencedImageReadFactory;
import com.revolsys.record.io.RecordIo;
import com.revolsys.record.io.RecordReader;
import com.revolsys.record.io.RecordReaderFactory;
import com.revolsys.record.schema.RecordDefinition;
import com.revolsys.record.schema.RecordStore;
import com.revolsys.swing.Borders;
import com.revolsys.swing.Icons;
import com.revolsys.swing.SwingUtil;
import com.revolsys.swing.component.ValueField;
import com.revolsys.swing.field.ComboBox;
import com.revolsys.swing.field.TextField;
import com.revolsys.swing.layout.GroupLayouts;
import com.revolsys.swing.map.layer.Project;
import com.revolsys.swing.map.layer.record.AbstractRecordLayer;
import com.revolsys.swing.menu.MenuFactory;
import com.revolsys.swing.tree.BaseTreeNode;
import com.revolsys.swing.tree.TreeNodes;
import com.revolsys.swing.tree.node.FunctionChildrenTreeNode;
import com.revolsys.swing.tree.node.LazyLoadTreeNode;
import com.revolsys.swing.tree.node.record.PathRecordStoreTreeNode;
import com.revolsys.util.Exceptions;
import com.revolsys.util.Property;
import com.revolsys.util.UrlProxy;
import com.revolsys.util.UrlUtil;
public class PathTreeNode extends LazyLoadTreeNode implements UrlProxy {
private static final JFileChooser CHOOSER = new JFileChooser();
public static final Icon ICON_FILE = CHOOSER.getIcon(FileUtil.newTempFile("xxxx", "6z4gsdj"));
public static final Icon ICON_FILE_DATABASE = Icons.getIconWithBadge(ICON_FILE, "database");
public static final Icon ICON_FILE_IMAGE = Icons.getIconWithBadge(ICON_FILE, "picture");
public static final Icon ICON_FILE_TABLE = Icons.getIconWithBadge(ICON_FILE, "table");
public static final Icon ICON_FILE_VECTOR = Icons.getIconWithBadge(ICON_FILE, "table");
public static final Icon ICON_FOLDER = Icons.getIcon("folder");
public static final Icon ICON_FOLDER_DRIVE = Icons.getIconWithBadge(ICON_FOLDER, "drive");
public static final Icon ICON_FOLDER_LINK = Icons.getIconWithBadge(ICON_FOLDER, "link");
public static final Icon ICON_FOLDER_MISSING = Icons.getIconWithBadge(ICON_FOLDER, "error");
private static final MenuFactory MENU = new MenuFactory("File");
static {
addRefreshMenuItem(MENU);
TreeNodes.addMenuItem(MENU, "default", "Add Layer", "map_add", PathTreeNode::isFileLayer,
PathTreeNode::actionAddLayer);
TreeNodes.addMenuItem(MENU, "default", "Export Records", "table_save",
PathTreeNode::isRecordFileLayer, PathTreeNode::actionExportRecords);
TreeNodes.addMenuItem(MENU, "default", "Add Folder Connection", "link_add",
PathTreeNode::isDirectory, PathTreeNode::actionAddFolderConnection);
}
public static void addPathNode(final List<BaseTreeNode> children, final Path path,
final boolean showHidden) {
if (showHidden || !Paths.isHidden(path) && Files.exists(path)) {
final BaseTreeNode child = newTreeNode(path);
children.add(child);
}
}
public static Icon getIcon(final Path path) {
if (path == null) {
return ICON_FOLDER_MISSING;
} else {
if (GeoreferencedImage.isReadable(path)) {
return ICON_FILE_IMAGE;
} else if (RecordReader.isReadable(path)) {
return ICON_FILE_TABLE;
}
File file;
try {
file = path.toFile();
final Icon icon = CHOOSER.getIcon(file);
return icon;
} catch (final UnsupportedOperationException e) {
if (Files.isDirectory(path)) {
return ICON_FOLDER;
}
final String fileNameExtension = Paths.getFileNameExtension(path);
file = FileUtil.newTempFile("1234567890", fileNameExtension);
final Icon icon = CHOOSER.getIcon(file);
file.delete();
return icon;
}
}
}
private static File getIconFile(final Path path) {
try {
return path.toFile();
} catch (final UnsupportedOperationException e) {
final String fileNameExtension = Paths.getFileNameExtension(path);
final File file = FileUtil.newTempFile("1234567890", fileNameExtension);
file.delete();
return file;
}
}
public static List<BaseTreeNode> getPathNodes(final Iterable<Path> paths,
final boolean showHidden) {
final List<BaseTreeNode> children = new ArrayList<>();
if (paths != null) {
for (final Path path : paths) {
addPathNode(children, path, showHidden);
}
}
return children;
}
public static List<BaseTreeNode> getPathNodes(final Path path) {
if (Files.isDirectory(path)) {
try (
final DirectoryStream<Path> children = Files.newDirectoryStream(path)) {
return getPathNodes(children, false);
} catch (final AccessDeniedException e) {
} catch (final IOException e) {
Logs.debug(PathTreeNode.class, "Unable to get children " + path);
}
}
return Collections.emptyList();
}
public static URL getUrl(final BaseTreeNode parent, final Path path) {
if (parent instanceof UrlProxy) {
final UrlProxy parentProxy = (UrlProxy)parent;
String childPath = Paths.getFileName(path);
if (Files.isDirectory(path)) {
childPath += "/";
}
return UrlUtil.getUrl(parentProxy, childPath);
} else {
try {
final URL url = path.toUri().toURL();
return url;
} catch (final MalformedURLException e) {
throw Exceptions.wrap(e);
}
}
}
public static boolean isAllowsChildren(final Path path) {
if (path == null) {
return true;
} else if (!Paths.exists(path)) {
return false;
} else if (Files.isDirectory(path)) {
return true;
} else {
return false;
}
}
public static BaseTreeNode newFileSystemsTreeNode() {
final BaseTreeNode fileSystems = new FunctionChildrenTreeNode(FileSystems.getDefault(),
"File Systems", ICON_FOLDER_DRIVE, (fileSystem) -> {
final Iterable<Path> roots = ((FileSystem)fileSystem).getRootDirectories();
return getPathNodes(roots, true);
});
fileSystems.setOpen(true);
return fileSystems;
}
public static BaseTreeNode newTreeNode(final Path path) {
if (RecordStore.isRecordStore(path)) {
return new PathRecordStoreTreeNode(path);
} else {
final List<String> fileNameExtensions = Paths.getFileNameExtensions(path);
if (fileNameExtensions.contains("zip") || fileNameExtensions.contains("jar")) {
try {
return new SingleFileSystemTreeNode(path);
} catch (final Throwable e) {
return new PathTreeNode(path);
}
} else {
return new PathTreeNode(path);
}
}
}
private boolean exists;
private boolean hasFile;
public PathTreeNode(final Path path) {
super(path);
final String fileName = Paths.getFileName(path);
setName(fileName);
refreshFields();
}
private void actionAddFolderConnection() {
if (isDirectory()) {
final Path path = getPath();
final String fileName = getName();
final ValueField panel = new ValueField();
panel.setTitle("Add Folder Connection");
Borders.titled(panel, "Folder Connection");
SwingUtil.addLabel(panel, "Folder");
final JLabel fileLabel = new JLabel(getIconFile(path).getAbsolutePath());
panel.add(fileLabel);
SwingUtil.addLabel(panel, "Name");
final TextField nameField = new TextField(20);
panel.add(nameField);
nameField.setText(fileName);
SwingUtil.addLabel(panel, "Folder Connections");
final List<FolderConnectionRegistry> registries = new ArrayList<>();
for (final FolderConnectionRegistry registry : FileConnectionManager.get()
.getVisibleConnectionRegistries()) {
if (!registry.isReadOnly()) {
registries.add(registry);
}
}
final ComboBox<FolderConnectionRegistry> registryField = ComboBox.newComboBox("registry",
new Vector<>(registries));
panel.add(registryField);
GroupLayouts.makeColumns(panel, 2, true);
panel.showDialog();
if (panel.isSaved()) {
final FolderConnectionRegistry registry = registryField.getSelectedItem();
String connectionName = nameField.getText();
if (!Property.hasValue(connectionName)) {
connectionName = fileName;
}
registry.addConnection(connectionName, getIconFile(path));
}
}
}
private void actionAddLayer() {
final URL url = getUrl();
final Project project = Project.get();
project.openFile(url);
}
private void actionExportRecords() {
final Path path = getPath();
boolean hasGeometryField;
try (
RecordReader reader = RecordReader.newRecordReader(path)) {
if (reader == null) {
return;
} else {
final RecordDefinition recordDefinition = reader.getRecordDefinition();
if (recordDefinition == null) {
return;
} else {
hasGeometryField = recordDefinition.hasGeometryField();
}
}
}
final String title = Paths.getBaseName(path);
AbstractRecordLayer.exportRecords(title, hasGeometryField, (targetFile) -> {
RecordIo.copyRecords(path, targetFile);
});
}
@Override
public boolean equals(final Object other) {
if (other == this) {
return true;
} else if (other instanceof PathTreeNode) {
if (getClass() == other.getClass()) {
final PathTreeNode fileNode = (PathTreeNode)other;
if (isExists() == fileNode.isExists()) {
final Path path = getPath();
final Path otherPath = fileNode.getPath();
final boolean equal = DataType.equal(path, otherPath);
return equal;
}
}
}
return false;
}
@Override
public Icon getIcon() {
Icon icon = super.getIcon();
if (icon == null) {
if (isExists()) {
final Path path = getPath();
icon = getIcon(path);
setIcon(icon);
}
}
return icon;
}
@Override
public MenuFactory getMenu() {
return MENU;
}
// @Override
// public String getType() {
// final Path path = getPath();
// if (Files.isDirectory(path)) {
// return "Folder";
// } else if (Files.exists(path)) {
// final String extension = Paths.getFileNameExtension(path);
// if (Property.hasValue(extension)) {
// final IoFactory factory = IoFactory.factoryByFileExtension(IoFactory.class,
// extension);
// if (factory != null) {
// return factory.getName();
// }
// }
// return "File";
// } else {
// return "Missing File/Folder";
// }
// }
public Path getPath() {
return getUserData();
}
@Override
public URL getUrl() {
final Path path = getPath();
final BaseTreeNode parent = getParent();
return getUrl(parent, path);
}
@Override
public int hashCode() {
final Path path = getPath();
if (path == null) {
return 0;
} else {
return path.hashCode();
}
}
@Override
public boolean isAllowsChildren() {
final Path path = getPath();
return isAllowsChildren(path);
}
public boolean isDirectory() {
if (isExists()) {
final Path path = getPath();
return Files.isDirectory(path);
} else {
return false;
}
}
@Override
public boolean isExists() {
return this.exists;
}
public boolean isFileLayer() {
if (isExists()) {
final Path path = getPath();
if (!this.hasFile) {
return false;
} else if (IoFactory.hasFactory(GeoreferencedImageReadFactory.class, path)) {
return true;
} else if (IoFactory.hasFactory(PointCloudReaderFactory.class, path)) {
return true;
} else if (IoFactory.hasFactory(RecordReaderFactory.class, path)) {
return true;
} else if (IoFactory.hasFactory(GriddedElevationModelReadFactory.class, path)) {
return true;
} else if (IoFactory.hasFactory(TriangulatedIrregularNetworkReadFactory.class, path)) {
return true;
}
}
return false;
}
public boolean isHasFile() {
return this.hasFile;
}
public boolean isRecordFileLayer() {
if (isExists()) {
final Path path = getPath();
if (!this.hasFile) {
return false;
} else if (IoFactory.hasFactory(RecordReaderFactory.class, path)) {
return true;
}
}
return false;
}
@Override
protected List<BaseTreeNode> loadChildrenDo() {
refreshFields();
final Path path = getPath();
return getPathNodes(path);
}
private void refreshFields() {
final Path path = getPath();
this.exists = Paths.exists(path);
final Icon icon = getIcon(path);
setIcon(icon);
try {
path.toFile();
this.hasFile = true;
} catch (final UnsupportedOperationException e) {
}
}
}