├── ToDoList Slides.pdf └── src ├── ToDoMain.java ├── model ├── TaskNameCompare.java ├── ToDoTask.java ├── ToDoModel.java └── ToDoList.java ├── test └── ToDoTest.java ├── controller └── ToDoController.java └── view └── ToDoView.java /ToDoList Slides.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xinli2/todo-list/HEAD/ToDoList Slides.pdf -------------------------------------------------------------------------------- /src/ToDoMain.java: -------------------------------------------------------------------------------- 1 | import javafx.application.Application; 2 | import view.ToDoView; 3 | 4 | public class ToDoMain { 5 | 6 | public static void main(String args[]) { 7 | Application.launch(ToDoView.class, args); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/model/TaskNameCompare.java: -------------------------------------------------------------------------------- 1 | package model; 2 | 3 | public class TaskNameCompare implements java.util.Comparator { 4 | 5 | @Override 6 | public int compare(ToDoTask t1, ToDoTask t2) { 7 | 8 | return t1.getName().compareTo(t2.getName()); 9 | 10 | } 11 | 12 | } -------------------------------------------------------------------------------- /src/test/ToDoTest.java: -------------------------------------------------------------------------------- 1 | package test; 2 | import static org.junit.jupiter.api.Assertions.assertFalse; 3 | import static org.junit.jupiter.api.Assertions.assertTrue; 4 | import org.junit.jupiter.api.Test; 5 | 6 | public class ToDoTest { 7 | 8 | /** 9 | * Test method for {@link ToDoList#addTask(java.lang.String)}. 10 | */ 11 | @Test 12 | void testaddTask() { 13 | 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/model/ToDoTask.java: -------------------------------------------------------------------------------- 1 | package model; 2 | 3 | import java.io.Serializable; 4 | import java.util.Date; 5 | 6 | 7 | //TODO: IMPLEMENT FIELDS AND FUNCTIONALITY FOR FIELDS: deadline, important 8 | 9 | public class ToDoTask implements Serializable{ 10 | /** 11 | * 12 | */ 13 | private static final long serialVersionUID = 1L; 14 | private String name; 15 | private String description; 16 | private String deadline; //leaving as string for now 17 | private Date createTime; 18 | private String location; 19 | private String important; 20 | private boolean complete; 21 | 22 | public ToDoTask() { 23 | this.name = "untitled task"; 24 | this.description = null; 25 | this.complete = false; 26 | } 27 | 28 | public ToDoTask(String name) { 29 | this.name = name; 30 | this.description = null; 31 | this.complete = false; 32 | } 33 | 34 | public ToDoTask(String name, String description,String deadline,String importance,String location) { 35 | this.name = name; 36 | this.description = description; 37 | this.deadline = deadline; 38 | this.important = importance; 39 | this.location = location; 40 | this.createTime = new Date(); 41 | this.complete = false; 42 | //System.out.println("Name:"+this.name+"\nDescription:"+this.description); //TESTING PURPOSES 43 | } 44 | 45 | public void rename(String newName) { //TODO: implement somehow when functionality is added to GUI 46 | if(newName == null) { 47 | System.out.println("Don't rename as null"); 48 | } else { 49 | this.name=newName; 50 | } 51 | } 52 | 53 | public String getName() { 54 | return this.name; 55 | } 56 | 57 | public String getDescription() { 58 | return this.description; 59 | } 60 | public String getDeadline() { 61 | return this.deadline; 62 | } 63 | public String getImportance() { 64 | return this.important; 65 | } 66 | public String getLocation(){ 67 | return this.location; 68 | } 69 | 70 | public boolean getCompletion() { 71 | return this.complete; 72 | } 73 | public void setImportance(String importance) { 74 | this.important = importance; 75 | } 76 | public void setCompletion(boolean complete) { 77 | this.complete = complete; 78 | } 79 | 80 | public Date getCreateTime(){ 81 | return this.createTime; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/controller/ToDoController.java: -------------------------------------------------------------------------------- 1 | package controller; 2 | 3 | import java.io.IOException; 4 | import java.util.Observer; 5 | 6 | import javafx.scene.control.Alert; 7 | import model.ToDoModel; 8 | 9 | 10 | public class ToDoController { 11 | private ToDoModel model; 12 | 13 | /** 14 | * Creates a ToDoController from the given ToDoModel. 15 | * 16 | * Note: View must use the method addObserver after this method in order 17 | * for it to become an Observer of the first list. 18 | * 19 | * @param model The ToDoModel which will store the data for the ToDoList 20 | * and its tasks. 21 | */ 22 | public ToDoController(ToDoModel model) { 23 | this.model = model; 24 | } 25 | 26 | /** 27 | * Loads the current List into view. 28 | * 29 | * Must be used after the controller was created in order to load 30 | * the data into the view correctly. 31 | */ 32 | public void loadView() { 33 | model.loadView(); 34 | } 35 | 36 | /** 37 | * Changes the list color to the given one. 38 | * 39 | * @param color The new list color. 40 | */ 41 | public void changeColor(String color) { 42 | model.changeColor(color); 43 | } 44 | 45 | /** 46 | * Creates a new list and switches to it. 47 | * 48 | * Note: addObserver method must be used after this method in order for the 49 | * view to become an Observer of the newly created list. 50 | * 51 | * @param name The name of the new list. 52 | */ 53 | public void addList(String name) { 54 | model.addList(name); 55 | } 56 | 57 | /** 58 | * Renames the current list to the given name. 59 | * 60 | * @param name The given name. 61 | */ 62 | public void renameList(String name) { 63 | model.renameList(name); 64 | } 65 | 66 | /** 67 | * Deletes the current list. 68 | * 69 | * In this program it is not possible to delete the current list 70 | * if the current list is the only list. Boolean is used so view 71 | * can recognize a failed delete due to there only being one list. 72 | * 73 | * @return True if the list was successfully deleted. False if the 74 | * list was not able to be deleted because the current list 75 | * is the only list. 76 | */ 77 | public boolean deleteList() { 78 | if (!model.moreThanOneList()) { 79 | return false; // Case where current list should not be deleted. 80 | } 81 | model.deleteList(); 82 | 83 | return true; 84 | } 85 | 86 | /** 87 | * Iterates to the next list. 88 | */ 89 | public void nextList() { 90 | model.nextList(); 91 | } 92 | 93 | /** 94 | * Iterates to the previous list. 95 | */ 96 | public void prevList() { 97 | model.prevList(); 98 | } 99 | 100 | /** 101 | * Adds a new task to the current viewable list. 102 | * 103 | * @param name The name of the task. 104 | * @param description The notes/description about the task. 105 | * @param deadline The deadline for the task. (Should be (m/d/yr)) 106 | * @param importance Indicates whether the task is important or not. 107 | */ 108 | public void addTask(String name, String description, String deadline, 109 | String importance,String location) { 110 | // TODO: Must have a way to check that deadline is a valid date 111 | // and that Importance is valid. Currently both are not really 112 | // implemented. 113 | if(name.equals("")) { 114 | name = "unnamed task"; 115 | } 116 | if(deadline.equals("mm/dd/year")) { 117 | deadline = ""; 118 | } 119 | else if(!deadline.equals("") && deadline.split("/").length!=3) { 120 | Alert error = new Alert(Alert.AlertType.INFORMATION); 121 | error.setTitle("ERROR"); 122 | error.setHeaderText("Invalid Date Entered"); 123 | error.setContentText("Use Format 'mm/dd/year'."); 124 | error.showAndWait(); 125 | return; 126 | } 127 | if(location.equals("Name/Address")) { 128 | location = ""; 129 | } 130 | model.addTask(name, description, deadline, importance,location); 131 | } 132 | 133 | /** 134 | * Removes the given task from the current viewable list. 135 | * 136 | * @param index The ToDoTask to be removed. 137 | */ 138 | public void removeTask(int index) { 139 | model.removeTask(index); 140 | } 141 | 142 | public void changeImportance(String important, int curr) { 143 | model.changeImportance(important, curr); 144 | } 145 | 146 | public void changeCompletion(boolean complete, int curr) { 147 | model.changeCompletion(complete, curr); 148 | } 149 | 150 | /** 151 | * Adds the view as an observer to the current list. 152 | * 153 | * Must be called whenever a new list is being added in order for 154 | * the GUI to be able to correctly display the new list. 155 | * 156 | * @param view The GUI view that will be the observer. 157 | */ 158 | public void addObserver(Observer view) { 159 | model.addObserver(view); 160 | } 161 | 162 | /** 163 | * Saves the ToDoModel which houses all of the data about the ToDoLists. 164 | * 165 | * @throws IOException Means that the file was not able to be written to. 166 | */ 167 | public void saveLists() throws IOException { 168 | model.saveLists(); 169 | } 170 | 171 | public void sort(String sortBy){ 172 | model.sort(sortBy); 173 | } 174 | 175 | public void hideCompletedTask(){ 176 | model.hideCompletedTask(); 177 | } 178 | 179 | public void showCompletedTask(){ 180 | model.showCompletedTask(); 181 | } 182 | 183 | public void moveUp(int pos){ 184 | model.moveUp(pos); 185 | } 186 | 187 | public void moveTop(int pos){ 188 | model.moveTop(pos); 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /src/model/ToDoModel.java: -------------------------------------------------------------------------------- 1 | package model; 2 | 3 | import java.io.FileOutputStream; 4 | import java.io.IOException; 5 | import java.io.ObjectOutputStream; 6 | import java.io.Serializable; 7 | import java.util.ArrayList; 8 | import java.util.Observer; 9 | 10 | public class ToDoModel implements Serializable { 11 | private static final long serialVersionUID = 1L; 12 | // Can change way to hold lists. 13 | private ArrayList lists; 14 | private int curList; 15 | private transient Observer observer; 16 | 17 | /** 18 | * Creates a List of ToDoLists that has only one ToDoList with no Tasks. 19 | */ 20 | public ToDoModel() { 21 | this.lists = new ArrayList(); 22 | this.lists.add(new ToDoList()); 23 | curList = 0; 24 | observer = null; 25 | } 26 | 27 | /** 28 | * Changes the currentList color to the specified color. 29 | * 30 | * @param color The color the list is changing to. 31 | */ 32 | public void changeColor(String color) { 33 | lists.get(curList).setColor(color); 34 | loadView(); 35 | } 36 | 37 | /** 38 | * Adds a new empty list to the list of lists. 39 | * 40 | * The view will be automatically added to this new list provided 41 | * that the addObserver method was used at least once before the calling 42 | * of this method. 43 | * 44 | * @param name The name of the new ToDoList. 45 | */ 46 | public void addList(String name) { 47 | lists.add(new ToDoList(name)); 48 | curList = lists.size()-1; 49 | lists.get(curList).addObserver(observer); 50 | loadView(); 51 | } 52 | 53 | /** 54 | * Deletes the current list. 55 | * 56 | * This method does not check to make sure that there is more than 1 list 57 | * to be deleted. That is the responsibility of whatever called this to 58 | * check to ensure that it is fine to delete. 59 | */ 60 | public void deleteList() { 61 | int toBeRemoved = curList; 62 | // Switches to the next list because the current one is about to be 63 | // removed. 64 | nextList(); 65 | lists.remove(toBeRemoved); 66 | } 67 | 68 | /** 69 | * Iterates to the next list. Will loop back to the start if there is no 70 | * next list. 71 | */ 72 | public void nextList() { 73 | if (curList + 1 >= lists.size()) { 74 | // Case where list should loop back to beginning 75 | curList = 0; 76 | } else { 77 | curList++; 78 | } 79 | loadView(); 80 | } 81 | 82 | /** 83 | * Iterates to the previous list. Will loop to the end of the lists if this 84 | * function is called when the curList is the first list. 85 | */ 86 | public void prevList() { 87 | if (curList - 1 < 0) { 88 | // Case where list should loop to the end 89 | curList = lists.size()-1; 90 | } else { 91 | curList--; 92 | } 93 | loadView(); 94 | } 95 | 96 | /** 97 | * @return True if the model holds more than one list currently. 98 | */ 99 | public boolean moreThanOneList() { 100 | return lists.size() > 1; 101 | } 102 | 103 | /** 104 | * Renames the current list to the given name and then notifies 105 | * the view that the list has been renamed. 106 | * 107 | * @param name The new name of the list. 108 | */ 109 | public void renameList(String name) { 110 | lists.get(curList).renameList(name); 111 | loadView(); 112 | } 113 | 114 | /** 115 | * Adds a new task with the given parameters. 116 | * 117 | * @param name The name of the task. 118 | * @param description The description/notes about the task. 119 | * @param deadline The deadline for the task. 120 | * @param importance Indication of whether the task is important or not. 121 | * @param location The location of the task. 122 | */ 123 | public void addTask(String name, String description, String deadline, 124 | String importance,String location) { 125 | if(lists.size() > 0) { 126 | lists.get(curList).addTask(name, description, deadline, importance,location); 127 | // Sorts the newly added list. 128 | sort(lists.get(curList).getCurrentSorting()); 129 | } else { 130 | System.out.println("THERE IS NO LIST TO ADD TO"); 131 | } 132 | } 133 | 134 | /** 135 | * Removes the task at the given index. 136 | * 137 | * @param index The task's index. 138 | */ 139 | public void removeTask(int index) { 140 | this.lists.get(curList).removeTask(index); 141 | loadView(); 142 | } 143 | 144 | 145 | 146 | /** 147 | * Adds an Observer to all of the lists held in the model. 148 | * 149 | * Will also store the Observer so that this model can add this 150 | * Observer to any newly created lists. 151 | * 152 | * @param view The Observer. 153 | */ 154 | @SuppressWarnings("deprecation") 155 | public void addObserver(Observer view) { 156 | observer = view; 157 | 158 | for (int i = 0; i < lists.size(); i++) { 159 | lists.get(i).addObserver(observer); 160 | } 161 | } 162 | 163 | 164 | /** 165 | * Saves this controller which houses all the lists for the ToDo lists 166 | * in the file save.dat 167 | * 168 | * @throws IOException Means that the file was not able to be written to. 169 | */ 170 | public void saveLists() throws IOException { 171 | FileOutputStream file = new FileOutputStream("save.dat"); 172 | ObjectOutputStream oos = new ObjectOutputStream(file); 173 | oos.writeObject(this); 174 | oos.close(); 175 | } 176 | 177 | /** 178 | * Loads the current List. 179 | */ 180 | public void loadView() { 181 | lists.get(curList).loadView(); 182 | } 183 | 184 | /** 185 | * Changes the task at the position curr's completion status. 186 | * 187 | * @param importance The new task importance status. 188 | * @param curr The index of the task to have their importance status 189 | * changed. 190 | */ 191 | public void changeImportance(String importance, int curr) { 192 | lists.get(curList).getTask(curr).setImportance(importance); 193 | if (lists.get(curList).getCurrentSorting().equals("Importance")) { 194 | // Must sort the new Important task. 195 | sort("Importance"); 196 | } else { 197 | loadView(); 198 | } 199 | } 200 | 201 | /** 202 | * Changes the task at the position curr's completion status. 203 | * 204 | * @param complete The new task completion status. 205 | * @param curr The index of the task to have their completion status 206 | * changed. 207 | */ 208 | public void changeCompletion(boolean complete, int curr) { 209 | lists.get(curList).getTask(curr).setCompletion(complete); 210 | if (lists.get(curList).getHideComplete()) { 211 | // Means this task must be now hidden. 212 | hideCompletedTask(); 213 | } else { 214 | loadView(); 215 | } 216 | } 217 | 218 | /** 219 | * Sorts the current list by the given sorting. 220 | * 221 | * Possible ways that the list can be sorted by: 222 | * Name, Deadline, Importance, Create Time, Custom 223 | * 224 | * @param sortBy The given sorting as String. 225 | */ 226 | public void sort(String sortBy){ 227 | switch (sortBy) { 228 | case "Name": 229 | lists.get(curList).sortByName(); 230 | break; 231 | case "Deadline": 232 | lists.get(curList).sortByDeadline(); 233 | break; 234 | case "Importance": 235 | lists.get(curList).sortByImportance(); 236 | break; 237 | case "Create time": 238 | lists.get(curList).sortByCreateTime(); 239 | break; 240 | case "Custom": 241 | // Does not sort as it indicates it is sorting by 242 | // Move up and move down. 243 | break; 244 | } 245 | loadView(); 246 | } 247 | 248 | public void hideCompletedTask(){ 249 | lists.get(curList).hideCompleted(); 250 | loadView(); 251 | } 252 | 253 | public void showCompletedTask(){ 254 | lists.get(curList).showCompleted(); 255 | // Must resort the current list with the newly shown tasks. 256 | sort(lists.get(curList).getCurrentSorting()); 257 | } 258 | 259 | public void moveUp(int pos){ 260 | lists.get(curList).moveUp(pos); 261 | loadView(); 262 | } 263 | 264 | public void moveTop(int pos){ 265 | lists.get(curList).moveTop(pos); 266 | loadView(); 267 | } 268 | } 269 | -------------------------------------------------------------------------------- /src/model/ToDoList.java: -------------------------------------------------------------------------------- 1 | package model; 2 | 3 | import java.io.Serializable; 4 | import java.text.ParsePosition; 5 | import java.text.SimpleDateFormat; 6 | import java.util.ArrayList; 7 | import java.util.Collections; 8 | import java.util.Date; 9 | import java.util.Observable; 10 | 11 | @SuppressWarnings("deprecation") 12 | public class ToDoList extends Observable implements Serializable { 13 | /** 14 | * 15 | */ 16 | private static final long serialVersionUID = 1L; 17 | private ArrayList tasks; 18 | private ArrayList completedTasks; 19 | private String name; 20 | private String color; 21 | private String currentSorting; 22 | private boolean hideComplete; 23 | 24 | /** 25 | * Creates a ToDoList with the name List 1 and the color gray. 26 | */ 27 | public ToDoList() { 28 | this.tasks = new ArrayList(); 29 | this.name = "List 1"; 30 | this.color = "beige"; 31 | this.currentSorting = "Custom"; 32 | this.hideComplete = false; 33 | } 34 | 35 | /** 36 | * Creates a ToDoList with the given name. List is automatically colored 37 | * biege. 38 | * 39 | * If given name is empty then the list will be automatically 40 | * named unamed list. 41 | * 42 | * @param name The name of the list. 43 | */ 44 | public ToDoList(String name) { 45 | this.tasks = new ArrayList(); 46 | if (name.equals("")) { 47 | this.name = "unamed list"; 48 | } else { 49 | this.name = name; 50 | } 51 | this.color = "beige"; 52 | this.currentSorting = "Custom"; 53 | this.hideComplete = false; 54 | } 55 | 56 | /** 57 | * @return The color of the list. 58 | */ 59 | public String getColor() { 60 | return color; 61 | } 62 | 63 | /** 64 | * Changes the list's color to the given one. 65 | * 66 | * @param color The new color. 67 | */ 68 | public void setColor(String color) { 69 | this.color = color; 70 | } 71 | 72 | /** 73 | * Renames the list to a new name and notifies the Observers 74 | * that the list has been renamed. 75 | * 76 | * @param name The new name for the ToDoList. 77 | */ 78 | public void renameList(String name) { 79 | this.name = name; 80 | } 81 | 82 | /** 83 | * @return The name of the list. 84 | */ 85 | public String getNameList() { 86 | return name; 87 | } 88 | 89 | public void addTask(String taskName, String description, String deadline, String importance,String location) { 90 | if (taskName != null) { 91 | ToDoTask newTask = new ToDoTask(taskName,description,deadline,importance,location); 92 | this.tasks.add(newTask); 93 | } 94 | } 95 | 96 | public void removeTask(int index) { 97 | boolean taskSeen = this.tasks.remove(index) != null; 98 | if (!taskSeen) { 99 | System.out.println("***Task entered is not in the To-Do List"); // for debugging 100 | } 101 | } 102 | 103 | /** 104 | * @return The amount of tasks in the ToDoList. 105 | */ 106 | public int amountTasks() { 107 | return tasks.size(); 108 | } 109 | 110 | /** 111 | * Gets the ToDoTask at the specified index. 112 | * 113 | * Assumes that index given is a valid index. Can make sure it is 114 | * a valid index if the index is smaller than the int returned 115 | * by the amountTasks method. 116 | * 117 | * @param index The index of the task. 118 | * @return The ToDoTask at the specified index. 119 | */ 120 | public ToDoTask getTask(int index) { 121 | return tasks.get(index); 122 | } 123 | 124 | /** 125 | * Notifys all observers by passing this List to it. 126 | */ 127 | public void loadView() { 128 | setChanged(); 129 | notifyObservers(this); 130 | } 131 | 132 | 133 | 134 | /** 135 | * taskList sort by deadline 136 | */ 137 | public void sortByDeadline(){ 138 | SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy"); 139 | Date d1; 140 | Date d2; 141 | String timeStr1; 142 | String timeStr2; 143 | ToDoTask temp; 144 | currentSorting = "Deadline"; 145 | 146 | for(int i=0; i important = new ArrayList<>(); 171 | ArrayList unimportant = new ArrayList<>(); 172 | 173 | sortByName(); 174 | // Must be placed after or else currentSorting will be set to Name 175 | currentSorting = "Importance"; 176 | 177 | for (ToDoTask task : tasks){ 178 | if (task.getImportance().contains("Important!!!")){ 179 | important.add(task); 180 | }else { 181 | unimportant.add(task); 182 | } 183 | } 184 | 185 | tasks.clear(); 186 | tasks.addAll(important); 187 | tasks.addAll(unimportant); 188 | } 189 | 190 | /** 191 | * taskList sort by name 192 | */ 193 | public void sortByName(){ 194 | currentSorting = "Name"; 195 | Collections.sort(tasks,new TaskNameCompare()); 196 | } 197 | 198 | /** 199 | * taskList sort by create time 200 | */ 201 | public void sortByCreateTime(){ 202 | currentSorting = "Create time"; 203 | Date d1,d2; 204 | ToDoTask temp; 205 | for(int i=0; i(); 228 | } 229 | for (ToDoTask task : tasks){ 230 | if (task.getCompletion()){ 231 | completedTasks.add(task); 232 | } 233 | } 234 | tasks.removeAll(completedTasks); 235 | 236 | } 237 | 238 | /** 239 | * show completed task 240 | */ 241 | public void showCompleted(){ 242 | hideComplete = true; 243 | tasks.addAll(completedTasks); 244 | completedTasks.clear(); 245 | } 246 | 247 | /** 248 | * Move the task up 249 | * 250 | * @param pos The index position of the Task to be moved up. 251 | */ 252 | public void moveUp(int pos){ 253 | currentSorting = "Custom"; 254 | ToDoTask temp; 255 | if (pos!=0){ 256 | temp = tasks.get(pos); 257 | tasks.set(pos, tasks.get(pos-1)); 258 | tasks.set(pos-1, temp); 259 | } 260 | 261 | } 262 | 263 | /** 264 | * Move the task to top 265 | * 266 | * @param pos The index position of the Task to be moved to the top. 267 | */ 268 | public void moveTop(int pos){ 269 | currentSorting = "Custom"; 270 | ToDoTask temp; 271 | if (pos!=0){ 272 | temp = tasks.get(pos); 273 | tasks.remove(pos); 274 | tasks.add(0, temp); 275 | } 276 | 277 | } 278 | 279 | /** 280 | * Returns how the list is currently sorted. 281 | * 282 | * Possible sortings are Name, Deadline, Importance, Create time, Custom 283 | * 284 | * @return The way the list is being sorted currently. 285 | */ 286 | public String getCurrentSorting() { 287 | return currentSorting; 288 | } 289 | 290 | /** 291 | * @return True if the completed tasks are currently being hidden. 292 | * False otherwise. 293 | */ 294 | public boolean getHideComplete() { 295 | return hideComplete; 296 | } 297 | } 298 | -------------------------------------------------------------------------------- /src/view/ToDoView.java: -------------------------------------------------------------------------------- 1 | package view; 2 | 3 | import java.io.FileInputStream; 4 | import java.io.FileNotFoundException; 5 | import java.io.IOException; 6 | import java.io.ObjectInputStream; 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | import java.util.Observable; 10 | import java.util.Observer; 11 | 12 | import controller.ToDoController; 13 | import javafx.beans.value.ChangeListener; 14 | import javafx.beans.value.ObservableValue; 15 | import javafx.scene.control.*; 16 | import model.ToDoList; 17 | import javafx.application.Application; 18 | import javafx.collections.FXCollections; 19 | import javafx.collections.ObservableList; 20 | import javafx.event.ActionEvent; 21 | import javafx.event.Event; 22 | import javafx.event.EventHandler; 23 | import javafx.geometry.Insets; 24 | import javafx.scene.Node; 25 | import javafx.scene.Scene; 26 | import javafx.scene.input.MouseEvent; 27 | import javafx.scene.layout.BorderPane; 28 | import javafx.scene.layout.ColumnConstraints; 29 | import javafx.scene.layout.GridPane; 30 | import javafx.scene.layout.HBox; 31 | import javafx.scene.layout.Pane; 32 | import javafx.scene.layout.Priority; 33 | import javafx.scene.layout.RowConstraints; 34 | import javafx.scene.layout.VBox; 35 | import javafx.stage.Stage; 36 | import javafx.stage.WindowEvent; 37 | import model.ToDoList; 38 | import model.ToDoModel; 39 | import model.ToDoTask; 40 | 41 | import javax.swing.*; 42 | import javax.swing.SingleSelectionModel; 43 | 44 | public class ToDoView extends Application implements Observer { 45 | private ToDoView view; 46 | private ToDoController control; 47 | private BorderPane window; 48 | private VBox taskSection; 49 | private Label listName; 50 | private ChoiceBox changeColor; 51 | private ComboBox sort; 52 | private CheckBox ck; 53 | private int id; 54 | private boolean startup; 55 | private boolean handle; 56 | 57 | public void start(Stage stage) { 58 | // Sets view to this view. This is what is passed to addObserver 59 | view = this; 60 | // Sets startup to true this indicates that a new list is being loaded in. 61 | startup = true; 62 | // Sets handle to false, so later on when first choice is set up by 63 | // computer it doesn't actually do what the button is supposed to. 64 | // Important to prevent errors. 65 | handle = false; 66 | stage.setTitle("ToDo"); 67 | window = new BorderPane(); 68 | // If anyone else wants a different window size mention it. 69 | Scene scene = new Scene(window, 800, 600); // 800 px wide, 600 px tall 70 | 71 | // VBox will be used to showoff all the tasks to the user 72 | taskSection = new VBox(10); // 10 px spacing between rows 73 | taskSection.setPadding(new Insets(10)); // 10px padding around VBox 74 | window.setCenter(taskSection); 75 | 76 | // Creates the model to be used by the controller. 77 | ToDoModel modelToBeSent = null; 78 | try { 79 | // Case where there is/are existing ToDoLists saved. 80 | FileInputStream file = new FileInputStream("save.dat"); 81 | ObjectInputStream ois = new ObjectInputStream(file); 82 | modelToBeSent = (ToDoModel) ois.readObject(); 83 | ois.close(); 84 | file.close(); 85 | } catch (FileNotFoundException e) { 86 | // Case where there is no existing ToDoLists saved. 87 | modelToBeSent = new ToDoModel(); 88 | } catch (IOException e) { 89 | // TODO Auto-generated catch block 90 | System.out.println("I/O error while reading ObjectInputStream"); 91 | } catch (ClassNotFoundException e) { 92 | System.out.println("Serialization class could not be found!"); 93 | } 94 | control = new ToDoController(modelToBeSent); 95 | control.addObserver(view); 96 | 97 | // topPanel holds all the buttons on top. 98 | HBox topPanel = new HBox(5); 99 | topPanel.setPadding(new Insets(5)); 100 | window.setTop(topPanel); 101 | 102 | // Buttons to be used to add tasks 103 | Button addTask = new Button("Add Task"); 104 | // Event handler when button is clicked. 105 | EventHandler taskHandler = new NewTaskHandler(); 106 | addTask.setOnAction(taskHandler); 107 | 108 | // ComboBox to choose sort criteria 109 | Label sortTip = new Label("Sort by: "); 110 | sort = new ComboBox<>(); 111 | sort.getItems().addAll("Name","Deadline","Importance","Create time","Custom"); 112 | sort.setEditable(false); 113 | sort.setVisibleRowCount(5); 114 | sort.getSelectionModel().selectedItemProperty().addListener(new ChangeListener() { 115 | @Override 116 | public void changed(ObservableValue observable, 117 | String oldValue, String newValue) { 118 | if (handle) 119 | control.sort(newValue); 120 | } 121 | }); 122 | 123 | //completed task 124 | ck = new CheckBox("Hide Completed Task"); 125 | ck.setSelected(false); 126 | ck.selectedProperty().addListener(new ChangeListener() { 127 | @Override 128 | public void changed(ObservableValue arg0, Boolean arg1, Boolean arg2) { 129 | if (handle) { 130 | if (ck.isSelected()){ 131 | control.hideCompletedTask(); 132 | } else { 133 | control.showCompletedTask(); 134 | } 135 | } 136 | } 137 | }); 138 | 139 | topPanel.getChildren().addAll(sortTip, sort, ck, addTask); 140 | 141 | 142 | // Sets up the bottom of the window which controls the current list 143 | // and allows user to create new lists or delete the current list. 144 | GridPane listSection = new GridPane(); 145 | listSection.setPadding(new Insets(10)); 146 | for (int i = 0; i < 3; i++) { 147 | RowConstraints row = new RowConstraints(); 148 | row.setPercentHeight(50); 149 | ColumnConstraints col = new ColumnConstraints(); 150 | col.setPercentWidth(33); 151 | listSection.getRowConstraints().add(row); 152 | listSection.getColumnConstraints().add(col); 153 | } 154 | // Adds the next and previous list buttons. 155 | Button nextButton = new Button("Next List"); 156 | nextButton.setOnAction(new EventHandler() { 157 | @Override 158 | public void handle(ActionEvent arg0) { 159 | startup = true; 160 | control.nextList(); 161 | } 162 | }); 163 | Button prevButton = new Button("Prev List"); 164 | prevButton.setOnAction(new EventHandler() { 165 | @Override 166 | public void handle(ActionEvent arg0) { 167 | startup = true; 168 | control.prevList(); 169 | } 170 | }); 171 | listSection.add(prevButton, 0, 0); 172 | listSection.add(nextButton, 2, 0); 173 | // Adds listName label which is where the name of the list will be. 174 | listName = new Label("List 1"); 175 | listSection.add(listName, 1, 0); 176 | // Adds the Add List Button 177 | Button addList = new Button("Add List"); 178 | EventHandler listAddHandler = new NewListHandler(); 179 | addList.setOnAction(listAddHandler); 180 | listSection.add(addList, 0, 1); 181 | // Adds the Rename List Button 182 | Button renameList = new Button("Rename List"); 183 | EventHandler listRenameHandler = new RenameListHandler(); 184 | renameList.setOnAction(listRenameHandler); 185 | listSection.add(renameList, 1, 1); 186 | // Adds the Delete List Button 187 | Button deleteList = new Button("Delete Current List"); 188 | EventHandler listDeleteHandler = new DeleteListHandler(); 189 | deleteList.setOnAction(listDeleteHandler); 190 | listSection.add(deleteList, 2, 1); 191 | // Adds the change color button 192 | changeColor = new ChoiceBox(); 193 | changeColor.getItems().add("List Color: Beige"); 194 | changeColor.getItems().add("List Color: Blue"); 195 | changeColor.getItems().add("List Color: Gray"); 196 | changeColor.getItems().add("List Color: Orange"); 197 | changeColor.getItems().add("List Color: Pink"); 198 | changeColor.getItems().add("List Color: Red"); 199 | changeColor.getItems().add("List Color: Tan"); 200 | changeColor.setOnAction(new EventHandler() { 201 | @Override 202 | public void handle(ActionEvent arg0) { 203 | if (handle) { 204 | String[] color = ((String) changeColor.getValue()).split(" "); 205 | control.changeColor(color[2].toLowerCase()); 206 | } 207 | } 208 | }); 209 | listSection.add(changeColor, 1, 2); 210 | // Makes it so the list switch/add/remove/rename stuff is at bottom of 211 | // window. 212 | window.setBottom(listSection); 213 | 214 | 215 | // Code to save all the lists when the window is closed. 216 | stage.setOnCloseRequest(new EventHandler() { 217 | @Override 218 | public void handle(WindowEvent arg0) { 219 | try { 220 | control.saveLists(); 221 | } catch (IOException e) { 222 | System.out.println("Error: Could not save Lists!"); 223 | } 224 | } 225 | }); 226 | 227 | stage.setScene(scene); 228 | stage.show(); 229 | 230 | control.loadView(); 231 | startup = false; 232 | } 233 | 234 | /** 235 | * Class deals with adding new lists when the Add List button is clicked. 236 | * 237 | * @author Henry Do 238 | * 239 | */ 240 | private class NewListHandler implements EventHandler{ 241 | 242 | @Override 243 | public void handle(ActionEvent arg0) { 244 | // Opens a new window for the user to implement info about 245 | // a new task for. 246 | GridPane window2 = new GridPane(); 247 | // Sets up 2nd window, so that there is are for new list name 248 | // input. 249 | for (int i = 0; i < 2; i++) { 250 | RowConstraints row = new RowConstraints(); 251 | row.setPercentHeight(50); 252 | window2.getRowConstraints().add(row); 253 | ColumnConstraints col = new ColumnConstraints(); 254 | col.setPercentWidth(50); 255 | window2.getColumnConstraints().add(col); 256 | } 257 | 258 | // Sets up area for user to input name of New List 259 | Label name = new Label("Name: "); 260 | TextField nameInput = new TextField(); 261 | window2.add(name, 0, 0); 262 | window2.add(nameInput, 1, 0); 263 | 264 | // Sets up button to close the window and create the new task 265 | Button enter = new Button("Create New List"); 266 | window2.add(enter, 1, 1); 267 | 268 | Scene scene2 = new Scene(window2, 250, 100); 269 | 270 | Stage stage2 = new Stage(); 271 | stage2.setTitle("New List"); 272 | stage2.setScene(scene2); 273 | 274 | // Implementation of New List button 275 | enter.setOnAction(new EventHandler() { 276 | 277 | @Override 278 | public void handle(ActionEvent arg0) { 279 | String curName = nameInput.getText(); 280 | control.addList(curName); 281 | stage2.close(); 282 | } 283 | }); 284 | stage2.showAndWait(); 285 | } 286 | 287 | } 288 | 289 | /** 290 | * Class deals with renaming lists when the Rename List button is clicked. 291 | * 292 | * @author Henry Do 293 | * 294 | */ 295 | private class RenameListHandler implements EventHandler{ 296 | 297 | @Override 298 | public void handle(ActionEvent arg0) { 299 | // Opens a new window for the user to implement info about 300 | // a new task for. 301 | GridPane window2 = new GridPane(); 302 | // Sets up 2nd window, so that there is are for new list name 303 | // input. 304 | for (int i = 0; i < 2; i++) { 305 | RowConstraints row = new RowConstraints(); 306 | row.setPercentHeight(50); 307 | window2.getRowConstraints().add(row); 308 | ColumnConstraints col = new ColumnConstraints(); 309 | col.setPercentWidth(50); 310 | window2.getColumnConstraints().add(col); 311 | } 312 | 313 | // Sets up area for user to input name of New List 314 | Label name = new Label("Name: "); 315 | TextField nameInput = new TextField(); 316 | window2.add(name, 0, 0); 317 | window2.add(nameInput, 1, 0); 318 | 319 | // Sets up button to close the window and create the new task 320 | Button enter = new Button("Rename the List"); 321 | window2.add(enter, 1, 1); 322 | 323 | Scene scene2 = new Scene(window2, 250, 100); 324 | 325 | Stage stage2 = new Stage(); 326 | stage2.setTitle("Rename List"); 327 | stage2.setScene(scene2); 328 | 329 | // Implementation of New List button 330 | enter.setOnAction(new EventHandler() { 331 | 332 | @Override 333 | public void handle(ActionEvent arg0) { 334 | String curName = nameInput.getText(); 335 | control.renameList(curName); 336 | stage2.close(); 337 | } 338 | }); 339 | stage2.showAndWait(); 340 | } 341 | 342 | } 343 | 344 | /** 345 | * Class deals with deleting lists when the Delete Current List 346 | * button is clicked. 347 | * 348 | * @author Henry Do 349 | * 350 | */ 351 | private class DeleteListHandler implements EventHandler{ 352 | 353 | @Override 354 | public void handle(ActionEvent arg0) { 355 | boolean valid = control.deleteList(); 356 | if (!valid) { 357 | Alert error = new Alert(Alert.AlertType.INFORMATION); 358 | error.setContentText("Can't Delete Current List Because it is" 359 | + " the Only List!"); 360 | error.showAndWait(); 361 | } 362 | } 363 | 364 | } 365 | 366 | /** 367 | * Class deals with adding new tasks to the list when the Add Task button is 368 | * clicked. 369 | * 370 | * @author Henry Do 371 | * 372 | */ 373 | private class NewTaskHandler implements EventHandler { 374 | 375 | @Override 376 | public void handle(ActionEvent arg0) { 377 | // Opens a new window for the user to implement info about 378 | // a new task for. 379 | GridPane window2 = new GridPane(); 380 | // Sets up 2nd window, so that there is enough space for labels 381 | // and textfield 382 | for (int i = 0; i <= 5; i++) { 383 | RowConstraints row = new RowConstraints(); 384 | row.setPercentHeight(25); 385 | window2.getRowConstraints().add(row); 386 | } 387 | ColumnConstraints col1 = new ColumnConstraints(); 388 | col1.setPercentWidth(50); 389 | window2.getColumnConstraints().add(col1); 390 | ColumnConstraints col2 = new ColumnConstraints(); 391 | col2.setPercentWidth(50); 392 | window2.getColumnConstraints().add(col2); 393 | 394 | // Sets up area for user to input name of New Task 395 | Label name = new Label("Name: "); 396 | TextField nameInput = new TextField(); 397 | window2.add(name, 0, 0); 398 | window2.add(nameInput, 1, 0); 399 | 400 | // Sets up area for user to input description of New Task 401 | Label description = new Label("Description: "); 402 | TextField descriptionInput = new TextField(); 403 | window2.add(description, 0, 1); 404 | window2.add(descriptionInput, 1, 1); 405 | 406 | // Sets up area for user to input deadline date of New Task 407 | Label deadline = new Label("Deadline: "); 408 | TextField deadlineInput = new TextField("mm/dd/year"); 409 | window2.add(deadline, 0, 2); 410 | window2.add(deadlineInput, 1, 2); 411 | 412 | // Sets up area for user to input importance 413 | // Maybe make this a button or just don't have the user able 414 | // to set importance here. Have them set it in main window? 415 | Label importance = new Label("Important: "); 416 | TextField importanceInput = new TextField("yes/no"); 417 | CheckBox importanceBox=new CheckBox("Important"); 418 | window2.add(importanceBox, 0, 3); 419 | importanceBox.setSelected(false); 420 | 421 | //window2.add(importanceInput, 1, 3); LEFTOVER FROM STRING IMPLEMENTATION 422 | 423 | //sets up area for user to input the location for the new task 424 | Label location = new Label("Location: "); 425 | TextField locationInput = new TextField("Name/Address"); 426 | window2.add(location, 0, 4); 427 | window2.add(locationInput, 1, 4); 428 | 429 | // Sets up button to close the window and create the new task 430 | Button enter = new Button("Create New Task"); 431 | window2.add(enter, 1, 5); 432 | 433 | Scene scene2 = new Scene(window2, 500, 300); 434 | 435 | Stage stage2 = new Stage(); 436 | stage2.setTitle("New Task"); 437 | stage2.setScene(scene2); 438 | 439 | // Implementation of New Task button 440 | enter.setOnAction(new EventHandler() { 441 | 442 | @Override 443 | public void handle(ActionEvent arg0) { 444 | String curName = nameInput.getText(); 445 | String curDescription = descriptionInput.getText(); 446 | String curDeadline = deadlineInput.getText(); 447 | String curImportant; 448 | if(importanceBox.isSelected()) { 449 | curImportant="Important!!!"; 450 | } 451 | else { 452 | curImportant=""; 453 | } 454 | String curLocation = locationInput.getText(); 455 | control.addTask(curName, curDescription, curDeadline, curImportant,curLocation); 456 | 457 | stage2.close(); 458 | } 459 | 460 | }); 461 | 462 | stage2.showAndWait(); 463 | } 464 | 465 | } 466 | private class importanceHandler implements EventHandler { 467 | 468 | @Override 469 | public void handle(ActionEvent arg0) { 470 | String currID = ((CheckBox) arg0.getSource()).getId(); 471 | int curr = Integer.parseInt(currID); 472 | if (((CheckBox) arg0.getSource()).isSelected()) { 473 | control.changeImportance("Important!!!", curr); 474 | } 475 | else { 476 | control.changeImportance("", curr); 477 | } 478 | } 479 | } 480 | private class completionHandler implements EventHandler { 481 | 482 | @Override 483 | public void handle(ActionEvent arg0) { 484 | String currID = ((CheckBox) arg0.getSource()).getId(); 485 | int curr = Integer.parseInt(currID); 486 | if (((CheckBox) arg0.getSource()).isSelected()) { 487 | control.changeCompletion(true, curr); 488 | } 489 | else { 490 | control.changeCompletion(false, curr); 491 | } 492 | } 493 | } 494 | 495 | private void checkboxHelper(String important, boolean complete, CheckBox c1, CheckBox c2) { 496 | if (complete) { 497 | c1.setSelected(true); 498 | } 499 | if (important != "") { 500 | c2.setSelected(true); 501 | } 502 | 503 | return; 504 | } 505 | 506 | /** 507 | * Updates the view with the passed Object. 508 | * 509 | */ 510 | @Override 511 | public void update(Observable o, Object newList) { 512 | ObservableList rows = FXCollections.observableArrayList(); 513 | taskSection.getChildren().clear(); 514 | id = 0; 515 | 516 | // Ensures that on startUp the button being selected doesn't do anything. 517 | handle = false; 518 | // Sets the color of the list. 519 | switch (((ToDoList) newList).getColor()) { 520 | case "blue": 521 | taskSection.setStyle("-fx-background-color: lightblue;"); 522 | if (startup) 523 | changeColor.getSelectionModel().select(1); 524 | break; 525 | case "gray": 526 | taskSection.setStyle("-fx-background-color: slategrey;"); 527 | if (startup) 528 | changeColor.getSelectionModel().select(2); 529 | break; 530 | case "orange": 531 | taskSection.setStyle("-fx-background-color: orange;"); 532 | if (startup) 533 | changeColor.getSelectionModel().select(3); 534 | break; 535 | case "pink": 536 | taskSection.setStyle("-fx-background-color: pink;"); 537 | if (startup) 538 | changeColor.getSelectionModel().select(4); 539 | break; 540 | case "red": 541 | taskSection.setStyle("-fx-background-color: crimson;"); 542 | if (startup) 543 | changeColor.getSelectionModel().select(5); 544 | break; 545 | case "tan": 546 | taskSection.setStyle("-fx-background-color: tan;"); 547 | if (startup) 548 | changeColor.getSelectionModel().select(6); 549 | break; 550 | default: 551 | // By default list is colored beige. 552 | taskSection.setStyle("-fx-background-color: beige;"); 553 | if (startup) 554 | changeColor.getSelectionModel().select(0); 555 | break; 556 | } 557 | // Sets the sorting method choice. 558 | switch (((ToDoList) newList).getCurrentSorting()) { 559 | case "Name": 560 | if (startup) 561 | sort.getSelectionModel().select(0); 562 | break; 563 | case "Deadline": 564 | if (startup) 565 | sort.getSelectionModel().select(1); 566 | break; 567 | case "Importance": 568 | if (startup) 569 | sort.getSelectionModel().select(2); 570 | break; 571 | case "Create time": 572 | if (startup) 573 | sort.getSelectionModel().select(3); 574 | break; 575 | default: 576 | // Default sort is Custom 577 | sort.getSelectionModel().select(4); 578 | break; 579 | } 580 | // Determines what the hide completed checkbox when a new list is 581 | // loaded into the view. 582 | if (((ToDoList) newList).getHideComplete()) { 583 | if (startup) 584 | ck.setSelected(true); 585 | } else { 586 | if (startup) 587 | ck.setSelected(false); 588 | } 589 | // Ensures that program knows that not a startUp and that buttons 590 | // being clicked should handle things again. 591 | startup = false; 592 | handle = true; 593 | 594 | // For loop sets up all the tasks within the model. 595 | for (int i = 0; i < ((ToDoList) newList).amountTasks(); i++) { 596 | ToDoTask newTask = ((ToDoList) newList).getTask(i); 597 | 598 | HBox h = new HBox(5); 599 | Label label = new Label(((ToDoTask) newTask).getName()); 600 | Pane pane = new Pane(); 601 | Button upButton = new Button("Move up"); 602 | Button topButton = new Button("Move Top"); 603 | Button button = new Button("Remove"); 604 | CheckBox c1 = new CheckBox("Complete"); 605 | CheckBox c2 = new CheckBox("Important"); 606 | c1.setId("" + id); 607 | c2.setId("" + id); 608 | checkboxHelper(newTask.getImportance(), newTask.getCompletion(), c1, c2); 609 | button.setId("" + id); 610 | upButton.setId("" + id); 611 | topButton.setId("" + id); 612 | id++; 613 | 614 | Label description=new Label(((ToDoTask) newTask).getDescription()); 615 | Label deadline=new Label(((ToDoTask)newTask).getDeadline()); 616 | Label location=new Label(((ToDoTask)newTask).getLocation()); 617 | h.getChildren().addAll(label, pane,description,deadline,location, c1, c2, upButton, topButton, button); 618 | 619 | EventHandler completionHandler = new completionHandler(); 620 | EventHandler importanceHandler = new importanceHandler(); 621 | c1.setOnAction(completionHandler); 622 | c2.setOnAction(importanceHandler); 623 | 624 | button.setOnMouseClicked(new EventHandler() { 625 | @Override 626 | public void handle(MouseEvent arg0) { 627 | // tell controller to update the view 628 | String index =((Node) arg0.getSource()).getId(); 629 | int ind = Integer.parseInt(index); 630 | for (int i = 0; i < id; i++) { 631 | if (i > ind) { 632 | String currID = rows.get(i).getChildren().get(7).getId(); 633 | int curr = Integer.parseInt(currID) - 1; 634 | rows.get(i).getChildren().get(5).setId("" + curr); 635 | rows.get(i).getChildren().get(6).setId("" + curr); 636 | rows.get(i).getChildren().get(7).setId("" + curr); 637 | } 638 | } 639 | rows.remove(ind); 640 | id--; 641 | control.removeTask(ind); 642 | } 643 | }); 644 | 645 | upButton.setOnMouseClicked(new EventHandler() { 646 | 647 | @Override 648 | public void handle(MouseEvent arg0) { 649 | String index =((Node) arg0.getSource()).getId(); 650 | int ind = Integer.parseInt(index); 651 | control.moveUp(ind); 652 | } 653 | }); 654 | 655 | topButton.setOnMouseClicked(new EventHandler() { 656 | 657 | @Override 658 | public void handle(MouseEvent arg0) { 659 | String index =((Node) arg0.getSource()).getId(); 660 | int ind = Integer.parseInt(index); 661 | control.moveTop(ind); 662 | } 663 | }); 664 | 665 | h.setStyle("-fx-background-color: white;"); 666 | label.setStyle("-fx-padding: 4 0 5 5;"); 667 | HBox.setHgrow(pane, Priority.ALWAYS); 668 | rows.add(h); 669 | ListView list = new ListView(); 670 | list.setItems(rows); 671 | 672 | taskSection.getChildren().clear(); 673 | taskSection.getChildren().addAll(rows); 674 | } 675 | // Sets up the name of the list. 676 | listName.setText(((ToDoList) newList).getNameList()); 677 | } 678 | 679 | } 680 | 681 | --------------------------------------------------------------------------------