package org.fnppl.opensdx.file_transfer.gui;
/*
* Copyright (C) 2010-2015
* fine people e.V. <opensdx@fnppl.org>
* Henning Thieß <ht@fnppl.org>
*
* http://fnppl.org
*/
/*
* Software license
*
* As far as this file or parts of this file is/are software, rather than documentation, this software-license applies / shall be applied.
*
* This file is part of openSDX
* openSDX is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* openSDX is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* and GNU General Public License along with openSDX.
* If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Documentation license
*
* As far as this file or parts of this file is/are documentation, rather than software, this documentation-license applies / shall be applied.
*
* This file is part of openSDX.
* Permission is granted to copy, distribute and/or modify this document
* under the terms of the GNU Free Documentation License, Version 1.3
* or any later version published by the Free Software Foundation;
* with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
* A copy of the license is included in the section entitled "GNU
* Free Documentation License" resp. in the file called "FDL.txt".
*
*/
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.Collections;
import java.util.Comparator;
import java.util.Vector;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTable;
import javax.swing.JTree;
import javax.swing.RowSorter;
import javax.swing.RowSorter.SortKey;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeExpansionListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import org.fnppl.opensdx.common.Util;
import org.fnppl.opensdx.gui.Dialogs;
import org.fnppl.opensdx.gui.helper.MyObservable;
import org.fnppl.opensdx.gui.helper.MyObserver;
public class TreeAndTablePanelLocal extends JPanel implements MyObservable, TreeAndTableChildrenGetter {
private JSplitPane split;
private JTree tree;
private TreeAndTableNode oneRoot;
private TreeAndTableNode root[];
private DefaultTreeModel tree_model;
private JTable table;
private DefaultTableModel table_model;
private JPanel buttons;
private JButton buTransfer;
private JButton buMkdir;
private JButton buRemove;
private JButton buRename;
private Vector<File> currentFiles = null;
private Comparator<TreeAndTableNode> compareNodes;
public TreeAndTablePanelLocal() {
compareNodes = new Comparator<TreeAndTableNode>() {
public int compare(TreeAndTableNode n1, TreeAndTableNode n2) {
return n1.toString().compareTo(n2.toString());
}
};
initComponents();
initLayout();
}
public Vector<TreeAndTableNode> getChildren(TreeAndTableNode node) {
boolean showHidden = false;
Vector<TreeAndTableNode> children = new Vector<TreeAndTableNode>();
if (node == oneRoot) {
for (int i=0;i<root.length;i++) {
children.add(root[i]);
}
return children;
} else {
File file = (File) node.getUserObject();
try {
File[] list = file.listFiles();
if (list == null)
return children;
for (File f : list) {
try {
if (f.isDirectory()) {
if (showHidden || !f.isHidden()) {
String name = f.getName();
TreeAndTableNode n = new TreeAndTableNode(this, name, true, f);
children.add(n);
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
//sort
Collections.sort(children, compareNodes);
return children;
}
}
public void setPreferredColumnWidth(int colNo, int width) {
try {
table.getColumnModel().getColumn(colNo).setPreferredWidth(width);
} catch (Exception ex) {}
}
public void setColumnRenderer(int colNo, TableCellRenderer renderer) {
try {
table.getColumnModel().getColumn(colNo).setCellRenderer(renderer);
} catch (Exception ex) {}
}
private void initComponents() {
tree = new JTree();
File[] roots = File.listRoots();
int anzRoot = roots.length;
System.out.println("roots count = "+anzRoot);
root = new TreeAndTableNode[roots.length];
for (int i=0;i<anzRoot;i++) {
System.out.println("root["+i+"] = "+roots[i].getPath());
root[i] = new TreeAndTableNode(this, roots[i].getPath(), true, roots[i]);
}
if (anzRoot == 1) {
root[0].populate();
oneRoot = root[0];
} else {
oneRoot = new TreeAndTableNode(this, "Computer", true, roots);
oneRoot.populate();
}
tree_model = new DefaultTreeModel(oneRoot);
tree.setModel(tree_model);
TreeExpansionListener expListen = new TreeExpansionListener() {
public void treeExpanded(TreeExpansionEvent event) {
TreePath path = event.getPath();
tree.setSelectionPath(path);
TreeAndTableNode node = (TreeAndTableNode)path.getLastPathComponent();
if (node.populate()) {
tree_model.nodeStructureChanged(node);
}
}
public void treeCollapsed(TreeExpansionEvent event) {
//do nothing
}
};
tree.addTreeExpansionListener(expListen);
tree.addTreeSelectionListener(new TreeSelectionListener() {
public void valueChanged(TreeSelectionEvent e) {
TreeAndTableNode node = (TreeAndTableNode)e.getPath().getLastPathComponent();
TableColumnModel colModel = table.getColumnModel();
int colCount = colModel.getColumnCount();
int[] width = new int[colCount];
TableCellRenderer[] render = new TableCellRenderer[colCount];
for (int i=0;i<colCount;i++) {
width[i] = colModel.getColumn(i).getWidth();
render[i] = colModel.getColumn(i).getCellRenderer();
}
updateTable(node);
for (int i=0;i<colCount;i++) {
colModel.getColumn(i).setPreferredWidth(width[i]);
colModel.getColumn(i).setCellRenderer(render[i]);
}
}
});
table = new JTable();
updateTable(null);
split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, new JScrollPane(tree), new JScrollPane(table));
split.setDividerLocation(230);
buttons = new JPanel();
buTransfer = new JButton("upload");
buTransfer.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
notifyChanges();
}
});
buMkdir = new JButton("mkdir");
buMkdir.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
File dir = getSelectedDir();
if (dir == null) {
Dialogs.showMessage("Please choose a parent directory first");
} else {
String name = Dialogs.showInputDialog("Make Directory", "Make a new Directory in:\n"+dir.getAbsolutePath()+"\n\nEnter new directory name:");
if (name!=null) {
TreePath path = tree.getSelectionPath();
File f = new File(dir,name);
boolean ok = f.mkdirs();
if (!ok) {
Dialogs.showMessage("Error, could not create directory:\n"+name+" in "+dir.getAbsolutePath());
}
refreshView(path);
}
}
}
});
buRemove = new JButton("remove");
buRemove.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Vector<File> files = getSelectedFiles();
if (files!=null && files.size()>0) {
//remove files
String msg = "Are you sure you want to remove the following files?";
for (File f : files) {
msg += "\n"+f.getName();
}
int q = Dialogs.showYES_NO_Dialog("Remove Files", msg);
if (q == Dialogs.YES) {
for (File f : files) {
boolean ok = f.delete();
if (!ok) {
Dialogs.showMessage("Error, could not remove:\n"+f.getAbsolutePath());
}
}
try {
updateTable((TreeAndTableNode)tree.getSelectionPath().getLastPathComponent());
} catch (Exception ex) {
//ex.printStackTrace();
try {
updateTable(oneRoot);
} catch (Exception ex2) {
ex2.printStackTrace();
}
}
}
} else {
File dir = getSelectedDir();
if (dir !=null) {
//remove dir
String msg = "Are you sure you want to remove the following directory?";
msg += "\n"+dir.getName();
int q = Dialogs.showYES_NO_Dialog("Remove Directory", msg);
if (q == Dialogs.YES) {
TreePath path = tree.getSelectionPath();
//recursive delete
boolean ok = Util.deleteDirectory(dir);
if (!ok) {
Dialogs.showMessage("Error, could not remove:\n"+dir.getAbsolutePath());
}
refreshView(path.getParentPath());
}
}
}
}
});
buRename = new JButton("rename");
buRename.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Vector<File> files = getSelectedFiles();
if (files==null || files.size()!=1) {
Dialogs.showMessage("Please select one file");
return;
}
File from = files.get(0);
String name = Dialogs.showInputDialog("Rename file", "Please enter new filename for file\n"+from.getName()+"\n",from.getName());
if (name!=null) {
File to =new File(from.getParentFile(),name);
boolean ok = from.renameTo(to);
if (!ok) {
Dialogs.showMessage("Error, could not rename:\n"+from.getAbsolutePath());
}
updateTable((TreeAndTableNode)tree.getSelectionPath().getLastPathComponent());
}
}
});
}
private void updateTable(TreeAndTableNode node) {
if (table_model == null) {
table_model = updateTableModel(node);
RowSorter<TableModel> sorter = new TableRowSorter<TableModel>(table_model) {
private Comparator colSizeComparator = new Comparator<String>() {
public int compare(String s1, String s2) {
int i1 = Integer.parseInt(s1.substring(0,s1.length()-2).trim());
int i2 = Integer.parseInt(s2.substring(0,s2.length()-2).trim());
return i1-i2;
}
};
@Override
public Comparator<?> getComparator(int column) {
if (column==2) {
return colSizeComparator;
}
return super.getComparator(column);
}
};
table.setRowSorter(sorter);
table.setModel(table_model);
} else {
java.util.List<? extends SortKey> sortkeys = null;
if (table.getRowSorter()!=null) {
sortkeys = table.getRowSorter().getSortKeys();
}
table_model.setDataVector(buildTableModelData(node), header);
if (table.getRowSorter()!=null) {
table.getRowSorter().setSortKeys(sortkeys);
}
}
}
public void refreshView(TreePath path) {
if (path!=null) {
try {
TreeAndTableNode node = (TreeAndTableNode)path.getLastPathComponent();
node.populateAgain();
tree.collapsePath(path);
tree.expandPath(path);
//tree.setSelectionPath(path);
} catch (Exception ex) {
ex.printStackTrace();
}
try {
updateTable((TreeAndTableNode)tree.getSelectionPath().getLastPathComponent());
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
public void refreshView() {
try {
TreePath path = tree.getSelectionPath();
TreeAndTableNode node;
if (path==null) {
node = oneRoot;
} else {
node = (TreeAndTableNode)path.getLastPathComponent();
}
node.populateAgain();
tree.collapsePath(path);
tree.expandPath(path);
//tree.setSelectionPath(path);
} catch (Exception ex) {
ex.printStackTrace();
}
try {
updateTable((TreeAndTableNode)tree.getSelectionPath().getLastPathComponent());
} catch (Exception ex) {
//ex.printStackTrace();
try {
updateTable(oneRoot);
} catch (Exception ex2) {
ex2.printStackTrace();
}
}
}
private String[] header = new String[] { "name", "type","size"};
private DefaultTableModel updateTableModel(TreeAndTableNode node) {
boolean showHidden = false;
if (node == null) {
return new DefaultTableModel(new String[0][header.length],header);
}
try {
File file = (File) node.getUserObject();
File[] list = file.listFiles();
currentFiles = new Vector<File>();
Vector<String[]> data = new Vector<String[]>();
for (int i = 0; i < list.length; i++) {
File f = list[i];
String[] d = new String[header.length];
d[0] = f.getName();
if (f.isDirectory()) {
// d[2] = "";
// d[1] = "[DIR]";
// data.add(d);
} else {
if (showHidden || !f.isHidden()) {
d[2] = (f.length() / 1000) + " kB";
d[1] = "";
int ind = d[0].lastIndexOf('.');
if (ind > 0 && ind + 1 < d[0].length()) {
d[1] = d[0].substring(ind + 1);
}
data.add(d);
currentFiles.add(f);
}
}
}
String[][] tdata = new String[data.size()][header.length];
for (int i=0;i<data.size();i++) {
tdata[i] = data.get(i);
}
DefaultTableModel model = new DefaultTableModel(tdata, header) {
public boolean isCellEditable(int row, int column) {
return false;
}
};
return model;
} catch (Exception ex) {
return new DefaultTableModel(new String[0][header.length],header);
}
}
private String[][] buildTableModelData(TreeAndTableNode node) {
boolean showHidden = false;
String[][] tdata = new String[0][header.length];
currentFiles = new Vector<File>();
if (node == null || node == oneRoot) {
return tdata;
}
try {
File file = (File) node.getUserObject();
Vector<String[]> data = new Vector<String[]>();
if (file.exists()) {
File[] list = file.listFiles();
for (int i = 0; i < list.length; i++) {
File f = list[i];
String[] d = new String[header.length];
d[0] = f.getName();
if (f.isDirectory()) {
// d[2] = "";
// d[1] = "[DIR]";
// data.add(d);
} else {
if (showHidden || !f.isHidden()) {
d[2] = (f.length() / 1000) + " kB";
d[1] = "";
int ind = d[0].lastIndexOf('.');
if (ind > 0 && ind + 1 < d[0].length()) {
d[1] = d[0].substring(ind + 1);
}
data.add(d);
currentFiles.add(f);
}
}
}
}
tdata = new String[data.size()][header.length];
for (int i=0;i<data.size();i++) {
tdata[i] = data.get(i);
}
return tdata;
} catch (Exception ex) {
ex.printStackTrace();
return new String[0][header.length];
}
}
public File getSelectedDir() {
try {
File f = (File)((TreeAndTableNode)tree.getSelectionPath().getLastPathComponent()).getUserObject();
return f;
} catch (Exception ex) {
//ex.printStackTrace();
}
return null;
}
public void setSelectedDir(File dir) {
Vector<String> parts = new Vector<String>();
//System.out.println("adding: "+dir.getName());
String name = dir.getName();
if (name.length()==0) {
name = dir.getAbsolutePath();
}
parts.add(name);
File parent = dir.getParentFile();
while (parent!=null) {
name = parent.getName();
if (name.length()==0) {
name = parent.getAbsolutePath();
}
parts.add(0,name);
//System.out.println("adding: "+name);
parent = parent.getParentFile();
}
for (int j=0;j<parts.size();j++) {
String searchNext = parts.get(j);
//System.out.println("searching for: "+searchNext);
boolean search = true;
int rowCount = tree.getRowCount();
for (int i=0;i<rowCount && search;i++) {
TreePath cp = tree.getPathForRow(i);
if (cp.getLastPathComponent().toString().equals(searchNext)) {
//System.out.println("found: "+searchNext);
//tree.setSelectionPath(cp);
tree.setSelectionRow(i);
tree.expandRow(i);
search = false;
}
}
}
}
public Vector<File> getSelectedFiles() {
Vector<File> sel = new Vector<File>();
int[] select = table.getSelectedRows();
if (select!=null && select.length>0) {
for (int i=0;i<select.length;i++) {
sel.add(currentFiles.get(table.getRowSorter().convertRowIndexToModel(select[i])));
//sel.add(currentFiles.get(select[i]));
}
}
return sel;
}
private void initLayout() {
this.setLayout(new BorderLayout());
this.add(split, BorderLayout.CENTER);
buttons.setLayout(new FlowLayout(FlowLayout.RIGHT));
buttons.add(buMkdir);
buttons.add(buRename);
buttons.add(buRemove);
buttons.add(buTransfer);
this.add(buttons, BorderLayout.SOUTH);
}
//observable
private Vector<MyObserver> observers = new Vector<MyObserver>();
public void addObserver(MyObserver observer) {
observers.add(observer);
}
public void notifyChanges() {
for (MyObserver ob : observers) {
ob.notifyChange(this);
}
}
}