dmolony-DiskBrowser/src/com/bytezone/diskbrowser/gui/TreeBuilder.java
2015-08-31 19:33:42 +10:00

361 lines
10 KiB
Java
Executable File

package com.bytezone.diskbrowser.gui;
import java.awt.image.BufferedImage;
import java.io.File;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.zip.CRC32;
import java.util.zip.Checksum;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import com.bytezone.diskbrowser.FileFormatException;
import com.bytezone.diskbrowser.disk.AppleDisk;
import com.bytezone.diskbrowser.disk.Disk;
import com.bytezone.diskbrowser.disk.DiskFactory;
import com.bytezone.diskbrowser.disk.FormattedDisk;
public class TreeBuilder
{
private static SimpleDateFormat sdf = new SimpleDateFormat ("dd MMM yyyy");
private static final boolean FULL_TREE = false;
private static final List<String> suffixes =
Arrays.asList ("po", "dsk", "do", "hdv", "2mg", "d13", "sdk", "gz");
FileComparator fc = new FileComparator ();
JTree tree;
int totalDisks;
int totalFolders;
Map<String, Integer> totalFiles = new TreeMap<String, Integer> ();
Map<String, List<DiskDetails>> duplicateDisks =
new TreeMap<String, List<DiskDetails>> ();
Map<String, File> diskNames = new HashMap<String, File> ();
Map<Long, List<File>> dosMap = new TreeMap<Long, List<File>> ();
public TreeBuilder (File folder)
{
assert(folder.exists ());
assert(folder.isDirectory ());
long start = System.currentTimeMillis ();
FileNode fn = new FileNode (folder);
DefaultMutableTreeNode root = new DefaultMutableTreeNode (fn);
fn.setTreeNode (root);
addFiles (root, folder);
DefaultTreeModel treeModel = new DefaultTreeModel (root);
tree = new JTree (treeModel);
long duration = System.currentTimeMillis () - start;
System.out.printf (
"Tree building took %,d milliseconds for %,d disk%s and %,d folder%s%n",
duration, totalDisks, (totalDisks == 1 ? "" : "s"), totalFolders,
(totalFolders == 1 ? "" : "s"));
treeModel.setAsksAllowsChildren (true);// allows empty nodes to appear as folders
setDiskIcon ("/com/bytezone/diskbrowser/icons/disk.png");
((FileNode) root.getUserObject ()).disks = totalDisks;
if (FULL_TREE)
{
System.out.printf ("%nFolders ..... %,5d%n", totalFolders);
System.out.printf ("Disks ....... %,5d%n%n", totalDisks);
int tf = 0;
for (String key : totalFiles.keySet ())
{
int t = totalFiles.get (key);
tf += t;
System.out.printf ("%13.13s %,5d%n", key + " ...........", t);
}
System.out.printf ("%nTotal ...... %,6d%n%n", tf);
}
}
private void addFiles (DefaultMutableTreeNode node, File directory)
{
File[] files = directory.listFiles ();
if (files == null || files.length == 0)
{
System.out.println ("Empty folder : " + directory.getAbsolutePath ());
return;
}
FileNode parentNode = (FileNode) node.getUserObject ();
Arrays.sort (files, fc);
for (File file : files)
{
if (file.isDirectory ())
{
FileNode fn = new FileNode (file);
DefaultMutableTreeNode newNode = new DefaultMutableTreeNode (fn);
fn.setTreeNode (newNode);
newNode.setAllowsChildren (true);
node.add (newNode);
totalFolders++;
if (FULL_TREE)
addFiles (newNode, file);// recursion!
continue;
}
if (FULL_TREE)
{
int pos = file.getName ().lastIndexOf ('.');
if (pos > 0)
{
String type = file.getName ().substring (pos + 1).toLowerCase ();
if (totalFiles.containsKey (type))
{
int t = totalFiles.get (type);
totalFiles.put (type, ++t);
}
else
totalFiles.put (type, 1);
}
}
if (file.length () != 143360 && file.length () != 116480 && file.length () != 819264
&& file.length () < 200000)
{
String name = file.getName ().toLowerCase ();
if (!name.endsWith (".sdk") && !name.endsWith (".dsk.gz"))
continue;
}
parentNode.disks++;
String filename = file.getAbsolutePath ();
if (validFileType (filename))
{
FileNode fn = new FileNode (file);
DefaultMutableTreeNode newNode = new DefaultMutableTreeNode (fn);
fn.setTreeNode (newNode);
newNode.setAllowsChildren (false);
node.add (newNode);
if (false)
checkDuplicates (file);
totalDisks++;
if (false)
checksumDos (file);
}
}
}
private void checksumDos (File file)
{
if (file.length () != 143360 || file.getAbsolutePath ().contains ("/ZDisks/"))
return;
Disk disk = new AppleDisk (file, 35, 16);
byte[] buffer = disk.readSector (0, 0);
Checksum checksum = new CRC32 ();
checksum.update (buffer, 0, buffer.length);
long cs = checksum.getValue ();
List<File> files = dosMap.get (cs);
if (files == null)
{
files = new ArrayList<File> ();
dosMap.put (cs, files);
}
files.add (file);
}
private void checkDuplicates (File file)
{
if (diskNames.containsKey (file.getName ()))
{
List<DiskDetails> diskList = duplicateDisks.get (file.getName ());
if (diskList == null)
{
diskList = new ArrayList<DiskDetails> ();
duplicateDisks.put (file.getName (), diskList);
diskList.add (new DiskDetails (diskNames.get (file.getName ())));// add the original
}
diskList.add (new DiskDetails (file));// add the duplicate
}
else
diskNames.put (file.getName (), file);
}
private boolean validFileType (String filename)
{
int dotPos = filename.lastIndexOf ('.');
if (dotPos < 0)
return false;
String suffix = filename.substring (dotPos + 1).toLowerCase ();
return suffixes.contains (suffix);
}
private void setDiskIcon (String iconName)
{
URL url = this.getClass ().getResource (iconName);
if (url != null)
{
ImageIcon icon = new ImageIcon (url);
DefaultTreeCellRenderer renderer =
(DefaultTreeCellRenderer) tree.getCellRenderer ();
renderer.setLeafIcon (icon);
tree.setCellRenderer (renderer);
tree.setRowHeight (18);
}
else
System.out.println ("Failed to set the disk icon : " + iconName);
}
/*
* Class used to control the text displayed by the JTree.
*/
public class FileNode implements DataSource
{
DefaultMutableTreeNode parentNode;
public final File file;
private static final int MAX_NAME_LENGTH = 36;
private static final int SUFFIX_LENGTH = 12;
private static final int PREFIX_LENGTH = MAX_NAME_LENGTH - SUFFIX_LENGTH - 3;
private FormattedDisk formattedDisk;
int disks;
boolean showDisks;
public FileNode (File file)
{
this.file = file;
}
public void setTreeNode (DefaultMutableTreeNode node)
{
this.parentNode = node;
}
public void readFiles ()
{
addFiles (parentNode, file);
}
public FormattedDisk getFormattedDisk ()
{
if (formattedDisk == null)
try
{
formattedDisk = DiskFactory.createDisk (file);
}
catch (FileFormatException e)
{
System.out.println ("Swallowing a FileFormatException in TreeBuilder");
System.out.println (e.getMessage ());
return null;
}
return formattedDisk;
}
public boolean replaceDisk (FormattedDisk disk)
{
String path = disk.getDisk ().getFile ().getAbsolutePath ();
if (formattedDisk != null && path.equals (file.getAbsolutePath ()))
{
formattedDisk = disk;
return true;
}
return false;
}
@Override
public String toString ()
{
String name = file.getName ();
if (name.length () > MAX_NAME_LENGTH)
name = name.substring (0, PREFIX_LENGTH) + "..."
+ name.substring (name.length () - SUFFIX_LENGTH);
if (showDisks && disks > 0)
return String.format ("%s (%,d)", name, disks);
return name;
}
@Override
public String getText ()
{
StringBuilder text = new StringBuilder ();
text.append ("Directory : " + file.getAbsolutePath () + "\n\n");
text.append ("D File names "
+ " Date Size Type\n");
text.append ("- ----------------------------------------"
+ " ----------- -------------- ---------\n");
for (File f : file.listFiles ())
{
String name = f.getName ();
if (name.startsWith ("."))
continue;
Date d = new Date (f.lastModified ());
int pos = name.lastIndexOf ('.');
String type = pos > 0 && !f.isDirectory () ? name.substring (pos) : "";
String size = f.isDirectory () ? "" : String.format ("%,14d", f.length ());
text.append (String.format ("%s %-40.40s %s %-14s %s%n",
f.isDirectory () ? "D" : " ", name, sdf.format (d),
size, type));
}
if (text.length () > 0)
text.deleteCharAt (text.length () - 1);
return text.toString ();
}
@Override
public String getAssembler ()
{
return null;
}
@Override
public String getHexDump ()
{
return null;
}
@Override
public BufferedImage getImage ()
{
return null;
}
@Override
public JComponent getComponent ()
{
return null;
}
}
private class FileComparator implements Comparator<File>
{
@Override
public int compare (File filea, File fileb)
{
boolean fileaIsDirectory = filea.isDirectory ();
boolean filebIsDirectory = fileb.isDirectory ();
if (fileaIsDirectory && !filebIsDirectory)
return -1;
if (!fileaIsDirectory && filebIsDirectory)
return 1;
return filea.getName ().compareToIgnoreCase (fileb.getName ());
}
}
}