diff --git a/README.md b/README.md
index c481c2784cb6..69c764924f7e 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,6 @@
[![Build Status](https://travis-ci.org/CS2103AUG2016-T14-C2/main.svg?branch=master)](https://travis-ci.org/CS2103AUG2016-T14-C2/main)
[![Coverage Status](https://coveralls.io/repos/github/CS2103AUG2016-T14-C2/main/badge.svg?branch=master)](https://coveralls.io/github/CS2103AUG2016-T14-C2/main?branch=master)
+[![Codacy Badge](https://api.codacy.com/project/badge/Grade/91232e72b4c645dc9d988942651ca906)](https://www.codacy.com/app/xefrog/main?utm_source=github.com&utm_medium=referral&utm_content=CS2103AUG2016-T14-C2/main&utm_campaign=Badge_Grade)
# Savvy Tasker
@@ -22,6 +23,7 @@
* Some parts of this sample application were inspired by the excellent
[Java FX tutorial](http://code.makery.ch/library/javafx-8-tutorial/) by *Marco Jakob*.
* This is a sample project created by [SE-EDU](https://githubcom/se-edu/) initiative.
+* [Natty](http://natty.joestelmach.com/) for parsing user input dates
#### Licence : [MIT](LICENSE)
diff --git a/collated/docs/A0138431L.md b/collated/docs/A0138431L.md
new file mode 100644
index 000000000000..02e7cee1bff4
--- /dev/null
+++ b/collated/docs/A0138431L.md
@@ -0,0 +1,63 @@
+# A0138431L
+###### \DeveloperGuide.md
+``` md
+### UI component
+
+
+
+**API** : [`Ui.java`](../src/main/java/seedu/savvytasker/ui/Ui.java)
+
+The UI consists of a `MainWindow` that is made up of parts e.g.`CommandBox`, `ResultDisplay`, `TaskListPanel`, `UpcomingPanel`, `DailyPanel`, `FloatingPanel`,
+`StatusBarFooter` etc. All these, including the `MainWindow`, inherit from the abstract `UiPart` class
+and they can be loaded using the `UiPartLoader`.
+
+The `UI` component uses JavaFx UI framework. The layout of these UI parts are defined in matching `.fxml` files
+ that are in the `src/main/resources/view` folder.
+ For example, the layout of the [`MainWindow`](../src/main/java/seedu/savvytasker/ui/MainWindow.java) is specified in
+ [`MainWindow.fxml`](../src/main/resources/view/MainWindow.fxml)
+
+The `UI` component,
+* Executes user commands using the `Logic` component.
+* Binds itself to some data in the `Model` so that the UI can auto-update when data in the `Model` change.
+* Responds to events raised from various parts of the App and updates the UI accordingly.
+
+The cursor will be focus to the `CommandBox` by default as the `CommandBox` carries out numerous keyboard shortcuts to make the app more user-friendly.
+
+```
+###### \UserGuide.md
+``` md
+
+#### Command stack history
+UP: Return last user input command in command box
+DOWN: Return (if any) next user input command in command box
+> Note that DOWN is only allowed after at least an UP is being entered
+
+
+#### Week Selection
+Ctrl + LEFT: Display previous week’s daily task list
+Ctrl + RIGHT: Display next week’s daily task list
+
+```
+###### \UserGuide.md
+``` md
+
+## Keyboard Shortcuts
+
+Key Codes | Function | Command Box Input
+-------- | :-------- | :--------
+Esc | Toggle to show/hide a list of keyboard shortcuts | -
+Ctrl + D | [Clear](#clearing-all-entries--clear) all entries | `clear`
+Ctrl + Q | [Exit](#exiting-the-program--exit) | `exit`
+Ctrl + L | [List](#listing-all-tasks-list) all unmarked task by date, earliest task first | `list`
+Ctrl + A | [List](#listing-all-tasks-list) archived tasks | `list archived`
+Ctrl + P | [List](#listing-all-tasks-list) all unmarked task by priority level, high priority first | `list priorityLevel`
+Ctrl + I | [List](#listing-all-tasks-list) all alias keys | `list alias`
+Ctrl + H | [Help](#viewing-help--help) | `help`
+Ctrl + S | Popups a directory chooser dialog box to choose a new filepath | `storage NEW_FILEPATH`
+Ctrl + Z | [Undo](#undo-the-most-recent-operation--undo) | `undo`
+Ctrl + Y | [Redo](#redo-the-most-recent-undo-operation--redo) | `redo`
+Ctrl + UP | Return [last user input](#command-stack-history) command in command box | -
+Ctrl + DOWN | Return (if any) [next user input](#command-stack-history) command in command box | -
+Ctrl + LEFT | Displays [previous week’s](#week-selection) daily task list | -
+Ctrl + RIGHT | Display [next week’s](#week-selection) daily task list | -
+```
diff --git a/collated/docs/A0139915W.md b/collated/docs/A0139915W.md
index d3102f52e3e7..bf3949d34116 100644
--- a/collated/docs/A0139915W.md
+++ b/collated/docs/A0139915W.md
@@ -172,13 +172,17 @@ Format: `modify INDEX [t/TASK_NAME] [s/START_DATE] [e/END_DATE] [l/LOCATION] [p/
#### Change storage location : `storage`
Changes the storage location of Savvy Tasker.
-Format: `storage PATH`
+Format: `storage NEW_FILEPATH`
> Parameters | Description
> -------- | :--------
> PATH | `Mandatory` Specifies the path where Savvy Tasker's task list is saved at.
>
-> If the new storage location specified by `PATH` is not accessible by Savvy Tasker, no change will be made to the existing path.
+> If the new storage location specified by `NEW_FILEPATH` is not accessible by Savvy Tasker, no change will be made to the existing path.
+
+```
+###### \UserGuide.md
+``` md
```
###### \UserGuide.md
@@ -198,9 +202,10 @@ Command | Format
[Help](#viewing-help--help) | `help`
[Modify](#modifies-a-task--modify) | `modify INDEX [t/TASK_NAME] [s/START_DATE] [e/END_DATE] [l/LOCATION] [p/PRIORITY_LEVEL] [r/RECURRING_TYPE] [n/NUMBER_OF_RECURRENCE] [c/CATEGORY] [d/DESCRIPTION]`
Example: `modify 2 t/Wednesday Weekly Milestone s/wed d/Project Meeting and Finalization`
[Mark](#mark-a-task-as-done--mark) | `mark INDEX [MORE_INDEX]`
Example: `mark 1 2 3`
-[Storage](#change-storage-location--storage) | `storage PATH`
Example: `storage data/savvytasker.xml`
+[Storage](#change-storage-location--storage) | `storage NEW_FILEPATH`
Example: `storage data/savvytasker.xml`
[Unmark](#unmark-a-task-as-done--unmark) | `unmark INDEX [MORE_INDEX]`
Example: `unmark 1 2 3`
[Undo](#undo-the-most-recent-operation--undo) | `undo`
[Redo](#redo-the-most-recent-undo-operation--redo) | `redo`
[Unalias](#unalias-a-keyword--unalias) | `unalias s/SHORT_KEYWORD`
Example: `unalias s/mss`
+
```
diff --git a/collated/docs/A0139916U.md b/collated/docs/A0139916U.md
index 79fcc57373bc..1f2e1869055d 100644
--- a/collated/docs/A0139916U.md
+++ b/collated/docs/A0139916U.md
@@ -56,8 +56,8 @@ Format: `alias k/KEYWORD r/REPRESENTATION`
> Parameters | Description
> -------- | :--------
-> KEYWORD | Specifies the keyword that will be replaced when met in a command, must be a single word
-> REPRESENTATION | Specifies the text that will replace the keyword
+> KEYWORD | Specifies the keyword that will be replaced when met in a command, must be a single word.
+> REPRESENTATION | Specifies the text that will replace the keyword. Cannot contain slashes.
Examples:
* `alias k/pjm r/Project Meeting`
diff --git a/collated/main/A0097627N.md b/collated/main/A0097627N.md
index 58bc1d6cc7f0..71f0fe56738c 100644
--- a/collated/main/A0097627N.md
+++ b/collated/main/A0097627N.md
@@ -687,8 +687,6 @@
public static final String MESSAGE_REDO_ACKNOWLEDGEMENT = "Last command redone";
- public RedoCommand() {}
-
@Override
public CommandResult execute() {
return new CommandResult(MESSAGE_REDO_ACKNOWLEDGEMENT);
@@ -899,8 +897,6 @@
public static final String MESSAGE_UNDO_ACKNOWLEDGEMENT = "Last command undone";
- public UndoCommand() {}
-
@Override
public CommandResult execute() {
return new CommandResult(MESSAGE_UNDO_ACKNOWLEDGEMENT);
@@ -1070,7 +1066,4 @@
}
}
else if (command.canUndo()){
- undoStack.push(command);
- redoStack.clear();
- }
```
diff --git a/collated/main/A0138431L.md b/collated/main/A0138431L.md
new file mode 100644
index 000000000000..c09bfabfb133
--- /dev/null
+++ b/collated/main/A0138431L.md
@@ -0,0 +1,2386 @@
+# A0138431L
+###### \java\seedu\savvytasker\commons\events\storage\DataSavingLocationChangedEvent.java
+``` java
+/**
+ * Indicates a change in location of the storage
+ */
+public class DataSavingLocationChangedEvent extends BaseEvent {
+
+ public final ReadOnlySavvyTasker data;
+ public final String newPath;
+
+ public DataSavingLocationChangedEvent(ReadOnlySavvyTasker data, String newPath) {
+ this.data = data;
+ this.newPath = newPath;
+ }
+
+ @Override
+ public String toString() {
+ return "number of tasks " + data.getReadOnlyListOfTasks().size() +
+ " new path " + this.newPath;
+ }
+
+}
+```
+###### \java\seedu\savvytasker\commons\events\ui\ShowCheatsheetEvent.java
+``` java
+
+package seedu.savvytasker.commons.events.ui;
+
+import seedu.savvytasker.commons.events.BaseEvent;
+
+/** Indicates cheatsheet display has been toggled */
+public class ShowCheatsheetEvent extends BaseEvent {
+ @Override
+ public String toString() {
+ return "Cheatsheet display has been toggled";
+ }
+
+}
+```
+###### \java\seedu\savvytasker\commons\events\ui\WeekSelectionChangedEvent.java
+``` java
+
+package seedu.savvytasker.commons.events.ui;
+
+import seedu.savvytasker.commons.events.BaseEvent;
+
+/** Indicates the SavvyTasker in the model has changed*/
+
+public class WeekSelectionChangedEvent extends BaseEvent {
+
+ @Override
+ public String toString() {
+ return "Selected week has been changed";
+ }
+
+}
+```
+###### \java\seedu\savvytasker\logic\commands\StorageAndModelRequiringCommand.java
+``` java
+/**
+ * Represents a command which requires the Storage class as a dependency.
+ * Commands should inherit this class if they only require dependency for
+ * storage and model components
+*/
+public abstract class StorageAndModelRequiringCommand extends Command {
+ protected Storage storage;
+ protected Model model;
+
+ public void setStorage(Storage storage) {
+ this.storage = storage;
+ }
+
+ public void setModel(Model model) {
+ this.model = model;
+ }
+}
+```
+###### \java\seedu\savvytasker\logic\commands\StorageCommand.java
+``` java
+/**
+ * Changes the storage location of Savvy Tasker
+ */
+public class StorageCommand extends StorageAndModelRequiringCommand {
+
+ public final String path;
+
+ public static final String COMMAND_WORD = "storage";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Sets the storage path to the path specified.\n"
+ + "Parameters: PATH\n"
+ + "Example: " + COMMAND_WORD + " data/savvytasker.xml";
+
+ public static final String MESSAGE_CHANGE_LOCATION_SUCCESS = "Changed storage location to: %1$s";
+ public static final String MESSAGE_CHANGE_LOCATION_FAILED = "Failed to change storage location to: %1$s";
+
+ public StorageCommand(String path) {
+ this.path = path;
+ }
+
+ @Override
+ public CommandResult execute() {
+ if (storage.setSavvyTaskerFilePath(path)) {
+ ReadOnlySavvyTasker savvyTasker = model.getSavvyTasker();
+ EventsCenter.getInstance().post(new DataSavingLocationChangedEvent(savvyTasker, path));
+ return new CommandResult(String.format(MESSAGE_CHANGE_LOCATION_SUCCESS, path));
+ } else {
+ return new CommandResult(String.format(MESSAGE_CHANGE_LOCATION_FAILED, path));
+ }
+ }
+
+```
+###### \java\seedu\savvytasker\logic\LogicManager.java
+``` java
+
+ @Override
+ public ObservableList getFilteredFloatingTasks() {
+ return model.getFilteredFloatingTasks();
+ }
+
+ @Override
+ public ObservableList getFilteredDailyTasks(int i, Date date) {
+ return model.getFilteredDailyTasks(i, date);
+ }
+
+ @Override
+ public ObservableList getFilteredUpcomingTasks(Date date) {
+ return model.getFilteredUpcomingTasks(date);
+ }
+```
+###### \java\seedu\savvytasker\logic\parser\TaskFieldParser.java
+``` java
+ public String parsefilePath(String filePathText) throws ParseException {
+ if (filePathText == null) {
+ return null;
+ }
+ return filePathText.trim();
+ }
+
+ public String parsefileName(String fileNameText) throws ParseException {
+ if (fileNameText == null) {
+ return null;
+ }
+ return fileNameText.trim();
+ }
+```
+###### \java\seedu\savvytasker\MainApp.java
+``` java
+ @Subscribe
+ public void handleSavvyTaskerSaveLocationChangedEvent(DataSavingLocationChangedEvent dslce) {
+ try {
+ String configPath = getApplicationParameter("config");
+ if(configPath == null) {
+ configPath = Config.DEFAULT_CONFIG_FILE;
+ }
+ config.setSavvyTaskerFilePath(dslce.newPath);
+ ConfigUtil.saveConfig(config, configPath);
+ } catch (IOException e) {
+ logger.warning("Failed to save config file : " + StringUtil.getDetails(e));
+ }
+ }
+```
+###### \java\seedu\savvytasker\model\Model.java
+``` java
+
+ /** Returns the filtered task list of floating task as an {@code UnmodifiableObservableList} */
+ UnmodifiableObservableList getFilteredFloatingTasks();
+
+ /** Returns the filtered task list of daily task as an {@code UnmodifiableObservableList}
+ * as of expected date */
+ UnmodifiableObservableList getFilteredDailyTasks(int dayOfWeek, Date date);
+
+ /** Returns the filtered task list of upcoming task as an {@code UnmodifiableObservableList}
+ * as of expected date */
+ UnmodifiableObservableList getFilteredUpcomingTasks(Date date);
+
+ /** Updates the filter of the filtered task list to show all floating tasks */
+ void updateFilteredListToShowFloating();
+
+ /** Updates the filter of the filtered task list to show all tasks of the selected week*/
+ void updateFilteredListToShowDaily(int i);
+
+ /** Updates the filter of the filtered task list to show all upcoming tasks after the selected week*/
+ void updateFilteredListToShowUpcoming();
+
+```
+###### \java\seedu\savvytasker\model\ModelManager.java
+``` java
+ private final SavvyTasker savvyTasker;
+ private final FilteredList filteredTasks;
+ private final SortedList sortedAndFilteredTasks;
+ private final FilteredList filteredFloatingTasks;
+ private final SortedList sortedAndFilteredFloatingTasks;
+ private final FilteredList filteredDay1Tasks;
+ private final SortedList sortedAndFilteredDay1Tasks;
+ private final FilteredList filteredDay2Tasks;
+ private final SortedList sortedAndFilteredDay2Tasks;
+ private final FilteredList filteredDay3Tasks;
+ private final SortedList sortedAndFilteredDay3Tasks;
+ private final FilteredList filteredDay4Tasks;
+ private final SortedList sortedAndFilteredDay4Tasks;
+ private final FilteredList filteredDay5Tasks;
+ private final SortedList sortedAndFilteredDay5Tasks;
+ private final FilteredList filteredDay6Tasks;
+ private final SortedList sortedAndFilteredDay6Tasks;
+ private final FilteredList filteredDay7Tasks;
+ private final SortedList sortedAndFilteredDay7Tasks;
+ private final FilteredList filteredUpcomingTasks;
+ private final SortedList sortedAndFilteredUpcomingTasks;
+
+ /**
+ * Initializes a ModelManager with the given SavvyTasker
+ * and its variables should not be null
+ */
+ public ModelManager(SavvyTasker src) {
+ super();
+ assert src != null;
+
+ logger.fine("Initializing with savvy tasker: " + src);
+
+ savvyTasker = new SavvyTasker(src);
+ filteredTasks = new FilteredList<>(savvyTasker.getTasks());
+ sortedAndFilteredTasks = new SortedList<>(filteredTasks, new TaskSortedByDefault());
+
+ filteredFloatingTasks = new FilteredList<>(savvyTasker.getTasks());
+ sortedAndFilteredFloatingTasks = new SortedList<>(filteredFloatingTasks, new TaskSortedByDefault());
+
+ filteredDay1Tasks = new FilteredList<>(savvyTasker.getTasks());
+ sortedAndFilteredDay1Tasks = new SortedList<>(filteredDay1Tasks, new TaskSortedByDefault());
+ filteredDay2Tasks = new FilteredList<>(savvyTasker.getTasks());
+ sortedAndFilteredDay2Tasks = new SortedList<>(filteredDay2Tasks, new TaskSortedByDefault());
+ filteredDay3Tasks = new FilteredList<>(savvyTasker.getTasks());
+ sortedAndFilteredDay3Tasks = new SortedList<>(filteredDay3Tasks, new TaskSortedByDefault());
+ filteredDay4Tasks = new FilteredList<>(savvyTasker.getTasks());
+ sortedAndFilteredDay4Tasks = new SortedList<>(filteredDay4Tasks, new TaskSortedByDefault());
+ filteredDay5Tasks = new FilteredList<>(savvyTasker.getTasks());
+ sortedAndFilteredDay5Tasks = new SortedList<>(filteredDay5Tasks, new TaskSortedByDefault());
+ filteredDay6Tasks = new FilteredList<>(savvyTasker.getTasks());
+ sortedAndFilteredDay6Tasks = new SortedList<>(filteredDay6Tasks, new TaskSortedByDefault());
+ filteredDay7Tasks = new FilteredList<>(savvyTasker.getTasks());
+ sortedAndFilteredDay7Tasks = new SortedList<>(filteredDay7Tasks, new TaskSortedByDefault());
+
+ filteredUpcomingTasks = new FilteredList<>(savvyTasker.getTasks());
+ sortedAndFilteredUpcomingTasks = new SortedList<>(filteredUpcomingTasks, new TaskSortedByDefault());
+
+ updateFilteredListToShowActive(); // shows only active tasks on start
+ }
+
+ public ModelManager() {
+ this(new SavvyTasker());
+ }
+
+ public ModelManager(ReadOnlySavvyTasker initialData) {
+ savvyTasker = new SavvyTasker(initialData);
+ filteredTasks = new FilteredList<>(savvyTasker.getTasks());
+ sortedAndFilteredTasks = new SortedList<>(filteredTasks, new TaskSortedByDefault());
+
+ filteredFloatingTasks = new FilteredList<>(savvyTasker.getTasks());
+ sortedAndFilteredFloatingTasks = new SortedList<>(filteredFloatingTasks, new TaskSortedByDefault());
+
+ filteredDay1Tasks = new FilteredList<>(savvyTasker.getTasks());
+ sortedAndFilteredDay1Tasks = new SortedList<>(filteredDay1Tasks, new TaskSortedByDefault());
+ filteredDay2Tasks = new FilteredList<>(savvyTasker.getTasks());
+ sortedAndFilteredDay2Tasks = new SortedList<>(filteredDay2Tasks, new TaskSortedByDefault());
+ filteredDay3Tasks = new FilteredList<>(savvyTasker.getTasks());
+ sortedAndFilteredDay3Tasks = new SortedList<>(filteredDay3Tasks, new TaskSortedByDefault());
+ filteredDay4Tasks = new FilteredList<>(savvyTasker.getTasks());
+ sortedAndFilteredDay4Tasks = new SortedList<>(filteredDay4Tasks, new TaskSortedByDefault());
+ filteredDay5Tasks = new FilteredList<>(savvyTasker.getTasks());
+ sortedAndFilteredDay5Tasks = new SortedList<>(filteredDay5Tasks, new TaskSortedByDefault());
+ filteredDay6Tasks = new FilteredList<>(savvyTasker.getTasks());
+ sortedAndFilteredDay6Tasks = new SortedList<>(filteredDay6Tasks, new TaskSortedByDefault());
+ filteredDay7Tasks = new FilteredList<>(savvyTasker.getTasks());
+ sortedAndFilteredDay7Tasks = new SortedList<>(filteredDay7Tasks, new TaskSortedByDefault());
+
+ filteredUpcomingTasks = new FilteredList<>(savvyTasker.getTasks());
+ sortedAndFilteredUpcomingTasks = new SortedList<>(filteredUpcomingTasks, new TaskSortedByDefault());
+
+ updateFilteredListToShowActive(); // shows only active tasks on start
+ }
+```
+###### \java\seedu\savvytasker\model\ModelManager.java
+``` java
+ /**
+ * Qualifier for checking if {@link Task} is an overdue task
+ *
+ * A overdue task is a deadline or event task with end dateTime after current dateTime
+ *
+ * @return true if the task is overdue
+ *
+ */
+ private class TaskIsOverdueQualifier implements Qualifier {
+
+ @Override
+ public boolean run(ReadOnlyTask task) {
+
+ Date today = new Date();
+
+ boolean isOverdue = false;
+
+ if (task.getEndDateTime() != null) {
+
+ Date endDateTime = task.getEndDateTime();
+
+ if (endDateTime.compareTo(today)<0 && task.isArchived() == false) {
+
+ isOverdue = true;
+ }
+
+ }
+
+ return isOverdue;
+
+ }
+
+ @Override
+ public String toString() {
+ return "isOverdue=true";
+ }
+ }
+
+ /**
+ * Qualifier for checking if {@link Task} is a floating task
+ *
+ * A floating task do not have start or end time
+ *
+ * @return true if the task falls on the date specified. else return false
+ *
+ */
+ private class TaskIsFloatingQualifier implements Qualifier {
+
+ @Override
+ public boolean run(ReadOnlyTask task) {
+
+ boolean isFloating = false;
+
+ if(task.getStartDateTime() == null && task.getEndDateTime() == null && task.isArchived() == false) {
+
+ isFloating = true;
+
+ }
+
+ return isFloating;
+
+ }
+
+ @Override
+ public String toString() {
+ return "isFloating=true";
+ }
+ }
+
+ /**
+ * Qualifier for checking if {@link Task} falls on the selected date
+ *
+ * Check whether the task is on the date specified (for deadline tasks)
+ * Check whether the date specified is within the range of date the task (for event tasks)
+ * Includes task that are completed.
+ *
+ * @return true if the task falls on the date specified. else return false
+ *
+ */
+ private class TaskIsOnDateQualifier implements Qualifier {
+
+ @Override
+ public boolean run(ReadOnlyTask task) {
+
+ Date expectedDate = onDate;
+
+ boolean isOnDate = false;
+
+ //Archived Task
+ if(task.isArchived() == true){
+
+ isOnDate = false;
+
+ }
+ //Deadline Task
+ else if(task.getStartDateTime() == null && task.getEndDateTime() != null) {
+
+ Date endDateTime = task.getEndDateTime();
+
+ if (DateUtils.isSameDay(endDateTime, expectedDate)) {
+
+ isOnDate = true;
+
+ }
+
+ }
+ //Event Task
+ else if(task.getStartDateTime() != null && task.getEndDateTime() != null) {
+
+ Date startDateTime = task.getStartDateTime();
+ Date endDateTime = task.getEndDateTime();
+
+ if (DateUtils.isSameDay(startDateTime, expectedDate)) {
+
+ isOnDate = true;
+
+ } else if (DateUtils.isSameDay(endDateTime, expectedDate)) {
+
+ isOnDate = true;
+
+ } else if (startDateTime.compareTo(expectedDate)<0 && expectedDate.compareTo(endDateTime)<0) {
+
+ isOnDate = true;
+
+ }
+ }
+
+ return isOnDate;
+ }
+
+ @Override
+ public String toString() {
+ return "isOnDate=true";
+ }
+ }
+
+ /**
+ * Qualifier for checking if {@link Task} task is upcoming
+ *
+ * A upcoming task is a task that will happen after the last day, 2359 of selected week
+ *
+ * @return true if the task is a upcoming task
+ *
+ */
+ private class TaskIsUpcomingQualifier implements Qualifier {
+
+ @Override
+ public boolean run(ReadOnlyTask task) {
+
+ Date lastDateOfExpectedWeek = firstDayOfSelectedWeek;
+
+ //convert date object to calendar object and add 7 days, last day of the selected week
+ Calendar calendarExpectedDate = Calendar.getInstance();
+ calendarExpectedDate.setTime(lastDateOfExpectedWeek);
+ calendarExpectedDate.add(Calendar.DAY_OF_MONTH, 7);
+ calendarExpectedDate.set(Calendar.HOUR_OF_DAY,23);
+ calendarExpectedDate.set(Calendar.MINUTE,59);
+ calendarExpectedDate.set(Calendar.SECOND,59);
+
+ //convert calendar object back to date object
+ lastDateOfExpectedWeek = calendarExpectedDate.getTime();
+
+ boolean isUpcoming = true;
+
+ //Archived Task
+ if(task.isArchived() == true){
+
+ isUpcoming = false;
+
+ }
+
+ //Floating Task
+ else if(task.getStartDateTime() == null && task.getEndDateTime() == null) {
+
+ isUpcoming = false;
+
+ }
+ //Deadline Task
+ else if(task.getStartDateTime() == null && task.getEndDateTime() != null) {
+
+
+ if (task.getEndDateTime().compareTo(lastDateOfExpectedWeek)<0) {
+
+ isUpcoming = false;
+
+ }
+
+ }
+ //Event Task
+ else {
+
+ if (task.getStartDateTime().compareTo(lastDateOfExpectedWeek)<0) {
+
+ isUpcoming = false;
+
+ }
+
+ }
+
+ return isUpcoming;
+ }
+
+ @Override
+ public String toString() {
+ return "isUpcoming=true";
+ }
+```
+###### \java\seedu\savvytasker\model\task\ReadOnlyTask.java
+``` java
+ static final String EMPTY_FIELD = " ";
+
+ static String DATE_PATTERN = "dd MMM yy";
+ static String TIME_PATTERN = "hh:mm a";
+
+ // String format for deadline tasks dateTime format
+ static String DEADLINE_FORMAT = "by %1$s, %2$s";
+
+ // String format for event tasks dateTime format
+ static String EVENT_DIFF_START_END_DATE_FORMAT = "%1$s, %2$s to %3$s, %4$s";
+ static String EVENT_SAME_START_END_DATE_FORMAT = "%1$s, %2$s to %3$s";
+
+ static Date lastDayOfSelectedWeek = new Date();
+
+ /**
+ * Generates the DateTime Format for all tasks with time.
+ *
+ * @param task the task to have its DateTime Format generated
+ *
+ * @return DateTime Format (e.g. (31 Oct 16, 10:00PM)
+ **/
+ default String generateDateTime(Date start, Date end) {
+ String dateTimeFormat;
+ //Floating Task
+ if(start == null && end == null) {
+ dateTimeFormat = EMPTY_FIELD;
+ }
+ //Deadline Task
+ else if(start == null && end != null) {
+ dateTimeFormat = generateDeadlineDateTime(end);
+ //Event Task
+ }else {
+ dateTimeFormat = generateEventDateTime(start, end);
+ }
+
+ return dateTimeFormat;
+
+ }
+
+ /**
+ * Generates the dateTimeFormat for deadline tasks
+ *
+ * @param task the task to have its dateTimeFormat generated
+ *
+ * @return dateTimeFormat (e.g. 30 Oct 16, 10:00PM)
+ */
+ default String generateDeadlineDateTime(Date end) {
+
+ String dateTimeFormat;
+
+ SimpleDateFormat dateFormatter = new SimpleDateFormat(DATE_PATTERN);
+ SimpleDateFormat timeFormatter = new SimpleDateFormat(TIME_PATTERN);
+
+ String taskEndDateFormat = dateFormatter.format(end.getTime());
+ String taskEndTimeFormat = timeFormatter.format(end.getTime());
+
+ dateTimeFormat = String.format(DEADLINE_FORMAT, taskEndDateFormat, taskEndTimeFormat);
+
+ return dateTimeFormat;
+
+ }
+
+ /**
+ * Generates the dateTimeFormat for ranged tasks
+ *
+ * @param task the task to have its dateTimeFormat generated
+ *
+ * @return dateTimeFormat (e.g. 30 Oct 16, 8:00AM to 9:00PM)
+ */
+ default String generateEventDateTime(Date start, Date end) {
+
+ String dateTimeFormat;
+
+ SimpleDateFormat dateFormatter = new SimpleDateFormat(DATE_PATTERN);
+ SimpleDateFormat timeFormatter = new SimpleDateFormat(TIME_PATTERN);
+
+ String taskStartDateFormat = dateFormatter.format(start.getTime());
+ String taskStartTimeFormat = timeFormatter.format(start.getTime());
+
+ String taskEndDateFormat = dateFormatter.format(end.getTime());
+ String taskEndTimeFormat = timeFormatter.format(end.getTime());
+
+ if(DateUtils.isSameDay(start, end) == false) {
+
+ dateTimeFormat = String.format(EVENT_DIFF_START_END_DATE_FORMAT, taskStartDateFormat, taskStartTimeFormat, taskEndDateFormat, taskEndTimeFormat);
+
+ } else {
+
+ dateTimeFormat = String.format(EVENT_SAME_START_END_DATE_FORMAT, taskEndDateFormat, taskStartTimeFormat, taskEndTimeFormat);
+
+ }
+
+ return dateTimeFormat;
+
+ }
+}
+```
+###### \java\seedu\savvytasker\storage\ConfigStorage.java
+``` java
+package seedu.savvytasker.storage;
+
+import java.io.IOException;
+import java.util.Optional;
+
+import seedu.savvytasker.commons.core.Config;
+import seedu.savvytasker.commons.exceptions.DataConversionException;
+
+/**
+ * Represents a storage for {@link seedu.savvytasker.commons.core.Config}.
+ */
+public interface ConfigStorage {
+ /**
+ * Returns Config data from storage.
+ * Returns {@code Optional.empty()} if storage file is not found.
+ * @throws DataConversionException if the data in storage is not in the expected format.
+ * @throws IOException if there was any problem when reading from the storage.
+ */
+ Optional readConfigFile() throws DataConversionException, IOException;
+
+ /**
+ * Saves the given {@link seedu.savvytasker.commons.core.Config} to the storage.
+ * @param config cannot be null.
+ * @throws IOException if there was any problem writing to the file.
+ */
+ void saveConfigFile(Config config) throws IOException;
+
+}
+```
+###### \java\seedu\savvytasker\storage\JsonConfigStorage.java
+``` java
+
+package seedu.savvytasker.storage;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Optional;
+import java.util.logging.Logger;
+
+import seedu.savvytasker.commons.core.Config;
+import seedu.savvytasker.commons.core.LogsCenter;
+import seedu.savvytasker.commons.exceptions.DataConversionException;
+import seedu.savvytasker.commons.util.FileUtil;
+
+/**
+ * A class to access Config stored in the hard disk as a json file
+ */
+public class JsonConfigStorage implements ConfigStorage {
+
+ private static final Logger logger = LogsCenter.getLogger(JsonConfigStorage.class);
+
+ private String filePath;
+
+ public JsonConfigStorage(String filePath) {
+
+ this.filePath = filePath;
+ }
+
+ @Override
+ public Optional readConfigFile() throws DataConversionException, IOException {
+
+ return readConfig(filePath);
+ }
+
+ @Override
+ public void saveConfigFile(Config config) throws IOException {
+
+ saveConfig(config, filePath);
+ }
+
+ /**
+ * Similar to {@link #readConfigFile()}
+ * @param configFilePath location of the data. Cannot be null.
+ * @throws DataConversionException if the file format is not as expected.
+ */
+ public Optional readConfig(String configFilePath) throws DataConversionException {
+
+ assert configFilePath != null;
+
+ File configFile = new File(configFilePath);
+
+ if (!configFile.exists()) {
+
+ logger.info("Config file " + configFile + " not found");
+
+ return Optional.empty();
+
+ }
+
+ Config config;
+
+ try {
+
+ config = FileUtil.deserializeObjectFromJsonFile(configFile, Config.class);
+
+ } catch (IOException e) {
+
+ logger.warning("Error reading from config file " + configFile + ": " + e);
+
+ throw new DataConversionException(e);
+
+ }
+
+ return Optional.of(config);
+ }
+
+ /**
+ * Similar to {@link #saveConfigFile(Config)}
+ * @param configFilePath location of the data. Cannot be null.
+ */
+ private void saveConfig(Config config, String configFilePath) throws IOException {
+
+ assert config != null;
+ assert configFilePath != null;
+ assert !configFilePath.isEmpty();
+
+ FileUtil.serializeObjectToJsonFile(new File(configFilePath), config);
+ }
+
+}
+```
+###### \java\seedu\savvytasker\storage\StorageManager.java
+``` java
+ @Override
+ @Subscribe
+ public void handleSavvyTaskerSaveLocationChangedEvent(DataSavingLocationChangedEvent dslce) {
+ logger.info(LogsCenter.getEventHandlingLogMessage(dslce, "Local storage location changed."));
+ try {
+ saveSavvyTasker(dslce.data);
+ } catch (IOException e) {
+ raise(new DataSavingExceptionEvent(e));
+ }
+ }
+```
+###### \java\seedu\savvytasker\ui\CommandBox.java
+``` java
+package seedu.savvytasker.ui;
+
+import java.io.File;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Stack;
+import java.util.logging.Logger;
+
+import com.google.common.eventbus.Subscribe;
+
+import javafx.fxml.FXML;
+import javafx.scene.Node;
+import javafx.scene.control.SplitPane;
+import javafx.scene.control.TextField;
+import javafx.scene.image.Image;
+import javafx.scene.image.ImageView;
+import javafx.scene.input.KeyCode;
+import javafx.scene.input.KeyCodeCombination;
+import javafx.scene.input.KeyCombination;
+import javafx.scene.input.KeyEvent;
+import javafx.scene.layout.AnchorPane;
+import javafx.stage.DirectoryChooser;
+import javafx.stage.Stage;
+import seedu.savvytasker.commons.core.LogsCenter;
+import seedu.savvytasker.commons.events.model.SavvyTaskerChangedEvent;
+import seedu.savvytasker.commons.events.ui.IncorrectCommandAttemptedEvent;
+import seedu.savvytasker.commons.events.ui.ShowCheatsheetEvent;
+import seedu.savvytasker.commons.events.ui.WeekSelectionChangedEvent;
+import seedu.savvytasker.commons.util.FxViewUtil;
+import seedu.savvytasker.logic.Logic;
+import seedu.savvytasker.logic.commands.CommandResult;
+
+public class CommandBox extends UiPart {
+ private final Logger logger = LogsCenter.getLogger(CommandBox.class);
+ private static final String FXML = "CommandBox.fxml";
+
+ private AnchorPane placeHolderPane;
+ private AnchorPane commandPane;
+ private ResultDisplay resultDisplay;
+ String previousCommandTest;
+ private Date date = new Date();
+ private static int DAYS_OF_WEEK = 7;
+
+ private final String UNDO_COMMAND = "undo";
+ private final String REDO_COMMAND = "redo";
+ private final String HELP_COMMAND = "help";
+ private final String EXIT_COMMAND = "exit";
+ private final String LIST_COMMAND = "list";
+ private final String LIST_ARCHIVED_COMMAND = "list archived";
+ private final String LIST_PRIORITY_COMMAND = "list priorityLevel";
+ private final String LIST_ALIAS_COMMAND = "list alias";
+ private final String CLEAR_COMMAND = "clear";
+ private final String STORAGE_COMMAND = "storage .";
+
+ KeyCombination saveKey = new KeyCodeCombination(KeyCode.S, KeyCombination.META_DOWN);
+ KeyCombination undoKey = new KeyCodeCombination(KeyCode.Z, KeyCombination.META_DOWN);
+ KeyCombination redoKey = new KeyCodeCombination(KeyCode.Y, KeyCombination.META_DOWN);
+ KeyCombination helpKey = new KeyCodeCombination(KeyCode.H, KeyCombination.META_DOWN);
+ KeyCombination exitKey = new KeyCodeCombination(KeyCode.Q, KeyCombination.META_DOWN);
+ KeyCombination listKey = new KeyCodeCombination(KeyCode.L, KeyCombination.META_DOWN);
+ KeyCombination listArchivedKey = new KeyCodeCombination(KeyCode.A, KeyCombination.META_DOWN);
+ KeyCombination listPriorityKey = new KeyCodeCombination(KeyCode.P, KeyCombination.META_DOWN);
+ KeyCombination listAliasKey = new KeyCodeCombination(KeyCode.I, KeyCombination.META_DOWN);
+ KeyCombination clearKey = new KeyCodeCombination(KeyCode.D, KeyCombination.META_DOWN);
+ KeyCombination leftKey = new KeyCodeCombination(KeyCode.LEFT, KeyCombination.META_DOWN);
+ KeyCombination rightKey = new KeyCodeCombination(KeyCode.RIGHT, KeyCombination.META_DOWN);
+
+ // stack to store commands history
+ private static Stack COMMAND_HISTORY_STACK = new Stack();
+ private static Stack COMMAND_FUTURE_STACK = new Stack();
+
+ private Logic logic;
+
+ @FXML
+ private TextField commandTextField;
+ private CommandResult mostRecentResult;
+
+ public static CommandBox load(Stage primaryStage, AnchorPane commandBoxPlaceholder,
+ ResultDisplay resultDisplay, Logic logic) {
+ CommandBox commandBox = UiPartLoader.loadUiPart(primaryStage, commandBoxPlaceholder, new CommandBox());
+ commandBox.configure(resultDisplay, logic);
+ commandBox.addToPlaceholder();
+ return commandBox;
+ }
+
+ public void configure(ResultDisplay resultDisplay, Logic logic) {
+ this.resultDisplay = resultDisplay;
+ this.logic = logic;
+ registerAsAnEventHandler(this);
+ }
+
+ private void addToPlaceholder() {
+ SplitPane.setResizableWithParent(placeHolderPane, false);
+ placeHolderPane.getChildren().add(commandTextField);
+ FxViewUtil.applyAnchorBoundaryParameters(commandPane, 0.0, 0.0, 0.0, 0.0);
+ FxViewUtil.applyAnchorBoundaryParameters(commandTextField, 0.0, 0.0, 0.0, 0.0);
+ }
+
+ @Override
+ public void setNode(Node node) {
+ commandPane = (AnchorPane) node;
+ }
+
+ @Override
+ public String getFxmlPath() {
+ return FXML;
+ }
+
+ @Override
+ public void setPlaceholder(AnchorPane pane) {
+ this.placeHolderPane = pane;
+ }
+
+
+ @FXML
+ private void handleCommandInputChanged() {
+ //Take a copy of the command text
+ previousCommandTest = commandTextField.getText();
+
+ COMMAND_HISTORY_STACK.push(previousCommandTest);
+ /* We assume the command is correct. If it is incorrect, the command box will be changed accordingly
+ * in the event handling code {@link #handleIncorrectCommandAttempted}
+ */
+ setStyleToIndicateCorrectCommand();
+ mostRecentResult = logic.execute(previousCommandTest);
+ resultDisplay.postMessage(mostRecentResult.feedbackToUser);
+ logger.info("Result: " + mostRecentResult.feedbackToUser);
+ }
+
+
+ /**
+ * Sets the command box style to indicate a correct command.
+ */
+ private void setStyleToIndicateCorrectCommand() {
+ commandTextField.getStyleClass().remove("error");
+ commandTextField.setText("");
+ }
+
+ @Subscribe
+ private void handleIncorrectCommandAttempted(IncorrectCommandAttemptedEvent event){
+ logger.info(LogsCenter.getEventHandlingLogMessage(event,"Invalid command: " + previousCommandTest));
+ setStyleToIndicateIncorrectCommand();
+ restoreCommandText();
+ }
+
+ /**
+ * Restores the command box text to the previously entered command
+ */
+ private void restoreCommandText() {
+ commandTextField.setText("");
+ }
+
+ /**
+ * Sets the command box style to indicate an error
+ */
+ private void setStyleToIndicateIncorrectCommand() {
+ commandTextField.getStyleClass().add("error");
+ }
+
+ public Node getCommandTextField() {
+ return commandTextField;
+ }
+
+ //==================== Keyboard Shortcuts Code =================================================================
+ /**
+ * Key pressed handler for text box.
+ *
+ * @param keyEvent key event for the button that is being pressed.
+ */
+ public void commandTextFieldOnKeyPressedHandler(KeyEvent keyEvent) {
+
+ String userInput = commandTextField.getText().trim();
+
+ try {
+
+ KeyCode keyCode = keyEvent.getCode();
+
+ if(saveKey.match(keyEvent)) {
+
+ processSave();
+
+ }else if (keyCode == KeyCode.ESCAPE) {
+
+ showCheatsheet();
+
+ } else if (keyCode == KeyCode.UP) {
+
+ processUp(userInput);
+
+ } else if (keyCode == KeyCode.DOWN) {
+
+ processDown(userInput);
+
+ } else if (leftKey.match(keyEvent)) {
+
+ processDate(-1);
+
+ } else if (rightKey.match(keyEvent)) {
+
+ processDate(1);
+
+ } else if (undoKey.match(keyEvent)) {
+
+ executeCommand(UNDO_COMMAND);
+
+ } else if (redoKey.match(keyEvent)) {
+
+ executeCommand(REDO_COMMAND);
+
+ } else if (helpKey.match(keyEvent)) {
+
+ executeCommand(HELP_COMMAND);
+
+ } else if (exitKey.match(keyEvent)) {
+
+ executeCommand(EXIT_COMMAND);
+
+ } else if (listKey.match(keyEvent)) {
+
+ executeCommand(LIST_COMMAND);
+
+ } else if (listArchivedKey.match(keyEvent)) {
+
+ executeCommand(LIST_ARCHIVED_COMMAND);
+
+ } else if (listPriorityKey.match(keyEvent)) {
+
+ executeCommand(LIST_PRIORITY_COMMAND);
+
+ } else if (listAliasKey.match(keyEvent)) {
+
+ executeCommand(LIST_ALIAS_COMMAND);
+
+ } else if (clearKey.match(keyEvent)) {
+
+ executeCommand(CLEAR_COMMAND);
+
+ }
+
+ } catch (IllegalArgumentException e) {
+
+ commandTextField.setText("");
+
+ COMMAND_HISTORY_STACK.add(userInput);
+
+ this.logger.info("Illegal Argument has been entered.");
+
+ } catch (Exception e) {
+
+ e.printStackTrace();
+ commandTextField.setText("");
+
+ this.logger.info("Illegal Argument has been entered.");
+
+ }
+
+ }
+
+ /**
+ * Process the event that occurs after the user presses the ctrl-S button.
+ *
+ * @param userInput the command keyed in by the user.
+ */
+ public void processSave() {
+
+ //Execute the save command
+ DirectoryChooser directoryChooser = new DirectoryChooser();
+ File selectedFile = directoryChooser.showDialog(primaryStage);
+ String filepath = selectedFile.getAbsolutePath();
+ executeCommand(STORAGE_COMMAND + filepath + "/savvytasker.xml");
+
+ }
+
+ /**
+ * Process the event that occurs after the user presses the [UP] button.
+ *
+ * @param userInput the command keyed in by the user.
+ */
+ public void processUp(String userInput) {
+
+ if (!COMMAND_HISTORY_STACK.isEmpty()) {
+
+ String previousCommand = COMMAND_HISTORY_STACK.pop();
+
+ if (!userInput.equals("")) {
+
+ COMMAND_FUTURE_STACK.push(userInput);
+
+ }
+
+ commandTextField.setText(previousCommand);
+
+ }
+
+ commandTextField.positionCaret(commandTextField.getText().length());
+
+ }
+
+ /**
+ * Process the event that occurs after the user presses the down button.
+ *
+ * @param userInput the command keyed in by the user.
+ */
+ public void processDown(String userInput) {
+
+ if (!COMMAND_FUTURE_STACK.isEmpty()) {
+
+ String nextCommand = COMMAND_FUTURE_STACK.pop();
+
+ COMMAND_HISTORY_STACK.push(userInput);
+ commandTextField.setText(nextCommand);
+
+ } else if (!userInput.equals("")) {
+
+ COMMAND_HISTORY_STACK.push(userInput);
+ commandTextField.setText("");
+
+ }
+
+ commandTextField.positionCaret(commandTextField.getText().length());
+
+ }
+
+ /**
+ * Process the event that occurs after the user presses the left or right button.
+ *
+ * @param numbers of week to be added to the current selected week to be displayed in the daily task list view
+ */
+ public void processDate(int numberOfWeek) {
+
+ date = addWeek(numberOfWeek, date);
+ indicateWeekSelectionChanged();
+ }
+
+ /** Raises an event to indicate the week to be displayed has changed */
+ private void indicateWeekSelectionChanged() {
+ raise(new WeekSelectionChangedEvent());
+ }
+
+ /** Raises an event to indicate the week to be displayed has changed */
+ private void showCheatsheet() {
+ raise(new ShowCheatsheetEvent());
+ }
+
+ /**
+ * Execute commands
+ *
+ * @param command to be executed
+ */
+ public void executeCommand(String commandInput) {
+ CommandResult commandResult = logic.execute(commandInput);
+ resultDisplay.postMessage(commandResult.feedbackToUser);
+ logger.info("Result: " + commandResult.feedbackToUser);
+ }
+
+ private Date addWeek(int numberOfWeek, Date date) {
+
+ //convert date object to calendar object and add 1 days
+ Calendar calendarExpectedDate = Calendar.getInstance();
+ calendarExpectedDate.setTime(date);
+
+ calendarExpectedDate.add(Calendar.DATE, (numberOfWeek*DAYS_OF_WEEK));
+
+ //convert calendar object back to date object
+ date = calendarExpectedDate.getTime();
+
+ return date;
+ }
+
+ public Date getDate() {
+ return date;
+ }
+}
+
+```
+###### \java\seedu\savvytasker\ui\DailyPanel.java
+``` java
+
+/**
+ * Panel containing the list overdue task.
+ * @author A0138431L
+ *
+ */
+public class DailyPanel extends UiPart {
+
+ private static String TODAY_TITLE = "Today";
+ private static String TOMORROW_TITLE = "Tomorrow";
+ private static String DAY_PATTERN = "EEEE";
+ private static String DATE_PATTERN = "dd MMM yy";
+ private static String DAY_DATE_FORMAT = "%1$s, %2$s";
+
+ private final Logger logger = LogsCenter.getLogger(TaskListPanel.class);
+ private static final String FXML = "DailyList.fxml";
+ private VBox panel;
+ private AnchorPane placeHolderPane;
+
+
+ @FXML
+ private TextField header;
+
+ @FXML
+ private ListView taskListView;
+
+ public DailyPanel() {
+ super();
+ }
+
+ @Override
+ public void setNode(Node node) {
+ panel = (VBox) node;
+ }
+
+ @Override
+ public String getFxmlPath() {
+ return FXML;
+ }
+
+ @Override
+ public void setPlaceholder(AnchorPane pane) {
+ this.placeHolderPane = pane;
+ }
+
+ public static DailyPanel load(Stage primaryStage, AnchorPane DailyListPlaceholder,
+ ObservableList taskList, int dayOfTheWeek, Date date) {
+ DailyPanel dailyPanel =
+ UiPartLoader.loadUiPart(primaryStage, DailyListPlaceholder, new DailyPanel());
+ dailyPanel.configure(taskList, dayOfTheWeek, date);
+ return dailyPanel;
+ }
+
+ private void configure(ObservableList taskList, int dayOfTheWeek, Date date) {
+
+ String dateHeader = generateHeader(dayOfTheWeek, date);
+ Date today = new Date();
+ if(date == today) {
+ placeHolderPane.setStyle("-fx-background-color:#FF0000");
+ header.setStyle("-fx-text-fill:#FF0000");
+ }
+ setConnections(taskList, dateHeader);
+ addToPlaceholder();
+
+ }
+
+ private void setConnections(ObservableList taskList, String dateHeader) {
+ header.clear();
+ header.setText(dateHeader);
+ taskListView.setItems(taskList);
+ taskListView.setCellFactory(listView -> new TaskListViewCell());
+ setEventHandlerForSelectionChangeEvent();
+ }
+
+ private void addToPlaceholder() {
+ SplitPane.setResizableWithParent(placeHolderPane, false);
+ placeHolderPane.getChildren().add(panel);
+ }
+
+ private void setEventHandlerForSelectionChangeEvent() {
+ taskListView.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
+ if (newValue != null) {
+ logger.fine("Selection in daily task list panel changed to : '" + newValue + "'");
+ raise(new TaskPanelSelectionChangedEvent(newValue));
+ }
+ });
+ }
+
+ public void scrollTo(int index) {
+ Platform.runLater(() -> {
+ taskListView.scrollTo(index);
+ taskListView.getSelectionModel().clearAndSelect(index);
+ });
+ }
+
+ private String generateHeader(int dayOfTheWeek, Date date) {
+
+ SimpleDateFormat dayFormatter = new SimpleDateFormat(DAY_PATTERN);
+ SimpleDateFormat dateFormatter = new SimpleDateFormat(DATE_PATTERN);
+
+ Date today = new Date();
+ Date tomorrow = new Date();
+ tomorrow = addDay(1, tomorrow);
+
+ String day;
+
+ if(DateUtils.isSameDay(date, today)) {
+
+ day = TODAY_TITLE;
+
+ } else if (DateUtils.isSameDay(date, tomorrow)) {
+
+ day = TOMORROW_TITLE;
+
+ } else {
+
+ day = dayFormatter.format(date);
+
+ }
+ String header = String.format(DAY_DATE_FORMAT, day, dateFormatter.format(date));
+
+ return header;
+ }
+
+ private Date addDay(int i, Date date) {
+
+ //convert date object to calendar object and add 1 days
+ Calendar calendarExpectedDate = Calendar.getInstance();
+ calendarExpectedDate.setTime(date);
+
+ calendarExpectedDate.add(Calendar.DATE, i);
+
+ //convert calendar object back to date object
+ date = calendarExpectedDate.getTime();
+
+ return date;
+ }
+
+ class TaskListViewCell extends ListCell {
+
+ public TaskListViewCell() {
+ }
+
+ @Override
+ protected void updateItem(ReadOnlyTask task, boolean empty) {
+ super.updateItem(task, empty);
+
+ if (empty || task == null) {
+ setGraphic(null);
+ setText(null);
+ } else {
+ setGraphic(TaskCard.load(task, 0, false).getLayout());
+ }
+ }
+ }
+
+}
+```
+###### \java\seedu\savvytasker\ui\FloatingPanel.java
+``` java
+
+/**
+ * Panel containing the list floating task.
+ * @author A0138431L
+ *
+ */
+public class FloatingPanel extends UiPart {
+ private final Logger logger = LogsCenter.getLogger(TaskListPanel.class);
+ private static final String FXML = "FloatingList.fxml";
+ private VBox panel;
+ private AnchorPane placeHolderPane;
+
+ @FXML
+ private ListView taskListView;
+
+ public FloatingPanel() {
+ super();
+ }
+
+ @Override
+ public void setNode(Node node) {
+ panel = (VBox) node;
+ }
+
+ @Override
+ public String getFxmlPath() {
+ return FXML;
+ }
+
+ @Override
+ public void setPlaceholder(AnchorPane pane) {
+ this.placeHolderPane = pane;
+ }
+
+ public static FloatingPanel load(Stage primaryStage, AnchorPane floatingListPlaceholder,
+ ObservableList taskList) {
+ FloatingPanel floatingPanel =
+ UiPartLoader.loadUiPart(primaryStage, floatingListPlaceholder, new FloatingPanel());
+ floatingPanel.configure(taskList);
+ return floatingPanel;
+ }
+
+ private void configure(ObservableList taskList) {
+ setConnections(taskList);
+ addToPlaceholder();
+ }
+
+ private void setConnections(ObservableList taskList) {
+ taskListView.setItems(taskList);
+ taskListView.setCellFactory(listView -> new TaskListViewCell());
+ setEventHandlerForSelectionChangeEvent();
+ }
+
+ private void addToPlaceholder() {
+ SplitPane.setResizableWithParent(placeHolderPane, false);
+ placeHolderPane.getChildren().add(panel);
+ }
+
+ private void setEventHandlerForSelectionChangeEvent() {
+ taskListView.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
+ if (newValue != null) {
+ logger.fine("Selection in floating task list panel changed to : '" + newValue + "'");
+ raise(new TaskPanelSelectionChangedEvent(newValue));
+ }
+ });
+ }
+
+ public void scrollTo(int index) {
+ Platform.runLater(() -> {
+ taskListView.scrollTo(index);
+ taskListView.getSelectionModel().clearAndSelect(index);
+ });
+ }
+
+ class TaskListViewCell extends ListCell {
+
+ public TaskListViewCell() {
+ }
+
+ @Override
+ protected void updateItem(ReadOnlyTask task, boolean empty) {
+ super.updateItem(task, empty);
+
+ if (empty || task == null) {
+ setGraphic(null);
+ setText(null);
+ } else {
+ setGraphic(TaskCard.load(task, 0, false).getLayout());
+ }
+ }
+ }
+
+}
+```
+###### \java\seedu\savvytasker\ui\MainWindow.java
+``` java
+
+package seedu.savvytasker.ui;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+
+import com.google.common.eventbus.Subscribe;
+
+import javafx.fxml.FXML;
+import javafx.scene.Node;
+import javafx.scene.Scene;
+import javafx.scene.control.MenuItem;
+import javafx.scene.image.Image;
+import javafx.scene.image.ImageView;
+import javafx.scene.input.KeyCombination;
+import javafx.scene.layout.AnchorPane;
+import javafx.scene.layout.VBox;
+import javafx.stage.Stage;
+
+import seedu.savvytasker.commons.core.Config;
+import seedu.savvytasker.commons.core.GuiSettings;
+import seedu.savvytasker.commons.core.LogsCenter;
+import seedu.savvytasker.commons.events.model.SavvyTaskerChangedEvent;
+import seedu.savvytasker.commons.events.ui.ExitAppRequestEvent;
+import seedu.savvytasker.commons.events.ui.ShowCheatsheetEvent;
+import seedu.savvytasker.commons.events.ui.WeekSelectionChangedEvent;
+import seedu.savvytasker.logic.Logic;
+import seedu.savvytasker.model.UserPrefs;
+import seedu.savvytasker.model.task.ReadOnlyTask;
+
+/**
+ * The Main Window. Provides the basic application layout containing
+ * a sorting and filtered list that display the result of the user command
+ * on the left and a week's view of the task
+ *
+ * The week's view contains 4 lists, namely the floating list,
+ * days of the week list and upcoming list
+ *
+ * Floating list contains task without start and end dateTime
+ * Days of the week list contains task that falls on the respective day of the selected week
+ * Upcoming list contains task with start date after the last day of selected week
+ *
+ * @author A0138431L
+ *
+ */
+public class MainWindow extends UiPart {
+
+ private static final String ICON = "/images/savvytasker-icon.png";
+ private static final Image image = new Image(MainWindow.class.getResourceAsStream(ICON));
+ private static final String CHEATSHEET = "/images/cheatsheet.png";
+ private static final Image imageOverlay = new Image(MainWindow.class.getResourceAsStream(CHEATSHEET));
+ private static final String FXML = "MainWindow.fxml";
+ public static final int MIN_HEIGHT = 700;
+ public static final int MIN_WIDTH = 1150;
+
+ private Logic logic;
+ Date firstDayOfSelectedWeek = new Date();
+ private static int DAYS_OF_WEEK = 7;
+ private boolean isShown = false;
+
+ // Independent Ui parts residing in this Ui container
+ //private BrowserPanel browserPanel;
+ private TaskListPanel taskListPanel;
+ private AliasSymbolListPanel aliasSymbolListPanel;
+ private ResultDisplay resultDisplay;
+ private StatusBarFooter statusBarFooter;
+ private CommandBox commandBox;
+ private Config config;
+ private UserPrefs userPrefs;
+ @FXML
+ private FloatingPanel floatingPanel;
+ @FXML
+ private DailyPanel dailyPanel;
+ @FXML
+ private UpcomingPanel upcomingPanel;
+
+ // Handles to elements of this Ui container
+ private VBox rootLayout;
+ private Scene scene;
+
+ private String addressBookName;
+
+ @FXML
+ private AnchorPane browserPlaceholder;
+
+ @FXML
+ private AnchorPane commandBoxPlaceholder;
+
+ @FXML
+ private ImageView imageIcon;
+
+ @FXML
+ private ImageView cheatsheet;
+
+ @FXML
+ private AnchorPane taskListPanelPlaceholder;
+
+ @FXML
+ private AnchorPane aliasSymbolListPanelPlaceholder;
+
+ @FXML
+ private AnchorPane resultDisplayPlaceholder;
+
+ @FXML
+ private AnchorPane statusbarPlaceholder;
+
+ @FXML
+ private VBox listPanel;
+
+ @FXML
+ private AnchorPane floatingPanelPlaceholder;
+
+ @FXML
+ private AnchorPane day1PanelPlaceholder;
+ @FXML
+ private AnchorPane day2PanelPlaceholder;
+ @FXML
+ private AnchorPane day3PanelPlaceholder;
+ @FXML
+ private AnchorPane day4PanelPlaceholder;
+ @FXML
+ private AnchorPane day5PanelPlaceholder;
+ @FXML
+ private AnchorPane day6PanelPlaceholder;
+ @FXML
+ private AnchorPane day7PanelPlaceholder;
+
+ @FXML
+ private AnchorPane upcomingPanelPlaceholder;
+
+ public MainWindow() {
+ super();
+ }
+
+ @Override
+ public void setNode(Node node) {
+ rootLayout = (VBox) node;
+ }
+
+ @Override
+ public String getFxmlPath() {
+ return FXML;
+ }
+
+ public static MainWindow load(Stage primaryStage, Config config, UserPrefs prefs, Logic logic) {
+
+ MainWindow mainWindow = UiPartLoader.loadUiPart(primaryStage, new MainWindow());
+ mainWindow.configure(config.getAppTitle(), config.getSavvyTaskerListName(), config, prefs, logic);
+ return mainWindow;
+ }
+
+ private void configure(String appTitle, String addressBookName, Config config, UserPrefs prefs,
+ Logic logic) {
+
+ //Set dependencies
+ this.logic = logic;
+ this.addressBookName = addressBookName;
+ this.config = config;
+ this.userPrefs = prefs;
+ registerAsAnEventHandler(this);
+
+ //Configure the UI
+ setTitle(appTitle);
+ setIcon(ICON);
+ setWindowMinSize();
+ setWindowDefaultSize(prefs);
+ scene = new Scene(rootLayout);
+ primaryStage.setScene(scene);
+
+ }
+
+ void fillInnerParts() {
+ imageIcon.setImage(image);
+ taskListPanel = TaskListPanel.load(primaryStage, getTaskListPlaceholder(), logic.getFilteredTaskList());
+ aliasSymbolListPanel = AliasSymbolListPanel.load(primaryStage, getAliasSymbolPlaceholder(), logic.getAliasSymbolList());
+ setDefaultView();
+ resultDisplay = ResultDisplay.load(primaryStage, getResultDisplayPlaceholder());
+ statusBarFooter = StatusBarFooter.load(primaryStage, getStatusbarPlaceholder(), config.getSavvyTaskerFilePath());
+ commandBox = CommandBox.load(primaryStage, getCommandBoxPlaceholder(), resultDisplay, logic);
+ commandBox.getCommandTextField().requestFocus();
+ floatingPanel = FloatingPanel.load(primaryStage, getFloatingPanelPlaceholder(), logic.getFilteredFloatingTasks());
+ loadDailyPanel();
+ upcomingPanel = UpcomingPanel.load(primaryStage, getUpcomingPanelPlaceholder(), logic.getFilteredUpcomingTasks(firstDayOfSelectedWeek));
+ cheatsheet.setImage(imageOverlay);
+ }
+
+ private void loadDailyPanel() {
+ firstDayOfSelectedWeek = commandBox.getDate();
+ for (int i = 0; i < DAYS_OF_WEEK; i++) {
+ Date onDate = new Date();
+ onDate.setTime(firstDayOfSelectedWeek.getTime());
+ onDate = addDay(i, onDate);
+ dailyPanel = DailyPanel.load(primaryStage, getDailyPanelPlaceholder(i),
+ logic.getFilteredDailyTasks(i, onDate), i, onDate);
+ }
+ }
+
+ /**
+ * Removes all the children in the taskPanel VBox
+ * Shows the default list, which is the list of tasks
+ */
+ private void setDefaultView() {
+ getListPanel().getChildren().remove(getAliasSymbolPlaceholder());
+ getListPanel().getChildren().remove(getTaskListPlaceholder());
+ getListPanel().getChildren().add(getTaskListPlaceholder());
+ }
+
+ /**
+ * Set to true to show the list of tasks. Set to false to show the list of alias
+ * @param isShown
+ */
+ public void showTaskList(boolean isShown) {
+ getListPanel().getChildren().remove(getAliasSymbolPlaceholder());
+ getListPanel().getChildren().remove(getTaskListPlaceholder());
+ if (isShown) {
+ getListPanel().getChildren().add(getTaskListPlaceholder());
+ } else {
+ getListPanel().getChildren().add(getAliasSymbolPlaceholder());
+ }
+ }
+
+ private VBox getListPanel() {
+ return listPanel;
+ }
+
+ private VBox getRootLayout() {
+ return rootLayout;
+ }
+
+ private AnchorPane getCommandBoxPlaceholder() {
+ return commandBoxPlaceholder;
+ }
+
+ private AnchorPane getStatusbarPlaceholder() {
+ return statusbarPlaceholder;
+ }
+
+ private AnchorPane getResultDisplayPlaceholder() {
+ return resultDisplayPlaceholder;
+ }
+
+ public AnchorPane getTaskListPlaceholder() {
+ return taskListPanelPlaceholder;
+ }
+
+ public AnchorPane getAliasSymbolPlaceholder() {
+ return aliasSymbolListPanelPlaceholder;
+ }
+
+ private AnchorPane getFloatingPanelPlaceholder() {
+ return floatingPanelPlaceholder;
+ }
+
+ private AnchorPane getDailyPanelPlaceholder(int index) {
+
+ switch(index) {
+
+ case 0:
+
+ return day1PanelPlaceholder;
+
+ case 1:
+
+ return day2PanelPlaceholder;
+
+ case 2:
+
+ return day3PanelPlaceholder;
+
+ case 3:
+
+ return day4PanelPlaceholder;
+
+ case 4:
+
+ return day5PanelPlaceholder;
+
+ case 5:
+
+ return day6PanelPlaceholder;
+
+ case 6:
+ default:
+
+ return day7PanelPlaceholder;
+
+ }
+
+ }
+
+ private AnchorPane getUpcomingPanelPlaceholder() {
+ return upcomingPanelPlaceholder;
+ }
+
+ private Date addDay(int i, Date date) {
+
+ //convert date object to calendar object and add 1 days
+ Calendar calendarExpectedDate = Calendar.getInstance();
+ calendarExpectedDate.setTime(date);
+
+ calendarExpectedDate.add(Calendar.DATE, i);
+
+ //convert calendar object back to date object
+ date = calendarExpectedDate.getTime();
+
+ return date;
+ }
+
+ public void hide() {
+ primaryStage.hide();
+ }
+
+ private void setTitle(String appTitle) {
+ primaryStage.setTitle(appTitle);
+ }
+
+ /**
+ * Sets the default size based on user preferences.
+ */
+ protected void setWindowDefaultSize(UserPrefs prefs) {
+ primaryStage.setHeight(prefs.getGuiSettings().getWindowHeight());
+ primaryStage.setWidth(prefs.getGuiSettings().getWindowWidth());
+ if (prefs.getGuiSettings().getWindowCoordinates() != null) {
+ primaryStage.setX(prefs.getGuiSettings().getWindowCoordinates().getX());
+ primaryStage.setY(prefs.getGuiSettings().getWindowCoordinates().getY());
+ }
+ }
+
+ private void setWindowMinSize() {
+ primaryStage.setMinHeight(MIN_HEIGHT);
+ primaryStage.setMinWidth(MIN_WIDTH);
+ }
+
+ /**
+ * Returns the current size and the position of the main Window.
+ */
+ public GuiSettings getCurrentGuiSetting() {
+ return new GuiSettings(primaryStage.getWidth(), primaryStage.getHeight(),
+ (int) primaryStage.getX(), (int) primaryStage.getY());
+ }
+
+ @FXML
+ public void handleHelp() {
+ HelpWindow helpWindow = HelpWindow.load(primaryStage);
+ helpWindow.show();
+ }
+
+ public void hideHelp() {
+ HelpWindow helpWindow = HelpWindow.load(primaryStage);
+ helpWindow.hide();
+ }
+
+ public void show() {
+ primaryStage.show();
+ }
+
+ /**
+ * Closes the application.
+ */
+ @FXML
+ private void handleExit() {
+ raise(new ExitAppRequestEvent());
+ }
+
+ public AliasSymbolListPanel getAliasSymbolListPanel() {
+ return this.aliasSymbolListPanel;
+ }
+
+ public TaskListPanel getTaskListPanel() {
+ return this.taskListPanel;
+ }
+
+ public void loadPersonPage(ReadOnlyTask task) {
+ //feature removed
+ //browserPanel.loadPersonPage(task);
+ }
+
+ public void releaseResources() {
+ //feature removed
+ //browserPanel.freeResources();
+ }
+
+ @Subscribe
+ public void handleSavvyTaskerChangedEvent(SavvyTaskerChangedEvent stce) {
+ loadDailyPanel();
+ }
+
+ @Subscribe
+ public void handleWeekSelectionChangedEvent(WeekSelectionChangedEvent stce) {
+ loadDailyPanel();
+ }
+
+ @Subscribe
+ public void handleCheatsheetDisplayToggledEvent(ShowCheatsheetEvent stce) {
+
+ if(isShown == false) {
+ cheatsheet.setVisible(true);
+ isShown = true;
+ } else {
+ cheatsheet.setVisible(false);
+ isShown = false;
+ }
+ }
+
+}
+```
+###### \java\seedu\savvytasker\ui\StatusBarFooter.java
+``` java
+ @Subscribe
+ public void handleSavvyTaskerSaveLocationChangedEvent(DataSavingLocationChangedEvent dslce) {
+ setSaveLocation(dslce.newPath);
+ }
+```
+###### \java\seedu\savvytasker\ui\TaskCard.java
+``` java
+
+package seedu.savvytasker.ui;
+
+import java.util.Date;
+
+import javafx.fxml.FXML;
+import javafx.scene.Node;
+import javafx.scene.control.Label;
+import javafx.scene.image.Image;
+import javafx.scene.image.ImageView;
+import javafx.scene.layout.HBox;
+import seedu.savvytasker.model.task.ReadOnlyTask;
+
+public class TaskCard extends UiPart{
+
+ private static final String FXML = "TaskListCard.fxml";
+
+ private static final String ICON = "/images/overdue.png";
+ private static final Image OVERDUE_IMAGE = new Image(MainWindow.class.getResourceAsStream(ICON));
+
+ public static final String LOW_PRIORITY_BACKGROUND = "-fx-background-color:#CEFFDC";
+ public static final String MEDIUM_PRIORITY_BACKGROUND = "-fx-background-color:#FFFED8";
+ public static final String HIGH_PRIORITY_BACKGROUND = "-fx-background-color:#FF8180";
+
+ @FXML
+ private HBox cardPane;
+ @FXML
+ private Label taskName;
+ @FXML
+ private Label id;
+ @FXML
+ private Label details;
+ @FXML
+ private ImageView overdueIcon;
+
+ private boolean isShowingIndex;
+ private ReadOnlyTask task;
+ private int displayedIndex;
+
+ public TaskCard(boolean isShowingIndex){
+ this.isShowingIndex = isShowingIndex;
+ }
+
+ public static TaskCard load(ReadOnlyTask task, int displayedIndex, boolean isShowingIndex){
+ TaskCard card = new TaskCard(isShowingIndex);
+ card.task = task;
+ card.displayedIndex = displayedIndex;
+ return UiPartLoader.loadUiPart(card);
+ }
+
+ @FXML
+ public void initialize() {
+
+ taskName.setText(task.getTaskName());
+ if (isShowingIndex) {
+ id.setText(displayedIndex + ". ");
+ }
+ details.setText(task.getTextForUi());
+ setCardBackground();
+ setOverdue();
+
+ }
+
+ public HBox getLayout() {
+ return cardPane;
+ }
+
+ private void setOverdue() {
+
+ Date today = new Date();
+
+ if (task.getEndDateTime() != null) {
+
+ Date endDateTime = task.getEndDateTime();
+
+ if (endDateTime.compareTo(today)<0 && task.isArchived() == false) {
+
+ overdueIcon.setImage(OVERDUE_IMAGE);
+ }
+ }
+
+ }
+ private void setCardBackground() {
+
+ if (task.getPriority().toString().equals("High")) {
+
+ cardPane.setStyle(HIGH_PRIORITY_BACKGROUND);
+
+ } else if (task.getPriority().toString().equals("Medium")) {
+
+ cardPane.setStyle(MEDIUM_PRIORITY_BACKGROUND);
+
+ } else if (task.getPriority().toString().equals("Low")) {
+
+ cardPane.setStyle(LOW_PRIORITY_BACKGROUND);
+
+ }
+
+ }
+
+
+ @Override
+ public void setNode(Node node) {
+ cardPane = (HBox)node;
+ }
+
+ @Override
+ public String getFxmlPath() {
+ return FXML;
+ }
+}
+```
+###### \java\seedu\savvytasker\ui\UpcomingPanel.java
+``` java
+
+/**
+* Panel containing the list overdue task.
+* @author A0138431L
+*
+*/
+public class UpcomingPanel extends UiPart {
+ private final Logger logger = LogsCenter.getLogger(TaskListPanel.class);
+ private static final String FXML = "UpcomingList.fxml";
+ private VBox panel;
+ private AnchorPane placeHolderPane;
+
+ @FXML
+ private ListView taskListView;
+
+ public UpcomingPanel() {
+ super();
+ }
+
+ @Override
+ public void setNode(Node node) {
+ panel = (VBox) node;
+ }
+
+ @Override
+ public String getFxmlPath() {
+ return FXML;
+ }
+
+ @Override
+ public void setPlaceholder(AnchorPane pane) {
+ this.placeHolderPane = pane;
+ }
+
+ public static UpcomingPanel load(Stage primaryStage, AnchorPane UpcomingListPlaceholder,
+ ObservableList taskList) {
+ UpcomingPanel upcomingPanel =
+ UiPartLoader.loadUiPart(primaryStage, UpcomingListPlaceholder, new UpcomingPanel());
+ upcomingPanel.configure(taskList);
+ return upcomingPanel;
+ }
+
+ private void configure(ObservableList taskList) {
+ setConnections(taskList);
+ addToPlaceholder();
+ }
+
+ private void setConnections(ObservableList taskList) {
+ taskListView.setItems(taskList);
+ taskListView.setCellFactory(listView -> new TaskListViewCell());
+ setEventHandlerForSelectionChangeEvent();
+ }
+
+ private void addToPlaceholder() {
+ SplitPane.setResizableWithParent(placeHolderPane, false);
+ placeHolderPane.getChildren().add(panel);
+ }
+
+ private void setEventHandlerForSelectionChangeEvent() {
+ taskListView.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
+ if (newValue != null) {
+ logger.fine("Selection in upcoming task list panel changed to : '" + newValue + "'");
+ raise(new TaskPanelSelectionChangedEvent(newValue));
+ }
+ });
+ }
+
+ public void scrollTo(int index) {
+ Platform.runLater(() -> {
+ taskListView.scrollTo(index);
+ taskListView.getSelectionModel().clearAndSelect(index);
+ });
+ }
+
+ class TaskListViewCell extends ListCell {
+
+ public TaskListViewCell() {
+ }
+
+ @Override
+ protected void updateItem(ReadOnlyTask task, boolean empty) {
+ super.updateItem(task, empty);
+
+ if (empty || task == null) {
+ setGraphic(null);
+ setText(null);
+ } else {
+ setGraphic(TaskCard.load(task, 0, false).getLayout());
+ }
+ }
+ }
+
+}
+```
+###### \resources\view\DarkTheme.css
+``` css
+.background {
+ -fx-background-color: derive(#1d1d1d, 20%);
+}
+
+.label {
+ -fx-font-size: 11pt;
+ -fx-font-family: "Segoe UI Semibold";
+ -fx-text-fill: #555555;
+ -fx-opacity: 0.9;
+}
+
+.label-bright {
+ -fx-font-size: 11pt;
+ -fx-font-family: "Segoe UI Semibold";
+ -fx-text-fill: white;
+ -fx-opacity: 1;
+}
+
+.label-header {
+ -fx-font-size: 32pt;
+ -fx-font-family: "Segoe UI Light";
+ -fx-text-fill: white;
+ -fx-opacity: 1;
+}
+
+.text-field {
+ -fx-font-size: 12pt;
+ -fx-font-family: "Segoe UI Semibold";
+}
+
+.tab-pane {
+ -fx-padding: 0 0 0 1;
+}
+
+.tab-pane .tab-header-area {
+ -fx-padding: 0 0 0 0;
+ -fx-min-height: 0;
+ -fx-max-height: 0;
+}
+
+.table-view {
+ -fx-base: #1d1d1d;
+ -fx-control-inner-background: #1d1d1d;
+ -fx-background-color: #1d1d1d;
+ -fx-table-cell-border-color: transparent;
+ -fx-table-header-border-color: transparent;
+ -fx-padding: 5;
+}
+
+.table-view .column-header-background {
+ -fx-background-color: transparent;
+}
+
+.table-view .column-header, .table-view .filler {
+ -fx-size: 35;
+ -fx-border-width: 0 0 1 0;
+ -fx-background-color: transparent;
+ -fx-border-color:
+ transparent
+ transparent
+ derive(-fx-base, 80%)
+ transparent;
+ -fx-border-insets: 0 10 1 0;
+}
+
+.table-view .column-header .label {
+ -fx-font-size: 20pt;
+ -fx-font-family: "Segoe UI Light";
+ -fx-text-fill: white;
+ -fx-alignment: center-left;
+ -fx-opacity: 1;
+}
+
+.table-view:focused .table-row-cell:filled:focused:selected {
+ -fx-background-color: -fx-focus-color;
+}
+
+.split-pane:horizontal .split-pane-divider {
+ -fx-border-color: transparent #1d1d1d transparent #1d1d1d;
+ -fx-background-color: transparent, derive(#1d1d1d, 10%);
+}
+
+.split-pane {
+ -fx-border-radius: 1;
+ -fx-border-width: 1;
+ -fx-background-color: derive(#1d1d1d, 20%);
+}
+
+.list-cell {
+ -fx-label-padding: 0 0 0 0;
+ -fx-graphic-text-gap : 0;
+ -fx-padding: 0 0 0 0;
+}
+
+.list-cell .label {
+ -fx-text-fill: #010504;
+ -fx-font-family:'Helvetica Condensed';
+}
+
+.cell_big_label {
+ -fx-font-size: 12px;
+ -fx-text-fill: #010504;
+ -fx-font-family:'Helvetica Condensed';
+}
+
+.cell_small_label {
+ -fx-font-size: 10px;
+ -fx-text-fill: #696969;
+}
+
+.anchor-pane {
+ -fx-background-color: derive(#1d1d1d, 20%);
+}
+
+.anchor-pane-with-border {
+ -fx-background-color: derive(#1d1d1d, 20%);
+ -fx-border-color: derive(#1d1d1d, 10%);
+ -fx-border-top-width: 1px;
+}
+
+.status-bar {
+ -fx-background-color: derive(#1d1d1d, 20%);
+ -fx-text-fill: black;
+}
+
+.result-display {
+ -fx-background-color: transparent;
+}
+
+.result-display .content {
+ -fx-background-color: #383838;
+}
+
+.result-display .label {
+ -fx-text-fill: black !important;
+}
+
+.status-bar .label {
+ -fx-text-fill: white;
+}
+
+.status-bar-with-border {
+ -fx-background-color: derive(#1d1d1d, 30%);
+ -fx-border-color: derive(#1d1d1d, 25%);
+ -fx-border-width: 1px;
+}
+
+.status-bar-with-border .label {
+ -fx-text-fill: white;
+}
+
+.grid-pane {
+ -fx-background-color: derive(#1d1d1d, 30%);
+ -fx-border-color: derive(#1d1d1d, 30%);
+ -fx-border-width: 1px;
+}
+
+.grid-pane .anchor-pane {
+ -fx-background-color: derive(#1d1d1d, 30%);
+}
+
+.context-menu {
+ -fx-background-color: derive(#1d1d1d, 50%);
+}
+
+.context-menu .label {
+ -fx-text-fill: white;
+}
+
+.menu-bar {
+ -fx-background-color: derive(#1d1d1d, 20%);
+}
+
+.menu-bar .label {
+ -fx-font-size: 14pt;
+ -fx-font-family: "Segoe UI Light";
+ -fx-text-fill: white;
+ -fx-opacity: 0.9;
+}
+
+.menu .left-container {
+ -fx-background-color: black;
+}
+
+/*
+ * Metro style Push Button
+ * Author: Pedro Duque Vieira
+ * http://pixelduke.wordpress.com/2012/10/23/jmetro-windows-8-controls-on-java/
+ */
+.button {
+ -fx-padding: 5 22 5 22;
+ -fx-border-color: #e2e2e2;
+ -fx-border-width: 2;
+ -fx-background-radius: 0;
+ -fx-background-color: #1d1d1d;
+ -fx-font-family: "Segoe UI", Helvetica, Arial, sans-serif;
+ -fx-font-size: 11pt;
+ -fx-text-fill: #d8d8d8;
+ -fx-background-insets: 0 0 0 0, 0, 1, 2;
+}
+
+.button:hover {
+ -fx-background-color: #3a3a3a;
+}
+
+.button:pressed, .button:default:hover:pressed {
+ -fx-background-color: white;
+ -fx-text-fill: #1d1d1d;
+}
+
+.button:focused {
+ -fx-border-color: white, white;
+ -fx-border-width: 1, 1;
+ -fx-border-style: solid, segments(1, 1);
+ -fx-border-radius: 0, 0;
+ -fx-border-insets: 1 1 1 1, 0;
+}
+
+.button:disabled, .button:default:disabled {
+ -fx-opacity: 0.4;
+ -fx-background-color: #1d1d1d;
+ -fx-text-fill: white;
+}
+
+.button:default {
+ -fx-background-color: -fx-focus-color;
+ -fx-text-fill: #ffffff;
+}
+
+.button:default:hover {
+ -fx-background-color: derive(-fx-focus-color, 30%);
+}
+
+.dialog-pane {
+ -fx-background-color: #1d1d1d;
+}
+
+.dialog-pane > *.button-bar > *.container {
+ -fx-background-color: #1d1d1d;
+}
+
+.dialog-pane > *.label.content {
+ -fx-font-size: 14px;
+ -fx-font-weight: bold;
+ -fx-text-fill: white;
+}
+
+.dialog-pane:header *.header-panel {
+ -fx-background-color: derive(#1d1d1d, 25%);
+}
+
+.dialog-pane:header *.header-panel *.label {
+ -fx-font-size: 18px;
+ -fx-font-style: italic;
+ -fx-fill: white;
+ -fx-text-fill: white;
+}
+
+.scroll-bar .thumb {
+ -fx-background-color: derive(#1d1d1d, 50%);
+ -fx-background-insets: 3;
+}
+
+.scroll-bar .increment-button, .scroll-bar .decrement-button {
+ -fx-background-color: transparent;
+ -fx-padding: 0 0 0 0;
+}
+
+.scroll-bar .increment-arrow, .scroll-bar .decrement-arrow {
+ -fx-shape: " ";
+}
+
+.scroll-bar:vertical .increment-arrow, .scroll-bar:vertical .decrement-arrow {
+ -fx-padding: 1 8 1 8;
+}
+
+.scroll-bar:horizontal .increment-arrow, .scroll-bar:horizontal .decrement-arrow {
+ -fx-padding: 8 1 8 1;
+}
+
+.cardPane {
+ -fx-border-color: #ffffff;
+ -fx-border-radius: 5px;
+}
+
+#commandTypeLabel {
+ -fx-font-size: 11px;
+ -fx-text-fill: #F70D1A;
+}
+
+#filterField, #personListPanel, #personWebpage {
+ -fx-effect: innershadow(gaussian, black, 10, 0, 0, 0);
+}
+
+#taskListView {
+ -fx-background-color: transparent;
+}
+
+#header {
+ fx-font-size: 11px;
+ -fx-text-fill: #000000;
+ -fx-font-family:'Helvetica Condensed';
+}
+
+/*------------------------------------------ FloatingPanel Styling ------------------------------------------*/
+
+.floating-scrollpane, .floating-panel {
+ -fx-background-color:#ACEDFF;
+ -fx-border-radius: 15px;
+ -fx-font-size: 14px;
+ -fx-text-fill: #000000;
+ -fx-font-family:'Helvetica Bold';
+}
+
+.floating-scrollpane {
+ -fx-border-radius: 15px;
+}
+
+.floating-scrollpane > .scroll-bar:horizontal .thumb,
+.floating-scrollpane > .scroll-bar:vertical .thumb {
+ -fx-background-color:#406C7F;
+}
+
+.floating-panel .title, .floating-panel .taskname {
+ -fx-text-fill:#000000;
+}
+
+.floating-panel .subtitle, .floating-panel .timestamp {
+ -fx-text-fill:#5997BS2;
+}
+
+/*------------------------------------------ DailyPanel Styling ------------------------------------------*/
+
+.daily-scrollpane, .daily-panel {
+ -fx-background-color:#99D3FF;
+ -fx-border-radius: 15px;
+ -fx-font-size: 14px;
+ -fx-text-fill: #000000;
+ -fx-font-family:'Helvetica Bold';
+}
+
+.daily-scrollpane > .scroll-bar:horizontal .thumb,
+.daily-scrollpane > .scroll-bar:vertical .thumb {
+ -fx-background-color:#7E7E45;
+}
+
+.daily-panel .title, .daily-panel .taskname {
+ -fx-text-fill:#5D5D33;
+}
+
+.daily-panel .subtitle, .daily-panel .timestamp {
+ -fx-text-fill:#B2B262;
+}
+
+/*------------------------------------------ UpcomingPanel Styling ------------------------------------------*/
+.upcoming-scrollpane, .upcoming-panel {
+ -fx-background-color:#D1E0FF;
+ -fx-border-radius: 15px;
+ -fx-font-size: 14px;
+ -fx-text-fill: #000000;
+ -fx-font-family:'Helvetica Bold';
+}
+
+.upcoming-scrollpane > .scroll-bar:horizontal .thumb,
+.upcoming-scrollpane > .scroll-bar:vertical .thumb {
+ -fx-background-color:#657E47;
+}
+
+.upcoming-panel .check-box > .box {
+ -fx-border-color:#657E47;
+}
+
+.upcoming-panel .check-box {
+ -fx-font-family:'Helvetica';
+ -fx-text-fill:#485A33;
+ -fx-font-size:10;
+ -fx-font-weight:bold;
+}
+
+.upcoming-panel .title, .upcoming-panel .taskname {
+ -fx-text-fill:#485A33;
+}
+
+.upcoming-panel .subtitle, .upcoming-panel .timestamp {
+ -fx-text-fill:#8EB264;
+}
+
+/*------------------------------------------ ArchivedPanel Styling ------------------------------------------*/
+
+.archived-panel .title {
+ -fx-font-family:'Helvetica Condensed';
+ -fx-font-size:24;
+ -fx-font-weight:normal;
+}
+
+.archived-panel .taskname, .archived-panel .timestamp {
+ -fx-text-fill:#FFFFFF;
+}
+```
diff --git a/collated/main/A0139915W.md b/collated/main/A0139915W.md
index 150582cad2c3..e81b39e96c3d 100644
--- a/collated/main/A0139915W.md
+++ b/collated/main/A0139915W.md
@@ -1,27 +1,4 @@
# A0139915W
-###### \java\seedu\savvytasker\commons\events\storage\DataSavingLocationChangedEvent.java
-``` java
-/**
- * Indicates a change in location of the storage
- */
-public class DataSavingLocationChangedEvent extends BaseEvent {
-
- public final ReadOnlySavvyTasker data;
- public final String newPath;
-
- public DataSavingLocationChangedEvent(ReadOnlySavvyTasker data, String newPath) {
- this.data = data;
- this.newPath = newPath;
- }
-
- @Override
- public String toString() {
- return "number of tasks " + data.getReadOnlyListOfTasks().size() +
- " new path " + this.newPath;
- }
-
-}
-```
###### \java\seedu\savvytasker\commons\events\ui\TaskPanelSelectionChangedEvent.java
``` java
@@ -57,7 +34,6 @@ public class TaskPanelSelectionChangedEvent extends BaseEvent {
``` java
/**
* Helper functions for handling dates.
- * @author A0139915W
*/
public class SmartDefaultDates {
@@ -77,41 +53,37 @@ public class SmartDefaultDates {
calendar = Calendar.getInstance();
today = Calendar.getInstance();
today.setTime(new Date());
- if (startDateTime == null && endDateTime == null) {
- // dates not being supplied, nothing to parse
- } else if (startDateTime == null && endDateTime != null) {
+ if (startDateTime == null && endDateTime != null) {
// apply smart default for endDateTime only
parseEnd(endDateTime);
} else if (startDateTime != null && endDateTime == null) {
// apply smart default for startDateTime only
parseStart(startDateTime);
- } else {
+ } else if (startDateTime != null && endDateTime != null) {
parseStartAndEnd(startDateTime, endDateTime);
}
}
/**
- * Gets the smart default for end date
+ * Gets the smart defaults for end date.
+ *
+ * If the date is not supplied, the date will default to today.
+ * If the time is not supplied, the time will default to 2359:59 on the specified date.
+ * If both date and time are not supplied, the date returned will be null.
* @param today the time now
* @param endDateTime the end time to parse
- * @return
*/
public Date getEnd(InferredDate endDateTime) {
if (endDateTime == null) return null;
calendar.setTime(endDateTime.getInferredDateTime());
if (endDateTime.isDateInferred() && endDateTime.isTimeInferred()) {
- // user didn't specify anything
// remove date field
return null;
} else if (endDateTime.isDateInferred()) {
- // date not supplied
- // defaults to today
calendar.set(Calendar.DATE, today.get(Calendar.DATE));
calendar.set(Calendar.MONTH, today.get(Calendar.MONTH));
calendar.set(Calendar.YEAR, today.get(Calendar.YEAR));
} else if (endDateTime.isTimeInferred()) {
- // time not supplied
- // defaults to 2359
calendar.set(Calendar.HOUR_OF_DAY, 23);
calendar.set(Calendar.MINUTE, 59);
calendar.set(Calendar.SECOND, 59);
@@ -146,7 +118,11 @@ public class SmartDefaultDates {
/**
- * Gets the smart default for start date
+ * Gets the smart default for start date.
+ *
+ * If the date is not supplied, the date will default to today.
+ * If the time is not supplied, the time will default to 0000:00 on the specified date.
+ * If both date and time are not supplied, the date returned will be null.
* @param today the time now
* @param startDateTime the start time to parse
* @return
@@ -159,14 +135,10 @@ public class SmartDefaultDates {
// remove date field
return null;
} else if (startDateTime.isDateInferred()) {
- // date not supplied
- // defaults to today
calendar.set(Calendar.DATE, today.get(Calendar.DATE));
calendar.set(Calendar.MONTH, today.get(Calendar.MONTH));
calendar.set(Calendar.YEAR, today.get(Calendar.YEAR));
} else if (startDateTime.isTimeInferred()) {
- // time not supplied
- // defaults to 0000
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
@@ -197,8 +169,12 @@ public class SmartDefaultDates {
/**
* Sets the starting and ending date/time based on defaults for providing both
- * start and end times
+ * start and end times.
+ *
+ * Note that this method has no restrictions on the starting and ending date/time.
+ * i.e. the starting time is later than the ending time.
* @param startDateTime start time supplied
+ * @param endDateTime end time supplied
*/
private void parseStartAndEnd(InferredDate startDateTime, InferredDate endDateTime) {
assert endDateTime.getInferredDateTime() != null;
@@ -288,11 +264,10 @@ public class SmartDefaultDates {
addToListOfTasksAdded(tasksAdded.toArray(new Task[tasksAdded.size()]));
}
+ // always >= 0 unless this is being run without UI.
int targetIndex = getIndexOfTask(taskAdded);
if (targetIndex >= 0) {
EventsCenter.getInstance().post(new JumpToListRequestEvent(targetIndex));
- } else {
- // GUI should never ever get here
}
return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd));
} catch (InvalidDateException ex) {
@@ -370,7 +345,6 @@ public class SmartDefaultDates {
``` java
/**
* Creates the List command to list the specified tasks
- * @author A0139915W
* @param commandModel Arguments for the List command, must not be null
*/
public ListCommand(ListType listType) {
@@ -389,9 +363,6 @@ public class SmartDefaultDates {
// specifies to show the alias
switch (_listType)
{
- case DueDate:
- model.updateFilteredListToShowActiveSortedByDueDate();
- break;
case PriorityLevel:
model.updateFilteredListToShowActiveSortedByPriorityLevel();
break;
@@ -401,10 +372,13 @@ public class SmartDefaultDates {
case Alias:
EventsCenter.getInstance().post(new ChangeListRequestEvent(DisplayedList.Alias));
break;
- default:
- // nothing to do
+ case DueDate:
+ // fall through.
+ default: // shows lists sorted by due date by default
+ model.updateFilteredListToShowActiveSortedByDueDate();
break;
}
+
if (_listType != ListType.Alias) {
EventsCenter.getInstance().post(new ChangeListRequestEvent(DisplayedList.Task));
return new CommandResult(getMessageForTaskListShownSummary(model.getFilteredTaskList().size()));
@@ -446,7 +420,7 @@ public class SmartDefaultDates {
}
ReadOnlyTask taskToModify = lastShownList.get(index - 1);
- replacement = new Task(taskToModify, taskName, startDateTime,
+ Task replacement = new Task(taskToModify, taskName, startDateTime,
endDateTime, location, priority,
recurringType, numberOfRecurrence,
category, description);
@@ -454,11 +428,11 @@ public class SmartDefaultDates {
try {
originalTask = (Task)taskToModify;
Task taskModified = model.modifyTask(taskToModify, replacement);
+
+ // GUI will always get index >= 0;
int targetIndex = getIndexOfTask(taskModified);
if (targetIndex >= 0) {
EventsCenter.getInstance().post(new JumpToListRequestEvent(targetIndex));
- } else {
- // GUI should never ever get here
}
} catch (TaskNotFoundException e) {
assert false : "The target task cannot be missing";
@@ -479,37 +453,16 @@ public class SmartDefaultDates {
return lastShownList.indexOf(task);
}
```
-###### \java\seedu\savvytasker\logic\commands\StorageAndModelRequiringCommand.java
-``` java
-/**
- * Represents a command which requires the Storage class as a dependency.
- * Commands should inherit this class if they only require dependency for
- * storage and model components
-*/
-public abstract class StorageAndModelRequiringCommand extends Command {
- protected Storage storage;
- protected Model model;
-
- public void setStorage(Storage storage) {
- this.storage = storage;
- }
-
- public void setModel(Model model) {
- this.model = model;
- }
-}
-```
###### \java\seedu\savvytasker\logic\LogicManager.java
``` java
@Override
public ObservableList getFilteredTaskList() {
return model.getFilteredTaskList();
}
-
@Override
public ObservableList getAliasSymbolList() {
return parser.getAliasSymbolList();
- }
+ }
```
###### \java\seedu\savvytasker\logic\parser\FindCommandParser.java
``` java
@@ -527,22 +480,6 @@ public abstract class StorageAndModelRequiringCommand extends Command {
throw new ParseException(commandText, String.format(Messages.MESSAGE_INVALID_COMMAND_FORMAT, getRequiredFormat()));
}
```
-###### \java\seedu\savvytasker\MainApp.java
-``` java
- @Subscribe
- public void handleSavvyTaskerSaveLocationChangedEvent(DataSavingLocationChangedEvent dslce) {
- try {
- String configPath = getApplicationParameter("config");
- if(configPath == null) {
- configPath = Config.DEFAULT_CONFIG_FILE;
- }
- config.setSavvyTaskerFilePath(dslce.newPath);
- ConfigUtil.saveConfig(config, configPath);
- } catch (IOException e) {
- logger.warning("Failed to save config file : " + StringUtil.getDetails(e));
- }
- }
-```
###### \java\seedu\savvytasker\model\Model.java
``` java
/**
@@ -593,39 +530,6 @@ public abstract class StorageAndModelRequiringCommand extends Command {
void updateFilteredTaskList(FindType findType, String[] keywords);
```
###### \java\seedu\savvytasker\model\ModelManager.java
-``` java
- private final SavvyTasker savvyTasker;
- private final FilteredList filteredTasks;
- private final SortedList sortedAndFilteredTasks;
-
- /**
- * Initializes a ModelManager with the given SavvyTasker
- * and its variables should not be null
- */
- public ModelManager(SavvyTasker src) {
- super();
- assert src != null;
-
- logger.fine("Initializing with savvy tasker: " + src);
-
- savvyTasker = new SavvyTasker(src);
- filteredTasks = new FilteredList<>(savvyTasker.getTasks());
- sortedAndFilteredTasks = new SortedList<>(filteredTasks, new TaskSortedByDueDate());
- updateFilteredListToShowActive(); // shows only active tasks on start
- }
-
- public ModelManager() {
- this(new SavvyTasker());
- }
-
- public ModelManager(ReadOnlySavvyTasker initialData) {
- savvyTasker = new SavvyTasker(initialData);
- filteredTasks = new FilteredList<>(savvyTasker.getTasks());
- sortedAndFilteredTasks = new SortedList<>(filteredTasks, new TaskSortedByDueDate());
- updateFilteredListToShowActive(); // shows only active tasks on start
- }
-```
-###### \java\seedu\savvytasker\model\ModelManager.java
``` java
@Override
public synchronized Task deleteTask(ReadOnlyTask target) throws TaskNotFoundException {
@@ -678,55 +582,56 @@ public abstract class StorageAndModelRequiringCommand extends Command {
public void updateFilteredListToShowActive() {
updateFilteredTaskList(new PredicateExpression(new TaskIsActiveQualifier()));
}
- private void updateFilteredListToShowActive(Comparator comparator) {
- updateFilteredTaskList(
- new PredicateExpression(new TaskIsActiveQualifier()),
- comparator);
- }
-
- @Override
- public void updateFilteredListToShowArchived() {
- updateFilteredTaskList(new PredicateExpression(new TaskIsArchivedQualifier()));
- }
-
- @Override
- public void updateFilteredTaskList(FindType findType, String[] keywords) {
- assert findType != null;
- Qualifier qualifier = null;
- switch (findType)
- {
- case Partial:
- qualifier = new TaskNamePartialMatchQualifier(keywords);
- break;
- case Full:
- qualifier = new TaskNameFullMatchQualifier(keywords);
- break;
- case Exact:
- qualifier = new TaskNameExactMatchQualifier(keywords);
- break;
- case Category:
- qualifier = new CategoryPartialMatchQualifier(keywords);
- break;
- default:
- assert false; // should never get here.
- }
- updateFilteredTaskList(new PredicateExpression(qualifier));
- }
- private void updateFilteredTaskList(Expression expression) {
- updateFilteredTaskList(expression, new TaskSortedByDefault());
- }
-
- private void updateFilteredTaskList(Expression expression, Comparator comparator) {
- filteredTasks.setPredicate(expression::satisfies);
- sortedAndFilteredTasks.setComparator(comparator);
- }
+ private void updateFilteredListToShowActive(Comparator comparator) {
+ updateFilteredTaskList(
+ new PredicateExpression(new TaskIsActiveQualifier()),
+ comparator);
+ }
+
+ @Override
+ public void updateFilteredListToShowArchived() {
+ updateFilteredTaskList(new PredicateExpression(new TaskIsArchivedQualifier()));
+ }
+
+ @Override
+ public void updateFilteredTaskList(FindType findType, String[] keywords) {
+ assert findType != null;
+ Qualifier qualifier = null;
+ switch (findType)
+ {
+ case Partial:
+ qualifier = new TaskNamePartialMatchQualifier(keywords);
+ break;
+ case Full:
+ qualifier = new TaskNameFullMatchQualifier(keywords);
+ break;
+ case Exact:
+ qualifier = new TaskNameExactMatchQualifier(keywords);
+ break;
+ case Category:
+ qualifier = new CategoryPartialMatchQualifier(keywords);
+ break;
+ default:
+ assert false; // should never get here.
+ break;
+ }
+ updateFilteredTaskList(new PredicateExpression(qualifier));
+ }
+
+ private void updateFilteredTaskList(Expression expression) {
+ updateFilteredTaskList(expression, new TaskSortedByDefault());
+ }
+
+ private void updateFilteredTaskList(Expression expression, Comparator comparator) {
+ filteredTasks.setPredicate(expression::satisfies);
+ sortedAndFilteredTasks.setComparator(comparator);
+ }
```
###### \java\seedu\savvytasker\model\ModelManager.java
``` java
/**
* Qualifier matching a partial word from the set of keywords
- * @author A0139915W
*/
private class CategoryPartialMatchQualifier implements Qualifier {
private Set keyWordsToMatch;
@@ -751,7 +656,6 @@ public abstract class StorageAndModelRequiringCommand extends Command {
/**
* Qualifier matching a partial word from the set of keywords
- * @author A0139915W
*/
private class TaskNamePartialMatchQualifier implements Qualifier {
private Set keyWordsToMatch;
@@ -776,7 +680,6 @@ public abstract class StorageAndModelRequiringCommand extends Command {
/**
* Qualifier matching a full word from the set of keywords
- * @author A0139915W
*/
private class TaskNameFullMatchQualifier implements Qualifier {
private Set keyWordsToMatch;
@@ -801,7 +704,6 @@ public abstract class StorageAndModelRequiringCommand extends Command {
/**
* Qualifier matching a exactly from the set of keywords
- * @author A0139915W
*/
private class TaskNameExactMatchQualifier implements Qualifier {
private Set keyWordsToMatch;
@@ -845,14 +747,13 @@ public abstract class StorageAndModelRequiringCommand extends Command {
/**
* Qualifier for checking if {@link Task} is active. Tasks that are not archived are active.
- * @author A0139915W
*
*/
private class TaskIsActiveQualifier implements Qualifier {
@Override
public boolean run(ReadOnlyTask task) {
- return task.isArchived() == false;
+ return !task.isArchived();
}
@Override
@@ -863,54 +764,59 @@ public abstract class StorageAndModelRequiringCommand extends Command {
/**
* Qualifier for checking if {@link Task} is archived
- * @author A0139915W
*
*/
private class TaskIsArchivedQualifier implements Qualifier {
@Override
public boolean run(ReadOnlyTask task) {
- return task.isArchived() == true;
+ return task.isArchived();
}
@Override
public String toString() {
return "isArchived=true";
}
- }
-
- //========== Inner classes/interfaces used for sorting ==================================================
+```
+###### \java\seedu\savvytasker\model\ModelManager.java
+``` java
+
+ //========== Inner classes/interfaces used for sorting ==================================================
/**
* Compares {@link Task} by their default field, id
- * @author A0139915W
- *
*/
private class TaskSortedByDefault implements Comparator {
@Override
public int compare(Task task1, Task task2) {
- if (task1 == null && task2 == null) return 0;
- else if (task1 == null) return 1;
- else if (task2 == null) return -1;
- else return task1.getId() - task2.getId();
+ if (task1 == null && task2 == null) {
+ return 0;
+ } else if (task1 == null) {
+ return 1;
+ } else if (task2 == null) {
+ return -1;
+ } else {
+ return task1.getId() - task2.getId();
+ }
}
}
/**
* Compares {@link Task} by their DueDate
- * @author A0139915W
- *
*/
private class TaskSortedByDueDate implements Comparator {
@Override
public int compare(Task task1, Task task2) {
- if (task1 == null && task2 == null) return 0;
- else if (task1 == null) return 1;
- else if (task2 == null) return -1;
- else {
+ if (task1 == null && task2 == null) {
+ return 0;
+ } else if (task1 == null) {
+ return 1;
+ } else if (task2 == null) {
+ return -1;
+ } else {
// End dates can be nulls (floating tasks)
// Check for existence of endDateTime before comparing
if (task1.getEndDateTime() == null &&
@@ -930,8 +836,6 @@ public abstract class StorageAndModelRequiringCommand extends Command {
/**
* Compares {@link Task} by their PriorityLevel
- * @author A0139915W
- *
*/
private class TaskSortedByPriorityLevel implements Comparator {
@@ -1093,8 +997,10 @@ public abstract class StorageAndModelRequiringCommand extends Command {
}
break;
case None:
+ //fall through
default:
assert false; // should not come here
+ break;
}
t.setStartDateTime(startDate);
t.setEndDateTime(endDate);
@@ -1212,8 +1118,10 @@ public interface ReadOnlyTask {
}
if (getDescription() != null && !getDescription().isEmpty()) {
builder.append(" Description: ")
- . append(getDescription());
+ .append(getDescription());
}
+ builder.append(" Archived: ")
+ .append(isArchived());
return builder.toString();
}
@@ -1223,14 +1131,8 @@ public interface ReadOnlyTask {
*/
default String getTextForUi() {
final StringBuilder builder = new StringBuilder();
- if (getStartDateTime() != null) {
- builder.append(" Start: ")
- .append(getStartDateTime())
- .append("\n");
- }
- if (getEndDateTime() != null) {
- builder.append(" End: ")
- .append(getEndDateTime())
+ if (getStartDateTime() != null || getEndDateTime() != null) {
+ builder.append(generateDateTime(getStartDateTime(), getEndDateTime()))
.append("\n");
}
if (getLocation() != null && !getLocation().isEmpty()) {
@@ -1238,9 +1140,6 @@ public interface ReadOnlyTask {
.append(getLocation())
.append("\n");
}
- builder.append(" Priority: ")
- .append(getPriority())
- .append("\n");
if (getCategory() != null && !getCategory().isEmpty()) {
builder.append(" Category: ")
.append(getCategory())
@@ -1251,12 +1150,8 @@ public interface ReadOnlyTask {
.append(getDescription())
.append("\n");
}
- builder.append(" Archived: ")
- .append(isArchived());
return builder.toString();
}
-
-}
```
###### \java\seedu\savvytasker\model\task\Task.java
``` java
@@ -1387,10 +1282,7 @@ public class Task implements ReadOnlyTask {
}
private void setStartDate(InferredDate inferredDate) {
- if (inferredDate == null) {
- // user didn't specify s/
- // keep existing start date
- } else {
+ if (inferredDate != null) {
if (inferredDate.isDateInferred() && inferredDate.isTimeInferred()) {
// user specified s/ but with nothing tagged to it
// remove existing start date
@@ -1405,10 +1297,7 @@ public class Task implements ReadOnlyTask {
}
private void setEndDate(InferredDate inferredDate) {
- if (inferredDate == null) {
- // user didn't specify e/
- // keep existing end date
- } else {
+ if (inferredDate != null) {
if (inferredDate.isDateInferred() && inferredDate.isTimeInferred()) {
// user specified e/ but with nothing tagged to it
// remove existing end date
@@ -1532,8 +1421,11 @@ public class Task implements ReadOnlyTask {
}
public void setArchived(boolean isArchived) {
- if (isArchived) mark();
- else unmark();
+ if (isArchived) {
+ mark();
+ } else {
+ unmark();
+ }
}
/**
@@ -1598,6 +1490,12 @@ public class Task implements ReadOnlyTask {
*/
public class TaskList implements Iterable {
+ private final ObservableList internalList = FXCollections.observableArrayList();
+ private int nextId = 0;
+ private boolean isNextIdInitialized = false;
+ private int nextGroupId = 0;
+ private boolean isNextGroupIdInitialized = false;
+
/**
* Signals that an operation would have violated the 'end time earlier than start time' property of the list.
*/
@@ -1639,17 +1537,6 @@ public class TaskList implements Iterable {
*/
private static final long serialVersionUID = -7591982407764643511L;
}
-
- private final ObservableList internalList = FXCollections.observableArrayList();
- private int nextId = 0;
- private boolean isNextIdInitialized = false;
- private int nextGroupId = 0;
- private boolean isNextGroupIdInitialized = false;
-
- /**
- * Constructs empty TaskList.
- */
- public TaskList() {}
/**
* Gets the next available id for uniquely identifying a task in
@@ -1710,11 +1597,8 @@ public class TaskList implements Iterable {
*/
public boolean isValidStartEnd(ReadOnlyTask toCheck) {
assert toCheck != null;
- if (toCheck.getStartDateTime() != null && toCheck.getEndDateTime() != null &&
- toCheck.getStartDateTime().compareTo(toCheck.getEndDateTime()) >= 0) {
- return false;
- }
- return true;
+ return toCheck.getStartDateTime() == null || toCheck.getEndDateTime() == null ||
+ toCheck.getStartDateTime().compareTo(toCheck.getEndDateTime()) < 0;
}
/**
@@ -1812,19 +1696,6 @@ public class TaskList implements Iterable {
return savvyTaskerStorage.setSavvyTaskerFilePath(path);
}
```
-###### \java\seedu\savvytasker\storage\StorageManager.java
-``` java
- @Override
- @Subscribe
- public void handleSavvyTaskerSaveLocationChangedEvent(DataSavingLocationChangedEvent dslce) {
- logger.info(LogsCenter.getEventHandlingLogMessage(dslce, "Local storage location changed."));
- try {
- saveSavvyTasker(dslce.data);
- } catch (IOException e) {
- raise(new DataSavingExceptionEvent(e));
- }
- }
-```
###### \java\seedu\savvytasker\storage\XmlAdaptedTask.java
``` java
/**
@@ -1918,10 +1789,3 @@ public class XmlAdaptedTask {
return false;
}
```
-###### \java\seedu\savvytasker\ui\StatusBarFooter.java
-``` java
- @Subscribe
- public void handleSavvyTaskerSaveLocationChangedEvent(DataSavingLocationChangedEvent dslce) {
- setSaveLocation(dslce.newPath);
- }
-```
diff --git a/collated/main/A0139916U.md b/collated/main/A0139916U.md
index 466daa605bbd..9d12c61e67f8 100644
--- a/collated/main/A0139916U.md
+++ b/collated/main/A0139916U.md
@@ -195,6 +195,15 @@ public class UnaliasCommand extends ModelRequiringCommand {
```
###### \java\seedu\savvytasker\logic\LogicManager.java
+``` java
+ undoDeque.addLast(command);
+ if (undoDeque.size() > MAX_UNDO_REDO_QUEUE_SIZE) {
+ undoDeque.removeFirst();
+ }
+ redoDeque.clear();
+ }
+```
+###### \java\seedu\savvytasker\logic\LogicManager.java
``` java
private void registerAllDefaultCommandParsers() {
parser.registerCommandParser(new AddCommandParser());
@@ -221,26 +230,34 @@ public class UnaliasCommand extends ModelRequiringCommand {
}
}
+ /**
+ * Undo last command and add it to the redo deque.
+ * @return true if undone successfully, false otherwise
+ */
private boolean undo() {
boolean undone = false;
- if (!undoStack.isEmpty()) {
- Command command = undoStack.pop();
+ if (!undoDeque.isEmpty()) {
+ Command command = undoDeque.removeLast();
command.undo();
- redoStack.push(command);
+ redoDeque.addLast(command);
undone = true;
}
return undone;
}
+ /**
+ * Redo last command and add it to undone deque.
+ * @return true if redone successfully, false otherwise
+ */
private boolean redo() {
boolean redone = false;
- if (!redoStack.isEmpty()) {
- Command command = redoStack.pop();
+ if (!redoDeque.isEmpty()) {
+ Command command = redoDeque.removeLast();
command.redo();
- undoStack.push(command);
+ undoDeque.addLast(command);
redone = true;
}
@@ -294,6 +311,7 @@ public class UnaliasCommand extends ModelRequiringCommand {
```
###### \java\seedu\savvytasker\logic\parser\AddCommandParser.java
``` java
+// Please see CommandParser interface for documentation for many of the overridden methods
package seedu.savvytasker.logic.parser;
import java.util.regex.Matcher;
@@ -415,9 +433,10 @@ public class AliasCommandParser implements CommandParser {
private String parseRepresentation(String originalText) throws ParseException {
String trimmedText = originalText.trim();
- if (trimmedText.isEmpty())
+ if (trimmedText.isEmpty()) {
throw new ParseException(trimmedText, "REPRESENTATION: Needs to be at least one character!");
-
+ }
+
return trimmedText;
}
@@ -607,16 +626,16 @@ public class DateParser {
List dateGroups = this.nattyParser.parse(input);
int totalDates = countDates(dateGroups);
- if (totalDates == 0)
+ if (totalDates == 0) {
throw new ParseException(input, "Failed to understand given date.");
+ }
- if (totalDates > 1)
+ if (totalDates > 1) {
throw new ParseException(input, "Too many dates entered.");
+ }
DateGroup group = dateGroups.get(0);
-
-
return new InferredDate(
group.getDates().get(0),
group.isDateInferred(),
@@ -818,15 +837,17 @@ public class IndexParser {
try {
index = Integer.parseInt(trimmedIndexText);
- if (index <= 0)
+ if (index <= 0) {
parseError = true;
+ }
} catch (NumberFormatException ex) {
parseError = true;
}
- if (parseError)
+ if (parseError) {
throw new ParseException(trimmedIndexText, "Must be a positive whole number.");
-
+ }
+
return index;
}
@@ -858,9 +879,10 @@ public class IndexParser {
parseError = true;
}
- if (parseError)
+ if (parseError) {
throw new ParseException(trimmedIndicesText, INDEX_MUST_BE_POSITIVE);
-
+ }
+
return indices;
}
}
@@ -910,8 +932,9 @@ public class ListCommandParser implements CommandParser {
}
private ListType parseListType(String listTypeText) throws ParseException {
- if (listTypeText == null)
+ if (listTypeText == null) {
return null;
+ }
try {
listTypeText = listTypeText.trim();
@@ -1127,8 +1150,9 @@ public class MasterParser {
String spaces = matcher.group(2); // Preserves the amount of spaces as that may be what user wants
AliasSymbol symbol = aliasingSymbols.get(keyword);
- if (symbol != null)
+ if (symbol != null) {
keyword = symbol.getRepresentation();
+ }
builder.append(keyword);
builder.append(spaces);
@@ -1154,10 +1178,12 @@ public class MasterParser {
public boolean registerCommandParser(CommandParser extends Command> commandParser) {
assert commandParser != null;
- if (commandParsers.containsKey(commandParser.getHeader()))
+ if (commandParsers.containsKey(commandParser.getHeader())) {
return false;
- if (aliasingSymbols.containsKey(commandParser.getHeader()))
+ }
+ if (aliasingSymbols.containsKey(commandParser.getHeader())) {
return false;
+ }
commandParsers.put(commandParser.getHeader(), commandParser);
return true;
@@ -1197,10 +1223,12 @@ public class MasterParser {
public boolean addAliasSymbol(AliasSymbol symbol) {
assert symbol != null;
- if (aliasingSymbols.containsKey(symbol.getKeyword()))
+ if (aliasingSymbols.containsKey(symbol.getKeyword())) {
return false;
- if (isCommandParserRegistered(symbol.getKeyword()))
+ }
+ if (isCommandParserRegistered(symbol.getKeyword())) {
return false;
+ }
aliasList.add(symbol);
aliasingSymbols.put(symbol.getKeyword(), symbol);
@@ -1479,7 +1507,8 @@ import seedu.savvytasker.model.task.RecurrenceType;
/**
* This class contains common parsing methods for parsing Task fields.
* Each of the parse method takes in a string which can be null, and return
- * the respective parsed object.
+ * the respective parsed object. If null is provided to each of the parse methods,
+ * null will be returned.
*/
public abstract class TaskFieldParser implements CommandParser {
/*
@@ -1502,8 +1531,9 @@ public abstract class TaskFieldParser implements CommandParse
}
protected String parseTaskName(String taskNameText) throws ParseException {
- if (taskNameText == null)
+ if (taskNameText == null) {
return null;
+ }
return taskNameText.trim();
}
@@ -1516,9 +1546,9 @@ public abstract class TaskFieldParser implements CommandParse
}
private InferredDate parseDate(String dateText, String errorField) throws ParseException {
- if (dateText == null)
+ if (dateText == null) {
return null;
-
+ }
String trimmedDateText = dateText.trim();
try {
return dateParser.parseSingle(trimmedDateText);
@@ -1528,14 +1558,16 @@ public abstract class TaskFieldParser implements CommandParse
}
protected String parseLocation(String locationText) throws ParseException {
- if (locationText == null)
+ if (locationText == null) {
return null;
+ }
return locationText.trim();
}
protected PriorityLevel parsePriorityLevel(String priorityLevelText) throws ParseException {
- if (priorityLevelText == null)
+ if (priorityLevelText == null) {
return null;
+ }
String trimmedPriorityLevelText = priorityLevelText.trim();
try {
@@ -1546,8 +1578,9 @@ public abstract class TaskFieldParser implements CommandParse
}
protected RecurrenceType parseRecurrenceType(String recurrenceTypeText) throws ParseException {
- if (recurrenceTypeText == null)
+ if (recurrenceTypeText == null) {
return null;
+ }
String trimmedRecurrenceTypeText = recurrenceTypeText.trim();
try {
@@ -1558,8 +1591,9 @@ public abstract class TaskFieldParser implements CommandParse
}
protected Integer parseNumberOfRecurrence(String numRecurrenceText) throws ParseException {
- if (numRecurrenceText == null)
+ if (numRecurrenceText == null) {
return null;
+ }
String trimmedNumRecurrenceText = numRecurrenceText.trim();
int numRecurrence = 0;
@@ -1567,30 +1601,33 @@ public abstract class TaskFieldParser implements CommandParse
try {
numRecurrence = Integer.parseInt(trimmedNumRecurrenceText);
- if (numRecurrence < 0)
+ if (numRecurrence < 0) {
parseError = true;
+ }
} catch (NumberFormatException ex) {
parseError = true;
}
- if (parseError)
+ if (parseError) {
throw new ParseException(trimmedNumRecurrenceText, "NUMBER_OF_RECURRENCE: Must be a nonnegative whole number!");
+ }
return numRecurrence;
}
protected String parseCategory(String categoryText) throws ParseException {
- if (categoryText == null)
+ if (categoryText == null) {
return null;
+ }
return categoryText.trim();
}
protected String parseDescription(String descriptionText) throws ParseException {
- if (descriptionText == null)
+ if (descriptionText == null) {
return null;
+ }
return descriptionText.trim();
}
-}
```
###### \java\seedu\savvytasker\logic\parser\UnaliasCommandParser.java
``` java
@@ -1987,8 +2024,9 @@ public enum ListType {
*/
public static ListType valueOfIgnoreCase(String name) {
for (ListType type : ListType.values()) {
- if (type.toString().equalsIgnoreCase(name))
+ if (type.toString().equalsIgnoreCase(name)) {
return type;
+ }
}
throw new IllegalArgumentException("Unknown list type: " + name);
@@ -1998,13 +2036,13 @@ public enum ListType {
###### \java\seedu\savvytasker\model\ModelManager.java
``` java
- private void indicateAliasSymbolAdded(AliasSymbol symbol) {
- raise(new AliasSymbolChangedEvent(symbol, AliasSymbolChangedEvent.Action.Added));
- }
-
- private void indicateAliasSymbolRemoved(AliasSymbol symbol) {
- raise(new AliasSymbolChangedEvent(symbol, AliasSymbolChangedEvent.Action.Removed));
- }
+ private void indicateAliasSymbolAdded(AliasSymbol symbol) {
+ raise(new AliasSymbolChangedEvent(symbol, AliasSymbolChangedEvent.Action.Added));
+ }
+
+ private void indicateAliasSymbolRemoved(AliasSymbol symbol) {
+ raise(new AliasSymbolChangedEvent(symbol, AliasSymbolChangedEvent.Action.Removed));
+ }
```
###### \java\seedu\savvytasker\model\ModelManager.java
``` java
@@ -2118,8 +2156,9 @@ public enum FindType {
*/
public static FindType valueOfIgnoreCase(String name) {
for (FindType type : FindType.values()) {
- if (type.toString().equalsIgnoreCase(name))
+ if (type.toString().equalsIgnoreCase(name)) {
return type;
+ }
}
throw new IllegalArgumentException("Unknown find type: " + name);
@@ -2145,8 +2184,9 @@ public enum PriorityLevel {
*/
public static PriorityLevel valueOfIgnoreCase(String name) {
for (PriorityLevel type : PriorityLevel.values()) {
- if (type.toString().equalsIgnoreCase(name))
+ if (type.toString().equalsIgnoreCase(name)) {
return type;
+ }
}
throw new IllegalArgumentException("Unknown priority level: " + name);
@@ -2189,8 +2229,9 @@ public enum RecurrenceType {
*/
public static RecurrenceType valueOfIgnoreCase(String name) {
for (RecurrenceType type : RecurrenceType.values()) {
- if (type.toString().equalsIgnoreCase(name))
+ if (type.toString().equalsIgnoreCase(name)) {
return type;
+ }
}
throw new IllegalArgumentException("Unknown recurrence type: " + name);
diff --git a/collated/test/A0097627N.md b/collated/test/A0097627N.md
new file mode 100644
index 000000000000..72053ece4fe2
--- /dev/null
+++ b/collated/test/A0097627N.md
@@ -0,0 +1,300 @@
+# A0097627N
+###### \java\guitests\RedoCommandTest.java
+``` java
+package guitests;
+
+import guitests.guihandles.TaskCardHandle;
+
+import org.junit.Test;
+
+import seedu.savvytasker.logic.commands.UndoCommand;
+import seedu.savvytasker.logic.commands.RedoCommand;
+import seedu.savvytasker.logic.commands.HelpCommand;
+import seedu.savvytasker.testutil.TestTask;
+import seedu.savvytasker.testutil.TestUtil;
+
+import static org.junit.Assert.assertTrue;
+import static seedu.savvytasker.commons.core.Messages.MESSAGE_UNKNOWN_COMMAND;
+import static seedu.savvytasker.logic.commands.RedoCommand.MESSAGE_REDO_ACKNOWLEDGEMENT;
+
+public class RedoCommandTest extends SavvyTaskerGuiTest {
+
+ TestTask[] expectedList = td.getTypicalTasks();
+ TestTask[] currentList = td.getTypicalTasks();
+ TestTask firstTaskToAdd = td.happy;
+ TestTask secondTaskToAdd = td.haloween;
+ TestTask pjmTaskToAdd = td.pjm;
+ TestTask projectMeetingTaskToAdd = td.projectMeeting;
+
+ @Test
+ // redo one add command
+ public void redoAddTest() {
+ expectedList = TestUtil.addTasksToList(currentList, firstTaskToAdd);
+ commandBox.runCommand(firstTaskToAdd.getAddCommand());
+ commandBox.runCommand("undo");
+ commandBox.runCommand("redo");
+ assertTrue(taskListPanel.isListMatching(expectedList));
+ assertResultMessage(MESSAGE_REDO_ACKNOWLEDGEMENT);
+ }
+
+ @Test
+ // redo a delete command
+ public void redoDeleteTest() {
+ expectedList = TestUtil.removeTaskFromList(currentList, 1);
+ commandBox.runCommand("delete 1");
+ commandBox.runCommand("undo");
+ commandBox.runCommand("redo");
+ assertTrue(taskListPanel.isListMatching(expectedList));
+ assertResultMessage(MESSAGE_REDO_ACKNOWLEDGEMENT);
+ }
+
+ @Test
+ // redo clear command
+ public void redoClearTest() {
+ commandBox.runCommand("clear");
+ commandBox.runCommand("undo");
+ commandBox.runCommand("redo");
+ assertListSize(0);
+ assertResultMessage(MESSAGE_REDO_ACKNOWLEDGEMENT);
+ }
+
+ @Test
+ // redo alias command
+ public void redoAliasTest() {
+ expectedList = td.getTypicalTasks();
+ expectedList = TestUtil.addTasksToList(expectedList, projectMeetingTaskToAdd);
+ commandBox.runCommand("alias k/pjm r/Project Meeting");
+ commandBox.runCommand("undo");
+ commandBox.runCommand("redo");
+ assertResultMessage(MESSAGE_REDO_ACKNOWLEDGEMENT);
+ commandBox.runCommand(pjmTaskToAdd.getAddCommand());
+ assertTrue(taskListPanel.isListMatching(expectedList));
+ }
+
+ @Test
+ // redo unalias command
+ public void redoUnaliasTest() {
+ expectedList = TestUtil.addTasksToList(currentList, pjmTaskToAdd);
+ commandBox.runCommand("alias k/pjm r/Project Meeting");
+ commandBox.runCommand("unalias pjm");
+ commandBox.runCommand("undo");
+ commandBox.runCommand("redo");
+ assertResultMessage(MESSAGE_REDO_ACKNOWLEDGEMENT);
+ commandBox.runCommand(pjmTaskToAdd.getAddCommand());
+ assertTrue(taskListPanel.isListMatching(expectedList));
+ }
+
+ // redo two add commands
+ @Test
+ public void redoTwoAddTest() {
+ expectedList = TestUtil.addTasksToList(currentList, firstTaskToAdd);
+ expectedList = TestUtil.addTasksToList(expectedList, secondTaskToAdd);
+ commandBox.runCommand(firstTaskToAdd.getAddCommand());
+ commandBox.runCommand(secondTaskToAdd.getAddCommand());
+ commandBox.runCommand("undo");
+ commandBox.runCommand("undo");
+ commandBox.runCommand("redo");
+ commandBox.runCommand("redo");
+ assertTrue(taskListPanel.isListMatching(expectedList));
+ assertResultMessage(MESSAGE_REDO_ACKNOWLEDGEMENT);
+ }
+
+ // redo two delete commands
+ @Test
+ public void redoTwoDeleteTest() {
+ expectedList = TestUtil.removeTaskFromList(currentList, 1);
+ expectedList = TestUtil.removeTaskFromList(expectedList, 1);
+ commandBox.runCommand("delete 1");
+ commandBox.runCommand("delete 1");
+ commandBox.runCommand("undo");
+ commandBox.runCommand("undo");
+ commandBox.runCommand("redo");
+ commandBox.runCommand("redo");
+ assertTrue(taskListPanel.isListMatching(expectedList));
+ assertResultMessage(MESSAGE_REDO_ACKNOWLEDGEMENT);
+ }
+
+ // redo a delete command followed by an add command
+ @Test
+ public void redoDeleteAddTest() {
+ expectedList = TestUtil.addTasksToList(currentList, firstTaskToAdd);
+ expectedList = TestUtil.removeTaskFromList(expectedList, 1);
+ commandBox.runCommand(firstTaskToAdd.getAddCommand());
+ commandBox.runCommand("delete 1");
+ commandBox.runCommand("undo");
+ commandBox.runCommand("undo");
+ commandBox.runCommand("redo");
+ commandBox.runCommand("redo");
+ assertTrue(taskListPanel.isListMatching(expectedList));
+ assertResultMessage(MESSAGE_REDO_ACKNOWLEDGEMENT);
+ }
+
+ // redo an add command followed by a delete command
+ @Test
+ public void redoAddDeleteTest() {
+ expectedList = TestUtil.removeTaskFromList(currentList, 1);
+ expectedList = TestUtil.addTasksToList(expectedList, firstTaskToAdd);
+ commandBox.runCommand("delete 1");
+ commandBox.runCommand(firstTaskToAdd.getAddCommand());
+ commandBox.runCommand("undo");
+ commandBox.runCommand("undo");
+ commandBox.runCommand("redo");
+ commandBox.runCommand("redo");
+ assertTrue(taskListPanel.isListMatching(expectedList));
+ assertResultMessage(MESSAGE_REDO_ACKNOWLEDGEMENT);
+ }
+
+ // invalid command
+ @Test
+ public void invalidTest() {
+ commandBox.runCommand("redos");
+ assertResultMessage("Input: redos\n" + String.format(MESSAGE_UNKNOWN_COMMAND, HelpCommand.MESSAGE_USAGE));
+ }
+}
+```
+###### \java\guitests\UndoCommandTest.java
+``` java
+package guitests;
+
+import guitests.guihandles.TaskCardHandle;
+
+import org.junit.Test;
+
+import seedu.savvytasker.logic.commands.UndoCommand;
+import seedu.savvytasker.logic.commands.HelpCommand;
+import seedu.savvytasker.testutil.TestTask;
+import seedu.savvytasker.testutil.TestUtil;
+
+import static org.junit.Assert.assertTrue;
+import static seedu.savvytasker.commons.core.Messages.MESSAGE_UNKNOWN_COMMAND;
+import static seedu.savvytasker.logic.commands.UndoCommand.MESSAGE_UNDO_ACKNOWLEDGEMENT;
+
+public class UndoCommandTest extends SavvyTaskerGuiTest {
+
+ TestTask[] expectedList = td.getTypicalTasks();
+ TestTask[] currentList = td.getTypicalTasks();
+ TestTask firstTaskToAdd = td.happy;
+ TestTask secondTaskToAdd = td.haloween;
+ TestTask pjmTaskToAdd = td.pjm;
+ TestTask projectMeetingTaskToAdd = td.projectMeeting;
+
+ @Test
+ // undo one add command
+ public void undoAddTest() {
+ expectedList = td.getTypicalTasks();
+ commandBox.runCommand(firstTaskToAdd.getAddCommand());
+ commandBox.runCommand("undo");
+ assertTrue(taskListPanel.isListMatching(expectedList));
+ assertResultMessage(MESSAGE_UNDO_ACKNOWLEDGEMENT);
+ }
+
+ @Test
+ // undo a delete command
+ public void undoDeleteTest() {
+ expectedList = td.getTypicalTasks();
+ commandBox.runCommand("delete 1");
+ commandBox.runCommand("undo");
+ assertTrue(taskListPanel.isListMatching(expectedList));
+ assertResultMessage(MESSAGE_UNDO_ACKNOWLEDGEMENT);
+ }
+
+ @Test
+ // undo clear command
+ public void undoClearTest() {
+ expectedList = td.getTypicalTasks();
+ commandBox.runCommand("clear");
+ commandBox.runCommand("undo");
+ assertTrue(taskListPanel.isListMatching(expectedList));
+ assertResultMessage(MESSAGE_UNDO_ACKNOWLEDGEMENT);
+ }
+
+ @Test
+ // undo alias command
+ public void undoAliasTest() {
+ expectedList = td.getTypicalTasks();
+ expectedList = TestUtil.addTasksToList(expectedList, pjmTaskToAdd);
+ commandBox.runCommand("alias k/pjm r/Project Meeting");
+ commandBox.runCommand("undo");
+ assertResultMessage(MESSAGE_UNDO_ACKNOWLEDGEMENT);
+ commandBox.runCommand(pjmTaskToAdd.getAddCommand());
+ assertTrue(taskListPanel.isListMatching(expectedList));
+ }
+
+ @Test
+ // undo unalias command
+ public void undoUnaliasTest() {
+ expectedList = TestUtil.addTasksToList(currentList, projectMeetingTaskToAdd);
+ commandBox.runCommand("alias k/pjm r/Project Meeting");
+ commandBox.runCommand("unalias pjm");
+ commandBox.runCommand("undo");
+ assertResultMessage(MESSAGE_UNDO_ACKNOWLEDGEMENT);
+ commandBox.runCommand(pjmTaskToAdd.getAddCommand());
+ assertTrue(taskListPanel.isListMatching(expectedList));
+ }
+
+ // undo mark command
+ @Test
+ public void undoMarkTest() {
+ expectedList = td.getTypicalTasks();
+ commandBox.runCommand("mark 1");
+ commandBox.runCommand("undo");
+ assertTrue(taskListPanel.isListMatching(expectedList));
+ assertResultMessage(MESSAGE_UNDO_ACKNOWLEDGEMENT);
+ }
+
+ // undo two add commands
+ @Test
+ public void undoTwoAddTest() {
+ expectedList = td.getTypicalTasks();
+ commandBox.runCommand(firstTaskToAdd.getAddCommand());
+ commandBox.runCommand(secondTaskToAdd.getAddCommand());
+ commandBox.runCommand("undo");
+ commandBox.runCommand("undo");
+ assertTrue(taskListPanel.isListMatching(expectedList));
+ assertResultMessage(MESSAGE_UNDO_ACKNOWLEDGEMENT);
+ }
+
+ // undo two delete commands
+ @Test
+ public void undoTwoDeleteTest() {
+ expectedList = td.getTypicalTasks();
+ commandBox.runCommand("delete 1");
+ commandBox.runCommand("delete 1");
+ commandBox.runCommand("undo");
+ commandBox.runCommand("undo");
+ assertTrue(taskListPanel.isListMatching(expectedList));
+ assertResultMessage(MESSAGE_UNDO_ACKNOWLEDGEMENT);
+ }
+
+ // undo a delete command followed by an add command
+ @Test
+ public void undoDeleteAddTest() {
+ expectedList = td.getTypicalTasks();
+ commandBox.runCommand(firstTaskToAdd.getAddCommand());
+ commandBox.runCommand("delete 1");
+ commandBox.runCommand("undo");
+ commandBox.runCommand("undo");
+ assertTrue(taskListPanel.isListMatching(expectedList));
+ assertResultMessage(MESSAGE_UNDO_ACKNOWLEDGEMENT);
+ }
+
+ // undo an add command followed by a delete command
+ @Test
+ public void undoAddDeleteTest() {
+ expectedList = td.getTypicalTasks();
+ commandBox.runCommand("delete 1");
+ commandBox.runCommand(firstTaskToAdd.getAddCommand());
+ commandBox.runCommand("undo");
+ commandBox.runCommand("undo");
+ assertTrue(taskListPanel.isListMatching(expectedList));
+ assertResultMessage(MESSAGE_UNDO_ACKNOWLEDGEMENT);
+ }
+
+ // invalid command
+ @Test
+ public void invalidTest() {
+ commandBox.runCommand("undos");
+ assertResultMessage("Input: undos\n" + String.format(MESSAGE_UNKNOWN_COMMAND, HelpCommand.MESSAGE_USAGE));
+ }
+}
+```
diff --git a/collated/test/A0138431L.md b/collated/test/A0138431L.md
new file mode 100644
index 000000000000..2df548b81caf
--- /dev/null
+++ b/collated/test/A0138431L.md
@@ -0,0 +1,36 @@
+# A0138431L
+###### \java\guitests\StorageCommandTest.java
+``` java
+public class StorageCommandTest extends SavvyTaskerGuiTest {
+
+ private static final String CONFIG_JSON = "config.json";
+ private static final String CONFIG_LOCATION = "./src/test/data/SaveLocationCommandTest";
+
+ @Test
+ public void saveToValidFilePath_success() throws DataConversionException, IOException, DuplicateTaskException {
+ String testFilePath = "./src/test/data/StorageCommandTest/newStorageLocation/";
+ commandBox.runCommand("storage " + testFilePath);
+ assertWriteToJsonSuccess();
+ assertWriteToXmlSuccess();
+ }
+ private void assertWriteToJsonSuccess() throws DataConversionException {
+ JsonConfigStorage jsonConfigStorage = new JsonConfigStorage(CONFIG_LOCATION);
+ Optional config = jsonConfigStorage.readConfig(CONFIG_JSON);
+ assert(config.isPresent());
+ }
+
+ private void assertWriteToXmlSuccess() {
+ TestTask[] currentList = td.getTypicalTasks();
+ assertTrue(taskListPanel.isListMatching(currentList));
+ }
+
+ @Test
+ public void storage() {
+ //invalid command
+ commandBox.runCommand("store");
+ assertResultMessage("Input: store\n" +
+ String.format(MESSAGE_UNKNOWN_COMMAND, HelpCommand.MESSAGE_USAGE));
+ }
+
+}
+```
diff --git a/collated/test/A0139915W.md b/collated/test/A0139915W.md
index 3a51dbc567e6..23287a4c2f9e 100644
--- a/collated/test/A0139915W.md
+++ b/collated/test/A0139915W.md
@@ -3,6 +3,9 @@
``` java
public class AddCommandTest extends SavvyTaskerGuiTest {
+ private DateFormat formatter = DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.getDefault());
+ private SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy");
+
@Test
public void add() {
//add one task
@@ -44,8 +47,7 @@ public class AddCommandTest extends SavvyTaskerGuiTest {
TestTask[] expectedList = TestUtil.addTasksToList(currentList, taskToAdd);
assertTrue(taskListPanel.isListMatching(expectedList));
}
-
- private DateFormat formatter = DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.getDefault());
+
private String getLocaleDateString(Date date) {
try {
return formatter.format(date);
@@ -55,7 +57,6 @@ public class AddCommandTest extends SavvyTaskerGuiTest {
return null;
}
- private SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy");
private Date getDate(String ddmmyyyy) {
try {
return format.parse(ddmmyyyy);
@@ -76,11 +77,9 @@ public class DeleteCommandTest extends SavvyTaskerGuiTest {
//delete the first in the list
TestTask[] currentList = td.getTypicalTasks();
int targetIndex = 1;
-
assertDeleteSuccess(targetIndex, currentList);
//delete the last in the list
-
currentList = TestUtil.removeTaskFromList(currentList, targetIndex);
targetIndex = currentList.length;
assertDeleteSuccess(targetIndex, currentList);
@@ -438,6 +437,9 @@ public class ListCommandTest extends SavvyTaskerGuiTest {
``` java
public class ModifyCommandTest extends SavvyTaskerGuiTest {
+ private DateFormat formatter = DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.getDefault());
+ private SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy");
+
@Test
public void add() {
//modify task
@@ -480,7 +482,6 @@ public class ModifyCommandTest extends SavvyTaskerGuiTest {
assertTrue(taskListPanel.isListMatching(expectedList));
}
- private DateFormat formatter = DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.getDefault());
private String getLocaleDateString(Date date) {
try {
return formatter.format(date);
@@ -490,7 +491,6 @@ public class ModifyCommandTest extends SavvyTaskerGuiTest {
return null;
}
- private SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy");
private Date getDate(String ddmmyyyy) {
try {
return format.parse(ddmmyyyy);
@@ -506,6 +506,8 @@ public class ModifyCommandTest extends SavvyTaskerGuiTest {
``` java
public class SmartDefaultDatesTest {
+ private SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy HHmmss");
+
@Test
public void smartDefaultDates_parseStart() {
DateParser dateParser = new DateParser();
@@ -520,10 +522,9 @@ public class SmartDefaultDatesTest {
SmartDefaultDates sdd = new SmartDefaultDates(inferredStart, inferredEnd);
// specifying only start date, assumed to on the given date at 12am
// and to end on the given date at 2359:59
- Date expectedStartTime = getDate("31/12/2016 000000");
- Date expectedEndTime = getDate("31/12/2016 235959");
- assertEquals(expectedStartTime, sdd.getStartDate());
- assertEquals(expectedEndTime, sdd.getEndDate());
+ assertStartEndEquals(
+ getDate("31/12/2016 000000"), getDate("31/12/2016 235959"),
+ sdd.getStartDate(), sdd.getEndDate());
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
Date today = today(0, 0);
@@ -536,10 +537,9 @@ public class SmartDefaultDatesTest {
sdd = new SmartDefaultDates(inferredStart, inferredEnd);
// specifying only start time, assumed to start today at the given time
// and to end today 2359:59
- expectedStartTime = getDate(sdf.format(today) + " 150000");
- expectedEndTime = getDate(sdf.format(today) + " 235959");
- assertEquals(expectedStartTime, sdd.getStartDate());
- assertEquals(expectedEndTime, sdd.getEndDate());
+ assertStartEndEquals(
+ getDate(sdf.format(today) + " 150000"), getDate(sdf.format(today) + " 235959"),
+ sdd.getStartDate(), sdd.getEndDate());
}
@Test
@@ -558,10 +558,9 @@ public class SmartDefaultDatesTest {
SmartDefaultDates sdd = new SmartDefaultDates(inferredStart, inferredEnd);
// specified only the end date, assumed to start today at 12am
// and to end on the given date at 2359:59
- Date expectedStartTime = getDate(sdf.format(today) + " 000000");
- Date expectedEndTime = getDate("31/12/2016 235959");
- assertEquals(expectedStartTime, sdd.getStartDate());
- assertEquals(expectedEndTime, sdd.getEndDate());
+ assertStartEndEquals(
+ getDate(sdf.format(today) + " 000000"), getDate("31/12/2016 235959"),
+ sdd.getStartDate(), sdd.getEndDate());
try {
//use MM-dd-yyyy
@@ -572,10 +571,9 @@ public class SmartDefaultDatesTest {
sdd = new SmartDefaultDates(inferredStart, inferredEnd);
// specified only the end time, assumed to start today at 12am
// and to end at the given time today
- expectedStartTime = getDate(sdf.format(today) + " 000000");
- expectedEndTime = getDate(sdf.format(today) + " 150000");
- assertEquals(expectedStartTime, sdd.getStartDate());
- assertEquals(expectedEndTime, sdd.getEndDate());
+ assertStartEndEquals(
+ getDate(sdf.format(today) + " 000000"), getDate(sdf.format(today) + " 150000"),
+ sdd.getStartDate(), sdd.getEndDate());
try {
@@ -587,10 +585,9 @@ public class SmartDefaultDatesTest {
sdd = new SmartDefaultDates(inferredStart, inferredEnd);
// specified only the end date in the past, start date will be null
// and to end on the given date at 2359:59
- expectedStartTime = null;
- expectedEndTime = getDate("31/12/2000 235959");
- assertEquals(expectedStartTime, sdd.getStartDate());
- assertEquals(expectedEndTime, sdd.getEndDate());
+ assertStartEndEquals(
+ null, getDate("31/12/2000 235959"),
+ sdd.getStartDate(), sdd.getEndDate());
}
@Test
@@ -617,10 +614,9 @@ public class SmartDefaultDatesTest {
// no time supplied for start and end
// start defaults to 0000
// end defaults to 2359:59
- Date expectedStartTime = getDate("31/12/2016 000000");
- Date expectedEndTime = getDate("31/12/2016 235959");
- assertEquals(expectedStartTime, sdd.getStartDate());
- assertEquals(expectedEndTime, sdd.getEndDate());
+ assertStartEndEquals(
+ getDate("31/12/2016 000000"), getDate("31/12/2016 235959"),
+ sdd.getStartDate(), sdd.getEndDate());
inferredStart = null;
inferredEnd = null;
@@ -636,10 +632,9 @@ public class SmartDefaultDatesTest {
// start defaults to 0000
// end defaults to 2359:59
// no restrictions imposed on end time earlier than start time
- expectedStartTime = getDate("31/12/2016 000000");
- expectedEndTime = getDate("30/12/2016 235959");
- assertEquals(expectedStartTime, sdd.getStartDate());
- assertEquals(expectedEndTime, sdd.getEndDate());
+ assertStartEndEquals(
+ getDate("31/12/2016 000000"), getDate("30/12/2016 235959"),
+ sdd.getStartDate(), sdd.getEndDate());
inferredStart = null;
inferredEnd = null;
@@ -653,10 +648,9 @@ public class SmartDefaultDatesTest {
sdd = new SmartDefaultDates(inferredStart, inferredEnd);
// no date supplied for start and end
// start and end defaults to the given time today
- expectedStartTime = getDate(sdf.format(today) + " 100000");
- expectedEndTime = getDate(sdf.format(today) + " 220000");
- assertEquals(expectedStartTime, sdd.getStartDate());
- assertEquals(expectedEndTime, sdd.getEndDate());
+ assertStartEndEquals(
+ getDate(sdf.format(today) + " 100000"), getDate(sdf.format(today) + " 220000"),
+ sdd.getStartDate(), sdd.getEndDate());
inferredStart = null;
inferredEnd = null;
@@ -671,10 +665,9 @@ public class SmartDefaultDatesTest {
// no date supplied for start and end, end time ends before start time
// start and end defaults to the given time today
// no restrictions imposed on end time being earlier
- expectedStartTime = getDate(sdf.format(today) + " 220000");
- expectedEndTime = getDate(sdf.format(today) + " 100000");
- assertEquals(expectedStartTime, sdd.getStartDate());
- assertEquals(expectedEndTime, sdd.getEndDate());
+ assertStartEndEquals(
+ getDate(sdf.format(today) + " 220000"), getDate(sdf.format(today) + " 100000"),
+ sdd.getStartDate(), sdd.getEndDate());
}
@Test
@@ -685,10 +678,8 @@ public class SmartDefaultDatesTest {
SmartDefaultDates sdd = new SmartDefaultDates(null, null);
Date actualStart = sdd.getStart(dateParser.new InferredDate(new Date(), true, true));
Date actualEnd = sdd.getEnd(dateParser.new InferredDate(new Date(), true, true));
- Date expectedStart = null;
- Date expectedEnd = null;
- assertEquals(expectedStart, actualStart);
- assertEquals(expectedEnd, actualEnd);
+ assertStartEndEquals(null, null,
+ actualStart, actualEnd);
try {
//use MM-dd-yyyy
@@ -697,10 +688,9 @@ public class SmartDefaultDatesTest {
} catch (ParseException e) {
assert false; //won't get here
}
- expectedStart = getDate(sdf.format(today) + " 220000");
- expectedEnd = getDate(sdf.format(today) + " 100000");
- assertEquals(expectedStart, actualStart);
- assertEquals(expectedEnd, actualEnd);
+ assertStartEndEquals(
+ getDate(sdf.format(today) + " 220000"), getDate(sdf.format(today) + " 100000"),
+ actualStart, actualEnd);
try {
//use MM-dd-yyyy
@@ -709,13 +699,16 @@ public class SmartDefaultDatesTest {
} catch (ParseException e) {
assert false; //won't get here
}
- expectedStart = getDate("31/12/2016 000000");
- expectedEnd = getDate("31/12/2016 235959");
+ assertStartEndEquals(getDate("31/12/2016 000000"), getDate("31/12/2016 235959"),
+ actualStart, actualEnd);
+ }
+
+ private void assertStartEndEquals(Date expectedStart, Date expectedEnd,
+ Date actualStart, Date actualEnd) {
assertEquals(expectedStart, actualStart);
assertEquals(expectedEnd, actualEnd);
}
- private SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy HHmmss");
private Date getDate(String ddmmyyyy) {
try {
return format.parse(ddmmyyyy);
@@ -1088,7 +1081,6 @@ public class TestTask implements ReadOnlyTask {
```
###### \java\seedu\savvytasker\testutil\TestUtil.java
``` java
- public static final Task[] sampleTaskData = getSampleTaskData();
private static Task[] getSampleTaskData() {
return new Task[]{
@@ -1166,7 +1158,7 @@ public class TestTask implements ReadOnlyTask {
public class TypicalTestTasks {
public TestTask highPriority, medPriority, lowPriority, furthestDue,
- nearerDue, notSoNearerDue, earliestDue, longDue, happy, haloween;
+ nearerDue, notSoNearerDue, earliestDue, longDue, happy, haloween, pjm, projectMeeting;
private SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy");
public TypicalTestTasks() {
@@ -1191,6 +1183,8 @@ public class TypicalTestTasks {
//Manually added
happy = new TaskBuilder().withId(9).withTaskName("Happy Task").build();
haloween = new TaskBuilder().withId(10).withTaskName("Haloween Task").build();
+ pjm = new TaskBuilder().withId(11).withTaskName("pjm").build();
+ projectMeeting = new TaskBuilder().withId(12).withTaskName("Project Meeting").build();
} catch (IllegalValueException e) {
e.printStackTrace();
assert false : "not possible";
diff --git a/docs/AboutUs.md b/docs/AboutUs.md
index aa805f3a4171..b4a3d6ee4b84 100644
--- a/docs/AboutUs.md
+++ b/docs/AboutUs.md
@@ -18,8 +18,18 @@
**Role**: Developer
Responsibilities: Team Lead
-Component SME: UI
-
+Component SME: [UI](DeveloperGuide.md#UI-component)
+* Aspects/tools in charge of: Documentation, Code Quality
+* Features implemented:
+ * [Storage](UserGuide.md#change-storage-location--storage)
+ * [UP](UserGuide.md#command-stack-history)
+ * [DOWN](UserGuide.md#command-stack-history)
+ * [LEFT](UserGuide.md#week-selection)
+ * [RIGHT](UserGuide.md#week-selection)
+* Code written: [[functional code](../collated/main/A0138431L.md)][[test code](../collated/test/A0138431L.md)][[docs](../collated/docs/A0138431L.md)]
+* Other major contributions:
+ * Design of UI which includes MainWindow.fxml, DailyList.fxml, FloatingList.fxml and UpcomingList.fxml
+
-----
#### [Low Zheng Heng Henry](http://github.com/e0003801)
@@ -66,6 +76,6 @@ Component SME: UI
* [Unmark task](UserGuide.md#unmark-a-task-as-done--unmark)
* [Undo task](UserGuide.md#undo-the-most-recent-operation--undo)
* [Redo task](UserGuide.md#redo-the-most-recent-undo-operation--redo)
-* Code written: [[functional code](../collated/main/A0097627N.md)][[docs](../collated/docs/A0097627N.md)]
+* Code written: [[functional code](../collated/main/A0097627N.md)][[test code](../collated/test/A0097627N.md)][[docs](../collated/docs/A0097627N.md)]
-----
diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md
index 16f7b1f58831..455eabffc885 100644
--- a/docs/DeveloperGuide.md
+++ b/docs/DeveloperGuide.md
@@ -109,14 +109,15 @@ The sections below give more details of each component.
[//]: # (@@author)
+[//]: # (@@author A0138431L)
### UI component
**API** : [`Ui.java`](../src/main/java/seedu/savvytasker/ui/Ui.java)
-The UI consists of a `MainWindow` that is made up of parts e.g.`CommandBox`, `ResultDisplay`, `PersonListPanel`,
-`StatusBarFooter`, `BrowserPanel` etc. All these, including the `MainWindow`, inherit from the abstract `UiPart` class
+The UI consists of a `MainWindow` that is made up of parts e.g.`CommandBox`, `ResultDisplay`, `TaskListPanel`, `UpcomingPanel`, `DailyPanel`, `FloatingPanel`,
+`StatusBarFooter` etc. All these, including the `MainWindow`, inherit from the abstract `UiPart` class
and they can be loaded using the `UiPartLoader`.
The `UI` component uses JavaFx UI framework. The layout of these UI parts are defined in matching `.fxml` files
@@ -129,6 +130,10 @@ The `UI` component,
* Binds itself to some data in the `Model` so that the UI can auto-update when data in the `Model` change.
* Responds to events raised from various parts of the App and updates the UI accordingly.
+The cursor will be focus to the `CommandBox` by default as the `CommandBox` carries out numerous keyboard shortcuts to make the app more user-friendly.
+
+[//]: # (@@author)
+
[//]: # (@@author A0139916U)
### Logic component
diff --git a/docs/UserGuide.md b/docs/UserGuide.md
index a2594b5d230f..b6cf2c1d6ae7 100644
--- a/docs/UserGuide.md
+++ b/docs/UserGuide.md
@@ -155,13 +155,13 @@ Format: `modify INDEX [t/TASK_NAME] [s/START_DATE] [e/END_DATE] [l/LOCATION] [p/
#### Change storage location : `storage`
Changes the storage location of Savvy Tasker.
-Format: `storage PATH`
+Format: `storage NEW_FILEPATH`
> Parameters | Description
> -------- | :--------
> PATH | `Mandatory` Specifies the path where Savvy Tasker's task list is saved at.
>
-> If the new storage location specified by `PATH` is not accessible by Savvy Tasker, no change will be made to the existing path.
+> If the new storage location specified by `NEW_FILEPATH` is not accessible by Savvy Tasker, no change will be made to the existing path.
[//]: # (@@author A0097627N)
@@ -256,6 +256,20 @@ Add task named "pjm" to task list
the file that contains the data of your previous Savvy Tasker folder.
+[//]: # (@@author A0139915W)
+
+[//]: # (@@author A0138431L)
+
+#### Command stack history
+UP: Return last user input command in command box
+DOWN: Return (if any) next user input command in command box
+> Note that DOWN is only allowed after at least an UP is being entered
+
+
+#### Week Selection
+Ctrl + LEFT: Display previous week’s daily task list
+Ctrl + RIGHT: Display next week’s daily task list
+
[//]: # (@@author A0139915W)
## Command Summary
@@ -272,8 +286,30 @@ Command | Format
[Help](#viewing-help--help) | `help`
[Modify](#modifies-a-task--modify) | `modify INDEX [t/TASK_NAME] [s/START_DATE] [e/END_DATE] [l/LOCATION] [p/PRIORITY_LEVEL] [r/RECURRING_TYPE] [n/NUMBER_OF_RECURRENCE] [c/CATEGORY] [d/DESCRIPTION]`
Example: `modify 2 t/Wednesday Weekly Milestone s/wed d/Project Meeting and Finalization`
[Mark](#mark-a-task-as-done--mark) | `mark INDEX [MORE_INDEX]`
Example: `mark 1 2 3`
-[Storage](#change-storage-location--storage) | `storage PATH`
Example: `storage data/savvytasker.xml`
+[Storage](#change-storage-location--storage) | `storage NEW_FILEPATH`
Example: `storage data/savvytasker.xml`
[Unmark](#unmark-a-task-as-done--unmark) | `unmark INDEX [MORE_INDEX]`
Example: `unmark 1 2 3`
[Undo](#undo-the-most-recent-operation--undo) | `undo`
[Redo](#redo-the-most-recent-undo-operation--redo) | `redo`
[Unalias](#unalias-a-keyword--unalias) | `unalias s/SHORT_KEYWORD`
Example: `unalias s/mss`
+
+[//]: # (@@author A0138431L)
+
+## Keyboard Shortcuts
+
+Key Codes | Function | Command Box Input
+-------- | :-------- | :--------
+Esc | Toggle to show/hide a list of keyboard shortcuts | -
+Ctrl + D | [Clear](#clearing-all-entries--clear) all entries | `clear`
+Ctrl + Q | [Exit](#exiting-the-program--exit) | `exit`
+Ctrl + L | [List](#listing-all-tasks-list) all unmarked task by date, earliest task first | `list`
+Ctrl + A | [List](#listing-all-tasks-list) archived tasks | `list archived`
+Ctrl + P | [List](#listing-all-tasks-list) all unmarked task by priority level, high priority first | `list priorityLevel`
+Ctrl + I | [List](#listing-all-tasks-list) all alias keys | `list alias`
+Ctrl + H | [Help](#viewing-help--help) | `help`
+Ctrl + S | Popups a directory chooser dialog box to choose a new filepath | `storage NEW_FILEPATH`
+Ctrl + Z | [Undo](#undo-the-most-recent-operation--undo) | `undo`
+Ctrl + Y | [Redo](#redo-the-most-recent-undo-operation--redo) | `redo`
+Ctrl + UP | Return [last user input](#command-stack-history) command in command box | -
+Ctrl + DOWN | Return (if any) [next user input](#command-stack-history) command in command box | -
+Ctrl + LEFT | Displays [previous week’s](#week-selection) daily task list | -
+Ctrl + RIGHT | Display [next week’s](#week-selection) daily task list | -
diff --git a/docs/images/Ui.png b/docs/images/Ui.png
index 4ae9de18c2d9..5ac53387fb40 100644
Binary files a/docs/images/Ui.png and b/docs/images/Ui.png differ
diff --git a/docs/images/UiClassDiagram.png b/docs/images/UiClassDiagram.png
index af140c15285f..dd8be5c36d4e 100644
Binary files a/docs/images/UiClassDiagram.png and b/docs/images/UiClassDiagram.png differ
diff --git a/src/main/java/seedu/savvytasker/commons/events/ui/ShowCheatsheetEvent.java b/src/main/java/seedu/savvytasker/commons/events/ui/ShowCheatsheetEvent.java
new file mode 100644
index 000000000000..30ffd9d6605e
--- /dev/null
+++ b/src/main/java/seedu/savvytasker/commons/events/ui/ShowCheatsheetEvent.java
@@ -0,0 +1,14 @@
+//@@author A0138431L
+
+package seedu.savvytasker.commons.events.ui;
+
+import seedu.savvytasker.commons.events.BaseEvent;
+
+/** Indicates cheatsheet display has been toggled */
+public class ShowCheatsheetEvent extends BaseEvent {
+ @Override
+ public String toString() {
+ return "Cheatsheet display has been toggled";
+ }
+
+}
diff --git a/src/main/java/seedu/savvytasker/commons/events/ui/WeekSelectionChangedEvent.java b/src/main/java/seedu/savvytasker/commons/events/ui/WeekSelectionChangedEvent.java
new file mode 100644
index 000000000000..dc74c7311f14
--- /dev/null
+++ b/src/main/java/seedu/savvytasker/commons/events/ui/WeekSelectionChangedEvent.java
@@ -0,0 +1,16 @@
+//@@author A0138431L
+
+package seedu.savvytasker.commons.events.ui;
+
+import seedu.savvytasker.commons.events.BaseEvent;
+
+/** Indicates the SavvyTasker in the model has changed*/
+
+public class WeekSelectionChangedEvent extends BaseEvent {
+
+ @Override
+ public String toString() {
+ return "Selected week has been changed";
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/seedu/savvytasker/logic/Logic.java b/src/main/java/seedu/savvytasker/logic/Logic.java
index 1cf9b6cba531..0250b878c806 100755
--- a/src/main/java/seedu/savvytasker/logic/Logic.java
+++ b/src/main/java/seedu/savvytasker/logic/Logic.java
@@ -27,9 +27,6 @@ public interface Logic {
/** */
boolean canParseHeader(String keyword);
- /** Returns the list of tasks that are overdue */
- ObservableList getFilteredOverdueTasks();
-
/** Returns the list of floating tasks */
ObservableList getFilteredFloatingTasks();
diff --git a/src/main/java/seedu/savvytasker/logic/LogicManager.java b/src/main/java/seedu/savvytasker/logic/LogicManager.java
index b7c4231b2213..69a3d1ffdb54 100755
--- a/src/main/java/seedu/savvytasker/logic/LogicManager.java
+++ b/src/main/java/seedu/savvytasker/logic/LogicManager.java
@@ -114,10 +114,6 @@ public ObservableList getAliasSymbolList() {
//@@author
//@@author A0138431L
- @Override
- public ObservableList getFilteredOverdueTasks() {
- return model.getFilteredOverdueTasks();
- }
@Override
public ObservableList getFilteredFloatingTasks() {
diff --git a/src/main/java/seedu/savvytasker/logic/commands/StorageAndModelRequiringCommand.java b/src/main/java/seedu/savvytasker/logic/commands/StorageAndModelRequiringCommand.java
index fd18f92fa260..88f26a7f3072 100644
--- a/src/main/java/seedu/savvytasker/logic/commands/StorageAndModelRequiringCommand.java
+++ b/src/main/java/seedu/savvytasker/logic/commands/StorageAndModelRequiringCommand.java
@@ -3,7 +3,7 @@
import seedu.savvytasker.model.Model;
import seedu.savvytasker.storage.Storage;
-//@@author A0139915W
+//@@author A0138431L
/**
* Represents a command which requires the Storage class as a dependency.
* Commands should inherit this class if they only require dependency for
diff --git a/src/main/java/seedu/savvytasker/model/Model.java b/src/main/java/seedu/savvytasker/model/Model.java
index bd52e32918b4..fd42b55aae28 100644
--- a/src/main/java/seedu/savvytasker/model/Model.java
+++ b/src/main/java/seedu/savvytasker/model/Model.java
@@ -83,9 +83,6 @@ public interface Model {
int getAliasSymbolCount();
//@@author A0138431L
- /** Returns the filtered task list of overdue task as an {@code UnmodifiableObservableList}
- * as of current date */
- UnmodifiableObservableList getFilteredOverdueTasks();
/** Returns the filtered task list of floating task as an {@code UnmodifiableObservableList} */
UnmodifiableObservableList getFilteredFloatingTasks();
@@ -97,9 +94,6 @@ public interface Model {
/** Returns the filtered task list of upcoming task as an {@code UnmodifiableObservableList}
* as of expected date */
UnmodifiableObservableList getFilteredUpcomingTasks(Date date);
-
- /** Updates the filter of the filtered task list to show all overdue tasks */
- void updateFilteredListToShowOverdue();
/** Updates the filter of the filtered task list to show all floating tasks */
void updateFilteredListToShowFloating();
@@ -109,5 +103,6 @@ public interface Model {
/** Updates the filter of the filtered task list to show all upcoming tasks after the selected week*/
void updateFilteredListToShowUpcoming();
+
//@@author
}
diff --git a/src/main/java/seedu/savvytasker/model/ModelManager.java b/src/main/java/seedu/savvytasker/model/ModelManager.java
index 396e49ed67ed..b58f9ae4ec01 100755
--- a/src/main/java/seedu/savvytasker/model/ModelManager.java
+++ b/src/main/java/seedu/savvytasker/model/ModelManager.java
@@ -45,8 +45,6 @@ public class ModelManager extends ComponentManager implements Model {
private final SortedList sortedAndFilteredTasks;
private final FilteredList filteredFloatingTasks;
private final SortedList sortedAndFilteredFloatingTasks;
- private final FilteredList filteredOverdueTasks;
- private final SortedList sortedAndFilteredOverdueTasks;
private final FilteredList filteredDay1Tasks;
private final SortedList sortedAndFilteredDay1Tasks;
private final FilteredList filteredDay2Tasks;
@@ -81,9 +79,6 @@ public ModelManager(SavvyTasker src) {
filteredFloatingTasks = new FilteredList<>(savvyTasker.getTasks());
sortedAndFilteredFloatingTasks = new SortedList<>(filteredFloatingTasks, new TaskSortedByDefault());
- filteredOverdueTasks = new FilteredList<>(savvyTasker.getTasks());
- sortedAndFilteredOverdueTasks = new SortedList<>(filteredOverdueTasks, new TaskSortedByDefault());
-
filteredDay1Tasks = new FilteredList<>(savvyTasker.getTasks());
sortedAndFilteredDay1Tasks = new SortedList<>(filteredDay1Tasks, new TaskSortedByDefault());
filteredDay2Tasks = new FilteredList<>(savvyTasker.getTasks());
@@ -117,9 +112,6 @@ public ModelManager(ReadOnlySavvyTasker initialData) {
filteredFloatingTasks = new FilteredList<>(savvyTasker.getTasks());
sortedAndFilteredFloatingTasks = new SortedList<>(filteredFloatingTasks, new TaskSortedByDefault());
- filteredOverdueTasks = new FilteredList<>(savvyTasker.getTasks());
- sortedAndFilteredOverdueTasks = new SortedList<>(filteredOverdueTasks, new TaskSortedByDefault());
-
filteredDay1Tasks = new FilteredList<>(savvyTasker.getTasks());
sortedAndFilteredDay1Tasks = new SortedList<>(filteredDay1Tasks, new TaskSortedByDefault());
filteredDay2Tasks = new FilteredList<>(savvyTasker.getTasks());
@@ -293,11 +285,6 @@ private void updateFilteredTaskList(Expression expression, Comparator comp
//@author A0138431L
//Get filtered task list according to date category
- @Override
- public UnmodifiableObservableList getFilteredOverdueTasks() {
- updateFilteredListToShowOverdue();
- return new UnmodifiableObservableList(filteredOverdueTasks);
- }
@Override
public UnmodifiableObservableList getFilteredFloatingTasks() {
@@ -336,20 +323,6 @@ public UnmodifiableObservableList getFilteredUpcomingTasks(Date da
return new UnmodifiableObservableList(filteredUpcomingTasks);
}
- //Binding isOverdue quantifier predicate to filtered list
- @Override
- public void updateFilteredListToShowOverdue() {
- updateFilteredOverdueTaskList(new PredicateExpression(new TaskIsOverdueQualifier()));
- }
-
- private void updateFilteredOverdueTaskList(Expression expression) {
- updateFilteredOverdueTaskList(expression, new TaskSortedByDefault());
- }
-
- private void updateFilteredOverdueTaskList(Expression expression, Comparator comparator) {
- filteredOverdueTasks.setPredicate(expression::satisfies);
- sortedAndFilteredOverdueTasks.setComparator(comparator);
- }
//Binding isFloating quantifier predicate to filtered list
@Override
diff --git a/src/main/java/seedu/savvytasker/model/task/ReadOnlyTask.java b/src/main/java/seedu/savvytasker/model/task/ReadOnlyTask.java
index a8648b5cfe9f..d29526f9e35a 100644
--- a/src/main/java/seedu/savvytasker/model/task/ReadOnlyTask.java
+++ b/src/main/java/seedu/savvytasker/model/task/ReadOnlyTask.java
@@ -1,7 +1,10 @@
package seedu.savvytasker.model.task;
+import java.text.SimpleDateFormat;
import java.util.Date;
+import org.apache.commons.lang.time.DateUtils;
+
//@@author A0139915W
/**
* A read-only immutable interface for a Task in the TaskList.
@@ -74,14 +77,8 @@ default String getAsText() {
*/
default String getTextForUi() {
final StringBuilder builder = new StringBuilder();
- if (getStartDateTime() != null) {
- builder.append(" Start: ")
- .append(getStartDateTime())
- .append("\n");
- }
- if (getEndDateTime() != null) {
- builder.append(" End: ")
- .append(getEndDateTime())
+ if (getStartDateTime() != null || getEndDateTime() != null) {
+ builder.append(generateDateTime(getStartDateTime(), getEndDateTime()))
.append("\n");
}
if (getLocation() != null && !getLocation().isEmpty()) {
@@ -89,9 +86,6 @@ default String getTextForUi() {
.append(getLocation())
.append("\n");
}
- builder.append(" Priority: ")
- .append(getPriority())
- .append("\n");
if (getCategory() != null && !getCategory().isEmpty()) {
builder.append(" Category: ")
.append(getCategory())
@@ -104,6 +98,103 @@ default String getTextForUi() {
}
return builder.toString();
}
+ //@@author
+
+ //@@author A0138431L
+ static final String EMPTY_FIELD = " ";
+
+ static String DATE_PATTERN = "dd MMM yy";
+ static String TIME_PATTERN = "hh:mm a";
+
+ // String format for deadline tasks dateTime format
+ static String DEADLINE_FORMAT = "by %1$s, %2$s";
+
+ // String format for event tasks dateTime format
+ static String EVENT_DIFF_START_END_DATE_FORMAT = "%1$s, %2$s to %3$s, %4$s";
+ static String EVENT_SAME_START_END_DATE_FORMAT = "%1$s, %2$s to %3$s";
+
+ static Date lastDayOfSelectedWeek = new Date();
+
+ /**
+ * Generates the DateTime Format for all tasks with time.
+ *
+ * @param task the task to have its DateTime Format generated
+ *
+ * @return DateTime Format (e.g. (31 Oct 16, 10:00PM)
+ **/
+ default String generateDateTime(Date start, Date end) {
+ String dateTimeFormat;
+ //Floating Task
+ if(start == null && end == null) {
+ dateTimeFormat = EMPTY_FIELD;
+ }
+ //Deadline Task
+ else if(start == null && end != null) {
+ dateTimeFormat = generateDeadlineDateTime(end);
+ //Event Task
+ }else {
+ dateTimeFormat = generateEventDateTime(start, end);
+ }
+
+ return dateTimeFormat;
+
+ }
+
+ /**
+ * Generates the dateTimeFormat for deadline tasks
+ *
+ * @param task the task to have its dateTimeFormat generated
+ *
+ * @return dateTimeFormat (e.g. 30 Oct 16, 10:00PM)
+ */
+ default String generateDeadlineDateTime(Date end) {
+
+ String dateTimeFormat;
+
+ SimpleDateFormat dateFormatter = new SimpleDateFormat(DATE_PATTERN);
+ SimpleDateFormat timeFormatter = new SimpleDateFormat(TIME_PATTERN);
+
+ String taskEndDateFormat = dateFormatter.format(end.getTime());
+ String taskEndTimeFormat = timeFormatter.format(end.getTime());
+
+ dateTimeFormat = String.format(DEADLINE_FORMAT, taskEndDateFormat, taskEndTimeFormat);
+
+ return dateTimeFormat;
+
+ }
+
+ /**
+ * Generates the dateTimeFormat for ranged tasks
+ *
+ * @param task the task to have its dateTimeFormat generated
+ *
+ * @return dateTimeFormat (e.g. 30 Oct 16, 8:00AM to 9:00PM)
+ */
+ default String generateEventDateTime(Date start, Date end) {
+
+ String dateTimeFormat;
+
+ SimpleDateFormat dateFormatter = new SimpleDateFormat(DATE_PATTERN);
+ SimpleDateFormat timeFormatter = new SimpleDateFormat(TIME_PATTERN);
+
+ String taskStartDateFormat = dateFormatter.format(start.getTime());
+ String taskStartTimeFormat = timeFormatter.format(start.getTime());
+
+ String taskEndDateFormat = dateFormatter.format(end.getTime());
+ String taskEndTimeFormat = timeFormatter.format(end.getTime());
+
+ if(DateUtils.isSameDay(start, end) == false) {
+
+ dateTimeFormat = String.format(EVENT_DIFF_START_END_DATE_FORMAT, taskStartDateFormat, taskStartTimeFormat, taskEndDateFormat, taskEndTimeFormat);
+
+ } else {
+
+ dateTimeFormat = String.format(EVENT_SAME_START_END_DATE_FORMAT, taskEndDateFormat, taskStartTimeFormat, taskEndTimeFormat);
+
+ }
+ return dateTimeFormat;
+
+ }
}
//@@author
diff --git a/src/main/java/seedu/savvytasker/ui/CommandBox.java b/src/main/java/seedu/savvytasker/ui/CommandBox.java
index e2d5d3c086d3..1f5e2eb15ecf 100755
--- a/src/main/java/seedu/savvytasker/ui/CommandBox.java
+++ b/src/main/java/seedu/savvytasker/ui/CommandBox.java
@@ -2,6 +2,8 @@
package seedu.savvytasker.ui;
import java.io.File;
+import java.util.Calendar;
+import java.util.Date;
import java.util.Stack;
import java.util.logging.Logger;
@@ -11,6 +13,8 @@
import javafx.scene.Node;
import javafx.scene.control.SplitPane;
import javafx.scene.control.TextField;
+import javafx.scene.image.Image;
+import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyCodeCombination;
import javafx.scene.input.KeyCombination;
@@ -19,7 +23,10 @@
import javafx.stage.DirectoryChooser;
import javafx.stage.Stage;
import seedu.savvytasker.commons.core.LogsCenter;
+import seedu.savvytasker.commons.events.model.SavvyTaskerChangedEvent;
import seedu.savvytasker.commons.events.ui.IncorrectCommandAttemptedEvent;
+import seedu.savvytasker.commons.events.ui.ShowCheatsheetEvent;
+import seedu.savvytasker.commons.events.ui.WeekSelectionChangedEvent;
import seedu.savvytasker.commons.util.FxViewUtil;
import seedu.savvytasker.logic.Logic;
import seedu.savvytasker.logic.commands.CommandResult;
@@ -32,6 +39,32 @@ public class CommandBox extends UiPart {
private AnchorPane commandPane;
private ResultDisplay resultDisplay;
String previousCommandTest;
+ private Date date = new Date();
+ private static int DAYS_OF_WEEK = 7;
+
+ private final String UNDO_COMMAND = "undo";
+ private final String REDO_COMMAND = "redo";
+ private final String HELP_COMMAND = "help";
+ private final String EXIT_COMMAND = "exit";
+ private final String LIST_COMMAND = "list";
+ private final String LIST_ARCHIVED_COMMAND = "list archived";
+ private final String LIST_PRIORITY_COMMAND = "list priorityLevel";
+ private final String LIST_ALIAS_COMMAND = "list alias";
+ private final String CLEAR_COMMAND = "clear";
+ private final String STORAGE_COMMAND = "storage .";
+
+ KeyCombination saveKey = new KeyCodeCombination(KeyCode.S, KeyCombination.META_DOWN);
+ KeyCombination undoKey = new KeyCodeCombination(KeyCode.Z, KeyCombination.META_DOWN);
+ KeyCombination redoKey = new KeyCodeCombination(KeyCode.Y, KeyCombination.META_DOWN);
+ KeyCombination helpKey = new KeyCodeCombination(KeyCode.H, KeyCombination.META_DOWN);
+ KeyCombination exitKey = new KeyCodeCombination(KeyCode.Q, KeyCombination.META_DOWN);
+ KeyCombination listKey = new KeyCodeCombination(KeyCode.L, KeyCombination.META_DOWN);
+ KeyCombination listArchivedKey = new KeyCodeCombination(KeyCode.A, KeyCombination.META_DOWN);
+ KeyCombination listPriorityKey = new KeyCodeCombination(KeyCode.P, KeyCombination.META_DOWN);
+ KeyCombination listAliasKey = new KeyCodeCombination(KeyCode.I, KeyCombination.META_DOWN);
+ KeyCombination clearKey = new KeyCodeCombination(KeyCode.D, KeyCombination.META_DOWN);
+ KeyCombination leftKey = new KeyCodeCombination(KeyCode.LEFT, KeyCombination.META_DOWN);
+ KeyCombination rightKey = new KeyCodeCombination(KeyCode.RIGHT, KeyCombination.META_DOWN);
// stack to store commands history
private static Stack COMMAND_HISTORY_STACK = new Stack();
@@ -139,15 +172,6 @@ public void commandTextFieldOnKeyPressedHandler(KeyEvent keyEvent) {
String userInput = commandTextField.getText().trim();
- KeyCombination saveKey = new KeyCodeCombination(KeyCode.S, KeyCombination.META_DOWN);
- KeyCombination undoKey = new KeyCodeCombination(KeyCode.Z, KeyCombination.META_DOWN);
- KeyCombination redoKey = new KeyCodeCombination(KeyCode.Y, KeyCombination.META_DOWN);
- KeyCombination helpKey = new KeyCodeCombination(KeyCode.H, KeyCombination.META_DOWN);
- KeyCombination exitKey = new KeyCodeCombination(KeyCode.Q, KeyCombination.META_DOWN);
- KeyCombination listKey = new KeyCodeCombination(KeyCode.L, KeyCombination.META_DOWN);
- KeyCombination listArchivedKey = new KeyCodeCombination(KeyCode.A, KeyCombination.META_DOWN);
- KeyCombination clearKey = new KeyCodeCombination(KeyCode.D, KeyCombination.META_DOWN);
-
try {
KeyCode keyCode = keyEvent.getCode();
@@ -158,10 +182,9 @@ public void commandTextFieldOnKeyPressedHandler(KeyEvent keyEvent) {
}else if (keyCode == KeyCode.ESCAPE) {
- //close help dialog
- //processEsc();
+ showCheatsheet();
- }else if (keyCode == KeyCode.UP) {
+ } else if (keyCode == KeyCode.UP) {
processUp(userInput);
@@ -169,33 +192,49 @@ public void commandTextFieldOnKeyPressedHandler(KeyEvent keyEvent) {
processDown(userInput);
+ } else if (leftKey.match(keyEvent)) {
+
+ processDate(-1);
+
+ } else if (rightKey.match(keyEvent)) {
+
+ processDate(1);
+
} else if (undoKey.match(keyEvent)) {
- executeCommand("undo");
+ executeCommand(UNDO_COMMAND);
} else if (redoKey.match(keyEvent)) {
- executeCommand("redo");
+ executeCommand(REDO_COMMAND);
} else if (helpKey.match(keyEvent)) {
- executeCommand("help");
+ executeCommand(HELP_COMMAND);
} else if (exitKey.match(keyEvent)) {
- executeCommand("exit");
+ executeCommand(EXIT_COMMAND);
} else if (listKey.match(keyEvent)) {
- executeCommand("list");
+ executeCommand(LIST_COMMAND);
} else if (listArchivedKey.match(keyEvent)) {
- executeCommand("list t/Archived");
+ executeCommand(LIST_ARCHIVED_COMMAND);
+
+ } else if (listPriorityKey.match(keyEvent)) {
+
+ executeCommand(LIST_PRIORITY_COMMAND);
+
+ } else if (listAliasKey.match(keyEvent)) {
+
+ executeCommand(LIST_ALIAS_COMMAND);
} else if (clearKey.match(keyEvent)) {
- executeCommand("clear");
+ executeCommand(CLEAR_COMMAND);
}
@@ -229,23 +268,10 @@ public void processSave() {
DirectoryChooser directoryChooser = new DirectoryChooser();
File selectedFile = directoryChooser.showDialog(primaryStage);
String filepath = selectedFile.getAbsolutePath();
- executeCommand("save " + filepath);
+ executeCommand(STORAGE_COMMAND + filepath + "/savvytasker.xml");
}
- /**
- * Process the event that occurs after the user presses the [ESC] button.
- *
- * @param userInput the command keyed in by the user.
-
- public void processEsc() {
-
- if (userInput.equals("") && isHelpViewVisible()) {
-
- hideHelpView();
-
- }
-
/**
* Process the event that occurs after the user presses the [UP] button.
*
@@ -296,6 +322,27 @@ public void processDown(String userInput) {
}
+ /**
+ * Process the event that occurs after the user presses the left or right button.
+ *
+ * @param numbers of week to be added to the current selected week to be displayed in the daily task list view
+ */
+ public void processDate(int numberOfWeek) {
+
+ date = addWeek(numberOfWeek, date);
+ indicateWeekSelectionChanged();
+ }
+
+ /** Raises an event to indicate the week to be displayed has changed */
+ private void indicateWeekSelectionChanged() {
+ raise(new WeekSelectionChangedEvent());
+ }
+
+ /** Raises an event to indicate the week to be displayed has changed */
+ private void showCheatsheet() {
+ raise(new ShowCheatsheetEvent());
+ }
+
/**
* Execute commands
*
@@ -306,5 +353,23 @@ public void executeCommand(String commandInput) {
resultDisplay.postMessage(commandResult.feedbackToUser);
logger.info("Result: " + commandResult.feedbackToUser);
}
+
+ private Date addWeek(int numberOfWeek, Date date) {
+
+ //convert date object to calendar object and add 1 days
+ Calendar calendarExpectedDate = Calendar.getInstance();
+ calendarExpectedDate.setTime(date);
+
+ calendarExpectedDate.add(Calendar.DATE, (numberOfWeek*DAYS_OF_WEEK));
+
+ //convert calendar object back to date object
+ date = calendarExpectedDate.getTime();
+
+ return date;
+ }
+
+ public Date getDate() {
+ return date;
+ }
}
diff --git a/src/main/java/seedu/savvytasker/ui/DailyPanel.java b/src/main/java/seedu/savvytasker/ui/DailyPanel.java
index d94c16d0f800..a252b9c33ea2 100644
--- a/src/main/java/seedu/savvytasker/ui/DailyPanel.java
+++ b/src/main/java/seedu/savvytasker/ui/DailyPanel.java
@@ -1,22 +1,27 @@
package seedu.savvytasker.ui;
import java.text.SimpleDateFormat;
+import java.util.Calendar;
import java.util.Date;
import java.util.logging.Logger;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang.time.DateUtils;
+
import javafx.application.Platform;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.Node;
-import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.SplitPane;
+import javafx.scene.control.TextField;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import seedu.savvytasker.commons.core.LogsCenter;
import seedu.savvytasker.commons.events.ui.TaskPanelSelectionChangedEvent;
+import seedu.savvytasker.commons.util.FxViewUtil;
import seedu.savvytasker.model.task.ReadOnlyTask;
//@@author A0138431L
@@ -39,8 +44,9 @@ public class DailyPanel extends UiPart {
private VBox panel;
private AnchorPane placeHolderPane;
+
@FXML
- private Label dayHeader;
+ private TextField header;
@FXML
private ListView taskListView;
@@ -75,12 +81,19 @@ public static DailyPanel load(Stage primaryStage, AnchorPane DailyListPlaceholde
private void configure(ObservableList taskList, int dayOfTheWeek, Date date) {
String dateHeader = generateHeader(dayOfTheWeek, date);
+ Date today = new Date();
+ if(date == today) {
+ placeHolderPane.setStyle("-fx-background-color:#FF0000");
+ header.setStyle("-fx-text-fill:#FF0000");
+ }
setConnections(taskList, dateHeader);
addToPlaceholder();
+
}
private void setConnections(ObservableList taskList, String dateHeader) {
- dayHeader.setText(dateHeader);
+ header.clear();
+ header.setText(dateHeader);
taskListView.setItems(taskList);
taskListView.setCellFactory(listView -> new TaskListViewCell());
setEventHandlerForSelectionChangeEvent();
@@ -112,30 +125,43 @@ private String generateHeader(int dayOfTheWeek, Date date) {
SimpleDateFormat dayFormatter = new SimpleDateFormat(DAY_PATTERN);
SimpleDateFormat dateFormatter = new SimpleDateFormat(DATE_PATTERN);
+ Date today = new Date();
+ Date tomorrow = new Date();
+ tomorrow = addDay(1, tomorrow);
+
String day;
- switch (dayOfTheWeek) {
-
- case 0:
+ if(DateUtils.isSameDay(date, today)) {
day = TODAY_TITLE;
- break;
-
- case 1:
+
+ } else if (DateUtils.isSameDay(date, tomorrow)) {
day = TOMORROW_TITLE;
- break;
-
- default:
+
+ } else {
day = dayFormatter.format(date);
- break;
}
String header = String.format(DAY_DATE_FORMAT, day, dateFormatter.format(date));
return header;
}
+
+ private Date addDay(int i, Date date) {
+
+ //convert date object to calendar object and add 1 days
+ Calendar calendarExpectedDate = Calendar.getInstance();
+ calendarExpectedDate.setTime(date);
+
+ calendarExpectedDate.add(Calendar.DATE, i);
+
+ //convert calendar object back to date object
+ date = calendarExpectedDate.getTime();
+
+ return date;
+ }
class TaskListViewCell extends ListCell {
@@ -150,7 +176,7 @@ protected void updateItem(ReadOnlyTask task, boolean empty) {
setGraphic(null);
setText(null);
} else {
- setGraphic(TaskCard.load(task, getIndex() + 1).getLayout());
+ setGraphic(TaskCard.load(task, 0, false).getLayout());
}
}
}
diff --git a/src/main/java/seedu/savvytasker/ui/FloatingPanel.java b/src/main/java/seedu/savvytasker/ui/FloatingPanel.java
index dd32e6abe677..2074179901d2 100644
--- a/src/main/java/seedu/savvytasker/ui/FloatingPanel.java
+++ b/src/main/java/seedu/savvytasker/ui/FloatingPanel.java
@@ -104,7 +104,7 @@ protected void updateItem(ReadOnlyTask task, boolean empty) {
setGraphic(null);
setText(null);
} else {
- setGraphic(TaskCard.load(task, getIndex() + 1).getLayout());
+ setGraphic(TaskCard.load(task, 0, false).getLayout());
}
}
}
diff --git a/src/main/java/seedu/savvytasker/ui/MainWindow.java b/src/main/java/seedu/savvytasker/ui/MainWindow.java
index c1eb8c6a6c5f..4f6a94758057 100755
--- a/src/main/java/seedu/savvytasker/ui/MainWindow.java
+++ b/src/main/java/seedu/savvytasker/ui/MainWindow.java
@@ -12,6 +12,8 @@
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.MenuItem;
+import javafx.scene.image.Image;
+import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCombination;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.VBox;
@@ -22,6 +24,8 @@
import seedu.savvytasker.commons.core.LogsCenter;
import seedu.savvytasker.commons.events.model.SavvyTaskerChangedEvent;
import seedu.savvytasker.commons.events.ui.ExitAppRequestEvent;
+import seedu.savvytasker.commons.events.ui.ShowCheatsheetEvent;
+import seedu.savvytasker.commons.events.ui.WeekSelectionChangedEvent;
import seedu.savvytasker.logic.Logic;
import seedu.savvytasker.model.UserPrefs;
import seedu.savvytasker.model.task.ReadOnlyTask;
@@ -31,11 +35,10 @@
* a sorting and filtered list that display the result of the user command
* on the left and a week's view of the task
*
- * The week's view contains 4 lists, namely the floating list, overdue list,
+ * The week's view contains 4 lists, namely the floating list,
* days of the week list and upcoming list
*
* Floating list contains task without start and end dateTime
- * Overdue list contains task with end date before current date
* Days of the week list contains task that falls on the respective day of the selected week
* Upcoming list contains task with start date after the last day of selected week
*
@@ -44,14 +47,18 @@
*/
public class MainWindow extends UiPart {
- private static final String ICON = "/images/address_book_32.png";
+ private static final String ICON = "/images/savvytasker-icon.png";
+ private static final Image image = new Image(MainWindow.class.getResourceAsStream(ICON));
+ private static final String CHEATSHEET = "/images/cheatsheet.png";
+ private static final Image imageOverlay = new Image(MainWindow.class.getResourceAsStream(CHEATSHEET));
private static final String FXML = "MainWindow.fxml";
public static final int MIN_HEIGHT = 700;
public static final int MIN_WIDTH = 1150;
private Logic logic;
- Date date = new Date();
- private static int DAYS_OF_WEEK = 7;
+ Date firstDayOfSelectedWeek = new Date();
+ private static int DAYS_OF_WEEK = 7;
+ private boolean isShown = false;
// Independent Ui parts residing in this Ui container
//private BrowserPanel browserPanel;
@@ -65,8 +72,6 @@ public class MainWindow extends UiPart {
@FXML
private FloatingPanel floatingPanel;
@FXML
- private OverduePanel overduePanel;
- @FXML
private DailyPanel dailyPanel;
@FXML
private UpcomingPanel upcomingPanel;
@@ -84,7 +89,10 @@ public class MainWindow extends UiPart {
private AnchorPane commandBoxPlaceholder;
@FXML
- private MenuItem helpMenuItem;
+ private ImageView imageIcon;
+
+ @FXML
+ private ImageView cheatsheet;
@FXML
private AnchorPane taskListPanelPlaceholder;
@@ -101,13 +109,9 @@ public class MainWindow extends UiPart {
@FXML
private VBox listPanel;
-
@FXML
private AnchorPane floatingPanelPlaceholder;
- @FXML
- private AnchorPane overduePanelPlaceholder;
-
@FXML
private AnchorPane day1PanelPlaceholder;
@FXML
@@ -122,7 +126,7 @@ public class MainWindow extends UiPart {
private AnchorPane day6PanelPlaceholder;
@FXML
private AnchorPane day7PanelPlaceholder;
-
+
@FXML
private AnchorPane upcomingPanelPlaceholder;
@@ -168,25 +172,25 @@ private void configure(String appTitle, String addressBookName, Config config, U
}
void fillInnerParts() {
- //browserPanel = BrowserPanel.load(browserPlaceholder);
+ imageIcon.setImage(image);
taskListPanel = TaskListPanel.load(primaryStage, getTaskListPlaceholder(), logic.getFilteredTaskList());
aliasSymbolListPanel = AliasSymbolListPanel.load(primaryStage, getAliasSymbolPlaceholder(), logic.getAliasSymbolList());
setDefaultView();
-
resultDisplay = ResultDisplay.load(primaryStage, getResultDisplayPlaceholder());
statusBarFooter = StatusBarFooter.load(primaryStage, getStatusbarPlaceholder(), config.getSavvyTaskerFilePath());
commandBox = CommandBox.load(primaryStage, getCommandBoxPlaceholder(), resultDisplay, logic);
commandBox.getCommandTextField().requestFocus();
floatingPanel = FloatingPanel.load(primaryStage, getFloatingPanelPlaceholder(), logic.getFilteredFloatingTasks());
- overduePanel = OverduePanel.load(primaryStage, getOverduePanelPlaceholder(), logic.getFilteredOverdueTasks());
loadDailyPanel();
- upcomingPanel = UpcomingPanel.load(primaryStage, getUpcomingPanelPlaceholder(), logic.getFilteredUpcomingTasks(date));
+ upcomingPanel = UpcomingPanel.load(primaryStage, getUpcomingPanelPlaceholder(), logic.getFilteredUpcomingTasks(firstDayOfSelectedWeek));
+ cheatsheet.setImage(imageOverlay);
}
private void loadDailyPanel() {
+ firstDayOfSelectedWeek = commandBox.getDate();
for (int i = 0; i < DAYS_OF_WEEK; i++) {
Date onDate = new Date();
- onDate.setTime(date.getTime());
+ onDate.setTime(firstDayOfSelectedWeek.getTime());
onDate = addDay(i, onDate);
dailyPanel = DailyPanel.load(primaryStage, getDailyPanelPlaceholder(i),
logic.getFilteredDailyTasks(i, onDate), i, onDate);
@@ -221,6 +225,10 @@ private VBox getListPanel() {
return listPanel;
}
+ private VBox getRootLayout() {
+ return rootLayout;
+ }
+
private AnchorPane getCommandBoxPlaceholder() {
return commandBoxPlaceholder;
}
@@ -245,10 +253,6 @@ private AnchorPane getFloatingPanelPlaceholder() {
return floatingPanelPlaceholder;
}
- private AnchorPane getOverduePanelPlaceholder() {
- return overduePanelPlaceholder;
- }
-
private AnchorPane getDailyPanelPlaceholder(int index) {
switch(index) {
@@ -276,14 +280,12 @@ private AnchorPane getDailyPanelPlaceholder(int index) {
case 5:
return day6PanelPlaceholder;
-
+
case 6:
+ default:
return day7PanelPlaceholder;
- default:
-
- return day1PanelPlaceholder;
}
}
@@ -370,18 +372,36 @@ public TaskListPanel getTaskListPanel() {
return this.taskListPanel;
}
-
public void loadPersonPage(ReadOnlyTask task) {
+ //feature removed
//browserPanel.loadPersonPage(task);
}
public void releaseResources() {
- //browserPanel.freeResources();
+ //feature removed
+ //browserPanel.freeResources();
}
@Subscribe
public void handleSavvyTaskerChangedEvent(SavvyTaskerChangedEvent stce) {
loadDailyPanel();
}
+
+ @Subscribe
+ public void handleWeekSelectionChangedEvent(WeekSelectionChangedEvent stce) {
+ loadDailyPanel();
+ }
+
+ @Subscribe
+ public void handleCheatsheetDisplayToggledEvent(ShowCheatsheetEvent stce) {
+
+ if(isShown == false) {
+ cheatsheet.setVisible(true);
+ isShown = true;
+ } else {
+ cheatsheet.setVisible(false);
+ isShown = false;
+ }
+ }
}
\ No newline at end of file
diff --git a/src/main/java/seedu/savvytasker/ui/OverduePanel.java b/src/main/java/seedu/savvytasker/ui/OverduePanel.java
deleted file mode 100644
index b4eba1935b7d..000000000000
--- a/src/main/java/seedu/savvytasker/ui/OverduePanel.java
+++ /dev/null
@@ -1,112 +0,0 @@
-package seedu.savvytasker.ui;
-
-import java.util.logging.Logger;
-
-import javafx.application.Platform;
-import javafx.collections.ObservableList;
-import javafx.fxml.FXML;
-import javafx.scene.Node;
-import javafx.scene.control.ListCell;
-import javafx.scene.control.ListView;
-import javafx.scene.control.SplitPane;
-import javafx.scene.layout.AnchorPane;
-import javafx.scene.layout.VBox;
-import javafx.stage.Stage;
-import seedu.savvytasker.commons.core.LogsCenter;
-import seedu.savvytasker.commons.events.ui.TaskPanelSelectionChangedEvent;
-import seedu.savvytasker.model.task.ReadOnlyTask;
-
-//@@author A0138431L
-
-/**
-* Panel containing the list overdue task.
-* @author A0138431L
-*
-*/
-public class OverduePanel extends UiPart {
- private final Logger logger = LogsCenter.getLogger(TaskListPanel.class);
- private static final String FXML = "OverdueList.fxml";
- private VBox panel;
- private AnchorPane placeHolderPane;
-
- @FXML
- private ListView taskListView;
-
- public OverduePanel() {
- super();
- }
-
- @Override
- public void setNode(Node node) {
- panel = (VBox) node;
- }
-
- @Override
- public String getFxmlPath() {
- return FXML;
- }
-
- @Override
- public void setPlaceholder(AnchorPane pane) {
- this.placeHolderPane = pane;
- }
-
- public static OverduePanel load(Stage primaryStage, AnchorPane overdueListPlaceholder,
- ObservableList taskList) {
- OverduePanel oveduePanel =
- UiPartLoader.loadUiPart(primaryStage, overdueListPlaceholder, new OverduePanel());
- oveduePanel.configure(taskList);
- return oveduePanel;
- }
-
- private void configure(ObservableList taskList) {
- setConnections(taskList);
- addToPlaceholder();
- }
-
- private void setConnections(ObservableList taskList) {
- taskListView.setItems(taskList);
- taskListView.setCellFactory(listView -> new TaskListViewCell());
- setEventHandlerForSelectionChangeEvent();
- }
-
- private void addToPlaceholder() {
- SplitPane.setResizableWithParent(placeHolderPane, false);
- placeHolderPane.getChildren().add(panel);
- }
-
- private void setEventHandlerForSelectionChangeEvent() {
- taskListView.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
- if (newValue != null) {
- logger.fine("Selection in overdue task list panel changed to : '" + newValue + "'");
- raise(new TaskPanelSelectionChangedEvent(newValue));
- }
- });
- }
-
- public void scrollTo(int index) {
- Platform.runLater(() -> {
- taskListView.scrollTo(index);
- taskListView.getSelectionModel().clearAndSelect(index);
- });
- }
-
- class TaskListViewCell extends ListCell {
-
- public TaskListViewCell() {
- }
-
- @Override
- protected void updateItem(ReadOnlyTask task, boolean empty) {
- super.updateItem(task, empty);
-
- if (empty || task == null) {
- setGraphic(null);
- setText(null);
- } else {
- setGraphic(TaskCard.load(task, getIndex() + 1).getLayout());
- }
- }
- }
-
-}
diff --git a/src/main/java/seedu/savvytasker/ui/TaskCard.java b/src/main/java/seedu/savvytasker/ui/TaskCard.java
index d978f9229316..1646d1a1b142 100644
--- a/src/main/java/seedu/savvytasker/ui/TaskCard.java
+++ b/src/main/java/seedu/savvytasker/ui/TaskCard.java
@@ -1,8 +1,14 @@
+//@@author A0138431L
+
package seedu.savvytasker.ui;
+import java.util.Date;
+
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.Label;
+import javafx.scene.image.Image;
+import javafx.scene.image.ImageView;
import javafx.scene.layout.HBox;
import seedu.savvytasker.model.task.ReadOnlyTask;
@@ -10,10 +16,13 @@ public class TaskCard extends UiPart{
private static final String FXML = "TaskListCard.fxml";
+ private static final String ICON = "/images/overdue.png";
+ private static final Image OVERDUE_IMAGE = new Image(MainWindow.class.getResourceAsStream(ICON));
+
public static final String LOW_PRIORITY_BACKGROUND = "-fx-background-color:#CEFFDC";
public static final String MEDIUM_PRIORITY_BACKGROUND = "-fx-background-color:#FFFED8";
public static final String HIGH_PRIORITY_BACKGROUND = "-fx-background-color:#FF8180";
-
+
@FXML
private HBox cardPane;
@FXML
@@ -22,12 +31,19 @@ public class TaskCard extends UiPart{
private Label id;
@FXML
private Label details;
+ @FXML
+ private ImageView overdueIcon;
+ private boolean isShowingIndex;
private ReadOnlyTask task;
private int displayedIndex;
+
+ public TaskCard(boolean isShowingIndex){
+ this.isShowingIndex = isShowingIndex;
+ }
- public static TaskCard load(ReadOnlyTask task, int displayedIndex){
- TaskCard card = new TaskCard();
+ public static TaskCard load(ReadOnlyTask task, int displayedIndex, boolean isShowingIndex){
+ TaskCard card = new TaskCard(isShowingIndex);
card.task = task;
card.displayedIndex = displayedIndex;
return UiPartLoader.loadUiPart(card);
@@ -35,16 +51,36 @@ public static TaskCard load(ReadOnlyTask task, int displayedIndex){
@FXML
public void initialize() {
- taskName.setText(task.getTaskName());
- id.setText(displayedIndex + ". ");
+
+ taskName.setText(task.getTaskName());
+ if (isShowingIndex) {
+ id.setText(displayedIndex + ". ");
+ }
details.setText(task.getTextForUi());
setCardBackground();
+ setOverdue();
+
}
public HBox getLayout() {
return cardPane;
}
+ private void setOverdue() {
+
+ Date today = new Date();
+
+ if (task.getEndDateTime() != null) {
+
+ Date endDateTime = task.getEndDateTime();
+
+ if (endDateTime.compareTo(today)<0 && task.isArchived() == false) {
+
+ overdueIcon.setImage(OVERDUE_IMAGE);
+ }
+ }
+
+ }
private void setCardBackground() {
if (task.getPriority().toString().equals("High")) {
diff --git a/src/main/java/seedu/savvytasker/ui/TaskListPanel.java b/src/main/java/seedu/savvytasker/ui/TaskListPanel.java
index 56b053ec13b1..659260270feb 100644
--- a/src/main/java/seedu/savvytasker/ui/TaskListPanel.java
+++ b/src/main/java/seedu/savvytasker/ui/TaskListPanel.java
@@ -58,6 +58,7 @@ public static TaskListPanel load(Stage primaryStage, AnchorPane personListPlaceh
private void configure(ObservableList taskList) {
setConnections(taskList);
addToPlaceholder();
+ setBackground();
}
private void setConnections(ObservableList taskList) {
@@ -70,8 +71,17 @@ private void addToPlaceholder() {
SplitPane.setResizableWithParent(placeHolderPane, false);
placeHolderPane.getChildren().add(panel);
}
+
+ private void setBackground() {
+ if (taskListView.getItems().size() > 0) {
+ taskListView.setStyle("-fx-background-color: transparent");
+ } else {
+ taskListView.setStyle("-fx-background-color: white");
+ }
+ }
private void setEventHandlerForSelectionChangeEvent() {
+ setBackground();
taskListView.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
if (newValue != null) {
logger.fine("Selection in task list panel changed to : '" + newValue + "'");
@@ -97,7 +107,7 @@ protected void updateItem(ReadOnlyTask task, boolean empty) {
setGraphic(null);
setText(null);
} else {
- setGraphic(TaskCard.load(task, getIndex() + 1).getLayout());
+ setGraphic(TaskCard.load(task, getIndex() + 1, true).getLayout());
}
}
}
diff --git a/src/main/java/seedu/savvytasker/ui/UpcomingPanel.java b/src/main/java/seedu/savvytasker/ui/UpcomingPanel.java
index 6c374a4410d7..7862582b15fa 100644
--- a/src/main/java/seedu/savvytasker/ui/UpcomingPanel.java
+++ b/src/main/java/seedu/savvytasker/ui/UpcomingPanel.java
@@ -104,7 +104,7 @@ protected void updateItem(ReadOnlyTask task, boolean empty) {
setGraphic(null);
setText(null);
} else {
- setGraphic(TaskCard.load(task, getIndex() + 1).getLayout());
+ setGraphic(TaskCard.load(task, 0, false).getLayout());
}
}
}
diff --git a/src/main/resources/images/cheatsheet.png b/src/main/resources/images/cheatsheet.png
new file mode 100644
index 000000000000..4c4c2bbfdc0b
Binary files /dev/null and b/src/main/resources/images/cheatsheet.png differ
diff --git a/src/main/resources/images/overdue.png b/src/main/resources/images/overdue.png
new file mode 100644
index 000000000000..ed1b6b13e27a
Binary files /dev/null and b/src/main/resources/images/overdue.png differ
diff --git a/src/main/resources/images/savvytasker-icon.png b/src/main/resources/images/savvytasker-icon.png
new file mode 100644
index 000000000000..a809380abe90
Binary files /dev/null and b/src/main/resources/images/savvytasker-icon.png differ
diff --git a/src/main/resources/view/DailyList.fxml b/src/main/resources/view/DailyList.fxml
index 0ad3c5149b13..6a359692d8bb 100644
--- a/src/main/resources/view/DailyList.fxml
+++ b/src/main/resources/view/DailyList.fxml
@@ -1,8 +1,8 @@
-
+
@@ -12,7 +12,7 @@
-
-
+
+
diff --git a/src/main/resources/view/DarkTheme.css b/src/main/resources/view/DarkTheme.css
index 1efb0b72e305..f46f4b2772e4 100755
--- a/src/main/resources/view/DarkTheme.css
+++ b/src/main/resources/view/DarkTheme.css
@@ -1,3 +1,4 @@
+/*@@author A0138431L */
.background {
-fx-background-color: derive(#1d1d1d, 20%);
}
@@ -94,16 +95,18 @@
.list-cell .label {
-fx-text-fill: #010504;
+ -fx-font-family:'Helvetica Condensed';
}
.cell_big_label {
- -fx-font-size: 16px;
+ -fx-font-size: 12px;
-fx-text-fill: #010504;
+ -fx-font-family:'Helvetica Condensed';
}
.cell_small_label {
- -fx-font-size: 11px;
- -fx-text-fill: #010504;
+ -fx-font-size: 10px;
+ -fx-text-fill: #696969;
}
.anchor-pane {
@@ -276,10 +279,9 @@
-fx-padding: 8 1 8 1;
}
-#cardPane {
- -fx-background-color: transparent;
- -fx-border-color: #d6d6d6;
- -fx-border-width: 1 1 1 1;
+.cardPane {
+ -fx-border-color: #ffffff;
+ -fx-border-radius: 5px;
}
#commandTypeLabel {
@@ -294,29 +296,21 @@
#taskListView {
-fx-background-color: transparent;
}
-/*------------------------------------------ OverduePanel Styling ------------------------------------------*/
-.overdue-scrollpane, .overdue-panel {
- -fx-background-color:#DCFFFD;
-}
-
-.overdue-scrollpane > .scroll-bar:horizontal .thumb,
-.overdue-scrollpane > .scroll-bar:vertical .thumb {
- -fx-background-color:#99534D;
-}
-
-.overdue-panel .title, .overdue-panel .taskname {
- -fx-text-fill:#000000;
-}
-
-.overdue-panel .subtitle, .overdue-panel .timestamp {
- -fx-text-fill:#B26059;
+#header {
+ fx-font-size: 11px;
+ -fx-text-fill: #000000;
+ -fx-font-family:'Helvetica Condensed';
}
/*------------------------------------------ FloatingPanel Styling ------------------------------------------*/
.floating-scrollpane, .floating-panel {
-fx-background-color:#ACEDFF;
+ -fx-border-radius: 15px;
+ -fx-font-size: 14px;
+ -fx-text-fill: #000000;
+ -fx-font-family:'Helvetica Bold';
}
.floating-scrollpane {
@@ -340,6 +334,10 @@
.daily-scrollpane, .daily-panel {
-fx-background-color:#99D3FF;
+ -fx-border-radius: 15px;
+ -fx-font-size: 14px;
+ -fx-text-fill: #000000;
+ -fx-font-family:'Helvetica Bold';
}
.daily-scrollpane > .scroll-bar:horizontal .thumb,
@@ -358,6 +356,10 @@
/*------------------------------------------ UpcomingPanel Styling ------------------------------------------*/
.upcoming-scrollpane, .upcoming-panel {
-fx-background-color:#D1E0FF;
+ -fx-border-radius: 15px;
+ -fx-font-size: 14px;
+ -fx-text-fill: #000000;
+ -fx-font-family:'Helvetica Bold';
}
.upcoming-scrollpane > .scroll-bar:horizontal .thumb,
@@ -395,81 +397,3 @@
.archived-panel .taskname, .archived-panel .timestamp {
-fx-text-fill:#FFFFFF;
}
-
-/*------------------------------------------ SearchPanel Styling ------------------------------------------*/
-
-.search-view-title {
- -fx-font-family:'Helvetica Condensed';
- -fx-font-size:24;
- -fx-font-weight:normal;
-}
-
-.search-panel .title {
- -fx-font-family:'Helvetica Condensed';
- -fx-font-size:20;
- -fx-font-weight:normal;
-}
-
-.search-panel .check-box {
- -fx-font-family:'Helvetica';
- -fx-text-fill:#FFFFFF;
- -fx-font-size:10;
- -fx-font-weight:bold;
-}
-
-.search-panel .taskname, .search-panel .timestamp {
- -fx-text-fill:#FFFFFF;
-}
-
-/*------------------------------------------ HelpPanel Styling ------------------------------------------*/
-
-.help-panel .title {
- -fx-font-family:'Helvetica Bold';
- -fx-font-size:48;
- -fx-font-weight:normal;
-}
-
-.help-panel .subtitle {
- -fx-font-family:'Helvetica';
- -fx-font-size:13;
- -fx-font-weight:bold;
-}
-
-.overlay-scrollpane, .overlay-scrollpane > .viewport {
- -fx-background-color:transparent;
-}
-
-.scroll-pane > .scroll-bar:horizontal,
-.scroll-pane > .scroll-bar:vertical {
- -fx-background-color:transparent;
- -fx-background-radius:2em;
- -fx-border-radius:2em;
-}
-
-.scorll-pane > .scroll-bar:horizontal .track,
-.scroll-pane > .scroll-bar:vertical .track {
- -fx-background-color:transparent;
- -fx-background-radius:0em;
- -fx-border-color:transparent;
- -fx-border-radius:2em;
-}
-
-.scroll-pane > .scroll-bar:horizontal .thumb,
-.scroll-pane > .scroll-bar:vertical .thumb {
- -fx-background-insets:4, 5, 6;
- -fx-background-radius:2em;
- -fx-border-radius:2em;
-}
-
-.scroll-pane > .scroll-bar > .increment-button,
-.scroll-pane > .scroll-bar > .decrement-button {
- -fx-background-color:transparent;
- -fx-background-radius:0em;
- -fx-padding:0 0 10 0;
-}
-
-.scroll-pane > .scroll-bar > .increment-button > .increment-arrow,
-.scroll-pane > .scroll-bar > .decrement-button > .decrement-arrow {
- -fx-shape:" ";
- -fx-padding:0;
-}
\ No newline at end of file
diff --git a/src/main/resources/view/FloatingList.fxml b/src/main/resources/view/FloatingList.fxml
index 8d58ccc772b8..b6e353e0d1fc 100644
--- a/src/main/resources/view/FloatingList.fxml
+++ b/src/main/resources/view/FloatingList.fxml
@@ -1,11 +1,10 @@
-
+
-
@@ -13,11 +12,7 @@
-
+
diff --git a/src/main/resources/view/MainWindow.fxml b/src/main/resources/view/MainWindow.fxml
index 9c39bab158f1..6c3ab490740a 100755
--- a/src/main/resources/view/MainWindow.fxml
+++ b/src/main/resources/view/MainWindow.fxml
@@ -21,7 +21,7 @@
-
+
@@ -37,15 +37,14 @@
-
+
-
+
-
@@ -56,12 +55,7 @@
-
-
-
-
-
-
+
@@ -73,56 +67,54 @@
-
+
+
+
+
+
+
-
+
-
-
-
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
+
diff --git a/src/main/resources/view/OverdueList.fxml b/src/main/resources/view/OverdueList.fxml
deleted file mode 100644
index ab5ca805ad79..000000000000
--- a/src/main/resources/view/OverdueList.fxml
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/main/resources/view/PersonListCard.fxml b/src/main/resources/view/PersonListCard.fxml
deleted file mode 100755
index 9953ce588beb..000000000000
--- a/src/main/resources/view/PersonListCard.fxml
+++ /dev/null
@@ -1,42 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/main/resources/view/PersonListPanel.fxml b/src/main/resources/view/PersonListPanel.fxml
deleted file mode 100755
index aa9c30ae99eb..000000000000
--- a/src/main/resources/view/PersonListPanel.fxml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/main/resources/view/TaskListCard.fxml b/src/main/resources/view/TaskListCard.fxml
index 987e7b0ec451..7077986c6f44 100755
--- a/src/main/resources/view/TaskListCard.fxml
+++ b/src/main/resources/view/TaskListCard.fxml
@@ -1,42 +1,38 @@
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
-
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/view/TaskListPanel.fxml b/src/main/resources/view/TaskListPanel.fxml
index aa9c30ae99eb..2ba5b1ab0454 100644
--- a/src/main/resources/view/TaskListPanel.fxml
+++ b/src/main/resources/view/TaskListPanel.fxml
@@ -1,14 +1,16 @@
-
-
-
+
+
+
+
+
-
+
diff --git a/src/main/resources/view/UpcomingList.fxml b/src/main/resources/view/UpcomingList.fxml
index 8cd68484bb65..c305cd526ca9 100644
--- a/src/main/resources/view/UpcomingList.fxml
+++ b/src/main/resources/view/UpcomingList.fxml
@@ -1,11 +1,10 @@
-
+
-
@@ -13,11 +12,7 @@
-
+
diff --git a/src/test/java/guitests/HelpWindowTest.java b/src/test/java/guitests/HelpWindowTest.java
index 0b84c09ceb78..7b549a9b7b83 100644
--- a/src/test/java/guitests/HelpWindowTest.java
+++ b/src/test/java/guitests/HelpWindowTest.java
@@ -10,14 +10,6 @@ public class HelpWindowTest extends SavvyTaskerGuiTest {
@Test
public void openHelpWindow() {
- taskListPanel.clickOnListView();
-
- // Feature removed
- //assertHelpWindowOpen(mainMenu.openHelpWindowUsingAccelerator());
-
- // Feature removed
- //assertHelpWindowOpen(mainMenu.openHelpWindowUsingMenu());
-
assertHelpWindowOpen(commandBox.runHelpCommand());
}
diff --git a/src/test/java/guitests/StorageCommandTest.java b/src/test/java/guitests/StorageCommandTest.java
new file mode 100644
index 000000000000..0a0eda4104a2
--- /dev/null
+++ b/src/test/java/guitests/StorageCommandTest.java
@@ -0,0 +1,52 @@
+package guitests;
+
+import org.junit.Test;
+
+import seedu.savvytasker.commons.core.Config;
+import seedu.savvytasker.commons.exceptions.DataConversionException;
+import seedu.savvytasker.logic.commands.HelpCommand;
+import seedu.savvytasker.model.task.TaskList.DuplicateTaskException;
+import seedu.savvytasker.storage.JsonConfigStorage;
+import seedu.savvytasker.testutil.TestTask;
+
+import static org.junit.Assert.assertTrue;
+import static seedu.savvytasker.commons.core.Messages.MESSAGE_UNKNOWN_COMMAND;
+
+import java.io.IOException;
+
+import java.util.Optional;
+
+//@@author A0138431L
+public class StorageCommandTest extends SavvyTaskerGuiTest {
+
+ private static final String CONFIG_JSON = "config.json";
+ private static final String CONFIG_LOCATION = "./src/test/data/SaveLocationCommandTest";
+
+ @Test
+ public void saveToValidFilePath_success() throws DataConversionException, IOException, DuplicateTaskException {
+ String testFilePath = "./src/test/data/StorageCommandTest/newStorageLocation/";
+ commandBox.runCommand("storage " + testFilePath);
+ assertWriteToJsonSuccess();
+ assertWriteToXmlSuccess();
+ }
+ private void assertWriteToJsonSuccess() throws DataConversionException {
+ JsonConfigStorage jsonConfigStorage = new JsonConfigStorage(CONFIG_LOCATION);
+ Optional config = jsonConfigStorage.readConfig(CONFIG_JSON);
+ assert(config.isPresent());
+ }
+
+ private void assertWriteToXmlSuccess() {
+ TestTask[] currentList = td.getTypicalTasks();
+ assertTrue(taskListPanel.isListMatching(currentList));
+ }
+
+ @Test
+ public void storage() {
+ //invalid command
+ commandBox.runCommand("store");
+ assertResultMessage("Input: store\n" +
+ String.format(MESSAGE_UNKNOWN_COMMAND, HelpCommand.MESSAGE_USAGE));
+ }
+
+}
+//@@author
\ No newline at end of file
diff --git a/src/test/java/seedu/savvytasker/TestApp.java b/src/test/java/seedu/savvytasker/TestApp.java
index ad08171828b1..2da3b7709f80 100644
--- a/src/test/java/seedu/savvytasker/TestApp.java
+++ b/src/test/java/seedu/savvytasker/TestApp.java
@@ -56,11 +56,10 @@ protected UserPrefs initPrefs(Config config) {
UserPrefs userPrefs = super.initPrefs(config);
double x = Screen.getPrimary().getVisualBounds().getMinX();
double y = Screen.getPrimary().getVisualBounds().getMinY();
- userPrefs.updateLastUsedGuiSetting(new GuiSettings(600.0, 600.0, (int) x, (int) y));
+ userPrefs.updateLastUsedGuiSetting(new GuiSettings(1150.0, 700.0, (int) x, (int) y));
return userPrefs;
}
-
-
+
@Override
public void start(Stage primaryStage) {
ui.start(primaryStage);