package istlab.KisoJikken;
import java.awt.BorderLayout;
import java.awt.Desktop;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Hashtable;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.event.MouseInputListener;
import javax.swing.event.TreeModelListener;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
public class Launcher extends JFrame implements MouseInputListener, KeyListener {
public static Launcher theapp;
public static String version = "0.5";
public static String downloadurl = "https://cit.istlab.info/KisoJikkenNWP/target/";
public static Path execPath;
// JPanel mainP;
File root;
JTree tree;
JCheckBoxMenuItem jcbmi;
Hashtable<File, Editor> file2editor;
// all generated processes (maybe alive only)
public static ArrayList<Process> allProcs = new ArrayList<Process>();
public Launcher(String[] args) {
super("Kiso NWP Launcher v" + version);
setDefaultCloseOperation(EXIT_ON_CLOSE);
// mainP = new JPanel();
file2editor = new Hashtable<File, Editor>();
theapp = this;
try {
execPath = getApplicationPath(this.getClass());
} catch (URISyntaxException e) {
e.printStackTrace();
}
if (args.length > 0)
root = new MyFile(args[0]);
else
root = new MyFile(App.userhome + App.nwpsrc);
// Create a TreeModel object to represent our tree of files
FileTreeModel model = new FileTreeModel(root, false);
// Create a JTree and tell it to display our model
tree = new JTree();
tree.setModel(model);
tree.addMouseListener(this);
tree.addKeyListener(this);
// The JTree can get big, so allow it to scroll.
JScrollPane scrollpane = new JScrollPane(tree);
// mainP.setLayout(new BoxLayout(mainP, BoxLayout.PAGE_AXIS));
// for (int i = 1; i < 8; i++) {
// JButton b = new JButton("j" + i);
// mainP.add(b);
// }
// ShellScriptPanel run11 = new ShellScriptPanel("run1-1.sh");
getContentPane().add(scrollpane, BorderLayout.CENTER);
// Menu
JMenuBar menuBar = new JMenuBar();
JMenu menu = new JMenu("App");
menuBar.add(menu);
JMenuItem mi = new JMenuItem("show version");
mi.addActionListener(ae -> JOptionPane.showMessageDialog(this, "Kiso NWP Launcher v" + version));
menu.add(mi);
mi = new JMenuItem("download latest");
mi.addActionListener(ae -> downloadLatest());
menu.add(mi);
mi = new JMenuItem("open download site");
mi.addActionListener(ae -> openURL(downloadurl));
menu.add(mi);
mi = new JMenuItem("open JAR folder");
mi.addActionListener(ae -> openExecPath());
menu.add(mi);
mi = new JMenuItem("exit");
mi.addActionListener(ae -> System.exit(0));
menu.add(mi);
menu = new JMenu("File");
menuBar.add(menu);
jcbmi = new JCheckBoxMenuItem("exclude class files");
jcbmi.addItemListener(ae -> reloadFiles());
menu.add(jcbmi);
mi = new JMenuItem("reload folders/files");
mi.addActionListener(ae -> reloadFiles());
menu.add(mi);
menu = new JMenu("Process");
menuBar.add(menu);
mi = new JMenuItem("stop alive");
mi.addActionListener(ae -> stopProcess(false));
menu.add(mi);
mi = new JMenuItem("stop all");
mi.addActionListener(ae -> stopProcess(true));
menu.add(mi);
mi = new JMenuItem("jps");
mi.addActionListener(ae -> runCommand(ae.getActionCommand()));
menu.add(mi);
mi = new JMenuItem("killall java");
mi.addActionListener(ae -> runCommand(ae.getActionCommand()));
menu.add(mi);
setJMenuBar(menuBar);
// getContentPane().add(mainP, BorderLayout.WEST);
setSize(400, 600);
}
public void runCommand(String cmd) {
System.out.println(cmd);
new CommandRunner(cmd).startstop();
}
public void stopProcess(boolean isAll) {
ArrayList<Process> toberemoved = new ArrayList<Process>();
for (Process proc : allProcs) {
if (!isAll) {
if (proc.isAlive())
continue;
}
proc.destroyForcibly();
toberemoved.add(proc);
}
for (Process delproc : toberemoved) {
allProcs.remove(delproc);
Enumeration<JTAConsole> enu = JTAConsole.winStack.elements();
while (enu.hasMoreElements()) {
JTAConsole con = enu.nextElement();
con.windowClosing(null);
con.frame.dispose();
}
}
}
public void reloadFiles() {
FileTreeModel model = new FileTreeModel(root, jcbmi.isSelected());
tree.setModel(model);
}
public void downloadLatest() {
// 最初に、ダウンロードサイトから最新版の情報を得る
// 更新があれば、ダウンロードし、ファイルを表示する。
StringBuilder sb = new StringBuilder();
String latestVersion = null;
try {
URL url = new URL(downloadurl);
InputStream is = url.openConnection().getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line = null;
while ((line = reader.readLine()) != null) {
if (latestVersion == null)
latestVersion = line.trim();
System.out.println(line);
sb.append(line + "\n");
}
reader.close();
} catch (Exception ex) {
}
// System.out.println(sb.toString());
// 同じかどうかチェック
System.out.println("[" + latestVersion + "]");
System.out.println("=" + execPath.getFileName() + "=");
if (latestVersion.equals(execPath.getFileName().toString())) {
JOptionPane.showMessageDialog(this, "This is latest version : v" + version);
} else {
int res = JOptionPane.showConfirmDialog(this, "Really download new version \n(" + latestVersion + ") ??");
if (res == JOptionPane.YES_OPTION) {
try {
URL url = new URL(downloadurl + "/" + latestVersion);
ReadableByteChannel readableByteChannel = Channels.newChannel(url.openStream());
FileOutputStream fileOutputStream = new FileOutputStream(latestVersion);
FileChannel fileChannel = fileOutputStream.getChannel();
fileOutputStream.getChannel().transferFrom(readableByteChannel, 0, Long.MAX_VALUE);
fileChannel.close();
fileOutputStream.close();
File execjar = new File(execPath.getParent().toString() + File.separator + latestVersion);
execjar.setExecutable(true);
} catch (Exception ex) {
} finally {
}
openExecPath();
}
}
}
public void openExecPath() {
File execFolder = execPath.getParent().toFile();
openFolder(execFolder);
}
public void openFolder(File path) {
try {
Desktop.getDesktop().open(path);
} catch (IOException e) {
e.printStackTrace();
}
}
public void openURL(String url) {
if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {
try {
Desktop.getDesktop().browse(new URI(url));
} catch (IOException | URISyntaxException e) {
e.printStackTrace();
}
}
}
public static Path getApplicationPath(Class<?> cls) throws URISyntaxException {
ProtectionDomain pd = cls.getProtectionDomain();
CodeSource cs = pd.getCodeSource();
URL location = cs.getLocation();
URI uri = location.toURI();
Path path = Paths.get(uri);
return path;
}
@Override
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2) {
openEditor();
}
}
private void openEditor() {
TreePath tp = tree.getSelectionModel().getSelectionPath();
if (tp == null)
return;
File node = (File) tp.getLastPathComponent();
// フォルダなら開かない
if (node.isDirectory())
return;
Editor ed = file2editor.get(node);
if (ed == null) {
ed = new Editor(node);
file2editor.put(node, ed);
} else {
ed.setVisible(true);
ed.toFront();
}
System.out.println(node.toString());
}
@Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseDragged(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseMoved(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == 32) {
openEditor();
}
if (e.isControlDown() || e.isAltDown() || e.isAltGraphDown() || e.isMetaDown()) {
if (e.getKeyCode() == 81) { // Q
System.exit(0);
}
if (e.getKeyCode() == 87) { // W (Close)
System.exit(0);
}
}
}
@Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
}
class MyFile extends File {
public MyFile(String pathname) {
super(pathname);
}
public String toString() {
return super.toString().replaceAll(App.userhome, "~");
}
}
/**
* The methods in this class allow the JTree component to traverse
* the file system tree, and display the files and directories.
**/
class FileTreeModel implements TreeModel {
// We specify the root directory when we create the model.
protected File root;
boolean isExcludeClassFiles = false;
public FileTreeModel(File root, boolean exCls) {
this.root = root;
isExcludeClassFiles = exCls;
}
// The model knows how to return the root object of the tree
public Object getRoot() {
return root;
}
// Tell JTree whether an object in the tree is a leaf or not
public boolean isLeaf(Object node) {
return ((File) node).isFile();
}
private File[] getChildFiles(File parent) {
if (isExcludeClassFiles) {
return parent.listFiles(path -> !path.toString().endsWith(".class"));
} else {
return parent.listFiles();
}
}
// Tell JTree how many children a node has
public int getChildCount(Object parent) {
File[] children = getChildFiles((File) parent);
if (children == null)
return 0;
return children.length;
}
// Fetch any numbered child of a node for the JTree.
// Our model returns File objects for all nodes in the tree. The
// JTree displays these by calling the File.toString() method.
public Object getChild(Object parent, int index) {
File[] children = getChildFiles((File) parent);
// String[] children = ((File) parent).list();
Arrays.sort(children);
if ((children == null) || (index >= children.length))
return null;
// return new File((File) parent, children[index]);
return new MyFile(children[index].getAbsolutePath());
}
// Figure out a child's position in its parent node.
public int getIndexOfChild(Object parent, Object child) {
File[] children = getChildFiles((File) parent);
// String[] children = ((File) parent).list();
Arrays.sort(children);
if (children == null)
return -1;
String childname = ((File) child).getName();
// if (childname.startsWith(".")) return -1;
for (int i = 0; i < children.length; i++) {
if (childname.equals(children[i].getName()))
return i;
}
return -1;
}
// This method is only invoked by the JTree for editable trees.
// This TreeModel does not allow editing, so we do not implement
// this method. The JTree editable property is false by default.
public void valueForPathChanged(TreePath path, Object newvalue) {
}
// Since this is not an editable tree model, we never fire any events,
// so we don't actually have to keep track of interested listeners.
public void addTreeModelListener(TreeModelListener l) {
}
public void removeTreeModelListener(TreeModelListener l) {
}
}