package ucar.nc2.ui;
import org.jdom2.input.SAXBuilder;
import org.jdom2.output.XMLOutputter;
import thredds.catalog.parser.jdom.FeatureCollectionReader;
import thredds.featurecollection.FeatureCollectionConfig;
import thredds.inventory.*;
import thredds.inventory.partition.DirectoryPartition;
import thredds.inventory.partition.DirectoryBuilder;
import ucar.coord.Coordinate;
import ucar.nc2.grib.collection.GribCdmIndex;
import ucar.nc2.grib.collection.GribCollectionMutable;
import ucar.nc2.grib.collection.PartitionCollectionMutable;
import ucar.nc2.ui.widget.*;
import ucar.nc2.ui.widget.PopupMenu;
import ucar.unidata.util.StringUtil2;
import ucar.util.prefs.PreferencesExt;
import ucar.util.prefs.ui.BeanTable;
import ucar.util.prefs.ui.ComboBox;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import java.awt.*;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.*;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.*;
import java.util.List;
/**
* GribCollection Directory Partition Viewer
*
* @author caron
* @since 11/9/13
*/
public class DirectoryPartitionViewer extends JPanel {
static private final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(DirectoryPartitionViewer.class);
private PreferencesExt prefs;
private FeatureCollectionConfig config;
private String collectionName;
private CdmIndex3Panel cdmIndexTables;
private PartitionsTable partitionsTable;
private JPanel tablePanel;
private JSplitPane mainSplit;
private PartitionTreeBrowser partitionTreeBrowser;
private MFileTable fileTable;
private TextHistoryPane infoTA;
private IndependentWindow infoWindow;
private ComboBox cb;
private FileManager dirFileChooser;
private boolean isFromIndex;
public DirectoryPartitionViewer(PreferencesExt prefs, JPanel topPanel, JPanel buttPanel) {
this.prefs = prefs;
partitionTreeBrowser = new PartitionTreeBrowser();
partitionsTable = new PartitionsTable((PreferencesExt) prefs.node("partTable"));
cdmIndexTables = new CdmIndex3Panel((PreferencesExt) prefs.node("cdmIdx"), buttPanel);
cdmIndexTables.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
firePropertyChange(evt.getPropertyName(), evt.getOldValue(), evt.getNewValue());
}
});
if (topPanel != null && buttPanel != null) {
cb = new ComboBox(prefs);
cb.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String filename = (String) cb.getSelectedItem();
if (filename == null) return;
File d = new File( filename);
if (d.isDirectory()) {
setDirectory(d);
} else if (d.getName().endsWith(".xml")) {
setCollectionFromConfig(d.getPath());
} else if (d.getName().endsWith(CollectionAbstract.NCX_SUFFIX)) {
setCollectionFromIndex(d.getPath());
}
cb.addItem(filename);
}
});
topPanel.add(new JLabel("dir,ncx3,or config:"), BorderLayout.WEST);
topPanel.add(cb, BorderLayout.CENTER);
// a file chooser that can choose a directory
dirFileChooser = new FileManager(null, null, null, (PreferencesExt) prefs.node("fileChooser"));
dirFileChooser.getFileChooser().setFileSelectionMode( JFileChooser.FILES_AND_DIRECTORIES);
AbstractAction dirFileAction = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
String filename = dirFileChooser.chooseFilename();
if (filename == null) return;
cb.setSelectedItem(filename);
}
};
BAMutil.setActionProperties(dirFileAction, "FileChooser", "choose file or directory...", false, 'L', -1);
BAMutil.addActionToContainer(buttPanel, dirFileAction);
/* AbstractButton infoButton = BAMutil.makeButtcon("Information", "Show Info", false);
infoButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
showInfo();
}
});
buttPanel.add(infoButton);
AbstractButton info2Button = BAMutil.makeButtcon("Information", "Show Detail Info", false);
info2Button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
showDetailInfo();
}
});
buttPanel.add(info2Button); */
}
setLayout(new BorderLayout());
JScrollPane treeScroll = new JScrollPane(partitionTreeBrowser.tree);
JPanel treePanel = new JPanel(new BorderLayout());
treePanel.add(treeScroll, BorderLayout.CENTER);
treePanel.add(partitionTreeBrowser.view, BorderLayout.SOUTH);
tablePanel = new JPanel(new BorderLayout());
tablePanel.add(cdmIndexTables, BorderLayout.CENTER);
current = cdmIndexTables;
mainSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, false, treePanel, tablePanel);
mainSplit.setDividerLocation(prefs.getInt("mainSplit", 100));
add(mainSplit, BorderLayout.CENTER);
// the info window
infoTA = new TextHistoryPane();
infoWindow = new IndependentWindow("Information", BAMutil.getImage("netcdfUI"), infoTA);
infoWindow.setBounds((Rectangle) prefs.getBean("InfoWindowBounds", new Rectangle(300, 300, 500, 300)));
// file popup window
fileTable = new MFileTable((PreferencesExt) prefs.node("MFileTable"), true);
fileTable.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
firePropertyChange(evt.getPropertyName(), evt.getOldValue(), evt.getNewValue());
}
});
}
public void save() {
if (mainSplit != null) prefs.putInt("mainSplit", mainSplit.getDividerLocation());
if (cb != null) cb.save();
if (dirFileChooser != null) dirFileChooser.save();
cdmIndexTables.save();
partitionsTable.save();
prefs.putBeanObject("InfoWindowBounds", infoWindow.getBounds());
fileTable.save();
}
public void clear() {
cdmIndexTables.clear();
partitionsTable.clear();
}
private Component current;
private void swap(Component want) {
if (current == want) return;
tablePanel.remove(current);
tablePanel.add(want, BorderLayout.CENTER);
tablePanel.revalidate();
current = want;
repaint();
}
public void showInfo() {
Formatter f = new Formatter();
if (current == partitionsTable) {
partitionsTable.showGroupDiffs(f);
} else if (current == cdmIndexTables) {
cdmIndexTables.showInfo(f);
} else {
return;
}
infoTA.setText(f.toString());
infoTA.gotoTop();
infoWindow.show();
}
public void showDetailInfo() {
Formatter f = new Formatter();
if (current == partitionsTable) {
partitionsTable.showGroupDiffs(f);
} else if (current == cdmIndexTables) {
cdmIndexTables.showInfo(f);
} else {
return;
}
infoTA.setText(f.toString());
infoTA.gotoTop();
infoWindow.show();
}
////////////////////////////////////////////////
// top directory
private void setDirectory(File dir) {
config = new FeatureCollectionConfig();
if (dir.isDirectory()) {
partitionTreeBrowser.setRoot(dir.toPath());
}
}
// feature collection config
private void setCollectionFromConfig(String name) {
Path f = Paths.get(name);
if (!Files.exists(f)) return;
org.jdom2.Document doc;
try {
SAXBuilder builder = new SAXBuilder();
doc = builder.build(f.toFile());
} catch (Exception e) {
javax.swing.JOptionPane.showMessageDialog(this, "Error parsing featureCollection: " + e.getMessage());
return;
}
if (true) {
XMLOutputter xmlOut = new XMLOutputter();
System.out.println(xmlOut.outputString(doc));
}
Formatter errlog = new Formatter();
config = FeatureCollectionReader.readFeatureCollection(doc.getRootElement());
CollectionSpecParser specp = config.getCollectionSpecParser(errlog);
partitionTreeBrowser.setRoot(Paths.get(specp.getRootDir()));
}
// ncx2 index
private void setCollectionFromIndex(String indexFilename) {
isFromIndex = true;
config = new FeatureCollectionConfig(); // LOOK !!
File indexFile = new File(indexFilename);
File parentFile = indexFile.getParentFile();
// whats the bloody collection name?
String name = indexFile.getName();
String dirName = parentFile.getName();
name = StringUtil2.removeFromEnd(name, CollectionAbstract.NCX_SUFFIX);
name = StringUtil2.removeFromEnd(name, dirName);
name = StringUtil2.removeFromEnd(name, "-");
this.collectionName = name;
setDirectory(parentFile);
}
/* private void moveCdmIndexAll(NodeInfo indexFile) {
Formatter out = new Formatter();
infoWindow.show();
for (File f : indexFile.getParentFile().listFiles()) {
if (!f.getName().endsWith(".ncx")) continue;
GribCollection gc = null;
try {
boolean ok = GribCdmIndex.moveCdmIndex(f, logger);
out.format("%s moved success=%s%n", f.getPath(), ok);
infoTA.appendLine(f.getPath() + " moved success=" + ok);
} catch (Throwable t) {
out.format("%s moved failed=%s%n", f.getPath(), t.getMessage());
}
}
infoTA.setText(out.toString());
infoTA.gotoTop();
infoWindow.show();
} */
/* private void showChildrenIndex(NodeInfo topDir) {
if (!topDir.isDirectory()) {
JOptionPane.showMessageDialog(this, topDir.getPath() + " not a directory: ");
return;
}
Formatter out = new Formatter();
try {
boolean ok = GribCdmIndex.showDirectoryPartitionIndex(collectionName, topDir, out);
out.format("%s showChildrenIndex success=%s%n", topDir.getPath(), ok);
infoTA.appendLine(out.toString());
infoTA.gotoTop();
infoWindow.show();
} catch (Throwable t) {
JOptionPane.showMessageDialog(this, topDir.getPath() + " showChildrenIndex failed: " + t.getMessage());
}
} */
private void cmdSummarizePartitions(final NodeInfo node) {
// long running task in background thread
Thread background = new Thread() {
public void run() {
Formatter out = new Formatter();
GribCdmIndex indexReader = new GribCdmIndex(logger);
final DirectoryPartition dpart = new DirectoryPartition(config, node.dir, true, indexReader, logger);
dpart.putAuxInfo(FeatureCollectionConfig.AUX_CONFIG, config);
try (PartitionCollectionMutable tp = (PartitionCollectionMutable) GribCdmIndex.openMutableGCFromIndex(dpart.getIndexFilename(), config, false, true, logger)) {
if (tp == null) return;
for (MCollection dcmp : dpart.makePartitions(null)) {
dcmp.putAuxInfo(FeatureCollectionConfig.AUX_CONFIG, config);
tp.addPartition(dcmp);
}
final List<GribCollectionMutable> gclist = new ArrayList<>();
for (PartitionCollectionMutable.Partition tpp : tp.getPartitions()) {
try ( GribCollectionMutable gc = tpp.makeGribCollection()) { // use index if it exists
if (gc != null)
gclist.add(gc);
} catch (Throwable t) {
t.printStackTrace();
out.format("Failed to open partition %s%n", tpp.getName());
logger.error(" Failed to open partition " + tpp.getName(), t);
}
}
// switch back to Swing event thread to manipulate GUI
SwingUtilities.invokeLater(new Runnable() {
public void run() {
partitionsTable.clear();
partitionsTable.setHeader(dpart.getCollectionName());
for (GribCollectionMutable gc : gclist)
partitionsTable.addGribCollection(gc);
swap(partitionsTable);
}
}
);
} catch (Throwable t) {
t.printStackTrace();
JOptionPane.showMessageDialog(DirectoryPartitionViewer.this, node.dir + " showPartitions failed: " + t.getMessage());
}
}
};
background.start();
}
private void cmdShowIndex(NodeInfo node) {
try {
// this opens the index file and constructs a GribCollection
Path index = node.part.getIndex();
if (index == null) {
node.part.findIndex();
}
cdmIndexTables.setIndexFile(node.part.getIndex(), config);
swap(cdmIndexTables);
} catch (Throwable t) {
t.printStackTrace();
JOptionPane.showMessageDialog(this, node + " showIndex failed: " + t.getMessage());
}
}
private void cmdMakeIndex(NodeInfo node) {
Formatter out = new Formatter();
out.format("makeTimePartitionIndex %s%n%n", node);
try {
boolean ok = GribCdmIndex.makeIndex(config, out, node.dir);
out.format("makeTimePartitionIndex success %s%n%n", ok);
infoTA.setText(out.toString());
infoTA.gotoTop();
infoWindow.show();
node.refresh();
// cmdShowIndex(node);
} catch (Throwable t) {
t.printStackTrace();
JOptionPane.showMessageDialog(this, node + " makeIndex failed: " + t.getMessage());
}
}
private class NodeInfo {
Path dir;
DirectoryBuilder part;
boolean hasIndex;
boolean isPartition = true;
NodeInfo(Path dir) {
this.dir = dir;
try {
part = new DirectoryBuilder(collectionName, dir, null);
hasIndex = part.getIndex() != null;
} catch (IOException e) {
e.printStackTrace();
}
}
NodeInfo(DirectoryBuilder part) {
this.part = part;
this.dir = part.getDir();
this.hasIndex = part.getIndex() != null;
}
List<NodeInfo> getChildren() {
return (isFromIndex) ? getChildrenFromIndex() : getChildrenFromScan();
}
private List<NodeInfo> getChildrenFromIndex() {
List<NodeInfo> result = new ArrayList<>(100);
try {
for (DirectoryBuilder child : part.constructChildrenFromIndex(new GribCdmIndex(logger), true))
result.add(new NodeInfo(child));
isPartition = (result.size() > 0);
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
private List<NodeInfo> getChildrenFromScan() {
List<NodeInfo> result = new ArrayList<>(100);
try {
for (DirectoryBuilder child : part.constructChildren(new GribCdmIndex(logger), CollectionUpdateType.test))
result.add(new NodeInfo(child));
isPartition = (result.size() > 0);
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
void refresh() {
try {
this.hasIndex = part.findIndex();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public String toString() {
Formatter f = new Formatter();
f.format("NodeInfo{ dir= %s", dir);
if (hasIndex) f.format(" index= %s", part.getIndex());
f.format("}");
return f.toString();
}
}
private class PartitionTreeBrowser {
//private FileSystemView fileSystemView;
private Icon dirIcon, fileIcon;
private NodeInfo currentNode;
JTree tree; // File-system tree. Built Lazily
private DefaultTreeModel treeModel;
private JProgressBar progressBar;
/* File details. */
JPanel view;
private JLabel nodeName;
private JTextField path;
private JLabel date;
private JLabel size;
private JCheckBox readable;
private JCheckBox writable;
private JRadioButton isDirectory;
private JRadioButton isFile;
public void setRoot(Path rootDir) {
if (!Files.isDirectory(rootDir)) return;
DefaultMutableTreeNode root = new DefaultMutableTreeNode();
root.setUserObject(new NodeInfo(rootDir));
treeModel = new DefaultTreeModel(root);
tree.setModel(treeModel);
tree.setSelectionInterval(0, 0);
}
public PartitionTreeBrowser() {
dirIcon = UIManager.getIcon("FileView.directoryIcon");
fileIcon = UIManager.getIcon("FileView.fileIcon");
DefaultMutableTreeNode root = new DefaultMutableTreeNode();
treeModel = new DefaultTreeModel(root);
TreeSelectionListener treeSelectionListener = new TreeSelectionListener() {
public void valueChanged(TreeSelectionEvent tse) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode) tse.getPath().getLastPathComponent();
showChildren(node);
currentNode = (NodeInfo) node.getUserObject();
setFileDetails(currentNode);
}
};
tree = new JTree(treeModel);
tree.setRootVisible(true);
tree.addTreeSelectionListener(treeSelectionListener);
tree.setCellRenderer(new FileTreeCellRenderer());
tree.expandRow(0);
// tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
tree.setToggleClickCount(1);
// as per trashgod tip
tree.setVisibleRowCount(15);
JScrollPane treeScroll = new JScrollPane(tree);
Dimension preferredSize = treeScroll.getPreferredSize();
Dimension widePreferred = new Dimension(200, (int) preferredSize.getHeight());
treeScroll.setPreferredSize(widePreferred);
makePopups();
/////////////////////
// details for a File
JPanel filePanel = new JPanel(new BorderLayout(4, 2));
filePanel.setBorder(new EmptyBorder(0, 6, 0, 6));
JPanel fileDetailsLabels = new JPanel(new GridLayout(0, 1, 2, 2));
filePanel.add(fileDetailsLabels, BorderLayout.WEST);
JPanel fileDetailsValues = new JPanel(new GridLayout(0, 1, 2, 2));
filePanel.add(fileDetailsValues, BorderLayout.CENTER);
fileDetailsLabels.add(new JLabel("File", JLabel.TRAILING));
nodeName = new JLabel();
fileDetailsValues.add(nodeName);
fileDetailsLabels.add(new JLabel("Path/name", JLabel.TRAILING));
path = new JTextField(5);
path.setEditable(false);
fileDetailsValues.add(path);
fileDetailsLabels.add(new JLabel("Last Modified", JLabel.TRAILING));
date = new JLabel();
fileDetailsValues.add(date);
fileDetailsLabels.add(new JLabel("File size", JLabel.TRAILING));
size = new JLabel();
fileDetailsValues.add(size);
fileDetailsLabels.add(new JLabel("Type", JLabel.TRAILING));
JPanel flags = new JPanel(new FlowLayout(FlowLayout.LEADING, 4, 0));
isDirectory = new JRadioButton("Directory");
flags.add(isDirectory);
isFile = new JRadioButton("File");
flags.add(isFile);
fileDetailsValues.add(flags);
//JToolBar toolBar = makeButtonBar();
flags.add(new JLabel(":: Flags"));
readable = new JCheckBox("Read ");
readable.setMnemonic('a');
flags.add(readable);
writable = new JCheckBox("Write ");
writable.setMnemonic('w');
flags.add(writable);
int count = fileDetailsLabels.getComponentCount();
for (int ii = 0; ii < count; ii++) {
fileDetailsLabels.getComponent(ii).setEnabled(false);
}
count = flags.getComponentCount();
for (int ii = 0; ii < count; ii++) {
flags.getComponent(ii).setEnabled(false);
}
///////////////
// progressBar
progressBar = new JProgressBar();
progressBar.setVisible(true);
//////////////
// put together the fileView
view = new JPanel(new BorderLayout(3, 3));
//view.add(toolBar, BorderLayout.NORTH);
view.add(progressBar, BorderLayout.NORTH);
view.add(filePanel, BorderLayout.CENTER);
}
private void makePopups() {
PopupMenu varPopup = new PopupMenu(tree, "Options");
varPopup.addAction("Make Index(es)", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
TreePath[] selectionPaths = tree.getSelectionPaths();
// JTree.getSelectionPaths() returns null instead of an empty array. Dumb.
if (selectionPaths == null) {
selectionPaths = new TreePath[0];
}
for (TreePath path : selectionPaths) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent();
cmdMakeIndex( (NodeInfo) node.getUserObject());
}
}
});
varPopup.addAction("Show Index", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
cmdShowIndex(currentNode);
}
});
varPopup.addAction("Summarize Children Partitions", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
// do this in another Thread
new Thread() {
public void run() {
cmdSummarizePartitions(currentNode);
}
}.start();
}
});
//////////////
// toolbar
//JToolBar toolBar = new JToolBar();
//toolBar.setFloatable(false); // mnemonics stop working in a floated toolbar
/* JButton moveIndexButt = new JButton("Move");
moveIndexButt.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
try {
moveCdmIndexFile(currentNode);
} catch (Throwable t) {
showThrowable(t);
}
repaint();
}
});
toolBar.add(moveIndexButt);
JButton moveAllButt = new JButton("MoveAll");
moveAllButt.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
try {
moveCdmIndexAll(currentNode);
} catch (Throwable t) {
showThrowable(t);
}
repaint();
}
});
toolBar.add(moveAllButt);
JButton showFileButt = new JButton("Show");
showFileButt.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
try {
showCdmIndexFile(currentNode);
} catch (Throwable t) {
showThrowable(t);
}
repaint();
}
});
toolBar.add(showFileButt);
JButton showIndexButt = new JButton("Show Children");
showIndexButt.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
try {
showChildrenIndex(currentNode);
} catch (Throwable t) {
showThrowable(t);
}
repaint();
}
});
toolBar.add(showIndexButt);
JButton showPartButt = new JButton("Show Partitions");
showPartButt.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
try {
showPartitions(currentNode);
} catch (Throwable t) {
showThrowable(t);
}
repaint();
}
});
toolBar.add(showPartButt);
JButton makeIndexButt = new JButton("Make Partition");
makeIndexButt.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
try {
makeIndex(currentNode);
} catch (Throwable t) {
showThrowable(t);
}
repaint();
}
});
toolBar.add(makeIndexButt); */
}
/**
* Add the files that are contained within the directory of this node.
* Thanks to Hovercraft Full Of Eels for the SwingWorker fix.
*/
private void showChildren(final DefaultMutableTreeNode node) {
tree.setEnabled(false);
progressBar.setVisible(true);
progressBar.setIndeterminate(true);
final List<NodeInfo> result = new ArrayList<>(100);
NodeInfo uobj = (NodeInfo) node.getUserObject();
if (uobj.hasIndex && uobj.isPartition) {
for (NodeInfo child : uobj.getChildren()) {
result.add(child);
}
} else {
try (DirectoryStream<Path> stream = Files.newDirectoryStream(uobj.dir)) {
for (Path child : stream) {
if (Files.isDirectory(child))
result.add(new NodeInfo(child));
}
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
if (result.size() == 0) {
progressBar.setIndeterminate(false);
tree.setEnabled(true);
return;
}
SwingWorker<Void, NodeInfo> worker = new SwingWorker<Void, NodeInfo>() {
@Override
public Void doInBackground() {
for (NodeInfo child : result)
publish(child);
return null;
}
@Override
protected void process(List<NodeInfo> chunks) {
for (NodeInfo child : chunks) {
node.add(new DefaultMutableTreeNode(child));
}
}
@Override
protected void done() {
progressBar.setIndeterminate(false);
//progressBar.setVisible(false);
tree.setEnabled(true);
}
};
worker.execute();
}
/**
* Update the File details view with the details of this File.
*/
private void setFileDetails(NodeInfo node) {
BasicFileAttributes attr;
try {
attr = Files.readAttributes(node.dir, BasicFileAttributes.class);
} catch (IOException e) {
logger.warn("An I/O error occurred.", e);
return;
}
nodeName.setIcon(attr.isDirectory() ? dirIcon : fileIcon);
nodeName.setText(node.dir.toString());
path.setText(node.dir.toString());
date.setText(attr.lastModifiedTime().toString());
size.setText(attr.size() + " bytes");
readable.setSelected(Files.isReadable(node.dir));
writable.setSelected(Files.isWritable(node.dir));
isDirectory.setSelected(attr.isDirectory());
repaint();
}
/**
* A TreeCellRenderer for a File.
*/
private class FileTreeCellRenderer extends DefaultTreeCellRenderer {
private JLabel label;
FileTreeCellRenderer() {
label = new JLabel();
label.setOpaque(true);
}
@Override
public Component getTreeCellRendererComponent(
JTree tree,
Object value,
boolean selected,
boolean expanded,
boolean leaf,
int row,
boolean hasFocus) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;
NodeInfo uobj = (NodeInfo) node.getUserObject();
if (uobj != null) {
label.setIcon(uobj.hasIndex ? fileIcon : dirIcon);
label.setText(uobj.hasIndex ? uobj.part.getIndex().toString() : uobj.dir.toString());
}
if (selected) {
label.setBackground(backgroundSelectionColor);
label.setForeground(textSelectionColor);
} else {
label.setBackground(backgroundNonSelectionColor);
label.setForeground(textNonSelectionColor);
}
return label;
}
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private class PartitionsTable extends JPanel {
private PreferencesExt prefs;
private BeanTable groupsTable, groupTable, varTable;
private JSplitPane split;
public PartitionsTable(PreferencesExt prefs) {
this.prefs = prefs;
PopupMenu varPopup;
////////////////
groupsTable = new BeanTable(GroupsBean.class, (PreferencesExt) prefs.node("GroupsBean"), false, "Groups", "GribCollection.GroupHcs", null);
groupsTable.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
GroupsBean bean = (GroupsBean) groupsTable.getSelectedBean();
if (bean != null)
setGroups(bean);
}
});
groupTable = new BeanTable(GroupBean.class, (PreferencesExt) prefs.node("GroupBean"), false, "Partitions for this Group", "GribCollection.GroupGC", null);
groupTable.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
GroupBean bean = (GroupBean) groupTable.getSelectedBean();
if (bean != null)
setGroup(bean.group);
}
});
varPopup = new PopupMenu(groupTable.getJTable(), "Options");
varPopup.addAction("Show Files Used", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
GroupBean bean = (GroupBean) groupTable.getSelectedBean();
if (bean != null) {
if (bean.group != null)
showFiles(null, bean.group);
}
}
});
varPopup.addAction("Show Variable Difference", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
List<GroupBean> beans = (List<GroupBean>) groupTable.getSelectedBeans();
if (beans.size() == 2) {
Formatter f = new Formatter();
showVariableDifferences(beans.get(0), beans.get(1), f);
infoTA.setText(f.toString());
infoTA.gotoTop();
infoWindow.show();
}
}
});
varTable = new BeanTable(VarBean.class, (PreferencesExt) prefs.node("Grib2Bean"), false, "Variables in group", "GribCollection.VariableIndex", null);
varPopup = new PopupMenu(varTable.getJTable(), "Options");
varPopup.addAction("Show Variable", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
VarBean bean = (VarBean) varTable.getSelectedBean();
if (bean != null) {
infoTA.setText(bean.v.toStringComplete());
infoTA.gotoTop();
infoWindow.show();
}
}
});
/////////////////////////////////////////
setLayout(new BorderLayout());
split = new JSplitPane(JSplitPane.VERTICAL_SPLIT, false, groupsTable, groupTable);
split.setDividerLocation(prefs.getInt("splitPos2", 600));
split = new JSplitPane(JSplitPane.VERTICAL_SPLIT, false, split, varTable);
split.setDividerLocation(prefs.getInt("splitPos", 900));
add(split, BorderLayout.CENTER);
}
public void save() {
groupsTable.saveState(false);
groupTable.saveState(false);
varTable.saveState(false);
if (split != null) prefs.putInt("splitPos", split.getDividerLocation());
}
private void setHeader(String header) {
groupsTable.setHeader(header);
}
private void setGroups(GroupsBean groups) {
groupTable.setBeans(groups.beans);
}
private void setGroup(GribCollectionMutable.GroupGC group) {
List<VarBean> vars = new ArrayList<>();
for (GribCollectionMutable.VariableIndex v : group.getVariables())
vars.add(new VarBean(v, group));
varTable.setBeans(vars);
}
// private void showFiles(File dir, List<MFile> files) {
// fileTable.setFiles(dir, files);
// }
private void showFiles(GribCollectionMutable gc, GribCollectionMutable.GroupGC group) {
Collection<MFile> files = (group == null) ? gc.getFiles() : group.getFiles();
File dir = (gc == null) ? null : gc.getDirectory();
fileTable.setFiles(dir, files);
}
private class Groups implements Comparable<Groups> {
String groupId;
SortedSet<String> parts = new TreeSet<>();
private Groups(String id) {
this.groupId = id;
}
@Override
public int compareTo(Groups o2) {
return groupId.compareTo(o2.groupId);
}
}
void showGroupDiffs(Formatter out) {
Map<Integer, Groups> map = new HashMap<>(100);
for (GroupsBean gsbean : groupsBeans.values()) {
for (GroupBean gbean : gsbean.beans) {
Groups gs = map.get(gbean.getGdsHash());
if (gs == null) {
gs = new Groups(gsbean.getGroupId());
map.put(gbean.getGdsHash(), gs);
}
gs.parts.add(gbean.getPartition());
}
}
List<Groups> groups = new ArrayList<>(map.values());
Collections.sort(groups);
out.format("=======================Groups%n");
for (Groups gs : groups) {
if (gs.parts.size() < partitionsAll.size()) {
out.format("Missing partitions for group %s:%n", gs.groupId);
for (String p : partitionsAll) {
if (!gs.parts.contains(p))
out.format(" %s%n", p);
}
}
}
out.format("=======================Partitions%n");
for (String p : partitionsAll) {
out.format("%s Missing groups:%n", p);
for (Groups gs : groups) {
if (!gs.parts.contains(p))
out.format(" %s%n", gs.groupId);
}
}
}
Map<String, GroupsBean> groupsBeans = new HashMap<>(50);
SortedSet<String> partitionsAll = new TreeSet<>();
void clear() {
groupsBeans = new HashMap<>(50);
partitionsAll = new TreeSet<>();
}
void addGribCollection(GribCollectionMutable gc) {
String partitionName = gc.getLocation();
int pos = partitionName.lastIndexOf("/");
if (pos < 0) pos = partitionName.lastIndexOf("\\");
if (pos > 0) partitionName = partitionName.substring(0, pos);
partitionsAll.add(partitionName);
for (GribCollectionMutable.Dataset ds : gc.getDatasets()) {
for (GribCollectionMutable.GroupGC g : ds.getGroups()) {
GroupsBean bean = groupsBeans.get(g.getId());
if (bean == null) {
bean = new GroupsBean(g);
groupsBeans.put(g.getId(), bean);
}
bean.addGroup(g, ds.gctype.toString(), partitionName);
}
}
groupsTable.setBeans(new ArrayList<>(groupsBeans.values()));
}
void showVariableDifferences(GroupBean bean1, GroupBean bean2, Formatter f) {
f.format("Compare %s to %s%n", bean1.getPartition(), bean2.getPartition());
for (GribCollectionMutable.VariableIndex var1 : bean1.group.getVariables()) {
if (bean2.group.findVariableByHash(var1) == null)
f.format("Var1 %s missing in partition 2%n", var1.id());
}
for (GribCollectionMutable.VariableIndex var2 : bean2.group.getVariables()) {
if (bean1.group.findVariableByHash(var2) == null)
f.format("Var2 %s missing in partition 1%n", var2.id());
}
}
}
private static class RangeTracker {
int min, max;
RangeTracker(int value) {
this.min = value;
this.max = value;
}
void add(int value) {
min = Math.min(min, value);
max = Math.max(max, value);
}
public String toString() {
Formatter f = new Formatter();
if (min == max) f.format("%3d", min);
else f.format("%3d - %3d", min, max);
return f.toString();
}
}
public class GroupsBean {
GribCollectionMutable.GroupGC group;
List<GroupBean> beans = new ArrayList<>(50);
RangeTracker nvars, nfiles, ncoords, ntimes;
public GroupsBean(GribCollectionMutable.GroupGC g) {
this.group = g;
nvars = new RangeTracker(count(g.getVariables().iterator()));
nfiles = new RangeTracker(g.getNFiles());
ncoords = new RangeTracker(count(g.getCoordinates().iterator()));
ntimes = new RangeTracker(countTimes(g.getCoordinates().iterator()));
}
public GroupsBean() {
}
private int count(Iterator iter) {
int count = 0;
while (iter.hasNext()) {
iter.next();
count++;
}
return count;
}
private int countTimes(Iterator<Coordinate> iter) {
int count = 0;
while (iter.hasNext()) {
Coordinate c = iter.next();
if (c.getType() == Coordinate.Type.time || c.getType() == Coordinate.Type.timeIntv || c.getType() == Coordinate.Type.time2D)
count++;
}
return count;
}
public void addGroup(GribCollectionMutable.GroupGC g, String dataset, String partitionName) {
beans.add(new GroupBean(g, dataset, partitionName));
nvars.add(count(g.getVariables().iterator()));
nfiles.add(g.getNFiles());
ncoords.add(count(g.getCoordinates().iterator()));
ntimes.add(countTimes(g.getCoordinates().iterator()));
}
public int getNPartitions() {
return beans.size();
}
public String getGroupId() {
return group.getId();
}
public int getGdsHash() {
return group.getGdsHash().hashCode();
}
public String getNVars() {
return nvars.toString();
}
public String getNFiles() {
return nfiles.toString();
}
public String getNCoords() {
return ncoords.toString();
}
public String getNTimes() {
return ntimes.toString();
}
}
public class GroupBean {
String partitionName;
String datasetName;
GribCollectionMutable.GroupGC group;
public GroupBean(GribCollectionMutable.GroupGC g, String datasetName, String partitionName) {
this.group = g;
this.partitionName = partitionName;
this.datasetName = datasetName;
}
public GroupBean() {
}
public String getGroupId() {
return group.getId();
}
public int getGdsHash() {
return group.getGdsHash().hashCode();
}
public int getNFiles() {
return group.getNFiles();
}
/* public int getNTimes() {
return group.timeCoords.size();
}
public int getNVerts() {
return group.vertCoords.size();
}
public int getNVars() {
return group.varIndex.size();
} */
public String getPartition() {
return partitionName;
}
public String getDataset() {
return datasetName;
}
void showFilesUsed(Formatter f) {
List<MFile> files = group.getFiles();
for (MFile file : files) {
f.format(" %s%n", file.getName());
}
}
}
////////////////////////////////////////////////////////////////////////////////////
public class VarBean {
GribCollectionMutable.VariableIndex v;
GribCollectionMutable.GroupGC group;
public VarBean() {
}
public VarBean(GribCollectionMutable.VariableIndex v, GribCollectionMutable.GroupGC group) {
this.v = v;
this.group = group;
}
public String getTimeCoord() {
if (0 <= v.getCoordinateIdx(Coordinate.Type.time)) return Coordinate.Type.time.toString();
if (0 <= v.getCoordinateIdx(Coordinate.Type.timeIntv)) return Coordinate.Type.timeIntv.toString();
if (0 <= v.getCoordinateIdx(Coordinate.Type.time2D)) return Coordinate.Type.time2D.toString();
return "ERR";
}
public int getVertCoord() {
return v.getCoordinateIdx(Coordinate.Type.vert);
}
public int getEnsCoord() {
return v.getCoordinateIdx(Coordinate.Type.ens);
}
public int getLevelType() {
return v.levelType;
}
public int getIntvType() {
return v.intvType;
}
public int getProbType() {
return v.probType;
}
public int getEnsType() {
return v.ensDerivedType;
}
public int getGenType() {
return v.genProcessType;
}
public String getIntvName() {
return v.getTimeIntvName();
}
public String getProbName() {
return v.probabilityName;
}
public int getHash() {
return v.hashCode();
}
public String getGroupId() {
return group.getId();
}
public String getVariableId() {
return v.discipline + "-" + v.category + "-" + v.parameter;
}
}
}