package groomiac.crocodesktop;
import groomiac.crocodesktop.Ini.P;
import groomiac.crocodesktop.Popups.ReturnListener;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.net.URLStreamHandlerFactory;
import java.nio.file.DirectoryStream;
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.Comparator;
import javax.swing.UIManager;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Worker.State;
import javafx.event.EventHandler;
import javafx.geometry.HPos;
import javafx.geometry.VPos;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.layout.Region;
import javafx.scene.paint.Color;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
import netscape.javascript.JSObject;
public class CrocodileNote extends Application{
@SuppressWarnings({ "rawtypes", "unused" })
private static Class THECLASS = CrocodileNote.class;
private static final String main = "___Main___";
private static ArrayList<FolderItem> l = new ArrayList<FolderItem>();
static File folderfile;
static long ctr = 0;
private static String userfolder = null;
private static final String ini = "CrocodileNote.ini";
/*
* TODO: make sure UTF-8 support for all files and folders
*
*/
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
}
launch(args);
}
private void loadInitFiles(){
userfolder = System.getProperty("user.home") + File.separator + ".crocodilenote";
new File(userfolder).mkdirs();
Base.secretpropFile = new File(userfolder, "secret.conf");
if(!Base.secretpropFile.exists() || !Base.secretpropFile.isFile()){
Base.secretpropFile.delete();
Base.dialog_createpw(new StringResult() {
@Override
void receive(String ret) {
loadMoreInitFiles();
initMainSystems();
}
});
return;
}
loadMoreInitFiles();
PWTrigger.main(new StringResult() {
@Override
void receive(String ret) {
if(!Base.loadpw(ret)){
PWTrigger.main(this);
return;
}
initMainSystems();
}
});
}
private void loadMoreInitFiles(){
Base.loadSecrets();
if(Log.DEBUG) System.out.println(Base.secretpropFile.getAbsolutePath());
File propfile = new File(userfolder, ini);
if(!propfile.exists()){
try {
propfile.createNewFile();
} catch (Exception e) {
e.printStackTrace();
}
}
Ini.load(propfile.getAbsolutePath());
String rawpath = Ini.get(P.path);
if(Log.DEBUG) System.out.println("RAW:" + rawpath);
if(rawpath == null){
rawpath = "data";
Ini.set(P.path, rawpath);
Ini.save(propfile);
}
if(rawpath.length() > 1 && (rawpath.charAt(1) == ':' || rawpath.charAt(0) == '\\' || rawpath.charAt(0) == '/')){
folderfile = new File(rawpath);
}
else{
folderfile = new File(userfolder, rawpath);
}
if(Log.DEBUG) System.out.println("LIVE:" + folderfile);
}
private Scene scene;
private Stage stage;
@Override
public void start(Stage stagex) throws Exception {
URL.setURLStreamHandlerFactory(new MyURLStreamHandlerFactory());
this.stage = stagex;
stage.getIcons().add(new Image(getClass().getResourceAsStream("CrocodileNote-32.png")));
//stage.getIcons().add(new Image(getClass().getResourceAsStream("CrocodileNote-64.png")));
loadInitFiles();
}
private void initMainSystems(){
folderfile.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
if (!pathname.isDirectory())
return false;
l.add(new FolderItem(pathname.getName(), null));
return true;
}
});
if (l.size() == 0){
l.add(FolderItem.createnew(main));
}
Collections.sort(l, new Comparator<FolderItem>() {
@Override
public int compare(FolderItem lfi, FolderItem rfi) {
if (lfi == null || rfi == null)
return 0;
String lhs = lfi.getShow();
String rhs = rfi.getShow();
if (main.equals(lhs))
return -1;
if (lhs == rhs)
return 0;
if (lhs == null && rhs == null)
return 0;
if (lhs == null)
return -1;
if (rhs == null)
return -1;
lhs = lhs.toLowerCase();
rhs = rhs.toLowerCase();
if (lhs.startsWith("_") && lhs.startsWith("_"))
return lhs.compareTo(rhs);
if (lhs.startsWith("_"))
return -1;
if (rhs.startsWith("_"))
return 1;
return lhs.compareTo(rhs);
}
});
if(Log.DEBUG) System.out.println(l);
String tmp = l.get(0).getReal();
FileItem.thefolder = new File(folderfile, tmp).getAbsolutePath();
FileItem.foldername = tmp;
Platform.runLater(new Runnable() {
public void run() {
Platform.setImplicitExit(false);
stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
@Override
public void handle(WindowEvent event) {
event.consume();
if(!"0".equals(b.executeScript("data_id.length").toString())){
new Popups().create("There are unsaved elements. Do you really want to exit without saving?", new ReturnListener() {
@Override
public void retrieve(int ret) {
if(ret == 0)
doExit();
}
}, 1, "Discard changes", "Cancel");
}
else{
doExit();
}
}
});
// create the scene
stage.setTitle(Base.appname);
Browser browse = new Browser();
b = browse.getB();
browse.dostuff();
scene = new Scene(browse, 800, 800, Color.web("#666970"));
stage.setMinHeight(650);
stage.setMinWidth(650);
stage.setScene(scene);
stage.show();
}
});
}
private void doExit(){
Base.logout();
Base.deinit();
stage.close();
Platform.exit();
}
private WebEngine b;
class Browser extends Region {
final WebView browser = new WebView();
final WebEngine webEngine = browser.getEngine();
public Browser() {
webEngine.load("myapp:///uibase.html");
getChildren().add(browser);
}
public WebEngine getB(){
return webEngine;
}
@Override
protected void layoutChildren() {
double w = getWidth();
double h = getHeight();
layoutInArea(browser, 0, 0, w, h, 0, HPos.CENTER, VPos.CENTER);
}
@Override
protected double computePrefWidth(double height) {
return 750;
}
@Override
protected double computePrefHeight(double width) {
return 500;
}
void dostuff(){
// process page loading
webEngine.getLoadWorker().stateProperty().addListener(
new ChangeListener<State>() {
@Override
public void changed(ObservableValue<? extends State> ov,
State oldState, State newState) {
if (newState == State.SUCCEEDED) {
JSObject win = (JSObject) webEngine.executeScript("window");
win.setMember("app", new GrooApp());
doInit();
webEngine.executeScript("start();");
}
}
}
);
}
}
public void doInit(){
for(int i=l.size()-1; i>-1; i--){
FolderItem f = l.get(i);
b.executeScript("addString('list', '<p onclick=\"clickList(this)\" class=\"tabentryx\" id=\"" + f.getReal() +"\">" + f.getShow() + "</p>')");
}
b.executeScript("clickListFromID('" + l.get(0).getReal() + "')");
if(Log.DEBUG) System.out.println("Init complete");
}
public class GrooApp {
public void log(String s) {
System.out.println(s);
}
public void log(Object o) {
System.out.println(o.toString());
}
public void reallyreload(final String s){
new Popups().create("There are unsaved elements. Do you really want to discard all changes?", new ReturnListener() {
@Override
public void retrieve(int ret) {
if(ret != 0) return;
b.executeScript("clickListFromID('" + s + "', false, true)");
}
}, 0, " Discard ", " Cancel ");
}
public void delokQ(final String s){
//TODO efficency: HashMap with IDs instead of loop?
int no = -1;
for(int i=0; i<l.size(); i++){
FolderItem fi = l.get(i);
if(fi.getReal().equals(s)){
no = i;
break;
}
}
final int theno = no;
new Popups().create("Do you really want to delete the complete folder \"" + l.get(no).getShow() + "\"?", new ReturnListener() {
@Override
public void retrieve(int ret) {
if(ret != 0) return;
l.remove(theno);
new Remover(new File(folderfile, s)).removeDir();
if (l.size() == 0){
l.add(FolderItem.createnew(main));
b.executeScript("addString('list', '<p onclick=\"clickList(this)\" class=\"tabentryx\" id=\"" + l.get(0).getReal() +"\">" + l.get(0).getShow() + "</p>')");
}
b.executeScript("delAction('" + s + "');");
}
}, 0, " Delete ", " Cancel ");
}
public void clickelem(String s){
if(Log.DEBUG) System.out.println("LOAD: " + s);
FileItem.thefolder = new File(folderfile, s).getAbsolutePath();
FileItem.foldername = s;
try {
ctr = 0;
Path dir = FileSystems.getDefault().getPath(FileItem.thefolder);
DirectoryStream<Path> stream = Files.newDirectoryStream(dir);
for (Path path: stream) {
if(!path.getFileName().toString().startsWith("data_") && !path.getFileName().toString().endsWith(".dat"))
continue;
ctr++;
}
stream.close();
} catch (Exception e) {
e.printStackTrace();
}
return;
}
public void newelem(){
NewTrigger.main(new StringResult() {
@Override
void receive(final String ret) {
l.add(FolderItem.createnew(ret));
Platform.runLater(new Runnable() {
@Override
public void run() {
String id = l.get(l.size() - 1).getReal();
b.executeScript("addString('list', '<p onclick=\"clickList(this)\" class=\"tabentryx\" id=\"" + id +"\">" + ret + "</p>')");
b.executeScript("clickListFromID('" + id + "', true)");
}
});
}
});
}
//TODO efficency? - cache file content in HashMap instead of file access; maybe not all but certain window size?; (update cache on save?)
public String extGet(int i){
try {
String tmp = FileItem.loadEncFiles(i);
if(tmp == null) tmp = "";
return tmp;
} catch (Exception e) {
e.printStackTrace();
}
return "error I323";
}
public long getLen(){
return ctr;
}
int savect;
public void save(int i, String content){
savect++;
FileItem.storeEncFiles(i, content);
}
public void startSave(){
savect = 0;
}
public void endSave(){
if(savect > 0) b.executeScript("toast('Saved (" + savect + ")');");
else b.executeScript("toast('Nothing to save');");
}
}
public class MyURLStreamHandlerFactory implements URLStreamHandlerFactory {
public URLStreamHandler createURLStreamHandler(String protocol) {
if (protocol.equals("myapp")) {
return new MyURLHandler();
}
return null;
}
}
public class MyURLHandler extends URLStreamHandler {
@Override
protected URLConnection openConnection(URL url) throws IOException {
return new MyURLConnection(url);
}
}
public class MyURLConnection extends URLConnection {
private String thefile;
public MyURLConnection(URL u) {
super(u);
thefile = u.toString();
thefile = thefile.substring("myapp:/".length(), thefile.length());
}
private byte[] data;
@Override
public void connect() throws IOException {
if (connected) {
return;
}
connected = true;
}
public String getHeaderField(String name) {
if ("Content-Type".equalsIgnoreCase(name)) {
return getContentType();
} else if ("Content-Length".equalsIgnoreCase(name)) {
return "" + getContentLength();
}
return null;
}
public String getContentType() {
// TODO: general switch based on file-type
if(thefile.endsWith(".html"))
return "text/html";
String fileName = getURL().getFile();
String ext = fileName.substring(fileName.lastIndexOf('.'));
return "image/" + ext;
}
public int getContentLength() {
return data.length;
}
public long getContentLengthLong() {
return data.length;
}
public boolean getDoInput() {
return true;
}
public InputStream getInputStream() throws IOException {
connect();
return getClass().getResourceAsStream(thefile);
}
public OutputStream getOutputStream() throws IOException {
return null;
}
public java.security.Permission getPermission() throws IOException {
return null;
}
}
}