From 36a73472ce3880a10bf9a5e05b7c58753d494ac2 Mon Sep 17 00:00:00 2001 From: Thomas Ba Date: Fri, 19 Jun 2015 03:34:32 +0200 Subject: [PATCH] Init --- TodoList.iml | 32 ++ ext/.keep | 0 .../dhbw/todolist/CSVHandler.java | 33 ++ .../dhbw/todolist/Controller.java | 352 ++++++++++++++++++ .../dhbw/todolist/ExportHandler.java | 42 +++ .../dhbw/todolist/InvalidDataException.java | 13 + src/de/t_battermann/dhbw/todolist/Main.java | 17 + src/de/t_battermann/dhbw/todolist/Todo.java | 165 ++++++++ .../t_battermann/dhbw/todolist/TodoList.java | 129 +++++++ src/de/t_battermann/dhbw/todolist/User.java | 205 ++++++++++ .../dhbw/todolist/XMLHandler.java | 286 ++++++++++++++ src/de/t_battermann/dhbw/todolist/login.fxml | 92 +++++ src/de/t_battermann/dhbw/todolist/main.fxml | 104 ++++++ .../t_battermann/dhbw/todolist/openFile.fxml | 33 ++ src/de/t_battermann/dhbw/todolist/saveAs.fxml | 21 ++ 15 files changed, 1524 insertions(+) create mode 100644 TodoList.iml create mode 100644 ext/.keep create mode 100644 src/de/t_battermann/dhbw/todolist/CSVHandler.java create mode 100644 src/de/t_battermann/dhbw/todolist/Controller.java create mode 100644 src/de/t_battermann/dhbw/todolist/ExportHandler.java create mode 100644 src/de/t_battermann/dhbw/todolist/InvalidDataException.java create mode 100644 src/de/t_battermann/dhbw/todolist/Main.java create mode 100644 src/de/t_battermann/dhbw/todolist/Todo.java create mode 100644 src/de/t_battermann/dhbw/todolist/TodoList.java create mode 100644 src/de/t_battermann/dhbw/todolist/User.java create mode 100644 src/de/t_battermann/dhbw/todolist/XMLHandler.java create mode 100644 src/de/t_battermann/dhbw/todolist/login.fxml create mode 100644 src/de/t_battermann/dhbw/todolist/main.fxml create mode 100644 src/de/t_battermann/dhbw/todolist/openFile.fxml create mode 100644 src/de/t_battermann/dhbw/todolist/saveAs.fxml diff --git a/TodoList.iml b/TodoList.iml new file mode 100644 index 0000000..feac04f --- /dev/null +++ b/TodoList.iml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ext/.keep b/ext/.keep new file mode 100644 index 0000000..e69de29 diff --git a/src/de/t_battermann/dhbw/todolist/CSVHandler.java b/src/de/t_battermann/dhbw/todolist/CSVHandler.java new file mode 100644 index 0000000..ce653ff --- /dev/null +++ b/src/de/t_battermann/dhbw/todolist/CSVHandler.java @@ -0,0 +1,33 @@ +package de.t_battermann.dhbw.todolist; + +import java.io.File; +import java.io.IOException; +import java.util.Map; + +/** + * Export the user data in a CSV file + */ +public class CSVHandler implements ExportHandler { + @Override + public void exportToFile(Map users, File filename) throws IOException { + // TODO: implement method + } + + @Override + public String exportToString(Map users) { + // TODO: implement method + return null; + } + + @Override + public Map importFromFile(File filename) throws IOException, InvalidDataException { + // TODO: implement method + return null; + } + + @Override + public Map importFromString(String str) throws InvalidDataException { + // TODO: implement method + return null; + } +} diff --git a/src/de/t_battermann/dhbw/todolist/Controller.java b/src/de/t_battermann/dhbw/todolist/Controller.java new file mode 100644 index 0000000..d6e4193 --- /dev/null +++ b/src/de/t_battermann/dhbw/todolist/Controller.java @@ -0,0 +1,352 @@ +package de.t_battermann.dhbw.todolist; + +import com.sun.javafx.collections.ObservableListWrapper; +import com.sun.javafx.collections.ObservableSequentialListWrapper; +import javafx.application.Platform; +import javafx.collections.ObservableList; +import javafx.fxml.FXMLLoader; +import javafx.scene.Node; +import javafx.scene.Scene; +import javafx.scene.control.*; +import javafx.stage.Stage; + +import java.io.File; +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.*; + +public class Controller { + private Map users = null; + private User currentUser = null; + private ObservableList todoLists = null; + private ObservableList todos; + private Todo currentTodo = null; + private String filename = null; + private Map scenes = new HashMap<>(); + private Stage primaryStage; + + public Controller(Stage primaryStage) { + this.primaryStage = primaryStage; + // Initialize needed scenes + try { + scenes.put("openFile", new Scene(FXMLLoader.load(getClass().getResource("openFile.fxml")),500,150)); + scenes.put("login", new Scene(FXMLLoader.load(getClass().getResource("login.fxml")),500,350)); + scenes.put("main", new Scene(FXMLLoader.load(getClass().getResource("main.fxml")),600,500)); + scenes.put("saveAs", new Scene(FXMLLoader.load(getClass().getResource("saveAs.fxml")),500,150)); + } catch (IOException e1) { + System.out.println("Could’t load a fxml file!"); + e1.printStackTrace(); + } + showLoadFileDialog(); + } + + /** + * Initialize new empty + */ + public void initEmpty() { + this.users = new TreeMap<>(); + } + + public void initFromFile(String filename) throws IOException, InvalidDataException { + File f = new File(filename); + if ( !f.isFile() || f.isDirectory() || !f.canRead()) { + throw new IOException(); + } + ExportHandler e; + if ( filename.endsWith(".csv") ) { + e = new CSVHandler(); + }else{ + e = new XMLHandler(); + } + this.users = e.importFromFile(new File(filename)); + this.filename = filename; + } + + public boolean export(String filename) { + if ( filename != null) { + File f = new File(filename); + if ( f.isDirectory() ) { + this.updateStatusLine("Couldn’t write to file '" + filename + "'"); + return false; + } + ExportHandler e; + if ( filename.endsWith(".csv") ) { + e = new CSVHandler(); + }else { + e = new XMLHandler(); + } + try { + e.exportToFile(this.users, f); + } catch (IOException e1) { + this.updateStatusLine("Could’t write to file!"); + e1.printStackTrace(); + return false; + } + return true; + } + return false; + } + + public void showLoadFileDialog() { + // log out (doesn't do anything if not logged in) + this.users = null; + this.currentUser = null; + this.todoLists = null; + this.todos = null; + this.filename = null; + // show dialog + primaryStage.setTitle("TodoList :: Open database"); + primaryStage.setScene(scenes.get("openFile")); + primaryStage.show(); + // register event handlers + Button b = (Button) primaryStage.getScene().lookup("#openFileButton"); + b.setOnMouseReleased(event -> { + Node n = primaryStage.getScene().lookup("#openFilePath"); + if ( n != null && n instanceof TextField ) { + try { + this.initFromFile(((TextField) n).getText()); + this.showLoginDialog(); + } catch (InvalidDataException | IOException e1) { + System.out.println("Can’t read file '" + this.filename + "'"); + e1.printStackTrace(); + } + }else{ + System.out.println("Didn’t find #openFilePath!"); + } + }); + b = (Button) primaryStage.getScene().lookup("#openFileNew"); + b.setOnMouseReleased(event -> { + this.initEmpty(); + this.showLoginDialog(); + }); + } + + private void showLoginDialog() { + primaryStage.setTitle("TodoList :: Log in"); + primaryStage.setScene(scenes.get("login")); + TitledPane a = (TitledPane) primaryStage.getScene().lookup(users.isEmpty() ? "#createNewUserPane" : "#loginPane"); + if ( a != null ) { + a.setExpanded(true); + } + // Log in + Node n = primaryStage.getScene().lookup("#loginButton"); + if ( n != null && n instanceof Button) { + n.setOnMouseReleased(event -> { + Label l = (Label) primaryStage.getScene().lookup("#labelHints"); + String name = null; + String pass = null; + Node m = primaryStage.getScene().lookup("#loginUsername"); + if (m != null && m instanceof TextField) { + name = ((TextField) m).getText(); + } else { + System.out.println("'#loginUsername' not found!"); + return; + } + m = primaryStage.getScene().lookup("#loginPassword"); + if (m != null && m instanceof PasswordField) { + pass = ((PasswordField) m).getText(); + } + if (this.users.containsKey(name)) { + this.currentUser = this.users.get(name); + if (this.currentUser.checkLoginData(pass)) { + this.todoLists = new ObservableListWrapper<>(currentUser.getTodoLists()); + this.showMainWindow(); + }else{ + this.currentUser = null; + l.setText("Invalid credentials!"); + } + }else{ + l.setText("Invalid credentials! 1"); + } + }); + }else{ + System.out.println("'#loginButton' not found!"); + } + n = primaryStage.getScene().lookup("#registerButton"); + if ( n != null && n instanceof Button) { + n.setOnMouseReleased(event -> { + Label l = (Label) primaryStage.getScene().lookup("#labelHintsCreateNewUser"); + // username + String username; + Node no = primaryStage.getScene().lookup("#registerUsername"); + if ( no != null && no instanceof TextField && User.checkUsername(((TextField) no).getText())) { + username = ((TextField) no).getText(); + }else{ + l.setText("Invalid username! (Regex: [a-zA-Z0-9_-]{3,})"); + return; + } + if ( users.containsKey(username)) { + l.setText("Username already taken!"); + return; + } + // password + String password; + no = primaryStage.getScene().lookup("#registerPassword"); + if( no != null && no instanceof PasswordField && User.checkPassword(((PasswordField) no).getText())) { + password = ((PasswordField) no).getText(); + no = primaryStage.getScene().lookup("#registerPasswordRepeat"); + if( no == null || !(no instanceof PasswordField) || !password.equals(((PasswordField) no).getText())) { + l.setText("The passwords didn’t match!"); + } + }else{ + l.setText("Password must be longer than 6 chars! And must contain numbers, lower and upper chars!"); + return; + } + // eMail + String email; + no = primaryStage.getScene().lookup("#registerEmail"); + if( no != null && no instanceof TextField && User.checkEmail( ((TextField) no).getText() ) ) { + email = ((TextField) no).getText(); + no = primaryStage.getScene().lookup("#registerEmailRepeat"); + if( no == null || !(no instanceof TextField) || !email.equals(((TextField) no).getText())) { + l.setText("The eMail addresses didn’t match!"); + } + }else{ + l.setText("No valid eMail address given!"); + return; + } + User nu = new User(username,password); + nu.setEmail(email); + currentUser = nu; + users.put(username, nu); + this.todoLists = new ObservableSequentialListWrapper<>(currentUser.getTodoLists()); + }); + }else{ + System.out.println("'#registerButton' not found!"); + } + } + + private void showMainWindow() { + primaryStage.setTitle("TodoList :: " + currentUser.getUsername() + " > Default"); + primaryStage.setScene(scenes.get("main")); + Node n = primaryStage.getScene().lookup("#todoLists"); + if ( n != null && n instanceof ListView) { + ListView lv = (ListView) n; + lv.setItems(this.todoLists); + lv.scrollTo(currentUser.getTodoList("Default")); + lv.getSelectionModel().selectedIndexProperty().addListener(event -> { + this.updateSelectedTodoList(); + }); + } + this.todos = new ObservableListWrapper<>(currentUser.getTodoList("Default").getTodos()); + n = primaryStage.getScene().lookup("#todos"); + if ( n != null && n instanceof ListView) { + ListView lv = (ListView) n; + lv.setItems(this.todos); + lv.getSelectionModel().selectedIndexProperty().addListener(event -> { + this.updateSelectedTodo(); + }); + } + n = primaryStage.getScene().lookup("#menuSave"); + if ( n != null && n instanceof Button) { + n.setOnMouseReleased(event -> { + if ( this.filename != null) { + this.export(this.filename); + }else{ + this.showSaveAs(); + } + }); + } + n = primaryStage.getScene().lookup("#menuSaveAs"); + if ( n != null && n instanceof Button ) { + n.setOnMouseReleased(event -> this.showSaveAs()); + } + n = primaryStage.getScene().lookup("#menuClose"); + if ( n != null && n instanceof Button ) { + n.setOnMouseReleased(event -> Platform.exit()); + } + this.primaryStage.setOnCloseRequest(event -> Platform.exit()); + } + + private void updateSelectedTodoList() { + Node n = primaryStage.getScene().lookup("#todoLists"); + if ( n == null || !(n instanceof ListView) ) { + return; + } + ListView l = (ListView) n; + n = primaryStage.getScene().lookup("#todos"); + if ( n == null || !(n instanceof ListView)) { + return; + } + ListView lt = (ListView) n; + if ( l.getSelectionModel().getSelectedItem() != null && l.getSelectionModel().getSelectedItem() instanceof TodoList ) { + TodoList t = (TodoList) l.getSelectionModel().getSelectedItem(); + this.todos = new ObservableListWrapper<>(t.getTodos()); + lt.setItems(this.todos); + lt.getSelectionModel().select(0); + } + updateSelectedTodo(); + } + + private void updateSelectedTodo() { + Node n = primaryStage.getScene().lookup("#todos"); + if ( n != null && n instanceof ListView) { + ListView lv = (ListView) n; + if(lv.getSelectionModel().getSelectedItem() != null) { + this.currentTodo = lv.getSelectionModel().getSelectedItem(); + } + } + // title + n = primaryStage.getScene().lookup("#todoDetailTitle"); + if ( n == null || !(n instanceof TextField)) + return; + ((TextField) n).setText( this.currentTodo.getTitle() ); + // comment + n = primaryStage.getScene().lookup("#todoDetailDescription"); + if ( n == null || !(n instanceof TextArea) ) + return; + ((TextArea) n).setText( this.currentTodo.getComment() ); + // if dueDate set: + n = primaryStage.getScene().lookup("#todoDetailDueDate"); + if ( n == null || !(n instanceof CheckBox) ) + return; + boolean dueDate = this.currentTodo.getDueDate() != null; + ((CheckBox) n).setSelected(dueDate); + // datePicker + n = primaryStage.getScene().lookup("#todoDetailDate"); + if( n == null || !(n instanceof DatePicker)) + return; + if(dueDate) { + ((DatePicker) n).setValue( LocalDateTime.ofInstant(this.currentTodo.getDueDate().getTime().toInstant(), ZoneId.systemDefault()).toLocalDate() ); + } + // time + n = primaryStage.getScene().lookup("#todoDetailTime"); + if ( n == null || !(n instanceof TextField)) + return; + ((TextField) n).setText(this.currentTodo.getTime()); + } + + private void updateStatusLine(String text) { + Node n = primaryStage.getScene().lookup("#statusLine"); + if ( n != null && n instanceof Label) { + ((Label) n).setText(text); + }else{ + System.out.println("Couldn’t find status line!"); + } + } + + private void showSaveAs() { + // TODO + Stage save = new Stage(); + save.setScene(scenes.get("saveAs")); + save.setTitle("Save as ..."); + save.show(); + Button s = (Button) save.getScene().lookup("#save"); + if ( s != null ) + s.setOnMouseReleased(event -> { + TextField f = (TextField)save.getScene().lookup("#filename"); + if ( f != null) { + File file = new File(f.getText()); + if ( !file.isDirectory() ) { + if ( this.filename == null) + this.filename = f.getText(); + if(this.export(f.getText())) + save.close(); + }else{ + this.updateStatusLine("Can’t write to file!"); + } + } + }); + } +} diff --git a/src/de/t_battermann/dhbw/todolist/ExportHandler.java b/src/de/t_battermann/dhbw/todolist/ExportHandler.java new file mode 100644 index 0000000..29032b4 --- /dev/null +++ b/src/de/t_battermann/dhbw/todolist/ExportHandler.java @@ -0,0 +1,42 @@ +package de.t_battermann.dhbw.todolist; + +import java.io.File; +import java.io.IOException; +import java.util.Map; + +/** + * Interface for exporting/saving the data + */ +public interface ExportHandler { + /** + * Export to file. + * + * @param users A Map containing the users + * @param filename Path to the file the data should be saved to + */ + void exportToFile(Map users, File filename) throws IOException; + + /** + * Export to string. + * + * @param users the users + * @return A String containing the data + */ + String exportToString(Map users); + + /** + * Import from file. + * + * @param filename Path to the saved data + * @return A Map containing the Users, username as index + */ + Map importFromFile(File filename) throws IOException, InvalidDataException; + + /** + * Import from string. + * + * @param str A String containing the Data + * @return A Map containing the User, username as index + */ + Map importFromString(String str) throws InvalidDataException; +} diff --git a/src/de/t_battermann/dhbw/todolist/InvalidDataException.java b/src/de/t_battermann/dhbw/todolist/InvalidDataException.java new file mode 100644 index 0000000..7c22b2b --- /dev/null +++ b/src/de/t_battermann/dhbw/todolist/InvalidDataException.java @@ -0,0 +1,13 @@ +package de.t_battermann.dhbw.todolist; + +/** + * This exception is thrown when the imported data is not as expected. + */ +public class InvalidDataException extends Exception { + public InvalidDataException() { + } + + public InvalidDataException(String message) { + super(message); + } +} diff --git a/src/de/t_battermann/dhbw/todolist/Main.java b/src/de/t_battermann/dhbw/todolist/Main.java new file mode 100644 index 0000000..896805f --- /dev/null +++ b/src/de/t_battermann/dhbw/todolist/Main.java @@ -0,0 +1,17 @@ +package de.t_battermann.dhbw.todolist; + +import javafx.application.Application; +import javafx.stage.Stage; + +public class Main extends Application { + + @Override + public void start(Stage primaryStage) throws Exception{ + new Controller(primaryStage); + } + + + public static void main(String[] args) { + launch(args); + } +} diff --git a/src/de/t_battermann/dhbw/todolist/Todo.java b/src/de/t_battermann/dhbw/todolist/Todo.java new file mode 100644 index 0000000..6a6fdf5 --- /dev/null +++ b/src/de/t_battermann/dhbw/todolist/Todo.java @@ -0,0 +1,165 @@ +package de.t_battermann.dhbw.todolist; + +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.UUID; + +/** + * This class represents a todo item containing all the data. + */ +public class Todo { + private String uuid; + private String title = "No title"; + private boolean done = false; + private boolean prio = false; + private String comment = ""; + private Calendar dueDate = null; + + /** + * Instantiates a new empty Todo item. + */ + public Todo() { + this.uuid = UUID.randomUUID().toString(); + } + + /** + * Instantiates a new Todo. + * + * @param uuid the uuid + * @param title the title + * @param comment the comment + * @param dueDate the due date + * @param done Is the item done? + * @param prio Has the item high priority? + */ + protected Todo(String uuid, String title, String comment, Calendar dueDate, boolean done, boolean prio) { + this.uuid = uuid; + this.title = title; + this.comment = comment; + this.dueDate = dueDate; + this.done = done; + this.prio = prio; + } + + /** + * Instantiates a new Todo. + * + * @param title the title + * @param comment the comment + */ + public Todo(String title, String comment) { + this.uuid = UUID.randomUUID().toString(); + this.title = title; + this.comment = comment; + } + + /** + * Gets uuid. + * + * @return the uuid + */ + public String getUuid() { + return this.uuid; + } + + /** + * Gets title. + * + * @return the title + */ + public String getTitle() { + return title; + } + + /** + * Sets title. + * + * @param title the title + */ + public void setTitle(String title) { + this.title = title; + } + + /** + * Is it done? + * + * @return the boolean + */ + public boolean isDone() { + return done; + } + + /** + * Sets done. + * + * @param done the done + */ + public void setDone(boolean done) { + this.done = done; + } + + /** + * Is prio. + * + * @return the boolean + */ + public boolean isPrio() { + return prio; + } + + /** + * Sets prio. + * + * @param prio the prio + */ + public void setPrio(boolean prio) { + this.prio = prio; + } + + /** + * Gets comment. + * + * @return the comment + */ + public String getComment() { + return comment; + } + + /** + * Sets comment. + * + * @param comment the comment + */ + public void setComment(String comment) { + this.comment = comment; + } + + /** + * Gets due date. + * + * @return the due date + */ + public Calendar getDueDate() { + return dueDate; + } + + /** + * Sets due date. + * + * @param dueDate the due date + */ + public void setDueDate(Calendar dueDate) { + this.dueDate = dueDate; + } + + public String getTime() { + SimpleDateFormat format = new SimpleDateFormat(); + format.applyPattern("yyyyMMdd'T'HH:mm:ssZ"); + return this.getDueDate() != null ? format.format(this.getDueDate().getTime()) : "00:00"; + } + + @Override + public String toString() { + return this.getTitle(); + } +} diff --git a/src/de/t_battermann/dhbw/todolist/TodoList.java b/src/de/t_battermann/dhbw/todolist/TodoList.java new file mode 100644 index 0000000..d1a68cf --- /dev/null +++ b/src/de/t_battermann/dhbw/todolist/TodoList.java @@ -0,0 +1,129 @@ +package de.t_battermann.dhbw.todolist; + +import java.util.*; + +/** + * This class contains a todo list with all its items. + */ +public class TodoList { + private String uuid = UUID.randomUUID().toString(); + private List todos = new LinkedList<>(); + private String name; + private boolean changeable; + + /** + * Instantiates a new Todo list. + * + * @param name the name + */ + public TodoList(String name) { + this.changeable = true; + this.name = name; + } + + /** + * Instantiates a new Todo list. + * + * @param name the name + * @param changeable Can the name be changed? + */ + public TodoList(String name, boolean changeable) { + this.changeable = changeable; + this.name = name; + this.initList(); + } + + /** + * Instantiates a new Todo list. + * + * @param uuid the uuid + * @param name the name + * @param changeable Can the name be changed? + */ + protected TodoList(String uuid, String name, boolean changeable) { + this.uuid = uuid; + this.todos = new LinkedList<>(); + this.name = name; + this.changeable = changeable; + } + + private void initList() { + this.todos.add(new Todo("Start using your TodoList", "Add, delete and modify entries.")); + } + + /** + * Gets uuid. + * + * @return the uuid + */ + public String getUuid() { + return this.uuid; + } + + /** + * Gets name. + * + * @return the name + */ + public String getName() { + return name; + } + + /** + * Sets name. + * + * @param name the name + */ + public void setName(String name) { + if (this.isChangeable()) + this.name = name; + } + + /** + * Gets todos. + * + * @return the todos + */ + public List getTodos() { + return todos; + } + + /** + * Add todo. + * + * @param todo the todo + * @return the boolean + */ + public boolean addTodo(Todo todo) { + if (todos.contains(todo)) { + return false; + } + todos.add(todo); + return true; + } + + /** + * Delete a todo item + * + * @param todo The Item to be deleted + */ + public void deleteTodo(Todo todo) { + if (todos.contains(todo)) { + todos.remove(todo); + } + } + + /** + * Is changeable. + * + * @return true if the name can be changed + */ + public boolean isChangeable() { + return changeable; + } + + @Override + public String toString() { + return this.getName(); + } +} diff --git a/src/de/t_battermann/dhbw/todolist/User.java b/src/de/t_battermann/dhbw/todolist/User.java new file mode 100644 index 0000000..ebdd5af --- /dev/null +++ b/src/de/t_battermann/dhbw/todolist/User.java @@ -0,0 +1,205 @@ +package de.t_battermann.dhbw.todolist; + +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.validator.routines.EmailValidator; + +import java.io.Serializable; +import java.util.*; + +/** + * This class contains all the users data. + */ +public class User implements Serializable { + private String username; + private String email; + private String password; + private String uuid = UUID.randomUUID().toString(); + private List todoLists; + + /** + * Instantiates a new User. + * + * @param username the username + * @param password the password + */ + public User(String username, String password) { + this.username = username; + this.password = hashPassword(password); + this.email = ""; + + todoLists = new LinkedList<>(); + TodoList tmp = new TodoList("Default", false); + todoLists.add(tmp); + } + + /** + * Instantiates a new User. + * Used to restore saved data + * + * @param uuid the uuid + * @param username the username + * @param hashedPassword the hashed password + * @param email the email + */ + protected User(String uuid, String username, String hashedPassword, String email) { + this.username = username; + this.uuid = uuid; + this.password = hashedPassword; + this.email = email; + this.todoLists = new LinkedList<>(); + TodoList tmp = new TodoList("Default", false); + todoLists.add(tmp); + } + + /** + * Gets username. + * + * @return the username + */ + public String getUsername() { + return this.username; + } + + /** + * Gets password. + * + * @return the password + */ + protected String getPassword() { + return this.password; + } + + /** + * Gets uuid. + * + * @return the uuid + */ + public String getUuid() { + return this.uuid; + } + + /** + * Gets email. + * + * @return the email + */ + public String getEmail() { + return this.email; + } + + /** + * Gets todo list. + * + * @param name the name + * @return the todo list + */ + public TodoList getTodoList(String name) { + for(TodoList l: todoLists) + if(l.getName().equals(name)) + return l; + System.out.println("TodoList not found: " + name); + return null; + } + + /** + * Gets todo lists. + * + * @return the todo lists + */ + public List getTodoLists() { + return todoLists; + } + + /** + * Check login data. + * + * @param password the password + * @return the boolean + */ + public boolean checkLoginData(String password) { + System.out.println("pw: " + password + " -> " + this.hashPassword(password)); + System.out.println("stored: " + this.password); + return this.hashPassword(password).equals(this.password); + } + + @Override + public String toString() { + return "Username: " + username + "\n" + + "eMail: " + email + "\n"; + } + + /** + * Add a todo list. + * + * @param name the name for the new list + * @return false if a list with the given name already exists + */ + public boolean addTodoList(String name) { + return this.addTodoList(new TodoList(name)); + } + + /** + * Add todo list. + * + * @param todoList the todo list + * @return false if a list with the given name already exists + */ + public boolean addTodoList(TodoList todoList) { + if ( this.getTodoList( todoList.getName()) == null ) { + this.todoLists.add(todoList); + return true; + } + System.out.println("A TodoList named '" + todoList.getName() + "' already exists!"); + return false; + } + + /** + * Update the users password + * + * @param password the password (cleartext) + */ + public void setPassword(String password) { + this.password = hashPassword(password); + } + + /** + * Sets email. + * + * @param email the email + * @return the email + */ + public boolean setEmail(String email) { + if (User.checkEmail(email)) { + this.email = email; + return true; + } + System.out.println("Invalid eMail: '" + email + "'"); + return false; + } + + /** + * Generate a salted hash + * + * @param password the password to salt and hash + * @return salted and hashed password + */ + private String hashPassword(String password) { + return DigestUtils.sha256Hex(uuid + password); + } + + /** + * Checks if eMail has correct syntax + * @param email string containing a eMail address + * @return true if valid syntax + */ + public static boolean checkEmail(String email) { + return email.length() != 0 && EmailValidator.getInstance().isValid(email); + } + + public static boolean checkUsername(String username) { + return username.matches("[a-zA-Z0-9_-]{3,}"); + } + public static boolean checkPassword(String password) { + return password.length() > 6 && password.matches(".*[A-Z].*") && password.matches(".*[a-z].*") && password.matches(".*[0-9].*"); + } +} diff --git a/src/de/t_battermann/dhbw/todolist/XMLHandler.java b/src/de/t_battermann/dhbw/todolist/XMLHandler.java new file mode 100644 index 0000000..40d348f --- /dev/null +++ b/src/de/t_battermann/dhbw/todolist/XMLHandler.java @@ -0,0 +1,286 @@ +package de.t_battermann.dhbw.todolist; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import java.io.*; +import java.nio.charset.Charset; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.*; + +/** + * This class implement the ExportHandler interface. It converts the data to XML and vice versa. + */ +public class XMLHandler implements ExportHandler { + /** + * Convert a map containing the users to a DOMSource containing XML + * + * @param users The users map + * @return DOMSource containing XML + */ + private DOMSource doExport(Map users) { + try { + DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); + + Document doc = docBuilder.newDocument(); + Element rootElement = doc.createElement("todolistapp"); + doc.appendChild(rootElement); + + for (User userEntry : users.values()) { + Element user = doc.createElement("user"); + + Element username = doc.createElement("username"); + username.appendChild(doc.createTextNode(userEntry.getUsername())); + user.appendChild(username); + + Element password = doc.createElement("password"); + password.appendChild(doc.createTextNode(userEntry.getPassword())); + user.appendChild(password); + + Element password_salt = doc.createElement("uuid"); + password_salt.appendChild(doc.createTextNode(userEntry.getUuid())); + user.appendChild(password_salt); + + Element email = doc.createElement("email"); + email.appendChild(doc.createTextNode(userEntry.getEmail())); + user.appendChild(email); + + for (TodoList todoListEntry : userEntry.getTodoLists()) { + Element list = doc.createElement("TodoList"); + list.setAttribute("changeable", todoListEntry.isChangeable() ? "true" : "false"); + + Element title = doc.createElement("name"); + title.appendChild(doc.createTextNode(todoListEntry.getName())); + list.appendChild(title); + + Element uuid = doc.createElement("uuid"); + uuid.appendChild(doc.createTextNode(todoListEntry.getUuid())); + list.appendChild(uuid); + + for (Todo entry : todoListEntry.getTodos()) { + SimpleDateFormat format = new SimpleDateFormat(); + format.applyPattern("yyyyMMdd'T'HH:mm:ssZ"); + Element todo = doc.createElement("item"); + todo.setAttribute("prio", entry.isPrio() ? "true" : "false"); + todo.setAttribute("done", entry.isDone() ? "true" : "false"); + + Element todoTitle = doc.createElement("title"); + todoTitle.appendChild(doc.createTextNode(entry.getTitle())); + todo.appendChild(todoTitle); + + Element todoUuid = doc.createElement("uuid"); + todoUuid.appendChild(doc.createTextNode(entry.getUuid())); + todo.appendChild(todoUuid); + + Element comment = doc.createElement("comment"); + comment.appendChild(doc.createTextNode(entry.getComment())); + todo.appendChild(comment); + + if (entry.getDueDate() != null) { + Element duedate = doc.createElement("duedate"); + duedate.appendChild(doc.createTextNode(format.format(entry.getDueDate().getTime()))); + todo.appendChild(duedate); + } // if duedate + list.appendChild(todo); + } // for todos + user.appendChild(list); + } // for todoLists + rootElement.appendChild(user); + } // for users + + return new DOMSource(doc); + } catch (ParserConfigurationException e) { + e.printStackTrace(); + return null; + } + } + + public void exportToFile(Map users, File file) { + try { + TransformerFactory transformerFactory = TransformerFactory.newInstance(); + Transformer transformer = transformerFactory.newTransformer(); + DOMSource source = this.doExport(users); + StreamResult result = new StreamResult(file); + transformer.transform(source, result); + } catch (TransformerException e) { + e.printStackTrace(); + } + } + + public String exportToString(Map users) { + try { + StringWriter sw = new StringWriter(); + TransformerFactory transformerFactory = TransformerFactory.newInstance(); + Transformer transformer = transformerFactory.newTransformer(); + DOMSource source = this.doExport(users); + transformer.transform(source, new StreamResult(sw)); + return sw.toString(); + } catch (TransformerConfigurationException e) { + e.printStackTrace(); + return ""; + } catch (TransformerException e) { + e.printStackTrace(); + return ""; + } + } + + /** + * Get a string-element from a node + * + * @param node The node to be searched in + * @param name The elements name + * @return the desired string or empty string if not found + */ + private String elementGetString(Element node, String name) { + NodeList nodes = node.getElementsByTagName(name); + if (nodes.getLength() >= 1) { + return nodes.item(0).getTextContent(); + } + return ""; + } + + /** + * Get a boolean value from a attribute + * + * @param node The node to be searched in + * @param name The attributes name + * @param defaultValue if the attribute is not set use this value + * @return either the value of the attribute or the default value if attribute not found + */ + private boolean elementGetBool(Element node, String name, boolean defaultValue) { + if (node.hasAttribute(name)) { + return node.getAttribute(name).compareTo("true") == 0; + } + return defaultValue; + } + + /** + * Get a date from a element + * + * @param node The node to be searched in + * @param name The elements name + * @return Either the date (if found) or null + */ + private Calendar elementGetDate(Element node, String name) { + SimpleDateFormat format = new SimpleDateFormat(); + format.applyPattern("yyyyMMdd'T'HH:mm:ssZ"); + NodeList nodes = node.getElementsByTagName(name); + if (nodes.getLength() >= 1) { + try { + Calendar r = new GregorianCalendar(); + r.setTime(format.parse(nodes.item(0).getTextContent())); + return r; + } catch (ParseException e) { + e.printStackTrace(); + } + } + return null; + } + + /** + * Helper function to convert the xml to a map containing the user data + * + * @param stream InputStream containing XML data + * @return The user object + * @throws IOException + * @throws InvalidDataException + */ + private Map doImport(InputStream stream) throws IOException, InvalidDataException { + // Temporary variables + TreeMap users = new TreeMap<>(); + User user; + TodoList todoList; + Todo todo; + try { + DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); + + Document doc = docBuilder.parse(stream); + doc.getDocumentElement().normalize(); + + // the actual import ... + if (!"todolistapp".equals(doc.getDocumentElement().getNodeName())) { + throw new InvalidDataException("Expected 'todolistapp' as root node"); + } + + NodeList nUsers = doc.getElementsByTagName("user"); + for (int i = 0; i < nUsers.getLength(); i++) { + Node nUser = nUsers.item(i); + if (nUser.getNodeType() == Node.ELEMENT_NODE) { + Element eUser = (Element) nUser; + user = new User( + this.elementGetString(eUser, "uuid"), + this.elementGetString(eUser, "username"), + this.elementGetString(eUser, "password"), + this.elementGetString(eUser, "email") + ); + NodeList nTodoLists = eUser.getElementsByTagName("TodoList"); + for (int j = 0; j < nTodoLists.getLength(); j++) { + Node nTodoList = nTodoLists.item(j); + if (nTodoList.getNodeType() == Node.ELEMENT_NODE) { + Element eTodoList = (Element) nTodoList; + todoList = new TodoList( + this.elementGetString(eTodoList, "uuid"), + this.elementGetString(eTodoList, "name"), + this.elementGetBool(eTodoList, "changeable", true) + ); + NodeList nTodos = eTodoList.getElementsByTagName("item"); + for (int k = 0; k < nTodos.getLength(); k++) { + Node nTodo = nTodos.item(k); + if (nTodo.getNodeType() == Node.ELEMENT_NODE) { + Element eTodo = (Element) nTodo; + // String uuid, String title, String comment, Calendar dueDate, boolean done, boolean prio + todo = new Todo( + this.elementGetString(eTodo, "uuid"), + this.elementGetString(eTodo, "title"), + this.elementGetString(eTodo, "comment"), + this.elementGetDate(eTodo, "duedate"), + this.elementGetBool(eTodo, "done", false), + this.elementGetBool(eTodo, "prio", false) + ); + todoList.addTodo(todo); + } + } + user.addTodoList(todoList); + } + } + users.put(user.getUsername(), user); + } + } + + + } catch (ParserConfigurationException | SAXException e) { + e.printStackTrace(); + } + return users; + } + + public Map importFromFile(File file) throws IOException, InvalidDataException { + InputStream inputStream = new FileInputStream(file); + return this.doImport(inputStream); + } + + public Map importFromString(String str) throws InvalidDataException { + try { + InputStream inputStream = new ByteArrayInputStream(str.getBytes(Charset.forName("UTF-8"))); + return this.doImport(inputStream); + } catch (IOException e) { + e.printStackTrace(); + return new TreeMap<>(); + } + } +} diff --git a/src/de/t_battermann/dhbw/todolist/login.fxml b/src/de/t_battermann/dhbw/todolist/login.fxml new file mode 100644 index 0000000..7a5328e --- /dev/null +++ b/src/de/t_battermann/dhbw/todolist/login.fxml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/de/t_battermann/dhbw/todolist/main.fxml b/src/de/t_battermann/dhbw/todolist/main.fxml new file mode 100644 index 0000000..c58f4ef --- /dev/null +++ b/src/de/t_battermann/dhbw/todolist/main.fxml @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + +