diff --git a/Collate-TUI.jar b/Collate-TUI.jar
new file mode 100644
index 000000000000..50bdfe6902f8
Binary files /dev/null and b/Collate-TUI.jar differ
diff --git a/collate.bat b/collate.bat
new file mode 100644
index 000000000000..741fde7c69e2
--- /dev/null
+++ b/collate.bat
@@ -0,0 +1,3 @@
+java -jar Collate-TUI.jar collate from src/main to collated/main include java, fxml, css
+java -jar Collate-TUI.jar collate from src/test to collated/test include java
+java -jar Collate-TUI.jar collate from docs to collated/docs include md, html
diff --git a/collated/docs/A0097627N.md b/collated/docs/A0097627N.md
index a6220770e2f9..0ca6bea6988a 100644
--- a/collated/docs/A0097627N.md
+++ b/collated/docs/A0097627N.md
@@ -5,7 +5,7 @@
Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unlikely to have) - `*`
-Priority | As a ... | I want to ... | So that I can...
+Priority | As a(n) ... | I want to ... | So that I can...
-------- | :-------- | :--------- | :-----------
`* * *` | new user | see usage instructions | refer to instructions when I forget how to use the App
`* * *` | new user | view more information about a particular command | learn how to use various commands
@@ -21,9 +21,9 @@ Priority | As a ... | I want to ... | So that I can...
`*` | user | sort tasks by priority level | see the most important tasks and prioritize accordingly
`*` | user | undo most recent command | undo the most recent operation
`*` | user | redo most recent undo command | redo the operation done by the most recent undo action
+`*` | user | change storage location | choose where my tasks are saved at
`*` | advanced user | alias keywords with shorter versions | type a command faster
`*` | advanced user | remove alias of keywords with shorter versions | get rid of shorter version of certain keywords
-{More to be added}
## Appendix B : Use Cases
@@ -33,7 +33,7 @@ Priority | As a ... | I want to ... | So that I can...
(For all use cases below, the **System** is the `Savvy Tasker` and the **Actor** is the `user`, unless specified otherwise)
-#### Use case: Add task
+### Use case: Add task
**MSS**
@@ -63,7 +63,7 @@ Use case ends.
> 2d1. Savvy Tasker shows an error message
> Use case resumes at step 1
-#### Use case: List tasks
+### Use case: List tasks
**MSS**
@@ -79,7 +79,7 @@ Use case ends.
> 3a1. Savvy Tasker shows an error message
Use case ends
-#### Use case: Find task
+### Use case: Find task
**MSS**
@@ -100,7 +100,7 @@ Use case ends.
> Use case ends
-#### Use case: Modify task
+### Use case: Modify task
**MSS**
@@ -125,7 +125,30 @@ Use case ends.
> 2b1. Savvy Tasker shows an error message and display the expected format
Use case resumes at step 3
-#### Use case: Mark task as done
+
+### Use case: Change storage location
+
+**MSS**
+
+1. Savvy Tasker waits for user command
+2. User requests to change the storage location of Savvy Tasker
+3. Savvy Tasker changes the storage location, saving all existing data in the new location
+Use case ends.
+
+**Extensions**
+
+2a. The given path is invalid
+
+> 2a1. Savvy Tasker shows an error message
+ Use case ends
+
+2b. The given path is is not accessible (read/write) by Savvy Tasker
+
+> 2b1. Savvy Tasker shows an error message
+ Use case ends
+
+
+### Use case: Mark task as done
**MSS**
@@ -148,7 +171,7 @@ Use case ends.
> 3b1. Savvy Tasker shows a 'task already marked' error message.
> Use case resumes at step 1
-###Use case: Unmark marked task
+### Use case: Unmark marked task
**MSS**
@@ -169,7 +192,7 @@ Use case ends.
> Use case resumes at step 1
-#### Use case: Delete task
+### Use case: Delete task
**MSS**
@@ -191,7 +214,7 @@ Use case ends.
> 4a1. Savvy Tasker shows an error message
> Use case resumes at step 3
-###Use case: Alias keyword and use shorten keyword
+### Use case: Alias keyword and use shorten keyword
**MSS**
@@ -213,7 +236,7 @@ Use case ends.
> 2b1. Savvy Tasker shows a error message and the shorten keyword's original associated keyword
> Use case resumes at step 1
-###Use case: Unalias keyword
+### Use case: Unalias keyword
**MSS**
@@ -228,7 +251,7 @@ Use case ends.
> 2a1. Savvy Tasker shows a 'not found' error message
> Use case resumes at step 1
-###Use case: Undo previous command
+### Use case: Undo previous command
**MSS**
@@ -243,7 +266,7 @@ Use case ends.
> 2a1. Savvy Tasker shows a 'cannot undo' error message
> Use case ends
-###Use case: Redo most recently undone command
+### Use case: Redo most recently undone command
**MSS**
@@ -269,7 +292,6 @@ Use case ends.
8. Should store data in text file.
9. Should work without requiring an installer.
-{More to be added}
## Appendix D : Glossary
diff --git a/collated/docs/A0139915W.md b/collated/docs/A0139915W.md
index 5ab0becbc7be..d3102f52e3e7 100644
--- a/collated/docs/A0139915W.md
+++ b/collated/docs/A0139915W.md
@@ -79,7 +79,7 @@ Format: `add TASK_NAME [s/START_DATE] [e/END_DATE] [l/LOCATION] [p/PRIORITY_LEVE
> LOCATION | `Optional` Specifies the location where the task happens.
> PRIORITY_LEVEL | `Optional` Specifies the priority level of the task.
`Accepts` values `low`, `medium`, `high`
`Defaults` to `???`
> RECURRING_TYPE | `Optional` Specifies the recurring type of the task.
`Accepts` values `none`, `daily`, `weekly`, `monthly`, `yearly`
`Defaults` to `none`
-> NUMBER_OF_RECURRENCE | `Optional` Specifies the number of times the task recurrs. A value of 0 specifies a never-ending recurrence.
`Defaults` to `0`
`Ignored` if RECURRING_TYPE is `none`
+> NUMBER_OF_RECURRENCE | `Optional` Specifies the number of times the task recurrs.
`Defaults` to `1`
`Ignored` if RECURRING_TYPE is `none`
> CATEGORY | `Optional` Specifies a custom category for the task. This can be used for keeping track of similar tasks.
> DESCRIPTION | `Optional` Describes the task.
@@ -95,11 +95,11 @@ Examples:
#### Listing all tasks: `list`
Shows a list of all tasks in Savvy Tasker
-Format: `list [t/LIST_TYPE]`
+Format: `list [LIST_TYPE]`
> Parameters | Description
> -------- | :--------
-> LIST_TYPE | `Optional` Specifies the name of the task.
`Accepts` values `DueDate`, `PriorityLevel`, `Archived`
`Defaults` to `DueDate`
+> LIST_TYPE | `Optional` Specifies the name of the task.
`Accepts` values `DueDate`, `PriorityLevel`, `Archived`, `Alias`
`Defaults` to `DueDate`
`LIST_TYPE` Explanation:
* `DueDate`
@@ -108,7 +108,9 @@ Format: `list [t/LIST_TYPE]`
* `PriorityLevel`
Tasks are sorted according to priority level beginning with the highest.
* `Archived`
- Tasks that have been [marked](#mark-a-task-as-done--mark) are listed. They are sorted according to the time of creation of the task.
+ Tasks that have been [marked](#mark-a-task-as-done--mark) are listed. They are sorted according to the time of creation of the task.
+* `Alias`
+ [Aliases](#alias-a-keyword--alias) that have been registered are listed.
#### Finding all task containing any keyword in its name: `find`
Finds tasks whose names contain any of the given keywords.
@@ -168,6 +170,16 @@ Format: `modify INDEX [t/TASK_NAME] [s/START_DATE] [e/END_DATE] [l/LOCATION] [p/
>
> Overwrites any of the specified fields ('LOCATION', 'DESCRIPTION'...) with the new values
+#### Change storage location : `storage`
+Changes the storage location of Savvy Tasker.
+Format: `storage PATH`
+
+> 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.
+
```
###### \UserGuide.md
``` md
@@ -182,10 +194,11 @@ Command | Format
[Delete](#deleting-a-task--delete) | `delete INDEX [MORE_INDEX]`
Example: `delete 1 2 3`
[Exit](#exiting-the-program--exit) | `exit`
[Find](#finding-all-task-containing-any-keyword-in-its-name-find) | `find [t/FIND_TYPE] KEYWORD [MORE_KEYWORDS]`
Example: `find t/exact CS2103 Meeting`
-[List](#listing-all-tasks-list) | `list [t/LIST_TYPE]`
Example: `list t/archived`
+[List](#listing-all-tasks-list) | `list [LIST_TYPE]`
Example: `list archived`
[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`
[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`
diff --git a/collated/main/A0097627N.md b/collated/main/A0097627N.md
index 8e35367693b4..58bc1d6cc7f0 100644
--- a/collated/main/A0097627N.md
+++ b/collated/main/A0097627N.md
@@ -17,7 +17,7 @@
@Override
public boolean redo() {
execute();
- return false;
+ return true;
}
/**
@@ -26,22 +26,84 @@
*/
@Override
public boolean undo() {
-
- UnmodifiableObservableList lastShownList = model.getFilteredTaskListTask();
-
- for (int i = 0; i < lastShownList.size(); i++) {
- if (lastShownList.get(i) == toAdd){
- ReadOnlyTask taskToDelete = lastShownList.get(i);
- try {
- model.deleteTask(taskToDelete);
- } catch (TaskNotFoundException e) {
- e.printStackTrace();
- }
+ Iterator itr = tasksAdded.iterator();
+ while (itr.hasNext()) {
+ try {
+ model.deleteTask(itr.next());
+ } catch (TaskNotFoundException e) {
+ // do nothing.
}
- }
+ }
+ // clears the list of tasks added.
+ // if redo is performed, the list will be populated again.
+ tasksAdded.clear();
+ return true;
+ }
+
+ /**
+ * Check if command is an undo command
+ * @return true if the command is an undo operation, false otherwise
+ */
+ @Override
+ public boolean isUndo() {
return false;
}
+ /**
+ * Check if command is a redo command
+ * @return true if the command is a redo operation, false otherwise
+ */
+ @Override
+ public boolean isRedo(){
+ return false;
+ }
+```
+###### \java\seedu\savvytasker\logic\commands\AliasCommand.java
+``` java
+ /**
+ * Checks if a command can perform undo operations
+ * @return true if the command supports undo, false otherwise
+ */
+ @Override
+ public boolean canUndo() {
+ return true;
+ }
+
+ /**
+ * Redo the alias command
+ * @return true if the operation completed successfully, false otherwise
+ */
+ @Override
+ public boolean redo() {
+ execute();
+ return true;
+ }
+ /**
+ * Undo the alias command
+ * @return true if the operation completed successfully, false otherwise
+ */
+ @Override
+ public boolean undo() {
+ // TODO Auto-generated method stub
+
+ assert model != null;
+
+ AliasSymbol toRemove = null;
+ for(AliasSymbol symbol : model.getSavvyTasker().getReadOnlyListOfAliasSymbols()) {
+ if (symbol.getKeyword().equals(this.keyword)) {
+ toRemove = symbol;
+ break;
+ }
+ }
+ try {
+ model.removeAliasSymbol(toRemove);
+ } catch (SymbolKeywordNotFoundException e) {
+ e.printStackTrace();
+ }
+
+ return true;
+ }
+
/**
* Check if command is an undo command
* @return true if the command is an undo operation, false otherwise
@@ -59,6 +121,7 @@
public boolean isRedo(){
return false;
}
+}
```
###### \java\seedu\savvytasker\logic\commands\ClearCommand.java
``` java
@@ -492,8 +555,7 @@
for(Task taskToMark : tasksToMark) {
if (!taskToMark.isArchived()){
taskToMark.setArchived(true);
- model.deleteTask(taskToMark);
- model.addTask(taskToMark);
+ model.modifyTask(taskToMark, taskToMark);
resultSb.append(String.format(MESSAGE_MARK_TASK_SUCCESS, taskToMark));
} else {
resultSb.append(String.format(MESSAGE_MARK_TASK_FAIL, taskToMark));
@@ -501,8 +563,6 @@
}
} catch (TaskNotFoundException pnfe) {
assert false : "The target task cannot be missing";
- } catch (DuplicateTaskException e) {
- e.printStackTrace();
} catch (InvalidDateException e) {
assert false : "The target task should be valid, only the archived flag is set";
}
@@ -730,6 +790,55 @@
return false;
}
```
+###### \java\seedu\savvytasker\logic\commands\StorageCommand.java
+``` java
+ /**
+ * Checks if a command can perform undo operations
+ * @return true if the command supports undo, false otherwise
+ */
+ @Override
+ public boolean canUndo() {
+ return false;
+ }
+
+ /**
+ * Redo the select command
+ * @return true if the operation completed successfully, false otherwise
+ */
+ @Override
+ public boolean redo() {
+ // nothing required to be done
+ return false;
+ }
+
+ /**
+ * Undo the select command
+ * @return true if the operation completed successfully, false otherwise
+ */
+ @Override
+ public boolean undo() {
+ // nothing required to be done
+ return false;
+ }
+
+ /**
+ * Check if command is an undo command
+ * @return true if the command is an undo operation, false otherwise
+ */
+ @Override
+ public boolean isUndo() {
+ return false;
+ }
+
+ /**
+ * Check if command is a redo command
+ * @return true if the command is a redo operation, false otherwise
+ */
+ @Override
+ public boolean isRedo(){
+ return false;
+ }
+```
###### \java\seedu\savvytasker\logic\commands\UnaliasCommand.java
``` java
/**
@@ -885,8 +994,7 @@
for(Task taskToUnmark : tasksToUnmark) {
if (taskToUnmark.isArchived()){
taskToUnmark.setArchived(false);
- model.deleteTask(taskToUnmark);
- model.addTask(taskToUnmark);
+ model.modifyTask(taskToUnmark, taskToUnmark);
model.updateFilteredListToShowArchived();
resultSb.append(String.format(MESSAGE_UNMARK_TASK_SUCCESS, taskToUnmark));
} else {
@@ -895,9 +1003,7 @@
}
} catch (TaskNotFoundException pnfe) {
assert false : "The target task cannot be missing";
- } catch (DuplicateTaskException e) {
- e.printStackTrace();
- }catch (InvalidDateException e) {
+ } catch (InvalidDateException e) {
assert false : "The target task should be valid, only the archived flag is set";
}
return new CommandResult(resultSb.toString());
diff --git a/collated/main/A0139915W.md b/collated/main/A0139915W.md
index 0942cfeac070..150582cad2c3 100644
--- a/collated/main/A0139915W.md
+++ b/collated/main/A0139915W.md
@@ -1,4 +1,27 @@
# 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
@@ -24,6 +47,12 @@ public class TaskPanelSelectionChangedEvent extends BaseEvent {
}
}
```
+###### \java\seedu\savvytasker\commons\util\FileUtil.java
+``` java
+ public static boolean createIfMissing(File file) throws IOException {
+ return createFile(file);
+ }
+```
###### \java\seedu\savvytasker\commons\util\SmartDefaultDates.java
``` java
/**
@@ -86,6 +115,7 @@ public class SmartDefaultDates {
calendar.set(Calendar.HOUR_OF_DAY, 23);
calendar.set(Calendar.MINUTE, 59);
calendar.set(Calendar.SECOND, 59);
+ calendar.set(Calendar.MILLISECOND, 0);
}
return calendar.getTime();
}
@@ -105,7 +135,13 @@ public class SmartDefaultDates {
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
+ calendar.set(Calendar.MILLISECOND, 0);
this.startDateTime = calendar.getTime();
+
+ if (this.startDateTime.compareTo(this.endDateTime) > 0) {
+ // end date is before today, leave start date as null
+ this.startDateTime = null;
+ }
}
@@ -134,6 +170,7 @@ public class SmartDefaultDates {
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
+ calendar.set(Calendar.MILLISECOND, 0);
}
return calendar.getTime();
}
@@ -154,6 +191,7 @@ public class SmartDefaultDates {
calendar.set(Calendar.HOUR_OF_DAY, 23);
calendar.set(Calendar.MINUTE, 59);
calendar.set(Calendar.SECOND, 59);
+ calendar.set(Calendar.MILLISECOND, 0);
this.endDateTime = calendar.getTime();
}
@@ -169,11 +207,6 @@ public class SmartDefaultDates {
Date end = getEnd(endDateTime);
this.startDateTime = start;
this.endDateTime = end;
- if (this.startDateTime.compareTo(this.endDateTime) > 0) {
- calendar.setTime(this.endDateTime);
- calendar.add(Calendar.DATE, 7);
- this.endDateTime = calendar.getTime();
- }
}
public Date getStartDate() {
@@ -185,6 +218,22 @@ public class SmartDefaultDates {
}
}
```
+###### \java\seedu\savvytasker\commons\util\StringUtil.java
+``` java
+ // reused original implementation of 'containsIgnoreCase' to find exact matches
+ public static boolean containsExactIgnoreCase(String source, String query) {
+ List strings = Arrays.asList(source);
+ return strings.stream().filter(s -> s.equalsIgnoreCase(query)).count() > 0;
+ }
+
+ // reused original implementation of 'containsIgnoreCase' to find partial matches
+ public static boolean containsPartialIgnoreCase(String source, String query) {
+ if (source == null) return false;
+ String[] split = source.toLowerCase().split("\\s+");
+ List strings = Arrays.asList(split);
+ return strings.stream().filter(s -> s.contains(query.toLowerCase())).count() > 0;
+ }
+```
###### \java\seedu\savvytasker\logic\commands\AddCommand.java
``` java
/**
@@ -202,16 +251,24 @@ public class SmartDefaultDates {
this.numberOfRecurrence = numberOfRecurrence;
this.category = category;
this.description = description;
+ tasksAdded = new LinkedList();
}
private void createTask() {
final boolean isArchived = false; // all tasks are first added as active tasks
final int taskId = 0; // taskId to be assigned by ModelManager, leave as 0
+ final int groupId = 0; // groupId to be assigned by ModelManager, leave as 0
- this.toAdd = new Task(taskId, taskName, startDateTime, endDateTime,
+ this.toAdd = new Task(taskId, groupId, taskName, startDateTime, endDateTime,
location, priority, recurringType, numberOfRecurrence,
category, description, isArchived);
}
+
+ private void addToListOfTasksAdded(Task... tasks) {
+ for (Task t : tasks) {
+ tasksAdded.add(t);
+ }
+ }
@Override
public CommandResult execute() {
@@ -219,15 +276,41 @@ public class SmartDefaultDates {
createTask();
try {
- model.addTask(toAdd);
+ Task taskAdded = null;
+ if (toAdd.getRecurringType() == RecurrenceType.None) {
+ // not a recurring task, add a single task
+ taskAdded = model.addTask(toAdd);
+ addToListOfTasksAdded(taskAdded);
+ } else {
+ // a recurring task, add a group of recurring tasks
+ LinkedList tasksAdded = model.addRecurringTask(toAdd);
+ taskAdded = tasksAdded.peekFirst();
+ addToListOfTasksAdded(tasksAdded.toArray(new Task[tasksAdded.size()]));
+ }
+
+ 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 (DuplicateTaskException e) {
- return new CommandResult(MESSAGE_DUPLICATE_TASK);
} catch (InvalidDateException ex) {
return new CommandResult(MESSAGE_INVALID_START_END);
}
}
+
+ /**
+ * Helper method to retrieve the index of the task in the tasklist that was added.
+ * @param task The task to find
+ * @return Returns the index of the task in the list, -1 if not found.
+ */
+ private int getIndexOfTask(Task task) {
+ model.updateFilteredListToShowActive(); //because newly added tasks are all active.
+ UnmodifiableObservableList lastShownList = model.getFilteredTaskList();
+ return lastShownList.indexOf(task);
+ }
```
###### \java\seedu\savvytasker\logic\commands\DeleteCommand.java
``` java
@@ -258,7 +341,7 @@ public class SmartDefaultDates {
//tasksToUndo.add((Task)taskToDelete);
resultSb.append(String.format(MESSAGE_DELETE_TASK_SUCCESS, taskToDelete));
}
- } catch (TaskNotFoundException pnfe) {
+ } catch (TaskNotFoundException tnfe) {
assert false : "The target task cannot be missing";
}
@@ -301,6 +384,9 @@ public class SmartDefaultDates {
// use default, sort by due date
_listType = ListType.DueDate;
}
+
+ // shows the task list by default, unless user
+ // specifies to show the alias
switch (_listType)
{
case DueDate:
@@ -312,10 +398,19 @@ public class SmartDefaultDates {
case Archived:
model.updateFilteredListToShowArchived();
break;
+ case Alias:
+ EventsCenter.getInstance().post(new ChangeListRequestEvent(DisplayedList.Alias));
+ break;
default:
- assert false; // should not reach here
+ // nothing to do
+ break;
+ }
+ if (_listType != ListType.Alias) {
+ EventsCenter.getInstance().post(new ChangeListRequestEvent(DisplayedList.Task));
+ return new CommandResult(getMessageForTaskListShownSummary(model.getFilteredTaskList().size()));
+ } else {
+ return new CommandResult(getMessageForAliasListShownSummary(model.getAliasSymbolCount()));
}
- return new CommandResult(getMessageForTaskListShownSummary(model.getFilteredTaskList().size()));
}
```
###### \java\seedu\savvytasker\logic\commands\ModifyCommand.java
@@ -358,7 +453,13 @@ public class SmartDefaultDates {
try {
originalTask = (Task)taskToModify;
- model.modifyTask(taskToModify, replacement);
+ Task taskModified = model.modifyTask(taskToModify, replacement);
+ 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";
} catch (InvalidDateException ex) {
@@ -367,6 +468,48 @@ public class SmartDefaultDates {
return new CommandResult(String.format(MESSAGE_SUCCESS, replacement));
}
+
+ /**
+ * Helper method to retrieve the index of the task in the tasklist that was added.
+ * @param task The task to find
+ * @return Returns the index of the task in the list, -1 if not found.
+ */
+ private int getIndexOfTask(Task task) {
+ UnmodifiableObservableList lastShownList = model.getFilteredTaskList();
+ 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
@@ -384,24 +527,55 @@ public class SmartDefaultDates {
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
- /** Deletes the given Task. */
- void deleteTask(ReadOnlyTask target) throws TaskNotFoundException;
+ /**
+ * Deletes the given Task.
+ * @throws {@link TaskNotFoundException} if the task does not exist
+ * @return Returns a Task if the delete operation is successful, an exception is thrown otherwise.
+ * */
+ Task deleteTask(ReadOnlyTask target) throws TaskNotFoundException;
- /** Modifies the given Task. */
- void modifyTask(ReadOnlyTask target, Task replacement) throws TaskNotFoundException, InvalidDateException;
+ /**
+ * Modifies the given Task.
+ * @throws {@link TaskNotFoundException} if the task does not exist
+ * @throws {@link InvalidDateException} if the end date is earlier than the start date
+ * @return Returns a Task if the modify operation is successful, an exception is thrown otherwise.
+ * */
+ Task modifyTask(ReadOnlyTask target, Task replacement) throws TaskNotFoundException, InvalidDateException;
/** Adds the given Task.
* @throws {@link DuplicateTaskException} if a duplicate is found
+ * @throws {@link InvalidDateException} if the end date is earlier than the start date
+ * @return Returns a Task if the add operation is successful, an exception is thrown otherwise.
+ * */
+ Task addTask(Task task) throws InvalidDateException;
+
+ /** Adds the given Task as a recurring task. The task's recurrence type must not be null.
+ * @throws {@link DuplicateTaskException} if a duplicate is found
+ * @throws {@link InvalidDateException} if the end date is earlier than the start date
+ * @return Returns the list of Tasks added if the add operation is successful, an exception is thrown otherwise.
* */
- void addTask(Task task) throws DuplicateTaskException, InvalidDateException;
+ LinkedList addRecurringTask(Task task) throws InvalidDateException;
/** Returns the filtered task list as an {@code UnmodifiableObservableList} */
UnmodifiableObservableList getFilteredTaskList();
-
- /** Returns the filtered task list as an {@code UnmodifiableObservableList} */
- UnmodifiableObservableList getFilteredTaskListTask();
/** Updates the filter of the filtered task list to show all active tasks sorted by due date */
void updateFilteredListToShowActiveSortedByDueDate();
@@ -436,7 +610,7 @@ public class SmartDefaultDates {
savvyTasker = new SavvyTasker(src);
filteredTasks = new FilteredList<>(savvyTasker.getTasks());
- sortedAndFilteredTasks = new SortedList<>(filteredTasks, new TaskSortedByDefault());
+ sortedAndFilteredTasks = new SortedList<>(filteredTasks, new TaskSortedByDueDate());
updateFilteredListToShowActive(); // shows only active tasks on start
}
@@ -447,30 +621,40 @@ public class SmartDefaultDates {
public ModelManager(ReadOnlySavvyTasker initialData) {
savvyTasker = new SavvyTasker(initialData);
filteredTasks = new FilteredList<>(savvyTasker.getTasks());
- sortedAndFilteredTasks = new SortedList<>(filteredTasks, new TaskSortedByDefault());
+ sortedAndFilteredTasks = new SortedList<>(filteredTasks, new TaskSortedByDueDate());
updateFilteredListToShowActive(); // shows only active tasks on start
}
```
###### \java\seedu\savvytasker\model\ModelManager.java
``` java
@Override
- public synchronized void deleteTask(ReadOnlyTask target) throws TaskNotFoundException {
- savvyTasker.removeTask(target);
+ public synchronized Task deleteTask(ReadOnlyTask target) throws TaskNotFoundException {
+ Task taskDeleted = savvyTasker.removeTask(target);
indicateSavvyTaskerChanged();
+ return taskDeleted;
}
@Override
- public void modifyTask(ReadOnlyTask target, Task replacement) throws TaskNotFoundException, InvalidDateException {
- savvyTasker.replaceTask(target, replacement);
+ public synchronized Task modifyTask(ReadOnlyTask target, Task replacement) throws TaskNotFoundException, InvalidDateException {
+ Task taskModified = savvyTasker.replaceTask(target, replacement);
indicateSavvyTaskerChanged();
+ return taskModified;
}
@Override
- public synchronized void addTask(Task t) throws DuplicateTaskException, InvalidDateException {
- t.setId(savvyTasker.getNextTaskId());
- savvyTasker.addTask(t);
+ public synchronized Task addTask(Task t) throws InvalidDateException {
+ Task taskAdded = savvyTasker.addTask(t);
updateFilteredListToShowActive();
indicateSavvyTaskerChanged();
+ return taskAdded;
+ }
+
+ @Override
+ public synchronized LinkedList addRecurringTask(Task recurringTask) throws InvalidDateException {
+ LinkedList recurringTasks = savvyTasker.addRecurringTasks(recurringTask);
+ updateFilteredListToShowActive();
+ indicateSavvyTaskerChanged();
+ return recurringTasks;
}
```
###### \java\seedu\savvytasker\model\ModelManager.java
@@ -479,11 +663,6 @@ public class SmartDefaultDates {
public UnmodifiableObservableList getFilteredTaskList() {
return new UnmodifiableObservableList(sortedAndFilteredTasks);
}
-
- @Override
- public UnmodifiableObservableList getFilteredTaskListTask() {
- return new UnmodifiableObservableList(sortedAndFilteredTasks);
- }
@Override
public void updateFilteredListToShowActiveSortedByDueDate() {
@@ -762,18 +941,7 @@ public class SmartDefaultDates {
else if (task1 == null) return 1;
else if (task2 == null) return -1;
else {
- // Priority Level can be nulls
- // Check for existence of priorityLevel before comparing
- if (task1.getPriority() == null &&
- task2.getPriority() == null) {
- return 0;
- } else if (task1.getPriority() == null) {
- return 1;
- } else if (task2.getPriority() == null) {
- return -1;
- } else {
- return task2.getPriority().compareTo(task1.getPriority());
- }
+ return task2.getPriority().compareTo(task1.getPriority());
}
}
@@ -795,40 +963,162 @@ public class SmartDefaultDates {
```
###### \java\seedu\savvytasker\model\SavvyTasker.java
``` java
+
/**
- * Returns the next available id for use to uniquely identify a task.
- * @author A0139915W
- * @return The next available id.
+ * Adds a task to savvy tasker.
+ * @throws {@link InvalidDateException} if the end date is earlier than the start date
+ * @return Returns the task added if the operation succeeds, an exception is thrown otherwise.
*/
- public int getNextTaskId() {
- return tasks.getNextId();
+ public Task addTask(Task t) throws InvalidDateException {
+ // guarantees unique ID
+ t.setId(tasks.getNextId());
+ try {
+ return tasks.add(t);
+ } catch (DuplicateTaskException e) {
+ // should never get here.
+ return null;
+ }
}
/**
- * Adds a task to savvy tasker.
- * @throws TaskList.DuplicateTaskException if an equivalent task already exists.
+ * Adds a group of recurring tasks to savvy tasker.
+ * @throws {@link InvalidDateException} if the end date is earlier than the start date
+ * @return Returns the list of recurring tasks if the operation succeeds, an exception is thrown otherwise
+ */
+ public LinkedList addRecurringTasks(Task recurringTask) throws InvalidDateException {
+ LinkedList tasksToAdd =
+ createRecurringTasks(recurringTask, recurringTask.getRecurringType(),
+ recurringTask.getNumberOfRecurrence());
+ Iterator itr = tasksToAdd.iterator();
+
+ while(itr.hasNext()) {
+ // this will be an atomic operation
+ // guaranteed no duplicates
+ // if the start/end dates are invalid,
+ // the first task to be added will fail immediately,
+ // subsequent tasks will not be added
+ try {
+ tasks.add(itr.next());
+ } catch (DuplicateTaskException e) {
+ // should never get here.
+ return null;
+ }
+ }
+ return tasksToAdd;
+ }
+
+ /**
+ * Creates a list of recurring tasks to be added into savvy tasker.
+ * @param recurringTask the task that recurs
+ * @param recurringType the type of recurrence
+ * @param numberOfRecurrences the number of recurrences
+ * @return A list of tasks that represents a recurring task.
*/
- public void addTask(Task t) throws DuplicateTaskException, InvalidDateException {
- tasks.add(t);
+ private LinkedList createRecurringTasks(Task recurringTask, RecurrenceType recurringType, int numberOfRecurrences) {
+ assert recurringTask.getRecurringType() != null;
+ assert recurringTask.getNumberOfRecurrence() > 0;
+
+ LinkedList listOfTasks = new LinkedList();
+ recurringTask.setGroupId(tasks.getNextGroupId());
+
+ for (int i = 0; i < numberOfRecurrences; ++i) {
+ Task t = recurringTask.clone();
+ // guarantees uniqueness
+ t.setId(tasks.getNextId());
+ listOfTasks.add(setDatesForRecurringType(t, recurringType, i));
+ }
+
+ return listOfTasks;
+ }
+
+ /**
+ * Helper function for createRecurringTasks(). Sets the respective start/end datetime for the
+ * i-th recurring task to be added
+ * @param t The first recurring task
+ * @param recurringType the type of recurrence
+ * @param index the index of the loop
+ * @return A task with its respective datetime set.
+ */
+ private Task setDatesForRecurringType(Task t, RecurrenceType recurringType, int index) {
+ Date startDate = t.getStartDateTime();
+ Date endDate = t.getEndDateTime();
+ Calendar calendar = Calendar.getInstance();
+ switch (recurringType) {
+ case Daily: // add one day to the i-th task
+ if (startDate != null) {
+ calendar.setTime(startDate);
+ calendar.add(Calendar.DATE, 1 * index);
+ startDate = calendar.getTime();
+ }
+ if (endDate != null) {
+ calendar.setTime(endDate);
+ calendar.add(Calendar.DATE, 1 * index);
+ endDate = calendar.getTime();
+ }
+ break;
+ case Weekly: // add 7 days to the i-th task
+ if (startDate != null) {
+ calendar.setTime(startDate);
+ calendar.add(Calendar.DATE, 7 * index);
+ startDate = calendar.getTime();
+ }
+ if (endDate != null) {
+ calendar.setTime(endDate);
+ calendar.add(Calendar.DATE, 7 * index);
+ endDate = calendar.getTime();
+ }
+ break;
+ case Monthly: // add 1 month to the i-th task
+ if (startDate != null) {
+ calendar.setTime(startDate);
+ calendar.add(Calendar.MONTH, 1 * index);
+ startDate = calendar.getTime();
+ }
+ if (endDate != null) {
+ calendar.setTime(endDate);
+ calendar.add(Calendar.MONTH, 1 * index);
+ endDate = calendar.getTime();
+ }
+ break;
+ case Yearly: // add 1 year to the i-th task
+ if (startDate != null) {
+ calendar.setTime(startDate);
+ calendar.add(Calendar.YEAR, 1 * index);
+ startDate = calendar.getTime();
+ }
+ if (endDate != null) {
+ calendar.setTime(endDate);
+ calendar.add(Calendar.YEAR, 1 * index);
+ endDate = calendar.getTime();
+ }
+ break;
+ case None:
+ default:
+ assert false; // should not come here
+ }
+ t.setStartDateTime(startDate);
+ t.setEndDateTime(endDate);
+ return t;
}
/**
* Removes a task from savvy tasker.
* @param key the task to be removed
- * @return true if the task is removed successfully
- * @throws TaskNotFoundException if the task to be removed does not exist
+ * @throws {@link TaskNotFoundException} if the task does not exist
+ * @return Returns a Task if the remove operation is successful, an exception is thrown otherwise.
*/
- public boolean removeTask(ReadOnlyTask key) throws TaskNotFoundException {
+ public Task removeTask(ReadOnlyTask key) throws TaskNotFoundException {
return tasks.remove(key);
}
/**
* Replaces a task from savvy tasker.
* @param key the task to be replaced
+ * @throws {@link TaskNotFoundException} if the task does not exist
+ * @throws {@link InvalidDateException} if the end date is earlier than the start date
* @return true if the task is removed successfully
- * @throws TaskNotFoundException if the task to be removed does not exist
*/
- public boolean replaceTask(ReadOnlyTask key, Task replacement) throws TaskNotFoundException, InvalidDateException {
+ public Task replaceTask(ReadOnlyTask key, Task replacement) throws TaskNotFoundException, InvalidDateException {
return tasks.replace(key, replacement);
}
```
@@ -871,6 +1161,7 @@ public class SmartDefaultDates {
public interface ReadOnlyTask {
int getId();
+ int getGroupId();
boolean isMarked();
boolean isArchived();
String getTaskName();
@@ -900,23 +1191,68 @@ public interface ReadOnlyTask {
.append(" Task Name: ")
.append(getTaskName())
.append(" Archived: ")
- .append(isArchived())
- .append(" Start: ")
- .append(getStartDateTime())
- .append(" End: ")
- .append(getEndDateTime())
- .append(" Location: ")
- .append(getLocation())
- .append(" Priority: ")
+ .append(isArchived());
+ if (getStartDateTime() != null) {
+ builder.append(" Start: ")
+ .append(getStartDateTime());
+ }
+ if (getEndDateTime() != null) {
+ builder.append(" End: ")
+ .append(getEndDateTime());
+ }
+ if (getLocation() != null && !getLocation().isEmpty()) {
+ builder.append(" Location: ")
+ .append(getLocation());
+ }
+ builder.append(" Priority: ")
+ .append(getPriority());
+ if (getCategory() != null && !getCategory().isEmpty()) {
+ builder.append(" Category: ")
+ .append(getCategory());
+ }
+ if (getDescription() != null && !getDescription().isEmpty()) {
+ builder.append(" Description: ")
+ . append(getDescription());
+ }
+ return builder.toString();
+ }
+
+
+ /**
+ * Formats the task as text, showing all task details, formatted for the UI.
+ */
+ 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())
+ .append("\n");
+ }
+ if (getLocation() != null && !getLocation().isEmpty()) {
+ builder.append(" Location: ")
+ .append(getLocation())
+ .append("\n");
+ }
+ builder.append(" Priority: ")
.append(getPriority())
- .append(" Recurring Type: ")
- .append(getRecurringType())
- .append(" Nr. Recurrence: ")
- .append(getNumberOfRecurrence())
- .append(" Category: ")
- .append(getCategory())
- .append(" Description: ")
- .append(getDescription());
+ .append("\n");
+ if (getCategory() != null && !getCategory().isEmpty()) {
+ builder.append(" Category: ")
+ .append(getCategory())
+ .append("\n");
+ }
+ if (getDescription() != null && !getDescription().isEmpty()) {
+ builder.append(" Description: ")
+ .append(getDescription())
+ .append("\n");
+ }
+ builder.append(" Archived: ")
+ .append(isArchived());
return builder.toString();
}
@@ -930,6 +1266,7 @@ public interface ReadOnlyTask {
public class Task implements ReadOnlyTask {
private int id;
+ private int groupId;
private String taskName;
private Date startDateTime;
private Date endDateTime;
@@ -944,12 +1281,13 @@ public class Task implements ReadOnlyTask {
/**
* Constructor with smart defaults
*/
- public Task(int id, String taskName, InferredDate startDateTime, InferredDate endDateTime, String location,
+ public Task(int id, int groupId, String taskName, InferredDate startDateTime, InferredDate endDateTime, String location,
PriorityLevel priority, RecurrenceType recurringType, Integer numberOfRecurrence,
String category, String description, boolean isArchived) {
SmartDefaultDates sdd = new SmartDefaultDates(startDateTime, endDateTime);
this.id = id;
+ this.groupId = groupId;
this.taskName = taskName;
this.startDateTime = sdd.getStartDate();
this.endDateTime = sdd.getEndDate();
@@ -965,7 +1303,7 @@ public class Task implements ReadOnlyTask {
this.recurringType = recurringType;
}
if (numberOfRecurrence == null) {
- this.numberOfRecurrence = 0;
+ this.numberOfRecurrence = 1;
} else {
this.numberOfRecurrence = numberOfRecurrence.intValue();
}
@@ -977,11 +1315,12 @@ public class Task implements ReadOnlyTask {
/**
* Constructor without smart defaults
*/
- public Task(int id, String taskName, Date startDateTime, Date endDateTime, String location,
+ public Task(int id, int groupId, String taskName, Date startDateTime, Date endDateTime, String location,
PriorityLevel priority, RecurrenceType recurringType, Integer numberOfRecurrence,
String category, String description, boolean isArchived) {
this.id = id;
+ this.groupId = groupId;
this.taskName = taskName;
this.startDateTime = startDateTime;
this.endDateTime = endDateTime;
@@ -997,7 +1336,7 @@ public class Task implements ReadOnlyTask {
this.recurringType = recurringType;
}
if (numberOfRecurrence == null) {
- this.numberOfRecurrence = 0;
+ this.numberOfRecurrence = 1;
} else {
this.numberOfRecurrence = numberOfRecurrence.intValue();
}
@@ -1010,15 +1349,13 @@ public class Task implements ReadOnlyTask {
this.taskName = taskName;
// sets initial default values
this.priority = PriorityLevel.Medium;
- this.recurringType = RecurrenceType.None;
- this.numberOfRecurrence = 0;
}
/**
* Copy constructor.
*/
public Task(ReadOnlyTask source) {
- this(source.getId(), source.getTaskName(), source.getStartDateTime(),
+ this(source.getId(), source.getGroupId(), source.getTaskName(), source.getStartDateTime(),
source.getEndDateTime(), source.getLocation(), source.getPriority(),
source.getRecurringType(), source.getNumberOfRecurrence(),
source.getCategory(), source.getDescription(), source.isArchived());
@@ -1030,12 +1367,13 @@ public class Task implements ReadOnlyTask {
public Task(ReadOnlyTask source, String taskName, InferredDate startDateTime, InferredDate endDateTime, String location,
PriorityLevel priority, RecurrenceType recurringType, Integer numberOfRecurrence, String category,
String description) {
- this(source.getId(), source.getTaskName(), source.getStartDateTime(),
+ this(source.getId(), source.getGroupId(), source.getTaskName(), source.getStartDateTime(),
source.getEndDateTime(), source.getLocation(), source.getPriority(),
source.getRecurringType(), source.getNumberOfRecurrence(),
source.getCategory(), source.getDescription(), source.isArchived());
//this.id should follow that of the source.
+ //this.groupId should follow that of the source.
//this.isArchived should follow that of the source.
this.taskName = taskName == null ? this.taskName : taskName;
setStartDate(startDateTime);
@@ -1089,6 +1427,11 @@ public class Task implements ReadOnlyTask {
return this.id;
}
+ @Override
+ public int getGroupId() {
+ return this.groupId;
+ }
+
@Override
public boolean isMarked() {
return isArchived(); // all marked tasks are archived
@@ -1148,6 +1491,10 @@ public class Task implements ReadOnlyTask {
this.id = id;
}
+ public void setGroupId(int groupId) {
+ this.groupId = groupId;
+ }
+
public void setTaskName(String taskName) {
this.taskName = taskName;
}
@@ -1226,6 +1573,17 @@ public class Task implements ReadOnlyTask {
public String toString() {
return getAsText();
}
+
+ /**
+ * Creates a deep copy of this object.
+ */
+ public Task clone() {
+ Task t = new Task(id, groupId, taskName,
+ (Date)startDateTime.clone(), (Date)endDateTime.clone(),
+ location, priority, recurringType, numberOfRecurrence,
+ category, description, isArchived);
+ return t;
+ }
}
```
@@ -1285,6 +1643,8 @@ 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;
/**
* Constructs empty TaskList.
@@ -1298,10 +1658,8 @@ public class TaskList implements Iterable {
*/
public int getNextId() {
if (!isNextIdInitialized) {
- int nextLowest = -1; // first id to be used is 0. Start finding with -1
- LinkedList usedIds = new LinkedList();
+ int nextLowest = 0; // first id to be used is 1. Start finding with 0
for (Task t : internalList) {
- usedIds.add(t.getId());
if (t.getId() > nextLowest) {
nextLowest = t.getId();
}
@@ -1315,6 +1673,29 @@ public class TaskList implements Iterable {
nextId++;
return nextId;
}
+
+ /**
+ * Gets the next available group id for uniquely identifying a group of recurring tasks in
+ * Savvy Tasker.
+ * @return The next available group id;
+ */
+ public int getNextGroupId() {
+ if (!isNextGroupIdInitialized) {
+ int nextLowest = 0; // first id to be used is 1. Start finding with 0
+ for (Task t : internalList) {
+ if (t.getId() > nextLowest) {
+ nextLowest = t.getGroupId();
+ }
+ }
+ // assumption that the number of tasks < 2^31
+ // implementation will be buggy if nextId exceeds 2^31
+ nextGroupId = nextLowest;
+ assert nextGroupId < Integer.MAX_VALUE;
+ isNextGroupIdInitialized = true;
+ }
+ nextGroupId++;
+ return nextGroupId;
+ }
/**
* Returns true if the list contains an equivalent task as the given argument.
@@ -1338,10 +1719,11 @@ public class TaskList implements Iterable {
/**
* Adds a task to the list.
- *
- * @throws DuplicateTaskException if the person to add is a duplicate of an existing task in the list.
+ * @throws {@link DuplicateTaskException} if a duplicate is found
+ * @throws {@link InvalidDateException} if the end date is earlier than the start date
+ * @return Returns the Task added if the add is successful, an exception is thrown otherwise.
*/
- public void add(Task toAdd) throws DuplicateTaskException, InvalidDateException {
+ public Task add(Task toAdd) throws DuplicateTaskException, InvalidDateException {
assert toAdd != null;
if (contains(toAdd)) {
throw new DuplicateTaskException();
@@ -1350,28 +1732,36 @@ public class TaskList implements Iterable {
throw new InvalidDateException();
}
internalList.add(toAdd);
+ return toAdd;
}
/**
* Removes the equivalent task from the list.
- *
- * @throws TaskNotFoundException if no such task could be found in the list.
+ * @throws {@link TaskNotFoundException} if the task does not exist
+ * @return Returns a Task if the delete operation is successful, an exception is thrown otherwise.
*/
- public boolean remove(ReadOnlyTask toRemove) throws TaskNotFoundException {
+ public Task remove(ReadOnlyTask toRemove) throws TaskNotFoundException {
assert toRemove != null;
- final boolean taskFoundAndDeleted = internalList.remove(toRemove);
- if (!taskFoundAndDeleted) {
+ int index = internalList.indexOf(toRemove);
+ if (index >= 0) {
+ final Task taskToDelete = internalList.get(index);
+ final boolean taskFoundAndDeleted = internalList.remove(toRemove);
+ if (!taskFoundAndDeleted) {
+ throw new TaskNotFoundException();
+ }
+ return taskToDelete;
+ } else {
throw new TaskNotFoundException();
}
- return taskFoundAndDeleted;
}
/**
* Replaces the equivalent task from the list.
- *
- * @throws TaskNotFoundException if no such task could be found in the list.
+ * @throws {@link TaskNotFoundException} if the task does not exist
+ * @throws {@link InvalidDateException} if the end date is earlier than the start date
+ * @return Returns the Task replaced if the replace is successful, an exception is thrown otherwise.
*/
- public boolean replace(ReadOnlyTask toReplace, Task replacement) throws TaskNotFoundException, InvalidDateException {
+ public Task replace(ReadOnlyTask toReplace, Task replacement) throws TaskNotFoundException, InvalidDateException {
assert toReplace != null;
assert replacement != null;
if (internalList.contains(toReplace)) {
@@ -1379,7 +1769,7 @@ public class TaskList implements Iterable {
throw new InvalidDateException();
}
internalList.set(internalList.indexOf(toReplace), replacement);
- return true;
+ return replacement;
}
else {
throw new TaskNotFoundException();
@@ -1408,6 +1798,33 @@ public class TaskList implements Iterable {
}
}
```
+###### \java\seedu\savvytasker\storage\SavvyTaskerStorage.java
+``` java
+ /**
+ * Sets the file path of the data file. Returns true if successful, false otherwise
+ */
+ boolean setSavvyTaskerFilePath(String path);
+```
+###### \java\seedu\savvytasker\storage\StorageManager.java
+``` java
+ @Override
+ public boolean setSavvyTaskerFilePath(String path) {
+ 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
/**
@@ -1417,6 +1834,8 @@ public class XmlAdaptedTask {
@XmlElement(required = true)
private int id;
+ @XmlElement(required = false)
+ private int groupId;
@XmlElement(required = true)
private String taskName;
@XmlElement(required = false)
@@ -1428,10 +1847,6 @@ public class XmlAdaptedTask {
@XmlElement(required = false)
private PriorityLevel priority;
@XmlElement(required = false)
- private RecurrenceType recurringType;
- @XmlElement(required = false)
- private int numberOfRecurrence;
- @XmlElement(required = false)
private String category;
@XmlElement(required = false)
private String description;
@@ -1451,13 +1866,12 @@ public class XmlAdaptedTask {
*/
public XmlAdaptedTask(ReadOnlyTask source) {
id = source.getId();
+ groupId = source.getGroupId();
taskName = source.getTaskName();
startDateTime = source.getStartDateTime();
endDateTime = source.getEndDateTime();
location = source.getLocation();
priority = source.getPriority();
- recurringType = source.getRecurringType();
- numberOfRecurrence = source.getNumberOfRecurrence();
category = source.getCategory();
description = source.getDescription();
isArchived = source.isArchived();
@@ -1475,13 +1889,39 @@ public class XmlAdaptedTask {
final Date endDateTime = this.endDateTime;
final String location = this.location;
final PriorityLevel priority = this.priority;
- final RecurrenceType recurringType = this.recurringType;
- final int numberOfRecurrence = this.numberOfRecurrence;
final String category = this.category;
final String description = this.description;
final boolean isArchived = this.isArchived;
- return new Task(id, taskName, startDateTime, endDateTime, location, priority,
- recurringType, numberOfRecurrence, category, description, isArchived);
+ return new Task(id, groupId, taskName, startDateTime, endDateTime, location, priority,
+ null, null, category, description, isArchived);
}
}
```
+###### \java\seedu\savvytasker\storage\XmlSavvyTaskerStorage.java
+``` java
+ @Override
+ /**
+ * Changes the path of the storage location if the file at newPath can be successfully created.
+ */
+ public boolean setSavvyTaskerFilePath(String newPath) {
+ try {
+ File file = new File(newPath);
+ if (FileUtil.createIfMissing(file)) {
+ this.filePath = newPath;
+ return true;
+ } else {
+ return false;
+ }
+ } catch (IOException e) {
+ // do nothing, can't set the path to new path
+ }
+ return false;
+ }
+```
+###### \java\seedu\savvytasker\ui\StatusBarFooter.java
+``` java
+ @Subscribe
+ public void handleSavvyTaskerSaveLocationChangedEvent(DataSavingLocationChangedEvent dslce) {
+ setSaveLocation(dslce.newPath);
+ }
+```
diff --git a/collated/main/A0139915Wreused.md b/collated/main/A0139915Wreused.md
deleted file mode 100644
index 34a4b0d4c6d1..000000000000
--- a/collated/main/A0139915Wreused.md
+++ /dev/null
@@ -1,17 +0,0 @@
-# A0139915Wreused
-###### \java\seedu\savvytasker\commons\util\StringUtil.java
-``` java
- // reused original implementation of 'containsIgnoreCase' to find exact matches
- public static boolean containsExactIgnoreCase(String source, String query) {
- List strings = Arrays.asList(source);
- return strings.stream().filter(s -> s.equalsIgnoreCase(query)).count() > 0;
- }
-
- // reused original implementation of 'containsIgnoreCase' to find partial matches
- public static boolean containsPartialIgnoreCase(String source, String query) {
- if (source == null) return false;
- String[] split = source.toLowerCase().split("\\s+");
- List strings = Arrays.asList(split);
- return strings.stream().filter(s -> s.contains(query.toLowerCase())).count() > 0;
- }
-```
diff --git a/collated/main/A0139916U.md b/collated/main/A0139916U.md
index 085b04221fa3..466daa605bbd 100644
--- a/collated/main/A0139916U.md
+++ b/collated/main/A0139916U.md
@@ -18,8 +18,8 @@ public class AliasSymbolChangedEvent extends BaseEvent {
Removed;
}
- public final AliasSymbol symbol;
- public final Action action;
+ private final AliasSymbol symbol;
+ private final Action action;
public AliasSymbolChangedEvent(AliasSymbol symbol, Action action) {
assert symbol != null;
@@ -33,6 +33,14 @@ public class AliasSymbolChangedEvent extends BaseEvent {
public String toString() {
return "Alias symbol " + action.toString() + ": " + symbol.toString();
}
+
+ public AliasSymbol getSymbol() {
+ return this.symbol;
+ }
+
+ public Action getAction() {
+ return this.action;
+ }
}
```
@@ -101,71 +109,6 @@ public class AliasCommand extends ModelRequiringCommand {
this.logic = logic;
}
-```
-###### \java\seedu\savvytasker\logic\commands\AliasCommand.java
-``` java
- /**
- * Checks if a command can perform undo operations
- * @return true if the command supports undo, false otherwise
- */
- @Override
- public boolean canUndo() {
- return true;
- }
-
- /**
- * Redo the alias command
- * @return true if the operation completed successfully, false otherwise
- */
- @Override
- public boolean redo() {
- execute();
- return true;
- }
- /**
- * Undo the alias command
- * @return true if the operation completed successfully, false otherwise
- */
- @Override
- public boolean undo() {
- // TODO Auto-generated method stub
-
- assert model != null;
-
- AliasSymbol toRemove = null;
- for(AliasSymbol symbol : model.getSavvyTasker().getReadOnlyListOfAliasSymbols()) {
- if (symbol.getKeyword().equals(this.keyword)) {
- toRemove = symbol;
- break;
- }
- }
- try {
- model.removeAliasSymbol(toRemove);
- } catch (SymbolKeywordNotFoundException e) {
- e.printStackTrace();
- }
-
- return true;
- }
-
- /**
- * Check if command is an undo command
- * @return true if the command is an undo operation, false otherwise
- */
- @Override
- public boolean isUndo() {
- return false;
- }
-
- /**
- * Check if command is a redo command
- * @return true if the command is a redo operation, false otherwise
- */
- @Override
- public boolean isRedo(){
- return false;
- }
-}
```
###### \java\seedu\savvytasker\logic\commands\Command.java
``` java
@@ -238,8 +181,10 @@ public class UnaliasCommand extends ModelRequiringCommand {
}
try {
- if (toRemove == null)
+ if (toRemove == null) {
return new CommandResult(MESSAGE_UNREGOGNIZED_ALIAS);
+ }
+
toUndo = toRemove;
model.removeAliasSymbol(toRemove);
return new CommandResult(String.format(MESSAGE_SUCCESS, toRemove));
@@ -247,6 +192,7 @@ public class UnaliasCommand extends ModelRequiringCommand {
return new CommandResult(MESSAGE_UNREGOGNIZED_ALIAS);
}
}
+
```
###### \java\seedu\savvytasker\logic\LogicManager.java
``` java
@@ -265,6 +211,7 @@ public class UnaliasCommand extends ModelRequiringCommand {
parser.registerCommandParser(new RedoCommandParser());
parser.registerCommandParser(new AliasCommandParser());
parser.registerCommandParser(new UnaliasCommandParser());
+ parser.registerCommandParser(new StorageCommandParser());
}
private void loadAllAliasSymbols() {
@@ -300,24 +247,42 @@ public class UnaliasCommand extends ModelRequiringCommand {
return redone;
}
+ /**
+ * Log the result of adding/removing a symbol in the parser.
+ *
+ * @param success if the operation succeeded
+ * @param changedSymbol the symbol that was involved in the operation
+ * @param successMsgFormat the message to print if the operation succeeded. It should contain a single
+ * %s string format specifier, which will be replaced by the symbol's string representation.
+ * @param failureMsgFormat the message to print if the operation failed. It should contain a single
+ * %s string format specifier, which will be replaced by the symbol's string representation.
+ */
+ private void logParserSymbolChange(boolean success, AliasSymbol changedSymbol,
+ String successMsgFormat, String failureMsgFormat) {
+ if (success) {
+ logger.info(String.format(successMsgFormat, changedSymbol));
+ } else {
+ logger.warning(String.format(failureMsgFormat, changedSymbol));
+ }
+ }
+
@Subscribe
public void handleAliasSymbolChangedEvent(AliasSymbolChangedEvent event) {
logger.info(LogsCenter.getEventHandlingLogMessage(
- event, "Alias symbol " + event.action.toString().toLowerCase()));
- if (event.action.equals(AliasSymbolChangedEvent.Action.Added)) {
- boolean success = parser.addAliasSymbol(event.symbol);
- if (success) {
- logger.info("Added alias symbol '"+event.symbol.getKeyword()+"' to parser");
- } else {
- logger.warning("Failed to add alias symbol '"+event.symbol.getKeyword()+" to parser");
- }
- } else {
- boolean success = parser.removeAliasSymbol(event.symbol.getKeyword());
- if (success) {
- logger.info("Removed alias symbol '"+event.symbol.getKeyword()+"' from parser");
- } else {
- logger.warning("Failed to remove alias symbol '"+event.symbol.getKeyword()+" from parser");
- }
+ event, "Alias symbol " + event.getAction().toString().toLowerCase()));
+
+ if (event.getAction().equals(AliasSymbolChangedEvent.Action.Added)) {
+ logParserSymbolChange(
+ parser.addAliasSymbol(event.getSymbol()),
+ event.getSymbol(),
+ "Added alias symbol '%s' to parser",
+ "Failed to add alias symbol '%s' to parser");
+ } else if (event.getAction().equals(AliasSymbolChangedEvent.Action.Removed)) {
+ logParserSymbolChange(
+ parser.removeAliasSymbol(event.getSymbol().getKeyword()),
+ event.getSymbol(),
+ "Removed alias symbol '%s' from parser",
+ "Failed to remove alias symbol '%s' from parser");
}
}
@@ -340,22 +305,12 @@ import seedu.savvytasker.logic.parser.DateParser.InferredDate;
import seedu.savvytasker.model.task.PriorityLevel;
import seedu.savvytasker.model.task.RecurrenceType;
-public class AddCommandParser implements CommandParser {
+public class AddCommandParser extends TaskFieldParser {
private static final String HEADER = "add";
private static final String READABLE_FORMAT = HEADER+" TASK_NAME [s/START_DATE] " +
"[e/END_DATE] [l/LOCATION] [p/PRIORITY_LEVEL] [r/RECURRING_TYPE] " +
"[n/NUMBER_OF_RECURRENCE] [c/CATEGORY] [d/DESCRIPTION]";
- private static final String REGEX_REF_TASK_NAME = "TaskName";
- private static final String REGEX_REF_START_DATE = "StartDate";
- private static final String REGEX_REF_END_DATE = "EndDate";
- private static final String REGEX_REF_LOCATION = "Location";
- private static final String REGEX_REF_PRIORITY_LEVEL = "Priority";
- private static final String REGEX_REF_RECURRING_TYPE = "RecurringType";
- private static final String REGEX_REF_NUMBER_OF_RECURRENCE = "RecurringNumber";
- private static final String REGEX_REF_CATEGORY = "Category";
- private static final String REGEX_REF_DESCRIPTION = "Description";
-
private static final Pattern REGEX_PATTERN = Pattern.compile(
HEADER+"\\s+(?<"+REGEX_REF_TASK_NAME+">([^/]+?(\\s+|$))+)((?<=\\s)(" +
"(s/(?<"+REGEX_REF_START_DATE+">[^/]+)(?!.*\\ss/))|" +
@@ -367,8 +322,6 @@ public class AddCommandParser implements CommandParser {
"(c/(?<"+REGEX_REF_CATEGORY+">[^/]+)(?!.*\\sc/))|" +
"(d/(?<"+REGEX_REF_DESCRIPTION+">[^/]+)(?!.*\\sd/))" +
")(\\s|$)){0,10}", Pattern.CASE_INSENSITIVE);
-
- private static final TaskFieldParser TASK_PARSER = new TaskFieldParser();
@Override
public String getHeader() {
@@ -384,15 +337,15 @@ public class AddCommandParser implements CommandParser {
public AddCommand parse(String commandText) throws ParseException {
Matcher matcher = REGEX_PATTERN.matcher(commandText);
if (matcher.matches()) {
- InferredDate startDate = TASK_PARSER.parseStartDate(matcher.group(REGEX_REF_START_DATE));
- InferredDate endDate = TASK_PARSER.parseEndDate(matcher.group(REGEX_REF_END_DATE));
- String taskName = TASK_PARSER.parseTaskName(matcher.group(REGEX_REF_TASK_NAME));
- String location = TASK_PARSER.parseLocation(matcher.group(REGEX_REF_LOCATION));
- PriorityLevel priority = TASK_PARSER.parsePriorityLevel(matcher.group(REGEX_REF_PRIORITY_LEVEL));
- RecurrenceType recurrence = TASK_PARSER.parseRecurrenceType(matcher.group(REGEX_REF_RECURRING_TYPE));
- Integer nrOfRecurrence = TASK_PARSER.parseNumberOfRecurrence(matcher.group(REGEX_REF_NUMBER_OF_RECURRENCE));
- String category = TASK_PARSER.parseCategory(matcher.group(REGEX_REF_CATEGORY));
- String description = TASK_PARSER.parseDescription(matcher.group(REGEX_REF_DESCRIPTION));
+ InferredDate startDate = parseStartDate(matcher.group(REGEX_REF_START_DATE));
+ InferredDate endDate = parseEndDate(matcher.group(REGEX_REF_END_DATE));
+ String taskName = parseTaskName(matcher.group(REGEX_REF_TASK_NAME));
+ String location = parseLocation(matcher.group(REGEX_REF_LOCATION));
+ PriorityLevel priority = parsePriorityLevel(matcher.group(REGEX_REF_PRIORITY_LEVEL));
+ RecurrenceType recurrence = parseRecurrenceType(matcher.group(REGEX_REF_RECURRING_TYPE));
+ Integer nrOfRecurrence = parseNumberOfRecurrence(matcher.group(REGEX_REF_NUMBER_OF_RECURRENCE));
+ String category = parseCategory(matcher.group(REGEX_REF_CATEGORY));
+ String description = parseDescription(matcher.group(REGEX_REF_DESCRIPTION));
return new AddCommand(taskName, startDate,
endDate, location, priority,
@@ -427,7 +380,8 @@ public class AliasCommandParser implements CommandParser {
HEADER+"\\s+((?<=\\s)(" +
"(r/(?<"+REGEX_REF_REPRESENTATION+">[^/]+)(?!.*\\sr/))|" +
"(k/(?<"+REGEX_REF_KEYWORD+">[^/]+)(?!.*\\sk/))" +
- ")(\\s|$)){2}"
+ ")(\\s|$)){2}",
+ Pattern.CASE_INSENSITIVE
);
@Override
@@ -920,16 +874,16 @@ import java.util.regex.Pattern;
import seedu.savvytasker.commons.core.Messages;
import seedu.savvytasker.logic.commands.ListCommand;
-import seedu.savvytasker.model.task.ListType;
+import seedu.savvytasker.model.ListType;
public class ListCommandParser implements CommandParser {
private static final String HEADER = "list";
- private static final String READABLE_FORMAT = HEADER+" [t/LIST_TYPE]";
+ private static final String READABLE_FORMAT = HEADER+" [LIST_TYPE]";
private static final String REGEX_REF_LIST_TYPE = "ListType";
private static final Pattern REGEX_PATTERN = Pattern.compile(
- HEADER+"\\s*((?<=\\s)t/(?<"+REGEX_REF_LIST_TYPE+">[^/]+))?",
+ HEADER+"\\s*((?<=\\s)(?<"+REGEX_REF_LIST_TYPE+">[^/]+))?",
Pattern.CASE_INSENSITIVE);
@Override
@@ -1033,45 +987,86 @@ import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
import seedu.savvytasker.logic.commands.Command;
import seedu.savvytasker.logic.commands.HelpCommand;
import seedu.savvytasker.logic.commands.IncorrectCommand;
import seedu.savvytasker.model.alias.AliasSymbol;
+/**
+ * Represents the master parser that is used by Logic. This is a parser containing
+ * all subparsers that will do the actual parsing to produce Command objects. This
+ * parser replaces keywords of the input with aliased representations before selecting
+ * a subparser to do the parsing. The selection of the subparser is based on the first
+ * word of the input, called the header, and matching it to the subparser that declares
+ * that it parses it.
+ */
public class MasterParser {
private static final Pattern KEYWORD_PATTERN =
- Pattern.compile("(\\S+)(\\s+|$)");
+ Pattern.compile("([^\\s/]+)([\\s/]+|$)");
private final Map> commandParsers;
private final Map aliasingSymbols;
+ private final ObservableList aliasList = FXCollections.observableArrayList();
+
public MasterParser() {
this.commandParsers = new HashMap>();
this.aliasingSymbols = new HashMap();
}
+ /**
+ * Parses the input text, selecting an appropriate registered parser to parse it.
+ * The parser selected is based on the first header word of the input text. The text
+ * is preprocessed, replacing any of its tokens that are keywords to an alias, before
+ * being passed to the parser.
+ *
+ * @param userInput the text to be parse
+ * @return the command that was parsed if successful, or IncorrectCommand if there is no
+ * parser that can parse the text or if there is a format error with the text.
+ */
public Command parse(String userInput) {
String[] pieces = preprocessInitial(userInput.trim());
- if (pieces == null)
- return new IncorrectCommand(userInput, String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE));
+ if (pieces == null) {
+ return new IncorrectCommand(userInput,
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE));
+ }
String header = pieces[0];
String body = pieces[1];
- String trueHeader = extractHeader(header);
- CommandParser extends Command> parser = commandParsers.get(trueHeader);
- if (parser == null)
- return new IncorrectCommand(header + body, String.format(MESSAGE_UNKNOWN_COMMAND, HelpCommand.MESSAGE_USAGE));
- if (parser.shouldPreprocess())
- body = preprocessBody(body);
+ CommandParser extends Command> parser = selectParser(extractTrueHeader(header));
+ if (parser == null) {
+ return new IncorrectCommand(header + body,
+ String.format(MESSAGE_UNKNOWN_COMMAND, HelpCommand.MESSAGE_USAGE));
+ }
- String combined = header + body;
+ if (parser.shouldPreprocess()) {
+ return makeParserParse(parser, header + preprocessBody(body));
+ } else {
+ return makeParserParse(parser, header + body);
+ }
+ }
+
+ /**
+ * Makes the parser parse the preprocessed text.
+ *
+ * @param parser the parser to use to parse
+ * @param preprocessedText the text to parse
+ * @return the output Command from the parsing, or IncorrectCommand object if the parse failed
+ */
+ private Command makeParserParse(CommandParser extends Command> parser, String preprocessedText) {
try {
- return parser.parse(combined);
+ return parser.parse(preprocessedText);
} catch (ParseException pe) {
- return new IncorrectCommand(combined, String.format(pe.getFailureDetails()));
+ return new IncorrectCommand(preprocessedText, String.format(pe.getFailureDetails()));
}
}
+ private CommandParser extends Command> selectParser(String header) {
+ return commandParsers.get(header);
+ }
+
/**
* Does an initial preprocessing of a command text in case the header is aliased.
* Returns a string array with 2 elements: the first is the header which is possibly aliased,
@@ -1102,13 +1097,13 @@ public class MasterParser {
}
/**
- * Gets the header from the preprocessed header as a preprocessed header may contain
+ * Gets the true header from the preprocessed header as a preprocessed header may contain
* several tokens.
*
* @param preprocessedHeader the preprocessed header
* @return the true header
*/
- private String extractHeader(String preprocessedHeader) {
+ private String extractTrueHeader(String preprocessedHeader) {
Matcher matcher = KEYWORD_PATTERN.matcher(preprocessedHeader);
if (matcher.find()) {
@@ -1206,7 +1201,8 @@ public class MasterParser {
return false;
if (isCommandParserRegistered(symbol.getKeyword()))
return false;
-
+
+ aliasList.add(symbol);
aliasingSymbols.put(symbol.getKeyword(), symbol);
return true;
}
@@ -1221,7 +1217,12 @@ public class MasterParser {
public boolean removeAliasSymbol(String symbolKeyword) {
assert symbolKeyword != null;
- return aliasingSymbols.remove(symbolKeyword) != null;
+ AliasSymbol symbol = aliasingSymbols.remove(symbolKeyword);
+ if (symbol != null) {
+ return aliasList.remove(symbol);
+ } else {
+ return false;
+ }
}
/**
@@ -1240,8 +1241,13 @@ public class MasterParser {
* @see #removeAliasSymbol
*/
public void clearAllAliasSymbols() {
+ aliasList.clear();
aliasingSymbols.clear();
}
+
+ public ObservableList getAliasSymbolList() {
+ return aliasList;
+ }
}
```
###### \java\seedu\savvytasker\logic\parser\ModifyCommandParser.java
@@ -1258,22 +1264,13 @@ import seedu.savvytasker.logic.parser.DateParser.InferredDate;
import seedu.savvytasker.model.task.PriorityLevel;
import seedu.savvytasker.model.task.RecurrenceType;
-public class ModifyCommandParser implements CommandParser {
+public class ModifyCommandParser extends TaskFieldParser {
private static final String HEADER = "modify";
private static final String READABLE_FORMAT = HEADER+" 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]";
private static final String REGEX_REF_INDEX = "Index";
- private static final String REGEX_REF_TASK_NAME = "TaskName";
- private static final String REGEX_REF_START_DATE = "StartDate";
- private static final String REGEX_REF_END_DATE = "EndDate";
- private static final String REGEX_REF_LOCATION = "Location";
- private static final String REGEX_REF_PRIORITY_LEVEL = "Priority";
- private static final String REGEX_REF_RECURRING_TYPE = "RecurringType";
- private static final String REGEX_REF_NUMBER_OF_RECURRENCE = "RecurringNumber";
- private static final String REGEX_REF_CATEGORY = "Category";
- private static final String REGEX_REF_DESCRIPTION = "Description";
private static final Pattern REGEX_PATTERN = Pattern.compile(
HEADER+"\\s+(?<"+REGEX_REF_INDEX+">([^/]+?(\\s+|$))+)((?<=\\s)(" +
@@ -1288,7 +1285,6 @@ public class ModifyCommandParser implements CommandParser {
"(d/(?<"+REGEX_REF_DESCRIPTION+">[^/]*)(?!.*\\sd/))" +
")(\\s|$)){0,11}", Pattern.CASE_INSENSITIVE);
- private static final TaskFieldParser TASK_PARSER = new TaskFieldParser();
private static final IndexParser INDEX_PARSER = new IndexParser();
@Override
@@ -1309,13 +1305,13 @@ public class ModifyCommandParser implements CommandParser {
int index = parseIndex(matcher.group(REGEX_REF_INDEX));
InferredDate startDate = parseDate(matcher.group(REGEX_REF_START_DATE));
InferredDate endDate = parseDate(matcher.group(REGEX_REF_END_DATE));
- String taskName = TASK_PARSER.parseTaskName(matcher.group(REGEX_REF_TASK_NAME));
- String location = TASK_PARSER.parseLocation(matcher.group(REGEX_REF_LOCATION));
- PriorityLevel priority = TASK_PARSER.parsePriorityLevel(matcher.group(REGEX_REF_PRIORITY_LEVEL));
- RecurrenceType recurrence = TASK_PARSER.parseRecurrenceType(matcher.group(REGEX_REF_RECURRING_TYPE));
- Integer nrOfRecurrence = TASK_PARSER.parseNumberOfRecurrence(matcher.group(REGEX_REF_NUMBER_OF_RECURRENCE));
- String category = TASK_PARSER.parseCategory(matcher.group(REGEX_REF_CATEGORY));
- String description = TASK_PARSER.parseDescription(matcher.group(REGEX_REF_DESCRIPTION));
+ String taskName = parseTaskName(matcher.group(REGEX_REF_TASK_NAME));
+ String location = parseLocation(matcher.group(REGEX_REF_LOCATION));
+ PriorityLevel priority = parsePriorityLevel(matcher.group(REGEX_REF_PRIORITY_LEVEL));
+ RecurrenceType recurrence = parseRecurrenceType(matcher.group(REGEX_REF_RECURRING_TYPE));
+ Integer nrOfRecurrence = parseNumberOfRecurrence(matcher.group(REGEX_REF_NUMBER_OF_RECURRENCE));
+ String category = parseCategory(matcher.group(REGEX_REF_CATEGORY));
+ String description = parseDescription(matcher.group(REGEX_REF_DESCRIPTION));
return new ModifyCommand(index, taskName, startDate,
endDate, location, priority,
@@ -1337,10 +1333,10 @@ public class ModifyCommandParser implements CommandParser {
private InferredDate parseDate(String dateText) throws ParseException {
if (dateText != null && dateText.trim().isEmpty()) {
- return TASK_PARSER.dateParser.new InferredDate(new Date(), true, true);
+ return dateParser.new InferredDate(new Date(), true, true);
}
- return TASK_PARSER.parseStartDate(dateText);
+ return parseStartDate(dateText);
}
}
```
@@ -1422,37 +1418,100 @@ public class RedoCommandParser implements CommandParser {
Messages.MESSAGE_INVALID_COMMAND_FORMAT, getRequiredFormat()));
}
+}
+```
+###### \java\seedu\savvytasker\logic\parser\StorageCommandParser.java
+``` java
+package seedu.savvytasker.logic.parser;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import seedu.savvytasker.commons.core.Messages;
+import seedu.savvytasker.logic.commands.StorageCommand;
+
+public class StorageCommandParser implements CommandParser {
+ private static final String HEADER = "storage";
+ private static final String READABLE_FORMAT = HEADER+" NEW_PATH";
+
+ private static final String REGEX_REF_PATH = "Path";
+
+ private static final Pattern REGEX_PATTERN = Pattern.compile(
+ HEADER+"\\s+(?<"+REGEX_REF_PATH+">.*)",
+ Pattern.CASE_INSENSITIVE);
+
+ @Override
+ public String getHeader() {
+ return HEADER;
+ }
+
+ @Override
+ public String getRequiredFormat() {
+ return READABLE_FORMAT;
+ }
+
+ @Override
+ public StorageCommand parse(String commandText) throws ParseException {
+ Matcher matcher = REGEX_PATTERN.matcher(commandText);
+ if (matcher.matches()) {
+ String path = matcher.group(REGEX_REF_PATH).trim();
+
+ if (!path.isEmpty()) {
+ return new StorageCommand(path);
+ }
+ }
+
+ throw new ParseException(commandText, String.format(
+ Messages.MESSAGE_INVALID_COMMAND_FORMAT, getRequiredFormat()));
+ }
+
}
```
###### \java\seedu\savvytasker\logic\parser\TaskFieldParser.java
``` java
package seedu.savvytasker.logic.parser;
+import seedu.savvytasker.logic.commands.Command;
import seedu.savvytasker.logic.parser.DateParser.InferredDate;
import seedu.savvytasker.model.task.PriorityLevel;
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.
*/
-public class TaskFieldParser {
+public abstract class TaskFieldParser implements CommandParser {
+ /*
+ * Provides standard regex ref names for various task fields that might be used by subclasses.
+ */
+ protected static final String REGEX_REF_TASK_NAME = "TaskName";
+ protected static final String REGEX_REF_START_DATE = "StartDate";
+ protected static final String REGEX_REF_END_DATE = "EndDate";
+ protected static final String REGEX_REF_LOCATION = "Location";
+ protected static final String REGEX_REF_PRIORITY_LEVEL = "Priority";
+ protected static final String REGEX_REF_RECURRING_TYPE = "RecurringType";
+ protected static final String REGEX_REF_NUMBER_OF_RECURRENCE = "RecurringNumber";
+ protected static final String REGEX_REF_CATEGORY = "Category";
+ protected static final String REGEX_REF_DESCRIPTION = "Description";
+
protected final DateParser dateParser;
- public TaskFieldParser() {
+ protected TaskFieldParser() {
this.dateParser = new DateParser();
}
- public String parseTaskName(String taskNameText) throws ParseException {
+ protected String parseTaskName(String taskNameText) throws ParseException {
if (taskNameText == null)
return null;
return taskNameText.trim();
}
- public InferredDate parseStartDate(String dateText) throws ParseException {
+ protected InferredDate parseStartDate(String dateText) throws ParseException {
return parseDate(dateText, "START_DATE: ");
}
- public InferredDate parseEndDate(String dateText) throws ParseException {
+ protected InferredDate parseEndDate(String dateText) throws ParseException {
return parseDate(dateText, "END_DATE: ");
}
@@ -1468,13 +1527,13 @@ public class TaskFieldParser {
}
}
- public String parseLocation(String locationText) throws ParseException {
+ protected String parseLocation(String locationText) throws ParseException {
if (locationText == null)
return null;
return locationText.trim();
}
- public PriorityLevel parsePriorityLevel(String priorityLevelText) throws ParseException {
+ protected PriorityLevel parsePriorityLevel(String priorityLevelText) throws ParseException {
if (priorityLevelText == null)
return null;
@@ -1486,7 +1545,7 @@ public class TaskFieldParser {
}
}
- public RecurrenceType parseRecurrenceType(String recurrenceTypeText) throws ParseException {
+ protected RecurrenceType parseRecurrenceType(String recurrenceTypeText) throws ParseException {
if (recurrenceTypeText == null)
return null;
@@ -1498,7 +1557,7 @@ public class TaskFieldParser {
}
}
- public Integer parseNumberOfRecurrence(String numRecurrenceText) throws ParseException {
+ protected Integer parseNumberOfRecurrence(String numRecurrenceText) throws ParseException {
if (numRecurrenceText == null)
return null;
@@ -1520,13 +1579,13 @@ public class TaskFieldParser {
return numRecurrence;
}
- public String parseCategory(String categoryText) throws ParseException {
+ protected String parseCategory(String categoryText) throws ParseException {
if (categoryText == null)
return null;
return categoryText.trim();
}
- public String parseDescription(String descriptionText) throws ParseException {
+ protected String parseDescription(String descriptionText) throws ParseException {
if (descriptionText == null)
return null;
return descriptionText.trim();
@@ -1550,7 +1609,8 @@ public class UnaliasCommandParser implements CommandParser {
private static final String REGEX_REF_KEYWORD = "Keyword";
private static final Pattern REGEX_PATTERN = Pattern.compile(
- HEADER+"\\s+(?<"+REGEX_REF_KEYWORD+">[^/]+)"
+ HEADER+"\\s+(?<"+REGEX_REF_KEYWORD+">[^/]+)",
+ Pattern.CASE_INSENSITIVE
);
@Override
@@ -1705,7 +1765,7 @@ public class AliasSymbol {
assert keyword != null && !keyword.matches(".*\\s+.*");
assert representation != null && !representation.isEmpty();
- this.keyword = keyword;
+ this.keyword = keyword.toLowerCase();
this.representation = representation;
}
@@ -1892,6 +1952,49 @@ public class SymbolKeywordNotFoundException extends IllegalValueException {
}
}
```
+###### \java\seedu\savvytasker\model\ListType.java
+``` java
+package seedu.savvytasker.model;
+
+/**
+ * This enum represents what and how to list tasks/symbols.
+ */
+public enum ListType {
+ /**
+ * List tasks by due date.
+ */
+ DueDate,
+
+ /**
+ * List tasks by priority level.
+ */
+ PriorityLevel,
+
+ /**
+ * List archived tasks.
+ */
+ Archived,
+
+ /**
+ * List aliases.
+ */
+ Alias;
+
+ /**
+ * Gets a ListType enum object from its enum name, ignoring cases.
+ * @param name the name of the ListType enum object
+ * @return the corresponding ListType enum object
+ */
+ public static ListType valueOfIgnoreCase(String name) {
+ for (ListType type : ListType.values()) {
+ if (type.toString().equalsIgnoreCase(name))
+ return type;
+ }
+
+ throw new IllegalArgumentException("Unknown list type: " + name);
+ }
+}
+```
###### \java\seedu\savvytasker\model\ModelManager.java
``` java
@@ -1918,6 +2021,11 @@ public class SymbolKeywordNotFoundException extends IllegalValueException {
indicateSavvyTaskerChanged();
indicateAliasSymbolRemoved(symbol);
}
+
+ @Override
+ public int getAliasSymbolCount() {
+ return savvyTasker.getAliasSymbolCount();
+ }
```
###### \java\seedu\savvytasker\model\ReadOnlySavvyTasker.java
``` java
@@ -2018,44 +2126,6 @@ public enum FindType {
}
}
```
-###### \java\seedu\savvytasker\model\task\ListType.java
-``` java
-package seedu.savvytasker.model.task;
-
-/**
- * This enum represents the different ways to list tasks.
- */
-public enum ListType {
- /**
- * List tasks by due date.
- */
- DueDate,
-
- /**
- * List tasks by priority level.
- */
- PriorityLevel,
-
- /**
- * List archived tasks.
- */
- Archived;
-
- /**
- * Gets a ListType enum object from its enum name, ignoring cases.
- * @param name the name of the ListType enum object
- * @return the corresponding ListType enum object
- */
- public static ListType valueOfIgnoreCase(String name) {
- for (ListType type : ListType.values()) {
- if (type.toString().equalsIgnoreCase(name))
- return type;
- }
-
- throw new IllegalArgumentException("Unknown list type: " + name);
- }
-}
-```
###### \java\seedu\savvytasker\model\task\PriorityLevel.java
``` java
package seedu.savvytasker.model.task;
diff --git a/collated/test/A0139915W.md b/collated/test/A0139915W.md
index aaae7a2d2735..3a51dbc567e6 100644
--- a/collated/test/A0139915W.md
+++ b/collated/test/A0139915W.md
@@ -22,7 +22,15 @@ public class AddCommandTest extends SavvyTaskerGuiTest {
//invalid command
commandBox.runCommand("adds Bad Command Task");
- assertResultMessage(String.format(MESSAGE_UNKNOWN_COMMAND, HelpCommand.MESSAGE_USAGE));
+ assertResultMessage("Input: adds Bad Command Task\n" +
+ String.format(MESSAGE_UNKNOWN_COMMAND, HelpCommand.MESSAGE_USAGE));
+
+ //invalid start end date
+ Date start = getDate("31/12/2015");
+ Date end = getDate("30/12/2015");
+ commandBox.runCommand("add bad start-end pair s/" + getLocaleDateString(start) +
+ " e/" + getLocaleDateString(end));
+ assertResultMessage(String.format(AddCommand.MESSAGE_INVALID_START_END));
}
private void assertAddSuccess(TestTask taskToAdd, TestTask... currentList) {
@@ -32,11 +40,30 @@ public class AddCommandTest extends SavvyTaskerGuiTest {
TaskCardHandle addedCard = taskListPanel.navigateToTask(taskToAdd.getTaskName());
assertMatching(taskToAdd, addedCard);
- //confirm the list now contains all previous persons plus the new person
+ //confirm the list now contains all previous tasks plus the new task
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);
+ } catch (Exception e) {
+ assert false; //should not get an invalid date....
+ }
+ return null;
+ }
+
+ private SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy");
+ private Date getDate(String ddmmyyyy) {
+ try {
+ return format.parse(ddmmyyyy);
+ } catch (Exception e) {
+ assert false; //should not get an invalid date....
+ }
+ return null;
+ }
}
```
###### \java\guitests\DeleteCommandTest.java
@@ -118,6 +145,11 @@ public class FindCommandTest extends SavvyTaskerGuiTest {
public void find_nonEmptyList_byExactMatch() {
assertFindResult("find t/exact Nearer Due Task", td.nearerDue); // one matching result only
}
+
+ @Test
+ public void find_nonEmptyList_byCategory() {
+ assertFindResult("find t/category priority", td.highPriority, td.medPriority, td.lowPriority); // matching 3 results
+ }
@Test
public void find_emptyList(){
@@ -128,7 +160,7 @@ public class FindCommandTest extends SavvyTaskerGuiTest {
@Test
public void find_invalidCommand_fail() {
commandBox.runCommand("findmyring");
- assertResultMessage(String.format(MESSAGE_UNKNOWN_COMMAND, HelpCommand.MESSAGE_USAGE));
+ assertResultMessage("Input: findmyring\n" + String.format(MESSAGE_UNKNOWN_COMMAND, HelpCommand.MESSAGE_USAGE));
}
private void assertFindResult(String command, TestTask... expectedHits) {
@@ -146,6 +178,7 @@ public class FindCommandTest extends SavvyTaskerGuiTest {
*/
public class TaskCardHandle extends GuiHandle {
private static final String TASKNAME_FIELD_ID = "#taskName";
+ private static final String DETAILS_FIELD_ID = "#details";
private Node node;
@@ -161,16 +194,21 @@ public class TaskCardHandle extends GuiHandle {
public String getTaskName() {
return getTextFromLabel(TASKNAME_FIELD_ID);
}
+
+ public String getDetails() {
+ return getTextFromLabel(DETAILS_FIELD_ID);
+ }
public boolean isSameTask(ReadOnlyTask task) {
- return getTaskName().equals(task.getTaskName());
+ return getTaskName().equals(task.getTaskName()) && getDetails().equals(task.getTextForUi());
}
@Override
public boolean equals(Object obj) {
if(obj instanceof TaskCardHandle) {
TaskCardHandle handle = (TaskCardHandle) obj;
- return getTaskName().equals(handle.getTaskName()); //TODO: compare the rest
+ return getTaskName().equals(handle.getTaskName()) &&
+ getDetails().equals(handle.getDetails());
}
return super.equals(obj);
}
@@ -354,6 +392,12 @@ public class ListCommandTest extends SavvyTaskerGuiTest {
td.highPriority, td.medPriority, td.lowPriority);
}
+ @Test
+ public void list_nonEmptyList_byInvalidSwitch() {
+ commandBox.runCommand("list badswitch");
+ assertResultMessage("Input: list badswitch\nLIST_TYPE: Unknown type \'badswitch\'");
+ }
+
@Test
public void list_nonEmptyList_byDueDate() {
// covered by list_nonEmptyList()
@@ -361,13 +405,13 @@ public class ListCommandTest extends SavvyTaskerGuiTest {
@Test
public void list_nonEmptyList_byPriority() {
- assertListResult("list t/PriorityLevel", td.highPriority, td.medPriority,
+ assertListResult("list PriorityLevel", td.highPriority, td.medPriority,
td.furthestDue, td.nearerDue, td.notSoNearerDue, td.earliestDue, td.lowPriority); //multiple results
}
@Test
public void list_nonEmptyList_byArchived() {
- assertListResult("list t/Archived", td.longDue); // one matching result only
+ assertListResult("list Archived", td.longDue); // one matching result only
}
@Test
@@ -379,7 +423,7 @@ public class ListCommandTest extends SavvyTaskerGuiTest {
@Test
public void find_invalidCommand_fail() {
commandBox.runCommand("listmytasks");
- assertResultMessage(String.format(MESSAGE_UNKNOWN_COMMAND, HelpCommand.MESSAGE_USAGE));
+ assertResultMessage("Input: listmytasks\n" + String.format(MESSAGE_UNKNOWN_COMMAND, HelpCommand.MESSAGE_USAGE));
}
private void assertListResult(String command, TestTask... expectedHits ) {
@@ -390,6 +434,383 @@ public class ListCommandTest extends SavvyTaskerGuiTest {
}
}
```
+###### \java\guitests\ModifyCommandTest.java
+``` java
+public class ModifyCommandTest extends SavvyTaskerGuiTest {
+
+ @Test
+ public void add() {
+ //modify task
+ TestTask[] currentList = td.getTypicalTasks();
+ TestTask taskToModify = currentList[0];
+ Date start = getDate("30/12/2016");
+ Date end = getDate("31/12/2016");
+ taskToModify.setStartDateTime(start);
+ taskToModify.setEndDateTime(end);
+ assertModifySuccess("modify 1 s/" + getLocaleDateString(start) +
+ " e/" + getLocaleDateString(end), taskToModify, currentList);
+ currentList = TestUtil.replaceTaskFromList(currentList, taskToModify);
+
+ taskToModify.setStartDateTime(null);
+ taskToModify.setEndDateTime(null);
+ assertModifySuccess("modify 1 s/ e/", taskToModify, currentList);
+ currentList = TestUtil.replaceTaskFromList(currentList, taskToModify);
+
+ //modify invalid index
+ commandBox.runCommand("modify " + currentList.length + "1" + " s/sat");
+ assertResultMessage(String.format(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX));
+
+ //modify with invalid end date
+ start = getDate("31/12/2016");
+ end = getDate("30/12/2016");
+ commandBox.runCommand("modify 1 s/" + getLocaleDateString(start) +
+ " e/" + getLocaleDateString(end));
+ assertResultMessage(String.format(Messages.MESSAGE_INVALID_START_END));
+ }
+
+ private void assertModifySuccess(String command, TestTask taskToModify, TestTask... currentList) {
+ commandBox.runCommand(command);
+
+ //confirm the new card contains the right data
+ TaskCardHandle modifiedCard = taskListPanel.navigateToTask(taskToModify.getTaskName());
+ assertMatching(taskToModify, modifiedCard);
+
+ //confirm the list now contains all previous persons plus the new person
+ TestTask[] expectedList = TestUtil.replaceTaskFromList(currentList, taskToModify);
+ assertTrue(taskListPanel.isListMatching(expectedList));
+ }
+
+ private DateFormat formatter = DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.getDefault());
+ private String getLocaleDateString(Date date) {
+ try {
+ return formatter.format(date);
+ } catch (Exception e) {
+ assert false; //should not get an invalid date....
+ }
+ return null;
+ }
+
+ private SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy");
+ private Date getDate(String ddmmyyyy) {
+ try {
+ return format.parse(ddmmyyyy);
+ } catch (Exception e) {
+ assert false; //should not get an invalid date....
+ }
+ return null;
+ }
+
+}
+```
+###### \java\seedu\savvytasker\commons\util\SmartDefaultDatesTest.java
+``` java
+public class SmartDefaultDatesTest {
+
+ @Test
+ public void smartDefaultDates_parseStart() {
+ DateParser dateParser = new DateParser();
+ InferredDate inferredStart = null;
+ try {
+ //use MM-dd-yyyy
+ inferredStart = dateParser.parseSingle("12/31/2016");
+ } catch (ParseException e) {
+ assert false; //won't get here
+ }
+ InferredDate inferredEnd = null;
+ 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());
+
+ SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
+ Date today = today(0, 0);
+ try {
+ //use MM-dd-yyyy
+ inferredStart = dateParser.parseSingle("3pm");
+ } catch (ParseException e) {
+ assert false; //won't get here
+ }
+ 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());
+ }
+
+ @Test
+ public void smartDefaultDates_parseEnd() {
+ SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
+ Date today = today(0, 0);
+ DateParser dateParser = new DateParser();
+ InferredDate inferredEnd = null;
+ try {
+ //use MM-dd-yyyy
+ inferredEnd = dateParser.parseSingle("12/31/2016");
+ } catch (ParseException e) {
+ assert false; //won't get here
+ }
+ InferredDate inferredStart = null;
+ 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());
+
+ try {
+ //use MM-dd-yyyy
+ inferredEnd = dateParser.parseSingle("3pm");
+ } catch (ParseException e) {
+ assert false; //won't get here
+ }
+ 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());
+
+
+ try {
+ //use MM-dd-yyyy
+ inferredEnd = dateParser.parseSingle("12/31/2000");
+ } catch (ParseException e) {
+ assert false; //won't get here
+ }
+ 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());
+ }
+
+ @Test
+ public void smartDefaultDates_parseStartEnd() {
+ // START_TIME
+ // date not supplied -> today
+ // time not supplied -> 0000
+ // END_TIME
+ // date not supplied -> today
+ // time not supplied -> 2359
+ SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
+ Date today = today(0, 0);
+ DateParser dateParser = new DateParser();
+ InferredDate inferredStart = null;
+ InferredDate inferredEnd = null;
+ try {
+ //use MM-dd-yyyy
+ inferredStart = dateParser.parseSingle("12/31/2016");
+ inferredEnd = dateParser.parseSingle("12/31/2016");
+ } catch (ParseException e) {
+ assert false; //won't get here
+ }
+ SmartDefaultDates sdd = new SmartDefaultDates(inferredStart, inferredEnd);
+ // 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());
+
+ inferredStart = null;
+ inferredEnd = null;
+ try {
+ //use MM-dd-yyyy
+ inferredStart = dateParser.parseSingle("12/31/2016");
+ inferredEnd = dateParser.parseSingle("12/30/2016");
+ } catch (ParseException e) {
+ assert false; //won't get here
+ }
+ sdd = new SmartDefaultDates(inferredStart, inferredEnd);
+ // no time supplied for start and end, end date earlier than start
+ // 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());
+
+ inferredStart = null;
+ inferredEnd = null;
+ try {
+ //use MM-dd-yyyy
+ inferredStart = dateParser.parseSingle("10am");
+ inferredEnd = dateParser.parseSingle("10pm");
+ } catch (ParseException e) {
+ assert false; //won't get here
+ }
+ 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());
+
+ inferredStart = null;
+ inferredEnd = null;
+ try {
+ //use MM-dd-yyyy
+ inferredStart = dateParser.parseSingle("10pm");
+ inferredEnd = dateParser.parseSingle("10am");
+ } catch (ParseException e) {
+ assert false; //won't get here
+ }
+ sdd = new SmartDefaultDates(inferredStart, inferredEnd);
+ // 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());
+ }
+
+ @Test
+ public void smartDefaultDates_defaultParse() {
+ SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
+ Date today = today(0, 0);
+ DateParser dateParser = new DateParser();
+ 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);
+
+ try {
+ //use MM-dd-yyyy
+ actualStart = sdd.getStart(dateParser.parseSingle("10pm"));
+ actualEnd = sdd.getEnd(dateParser.parseSingle("10am"));
+ } 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);
+
+ try {
+ //use MM-dd-yyyy
+ actualStart = sdd.getStart(dateParser.parseSingle("12/31/2016"));
+ actualEnd = sdd.getEnd(dateParser.parseSingle("12/31/2016"));
+ } catch (ParseException e) {
+ assert false; //won't get here
+ }
+ expectedStart = getDate("31/12/2016 000000");
+ expectedEnd = getDate("31/12/2016 235959");
+ 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);
+ } catch (Exception e) {
+ assert false; //should not get an invalid date....
+ }
+ return null;
+ }
+
+ private Date today(int hours_24, int minute_60) {
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(new Date());
+ calendar.set(Calendar.HOUR_OF_DAY, hours_24);
+ calendar.set(Calendar.MINUTE, minute_60);
+ calendar.set(Calendar.SECOND, 0);
+ calendar.set(Calendar.MILLISECOND, 0);
+ return calendar.getTime();
+ }
+}
+```
+###### \java\seedu\savvytasker\model\task\TaskListTest.java
+``` java
+public class TaskListTest {
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Test
+ public void taskList_addDuplicate() throws DuplicateTaskException, InvalidDateException {
+ thrown.expect(DuplicateTaskException.class);
+ TaskList tasks = new TaskList();
+ Task t = new Task("Test Task");
+ t.setId(1);
+ tasks.add(t); // passes
+ assertEquals(1, tasks.getInternalList().size());
+ tasks.add(t); // fails
+ }
+
+ @Test
+ public void taskList_addInvalidDate() throws DuplicateTaskException, InvalidDateException {
+ thrown.expect(InvalidDateException.class);
+ TaskList tasks = new TaskList();
+ Task t = new Task("Test Task");
+ t.setId(1);
+ t.setStartDateTime(getDate("31/12/2016"));
+ t.setEndDateTime(getDate("31/12/2015"));
+ tasks.add(t); // fails, end date earlier than start date
+ }
+
+ @Test
+ public void taskList_removeNonExistent() throws TaskNotFoundException {
+ thrown.expect(TaskNotFoundException.class);
+ TaskList tasks = new TaskList();
+ Task t = new Task("Test Task");
+ t.setId(1);
+ assertEquals(0, tasks.getInternalList().size());
+ tasks.remove(t); // fails
+ }
+
+ @Test
+ public void taskList_replaceNonExistent() throws TaskNotFoundException, InvalidDateException {
+ thrown.expect(TaskNotFoundException.class);
+ TaskList tasks = new TaskList();
+ Task t = new Task("Test Task");
+ t.setId(1);
+ assertEquals(0, tasks.getInternalList().size());
+ tasks.replace(t, t); // fails
+ }
+
+ @Test
+ public void taskList_replaceInvalidDate() throws TaskNotFoundException, InvalidDateException, DuplicateTaskException {
+ thrown.expect(InvalidDateException.class);
+ TaskList tasks = new TaskList();
+ Task t = new Task("Test Task");
+ t.setId(1);
+ t.setStartDateTime(getDate("30/12/2016"));
+ t.setEndDateTime(getDate("31/12/2016"));
+ tasks.add(t);
+ assertEquals(1, tasks.getInternalList().size());
+ t.setStartDateTime(getDate("31/12/2016"));
+ t.setEndDateTime(getDate("31/12/2015"));
+ tasks.replace(t, t); // fails, end date earlier than start date
+ }
+
+ private SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy");
+ private Date getDate(String ddmmyyyy) {
+ try {
+ return format.parse(ddmmyyyy);
+ } catch (Exception e) {
+ assert false; //should not get an invalid date....
+ }
+ return null;
+ }
+}
+```
###### \java\seedu\savvytasker\testutil\SavvyTaskerBuilder.java
``` java
/**
@@ -497,6 +918,7 @@ public class TaskBuilder {
public class TestTask implements ReadOnlyTask {
private int id;
+ private int groupId;
private String taskName;
private Date startDateTime;
private Date endDateTime;
@@ -515,10 +937,16 @@ public class TestTask implements ReadOnlyTask {
this.numberOfRecurrence = 0;
}
+ @Override
public int getId() {
return id;
}
+ @Override
+ public int getGroupId() {
+ return groupId;
+ }
+
@Override
public String getTaskName() {
return taskName;
@@ -577,6 +1005,10 @@ public class TestTask implements ReadOnlyTask {
public void setId(int id) {
this.id = id;
}
+
+ public void setGroupId(int groupId) {
+ this.groupId = groupId;
+ }
public void setTaskName(String taskName) {
this.taskName = taskName;
@@ -624,8 +1056,32 @@ public class TestTask implements ReadOnlyTask {
}
public String getAddCommand() {
+ SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy HHmm");
StringBuilder sb = new StringBuilder();
sb.append("add " + this.getTaskName());
+ if (startDateTime != null) {
+ sb.append(" s/ ").append(sdf.format(startDateTime));
+ }
+ if (endDateTime != null) {
+ sb.append(" e/ ").append(sdf.format(endDateTime));
+ }
+ if (location != null && !location.isEmpty()) {
+ sb.append(" l/ ").append(location);
+ }
+ if (priority != null && priority != PriorityLevel.Medium) {
+ // p/ defaults to medium, if set to medium, take as non-existent
+ sb.append(" p/ ").append(priority.toString());
+ }
+ if (recurringType != null && recurringType != RecurrenceType.None) {
+ // r/ defaults to none, if set to none, take as non-existent
+ sb.append(" r/ ").append(recurringType.toString());
+ }
+ if (category != null && !category.isEmpty()) {
+ sb.append(" c/ ").append(category);
+ }
+ if (description != null && !description.isEmpty()) {
+ sb.append(" d/ ").append(description);
+ }
return sb.toString();
}
}
@@ -674,8 +1130,13 @@ public class TestTask implements ReadOnlyTask {
* @param index The index of the task to be replaced.
* @return
*/
- public static TestTask[] replaceTaskFromList(TestTask[] tasks, TestTask task, int index) {
- tasks[index] = task;
+ public static TestTask[] replaceTaskFromList(TestTask[] tasks, TestTask task) {
+ for (int i = 0; i < tasks.length; ++i) {
+ if (tasks[i].getId() == task.getId()) {
+ tasks[i] = task;
+ break;
+ }
+ }
return tasks;
}
@@ -710,26 +1171,26 @@ public class TypicalTestTasks {
public TypicalTestTasks() {
try {
- highPriority = new TaskBuilder().withId(0).withTaskName("High Priority Task")
- .withPriority(PriorityLevel.High).build();
- medPriority = new TaskBuilder().withId(1).withTaskName("Medium Priority Task")
- .withPriority(PriorityLevel.Medium).build();
- lowPriority = new TaskBuilder().withId(2).withTaskName("Low Priority Task")
- .withPriority(PriorityLevel.Low).build();
- furthestDue = new TaskBuilder().withId(3).withTaskName("Furthest Due Task")
+ highPriority = new TaskBuilder().withId(1).withTaskName("High Priority Task")
+ .withPriority(PriorityLevel.High).withCategory("priority").build();
+ medPriority = new TaskBuilder().withId(2).withTaskName("Medium Priority Task")
+ .withPriority(PriorityLevel.Medium).withCategory("priority").build();
+ lowPriority = new TaskBuilder().withId(3).withTaskName("Low Priority Task")
+ .withPriority(PriorityLevel.Low).withCategory("priority").build();
+ furthestDue = new TaskBuilder().withId(4).withTaskName("Furthest Due Task")
.withEndDateTime(getDate("01/12/2016")).build();
- nearerDue = new TaskBuilder().withId(4).withTaskName("Nearer Due Task")
+ nearerDue = new TaskBuilder().withId(5).withTaskName("Nearer Due Task")
.withEndDateTime(getDate("01/11/2016")).build();
- notSoNearerDue = new TaskBuilder().withId(5).withTaskName("Not So Nearer Due Task")
+ notSoNearerDue = new TaskBuilder().withId(6).withTaskName("Not So Nearer Due Task")
.withEndDateTime(getDate("02/11/2016")).build();
- earliestDue = new TaskBuilder().withId(6).withTaskName("Earliest Due Task")
+ earliestDue = new TaskBuilder().withId(7).withTaskName("Earliest Due Task")
.withEndDateTime(getDate("01/10/2016")).build();
- longDue = new TaskBuilder().withId(7).withTaskName("Long Due Task")
+ longDue = new TaskBuilder().withId(8).withTaskName("Long Due Task")
.withEndDateTime(getDate("01/1/2016")).withArchived(true).build();
//Manually added
- happy = new TaskBuilder().withId(8).withTaskName("Happy Task").build();
- haloween = new TaskBuilder().withId(9).withTaskName("Haloween Task").build();
+ happy = new TaskBuilder().withId(9).withTaskName("Happy Task").build();
+ haloween = new TaskBuilder().withId(10).withTaskName("Haloween Task").build();
} catch (IllegalValueException e) {
e.printStackTrace();
assert false : "not possible";
@@ -747,8 +1208,6 @@ public class TypicalTestTasks {
st.addTask(new Task(td.notSoNearerDue));
st.addTask(new Task(td.earliestDue));
st.addTask(new Task(td.longDue));
- } catch (DuplicateTaskException e) {
- assert false : "not possible";
} catch (InvalidDateException e) {
assert false : "not possible";
}
diff --git a/collated/test/A0139916U.md b/collated/test/A0139916U.md
index aef3ff61c827..8870b3a9d0e2 100644
--- a/collated/test/A0139916U.md
+++ b/collated/test/A0139916U.md
@@ -34,6 +34,7 @@ public class ParserTest {
private RedoCommandParser redoParser;
private AliasCommandParser aliasParser;
private UnaliasCommandParser unaliasParser;
+ private StorageCommandParser storageParser;
@Rule
public ExpectedException thrown = ExpectedException.none();
@@ -54,49 +55,50 @@ public class ParserTest {
redoParser = new RedoCommandParser();
aliasParser = new AliasCommandParser();
unaliasParser = new UnaliasCommandParser();
+ storageParser = new StorageCommandParser();
}
@Test
- public void parse_add_reorder() throws ParseException {
+ public void parseAdd_reorder() throws ParseException {
assertNotNull(addParser.parse("add task l/ comp e/ tomorrow, 3pm s/ today, 2pm n/ 2"));
}
@Test
- public void parse_add_multipleSpaces() throws ParseException {
+ public void parseAdd_multipleSpaces() throws ParseException {
assertNotNull(addParser.parse("add Multiple Spaces s/ 2pm"));
}
@Test
- public void parse_add_sameOptionMultipleTimes() throws ParseException {
+ public void parseAdd_sameOptionMultipleTimes_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
addParser.parse("add task s/ tomorrow 3pm s/ tomorrow 10pm");
}
@Test
- public void parse_add_missingTaskName() throws ParseException {
+ public void parseAdd_missingTaskName_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
addParser.parse("add s/ tomorrow 3pm");
}
@Test
- public void parse_add_arbitrarySlash() throws ParseException {
+ public void parseAdd_arbitrarySlash_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
addParser.parse("add task s/ tomorrow 2pm/3pm e/ sunday");
}
@Test
- public void parse_add_fullValid() throws ParseException {
+ public void parseAdd_fullValid() throws ParseException {
assertNotNull(addParser.parse("add task s/wednesday e/thursday l/ comp p/ high r/ none n/ 1 c/ test d/ test"));
}
@Test
- public void parse_add_invalidRecurrenceType() throws ParseException {
+ public void parseAdd_invalidRecurrenceType_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
addParser.parse("add task r/ Error ");
}
@Test
- public void parse_add_invalidPriorityLevel() throws ParseException {
+ public void parseAdd_invalidPriorityLevel_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
addParser.parse("add task p/ Error ");
}
@@ -104,34 +106,34 @@ public class ParserTest {
//==================================================================================
@Test
- public void parse_delete_noIndexSpecified() throws ParseException {
+ public void parseDelete_noIndexSpecified_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
deleteParser.parse("delete");
}
@Test
- public void parse_delete_oneIndex() throws ParseException {
+ public void parseDelete_oneIndex() throws ParseException {
assertNotNull(deleteParser.parse("delete 1"));
}
@Test
- public void parse_delete_multipleIndices() throws ParseException {
+ public void parseDelete_multipleIndices() throws ParseException {
assertNotNull(deleteParser.parse("delete 1 2 3"));
}
@Test
- public void parse_delete_multipleSpacesIndices() throws ParseException {
+ public void parseDelete_multipleSpacesIndices() throws ParseException {
assertNotNull(deleteParser.parse("delete 1 2 3"));
}
@Test
- public void parse_delete_negativeIndex() throws ParseException {
+ public void parseDelete_negativeIndex_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
deleteParser.parse("delete -1");
}
@Test
- public void parse_delete_zeroIndex() throws ParseException {
+ public void parseDelete_zeroIndex_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
deleteParser.parse("delete 0");
}
@@ -139,198 +141,198 @@ public class ParserTest {
//==================================================================================
@Test
- public void parse_modify_noIndex() throws ParseException {
+ public void parseModify_noIndex_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
modifyParser.parse("modify t/ newtask");
}
@Test
- public void parse_modify_multipleIndex() throws ParseException {
+ public void parseModify_multipleIndex_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
modifyParser.parse("modify 1 2 3 t/ newtask");
}
@Test
- public void parse_modify_negativeIndex() throws ParseException {
+ public void parseModify_negativeIndex_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
modifyParser.parse("modify -1 t/ newtask");
}
@Test
- public void parse_modify_zeroIndex() throws ParseException {
+ public void parseModify_zeroIndex_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
modifyParser.parse("modify 0 t/ newtask");
}
@Test
- public void parse_modify_onlySpecifyIndex() throws ParseException {
+ public void parseModify_onlySpecifyIndex() throws ParseException {
assertNotNull(modifyParser.parse("modify 1"));
}
@Test
- public void parse_modify_fullValid() throws ParseException {
+ public void parseModify_fullValid() throws ParseException {
assertNotNull(modifyParser.parse("modify 3 t/ newtask s/wednesday e/thursday l/ comp p/ high r/ none n/ 1 c/ test d/ test"));
}
@Test
- public void parse_modify_reorder() throws ParseException {
+ public void parseModify_reorder() throws ParseException {
assertNotNull(modifyParser.parse("modify 1 l/ comp e/ tomorrow, 3pm s/ today, 2pm n/ 2"));
}
@Test
- public void parse_modify_multipleSpaces() throws ParseException {
+ public void parseModify_multipleSpaces() throws ParseException {
assertNotNull(modifyParser.parse("modify 1 t/ Multiple Spaces s/ 2pm"));
}
//==================================================================================
@Test
- public void parse_clear_spaces() throws ParseException {
+ public void parseClear_spaces() throws ParseException {
assertNotNull(clearParser.parse("clear "));
}
@Test
- public void parse_clear_invalid() throws ParseException {
+ public void parseClear_invalid_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
clearParser.parse("clear 1");
}
@Test
- public void parse_clear_valid() throws ParseException {
+ public void parseClear_valid() throws ParseException {
assertNotNull(clearParser.parse("clear"));
}
//==================================================================================
@Test
- public void parse_list_noParameters() throws ParseException {
+ public void parseList_noParameters() throws ParseException {
assertNotNull(listParser.parse("list"));
}
@Test
- public void parse_list_noParametersSpaces() throws ParseException {
+ public void parseList_noParametersSpaces() throws ParseException {
assertNotNull(listParser.parse("list "));
}
@Test
public void parse_list_valid() throws ParseException {
- assertNotNull(listParser.parse("list t/ Priority Level "));
+ assertNotNull(listParser.parse("list Priority Level "));
}
@Test
- public void parse_list_invalidType() throws ParseException {
+ public void parseList_invalidType_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
- listParser.parse("list t/ Error ");
+ listParser.parse("list Error ");
}
//==================================================================================
@Test
- public void parse_find_noKeywords() throws ParseException {
+ public void parseFind_noKeywords_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
findParser.parse("find");
}
@Test
- public void parse_find_noKeywordsSpaces() throws ParseException {
+ public void parseFind_noKeywordsSpaces_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
findParser.parse("find ");
}
@Test
- public void parse_find_noKeywordsButWithType() throws ParseException {
+ public void parseFind_noKeywordsButWithType_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
findParser.parse("find t/ Exact ");
}
@Test
- public void parse_find_invalidType() throws ParseException {
+ public void parseFind_invalidType_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
findParser.parse("find t/ Error some words");
}
@Test
- public void parse_find_validAfter() throws ParseException {
+ public void parseFind_validAfter() throws ParseException {
assertNotNull(findParser.parse("find t/ Exact this word "));
}
@Test
- public void parse_find_validBefore() throws ParseException {
+ public void parseFind_validBefore() throws ParseException {
assertNotNull(findParser.parse("find some words t/ Partial "));
}
@Test
- public void parse_find_validBeforeAndAfter() throws ParseException {
+ public void parseFind_validBeforeAndAfter() throws ParseException {
assertNotNull(findParser.parse("find some words t/ Full some words after "));
}
//==================================================================================
@Test
- public void parse_help_spaces() throws ParseException {
+ public void parseHelp_spaces() throws ParseException {
assertNotNull(helpParser.parse("help "));
}
@Test
- public void parse_help_invalid() throws ParseException {
+ public void parseHelp_invalid_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
helpParser.parse("help 1");
}
@Test
- public void parse_help_valid() throws ParseException {
+ public void parseHelp_valid() throws ParseException {
assertNotNull(helpParser.parse("help"));
}
//==================================================================================
@Test
- public void parse_exit_spaces() throws ParseException {
+ public void parseExit_spaces() throws ParseException {
assertNotNull(exitParser.parse("exit "));
}
@Test
- public void parse_exit_invalid() throws ParseException {
+ public void parseExit_invalid_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
helpParser.parse("exit 1");
}
@Test
- public void parse_exit_valid() throws ParseException {
+ public void parseExit_valid() throws ParseException {
assertNotNull(exitParser.parse("exit"));
}
//==================================================================================
@Test
- public void parse_mark_noIndexSpecified() throws ParseException {
+ public void parseMark_noIndexSpecified_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
markParser.parse("mark");
}
@Test
- public void parse_mark_oneIndex() throws ParseException {
+ public void parseMark_oneIndex() throws ParseException {
assertNotNull(markParser.parse("mark 1"));
}
@Test
- public void parse_mark_multipleIndices() throws ParseException {
+ public void parseMark_multipleIndices() throws ParseException {
assertNotNull(markParser.parse("mark 1 2 3"));
}
@Test
- public void parse_mark_multipleSpacesIndices() throws ParseException {
+ public void parseMark_multipleSpacesIndices() throws ParseException {
assertNotNull(markParser.parse("mark 1 2 3"));
}
@Test
- public void parse_mark_negativeIndex() throws ParseException {
+ public void parseMark_negativeIndex_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
markParser.parse("mark -1");
}
@Test
- public void parse_mark_zeroIndex() throws ParseException {
+ public void parseMark_zeroIndex_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
markParser.parse("mark 0");
}
@@ -338,34 +340,34 @@ public class ParserTest {
//==================================================================================
@Test
- public void parse_unmark_noIndexSpecified() throws ParseException {
+ public void parseUnmark_noIndexSpecified_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
unmarkParser.parse("unmark");
}
@Test
- public void parse_unmark_oneIndex() throws ParseException {
+ public void parseUnmark_oneIndex() throws ParseException {
assertNotNull(unmarkParser.parse("unmark 1"));
}
@Test
- public void parse_unmark_multipleIndices() throws ParseException {
+ public void parseUnmark_multipleIndices() throws ParseException {
assertNotNull(unmarkParser.parse("unmark 1 2 3"));
}
@Test
- public void parse_unmark_multipleSpacesIndices() throws ParseException {
+ public void parseUnmark_multipleSpacesIndices() throws ParseException {
assertNotNull(unmarkParser.parse("unmark 1 2 3"));
}
@Test
- public void parse_unmark_negativeIndex() throws ParseException {
+ public void parseUnmark_negativeIndex_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
unmarkParser.parse("unmark -1");
}
@Test
- public void parse_unmark_zeroIndex() throws ParseException {
+ public void parseUnmark_zeroIndex_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
unmarkParser.parse("unmark 0");
}
@@ -373,106 +375,118 @@ public class ParserTest {
//==================================================================================
@Test
- public void parse_undo_spaces() throws ParseException {
+ public void parseUndo_spaces() throws ParseException {
assertNotNull(undoParser.parse("undo "));
}
@Test
- public void parse_undo_invalid() throws ParseException {
+ public void parseUndo_invalid() throws ParseException {
thrown.expect(ParseException.class);
helpParser.parse("undo 1");
}
@Test
- public void parse_undo_valid() throws ParseException {
+ public void parseUndo_valid() throws ParseException {
assertNotNull(undoParser.parse("undo"));
}
//==================================================================================
@Test
- public void parse_redo_spaces() throws ParseException {
+ public void parseRedo_spaces() throws ParseException {
assertNotNull(redoParser.parse("redo "));
}
@Test
- public void parse_redo_invalid() throws ParseException {
+ public void parseRedo_invalid_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
helpParser.parse("redo 1");
}
@Test
- public void parse_redo_valid() throws ParseException {
+ public void parseRedo_valid() throws ParseException {
assertNotNull(redoParser.parse("redo"));
}
//==================================================================================
@Test
- public void parse_alias_keywordUnspecified() throws ParseException {
+ public void parseAlias_keywordUnspecified_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
aliasParser.parse("alias r/ a string of things");
}
@Test
- public void parse_alias_textUnspecified() throws ParseException {
+ public void parseAlias_textUnspecified_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
aliasParser.parse("alias k/ xyz");
}
@Test
- public void parse_alias_noSwitchesSpecified() throws ParseException {
+ public void parseAlias_noSwitchesSpecified_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
aliasParser.parse("alias power overwhelming");
}
@Test
- public void parse_alias_keywordTooLong() throws ParseException {
+ public void parseAlias_keywordNotSingleWord_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
aliasParser.parse("alias k/ not a single word r/ project management");
}
@Test
- public void parse_alias_keywordEmpty() throws ParseException {
+ public void parseAlias_keywordEmpty_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
aliasParser.parse("alias k/ r/ project management");
}
@Test
- public void parse_alias_textEmpty() throws ParseException {
+ public void parseAlias_textEmpty_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
aliasParser.parse("alias k/ pjm r/ ");
}
@Test
- public void parse_alias_fullValid() throws ParseException {
+ public void parseAlias_fullValid() throws ParseException {
assertNotNull(aliasParser.parse("alias k/ pjm r/ project management "));
}
//==================================================================================
@Test
- public void parse_unalias_emptyKeyword() throws ParseException {
+ public void parseUnalias_emptyKeyword_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
unaliasParser.parse("unalias ");
}
@Test
- public void parse_unalias_valid() throws ParseException {
+ public void parseUnalias_valid() throws ParseException {
assertNotNull(unaliasParser.parse("unalias something "));
}
//==================================================================================
-
+
+ @Test
+ public void parseStorage_invalid_exceptionThrown() throws ParseException {
+ thrown.expect(ParseException.class);
+ storageParser.parse("storage ");
+ }
+
+ @Test
+ public void parseStorage_valid() throws ParseException {
+ assertNotNull(storageParser.parse("storage C:/Users/Brown/Desktop/file.xml "));
+ }
+
+ //==================================================================================
@Test
- public void parse_master_subparser() throws ParseException {
+ public void masterParser_subparserParsing_returnParsedCommand() throws ParseException {
MasterParser parser = new MasterParser();
parser.registerCommandParser(new AddCommandParser());
assertTrue(parser.parse(" add A New Task s/ tomorrow e/ the day after tomorrow, l/ SR10 ") instanceof AddCommand);
}
@Test
- public void parse_master_subparserRemoved() throws ParseException {
+ public void masterParser_subparserRemoved_returnIncorrectCommand() throws ParseException {
MasterParser parser = new MasterParser();
parser.registerCommandParser(new AddCommandParser());
parser.unregisterCommandParser("add");
@@ -480,7 +494,7 @@ public class ParserTest {
}
@Test
- public void parse_master_alias() throws ParseException {
+ public void masterParser_alias_returnParsedCommand() throws ParseException {
MasterParser parser = new MasterParser();
parser.registerCommandParser(new AddCommandParser());
parser.addAliasSymbol(new AliasSymbol("xyz", "add A New Task"));
@@ -489,14 +503,14 @@ public class ParserTest {
}
@Test
- public void parse_master_invalidAlias() throws ParseException {
+ public void masterParser_invalidAlias_returnFalse() throws ParseException {
MasterParser parser = new MasterParser();
parser.registerCommandParser(new AddCommandParser());
assertFalse(parser.addAliasSymbol(new AliasSymbol("add", "add A New Task")));
}
@Test
- public void parse_master_removedAlias() throws ParseException {
+ public void masterParser_removedAlias_returnIncorrectCommand() throws ParseException {
MasterParser parser = new MasterParser();
parser.registerCommandParser(new AddCommandParser());
parser.addAliasSymbol(new AliasSymbol("xyz", "add A New Task"));
diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md
index d985b50905ac..16f7b1f58831 100644
--- a/docs/DeveloperGuide.md
+++ b/docs/DeveloperGuide.md
@@ -293,7 +293,7 @@ b. Require developers to download those libraries manually (this creates extra w
Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unlikely to have) - `*`
-Priority | As a ... | I want to ... | So that I can...
+Priority | As a(n) ... | I want to ... | So that I can...
-------- | :-------- | :--------- | :-----------
`* * *` | new user | see usage instructions | refer to instructions when I forget how to use the App
`* * *` | new user | view more information about a particular command | learn how to use various commands
@@ -309,9 +309,9 @@ Priority | As a ... | I want to ... | So that I can...
`*` | user | sort tasks by priority level | see the most important tasks and prioritize accordingly
`*` | user | undo most recent command | undo the most recent operation
`*` | user | redo most recent undo command | redo the operation done by the most recent undo action
+`*` | user | change storage location | choose where my tasks are saved at
`*` | advanced user | alias keywords with shorter versions | type a command faster
`*` | advanced user | remove alias of keywords with shorter versions | get rid of shorter version of certain keywords
-{More to be added}
## Appendix B : Use Cases
@@ -319,7 +319,7 @@ Priority | As a ... | I want to ... | So that I can...
(For all use cases below, the **System** is the `Savvy Tasker` and the **Actor** is the `user`, unless specified otherwise)
-#### Use case: Add task
+### Use case: Add task
**MSS**
@@ -349,7 +349,7 @@ Use case ends.
> 2d1. Savvy Tasker shows an error message
> Use case resumes at step 1
-#### Use case: List tasks
+### Use case: List tasks
**MSS**
@@ -365,7 +365,7 @@ Use case ends.
> 3a1. Savvy Tasker shows an error message
Use case ends
-#### Use case: Find task
+### Use case: Find task
**MSS**
@@ -386,7 +386,7 @@ Use case ends.
> Use case ends
-#### Use case: Modify task
+### Use case: Modify task
**MSS**
@@ -411,7 +411,30 @@ Use case ends.
> 2b1. Savvy Tasker shows an error message and display the expected format
Use case resumes at step 3
-#### Use case: Mark task as done
+
+### Use case: Change storage location
+
+**MSS**
+
+1. Savvy Tasker waits for user command
+2. User requests to change the storage location of Savvy Tasker
+3. Savvy Tasker changes the storage location, saving all existing data in the new location
+Use case ends.
+
+**Extensions**
+
+2a. The given path is invalid
+
+> 2a1. Savvy Tasker shows an error message
+ Use case ends
+
+2b. The given path is is not accessible (read/write) by Savvy Tasker
+
+> 2b1. Savvy Tasker shows an error message
+ Use case ends
+
+
+### Use case: Mark task as done
**MSS**
@@ -434,7 +457,7 @@ Use case ends.
> 3b1. Savvy Tasker shows a 'task already marked' error message.
> Use case resumes at step 1
-###Use case: Unmark marked task
+### Use case: Unmark marked task
**MSS**
@@ -455,7 +478,7 @@ Use case ends.
> Use case resumes at step 1
-#### Use case: Delete task
+### Use case: Delete task
**MSS**
@@ -477,7 +500,7 @@ Use case ends.
> 4a1. Savvy Tasker shows an error message
> Use case resumes at step 3
-###Use case: Alias keyword and use shorten keyword
+### Use case: Alias keyword and use shorten keyword
**MSS**
@@ -499,7 +522,7 @@ Use case ends.
> 2b1. Savvy Tasker shows a error message and the shorten keyword's original associated keyword
> Use case resumes at step 1
-###Use case: Unalias keyword
+### Use case: Unalias keyword
**MSS**
@@ -514,7 +537,7 @@ Use case ends.
> 2a1. Savvy Tasker shows a 'not found' error message
> Use case resumes at step 1
-###Use case: Undo previous command
+### Use case: Undo previous command
**MSS**
@@ -529,7 +552,7 @@ Use case ends.
> 2a1. Savvy Tasker shows a 'cannot undo' error message
> Use case ends
-###Use case: Redo most recently undone command
+### Use case: Redo most recently undone command
**MSS**
@@ -555,7 +578,6 @@ Use case ends.
8. Should store data in text file.
9. Should work without requiring an installer.
-{More to be added}
## Appendix D : Glossary
diff --git a/docs/UserGuide.md b/docs/UserGuide.md
index 7aaa71e72095..eb6fc76c9f68 100644
--- a/docs/UserGuide.md
+++ b/docs/UserGuide.md
@@ -62,7 +62,7 @@ Format: `add TASK_NAME [s/START_DATE] [e/END_DATE] [l/LOCATION] [p/PRIORITY_LEVE
> LOCATION | `Optional` Specifies the location where the task happens.
> PRIORITY_LEVEL | `Optional` Specifies the priority level of the task.
`Accepts` values `low`, `medium`, `high`
`Defaults` to `???`
> RECURRING_TYPE | `Optional` Specifies the recurring type of the task.
`Accepts` values `none`, `daily`, `weekly`, `monthly`, `yearly`
`Defaults` to `none`
-> NUMBER_OF_RECURRENCE | `Optional` Specifies the number of times the task recurrs. A value of 0 specifies a never-ending recurrence.
`Defaults` to `0`
`Ignored` if RECURRING_TYPE is `none`
+> NUMBER_OF_RECURRENCE | `Optional` Specifies the number of times the task recurrs.
`Defaults` to `1`
`Ignored` if RECURRING_TYPE is `none`
> CATEGORY | `Optional` Specifies a custom category for the task. This can be used for keeping track of similar tasks.
> DESCRIPTION | `Optional` Describes the task.
@@ -78,11 +78,11 @@ Examples:
#### Listing all tasks: `list`
Shows a list of all tasks in Savvy Tasker
-Format: `list [t/LIST_TYPE]`
+Format: `list [LIST_TYPE]`
> Parameters | Description
> -------- | :--------
-> LIST_TYPE | `Optional` Specifies the name of the task.
`Accepts` values `DueDate`, `PriorityLevel`, `Archived`
`Defaults` to `DueDate`
+> LIST_TYPE | `Optional` Specifies the name of the task.
`Accepts` values `DueDate`, `PriorityLevel`, `Archived`, `Alias`
`Defaults` to `DueDate`
`LIST_TYPE` Explanation:
* `DueDate`
@@ -91,7 +91,9 @@ Format: `list [t/LIST_TYPE]`
* `PriorityLevel`
Tasks are sorted according to priority level beginning with the highest.
* `Archived`
- Tasks that have been [marked](#mark-a-task-as-done--mark) are listed. They are sorted according to the time of creation of the task.
+ Tasks that have been [marked](#mark-a-task-as-done--mark) are listed. They are sorted according to the time of creation of the task.
+* `Alias`
+ [Aliases](#alias-a-keyword--alias) that have been registered are listed.
#### Finding all task containing any keyword in its name: `find`
Finds tasks whose names contain any of the given keywords.
@@ -151,6 +153,16 @@ Format: `modify INDEX [t/TASK_NAME] [s/START_DATE] [e/END_DATE] [l/LOCATION] [p/
>
> Overwrites any of the specified fields ('LOCATION', 'DESCRIPTION'...) with the new values
+#### Change storage location : `storage`
+Changes the storage location of Savvy Tasker.
+Format: `storage PATH`
+
+> 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.
+
[//]: # (@@author A0097627N)
#### Mark a task as done : `mark`
@@ -256,10 +268,11 @@ Command | Format
[Delete](#deleting-a-task--delete) | `delete INDEX [MORE_INDEX]`
Example: `delete 1 2 3`
[Exit](#exiting-the-program--exit) | `exit`
[Find](#finding-all-task-containing-any-keyword-in-its-name-find) | `find [t/FIND_TYPE] KEYWORD [MORE_KEYWORDS]`
Example: `find t/exact CS2103 Meeting`
-[List](#listing-all-tasks-list) | `list [t/LIST_TYPE]`
Example: `list t/archived`
+[List](#listing-all-tasks-list) | `list [LIST_TYPE]`
Example: `list archived`
[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`
[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`
diff --git a/src/main/java/seedu/savvytasker/MainApp.java b/src/main/java/seedu/savvytasker/MainApp.java
index 26073d7271ad..787ff282cca2 100644
--- a/src/main/java/seedu/savvytasker/MainApp.java
+++ b/src/main/java/seedu/savvytasker/MainApp.java
@@ -14,6 +14,7 @@
import seedu.savvytasker.commons.core.EventsCenter;
import seedu.savvytasker.commons.core.LogsCenter;
import seedu.savvytasker.commons.core.Version;
+import seedu.savvytasker.commons.events.storage.DataSavingLocationChangedEvent;
import seedu.savvytasker.commons.events.ui.ExitAppRequestEvent;
import seedu.savvytasker.commons.exceptions.DataConversionException;
import seedu.savvytasker.commons.util.ConfigUtil;
@@ -44,6 +45,7 @@ public class MainApp extends Application {
protected Model model;
protected Config config;
protected UserPrefs userPrefs;
+ protected static MainApp instance;
public MainApp() {}
@@ -51,9 +53,10 @@ public MainApp() {}
public void init() throws Exception {
logger.info("=============================[ Initializing Savvy Tasker ]===========================");
super.init();
-
+ instance = this;
+
config = initConfig(getApplicationParameter("config"));
- storage = new StorageManager(config.getAddressBookFilePath(), config.getUserPrefsFilePath());
+ storage = new StorageManager(config.getSavvyTaskerFilePath(), config.getUserPrefsFilePath());
userPrefs = initPrefs(config);
@@ -179,6 +182,22 @@ public void stop() {
Platform.exit();
System.exit(0);
}
+
+ //@@author A0139915W
+ @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));
+ }
+ }
+ //@@author
@Subscribe
public void handleExitAppRequestEvent(ExitAppRequestEvent event) {
diff --git a/src/main/java/seedu/savvytasker/commons/core/Config.java b/src/main/java/seedu/savvytasker/commons/core/Config.java
index 3f360ba2bedf..249cc84d3a8a 100644
--- a/src/main/java/seedu/savvytasker/commons/core/Config.java
+++ b/src/main/java/seedu/savvytasker/commons/core/Config.java
@@ -14,8 +14,8 @@ public class Config {
private String appTitle = "Savvy Tasker";
private Level logLevel = Level.INFO;
private String userPrefsFilePath = "preferences.json";
- private String addressBookFilePath = "data/savvytasker.xml";
- private String addressBookName = "MyTaskList";
+ private String savvyTaskerFilePath = "data/savvytasker.xml";
+ private String savvyTaskerListName = "MyTaskList";
public Config() {
@@ -45,20 +45,20 @@ public void setUserPrefsFilePath(String userPrefsFilePath) {
this.userPrefsFilePath = userPrefsFilePath;
}
- public String getAddressBookFilePath() {
- return addressBookFilePath;
+ public String getSavvyTaskerFilePath() {
+ return savvyTaskerFilePath;
}
- public void setAddressBookFilePath(String addressBookFilePath) {
- this.addressBookFilePath = addressBookFilePath;
+ public void setSavvyTaskerFilePath(String savvyTaskerFilePath) {
+ this.savvyTaskerFilePath = savvyTaskerFilePath;
}
- public String getAddressBookName() {
- return addressBookName;
+ public String getSavvyTaskerListName() {
+ return savvyTaskerListName;
}
- public void setAddressBookName(String addressBookName) {
- this.addressBookName = addressBookName;
+ public void setSavvyTaskerName(String savvyTaskerName) {
+ this.savvyTaskerListName = savvyTaskerName;
}
@@ -76,13 +76,13 @@ public boolean equals(Object other) {
return Objects.equals(appTitle, o.appTitle)
&& Objects.equals(logLevel, o.logLevel)
&& Objects.equals(userPrefsFilePath, o.userPrefsFilePath)
- && Objects.equals(addressBookFilePath, o.addressBookFilePath)
- && Objects.equals(addressBookName, o.addressBookName);
+ && Objects.equals(savvyTaskerFilePath, o.savvyTaskerFilePath)
+ && Objects.equals(savvyTaskerListName, o.savvyTaskerListName);
}
@Override
public int hashCode() {
- return Objects.hash(appTitle, logLevel, userPrefsFilePath, addressBookFilePath, addressBookName);
+ return Objects.hash(appTitle, logLevel, userPrefsFilePath, savvyTaskerFilePath, savvyTaskerListName);
}
@Override
@@ -91,8 +91,8 @@ public String toString(){
sb.append("App title : " + appTitle);
sb.append("\nCurrent log level : " + logLevel);
sb.append("\nPreference file Location : " + userPrefsFilePath);
- sb.append("\nLocal data file location : " + addressBookFilePath);
- sb.append("\nAddressBook name : " + addressBookName);
+ sb.append("\nLocal data file location : " + savvyTaskerFilePath);
+ sb.append("\nSavvy Tasker List name : " + savvyTaskerListName);
return sb.toString();
}
diff --git a/src/main/java/seedu/savvytasker/commons/core/Messages.java b/src/main/java/seedu/savvytasker/commons/core/Messages.java
index 134dcd37d6b9..bb130b8ebb7e 100644
--- a/src/main/java/seedu/savvytasker/commons/core/Messages.java
+++ b/src/main/java/seedu/savvytasker/commons/core/Messages.java
@@ -9,6 +9,7 @@ public class Messages {
public static final String MESSAGE_INVALID_COMMAND_FORMAT = "Invalid command format! \n%1$s";
public static final String MESSAGE_INVALID_TASK_DISPLAYED_INDEX = "The task index provided is invalid";
public static final String MESSAGE_TASKS_LISTED_OVERVIEW = "%1$d tasks listed!";
+ public static final String MESSAGE_ALIASES_LISTED_OVERVIEW = "%1$d aliases listed!";
public static final String MESSAGE_INVALID_START_END = "The end time cannot be earlier than the start time";
}
diff --git a/src/main/java/seedu/savvytasker/commons/events/model/AliasSymbolChangedEvent.java b/src/main/java/seedu/savvytasker/commons/events/model/AliasSymbolChangedEvent.java
index 3db6aaa27df1..c3c2ff8a129b 100644
--- a/src/main/java/seedu/savvytasker/commons/events/model/AliasSymbolChangedEvent.java
+++ b/src/main/java/seedu/savvytasker/commons/events/model/AliasSymbolChangedEvent.java
@@ -16,8 +16,8 @@ public enum Action {
Removed;
}
- public final AliasSymbol symbol;
- public final Action action;
+ private final AliasSymbol symbol;
+ private final Action action;
public AliasSymbolChangedEvent(AliasSymbol symbol, Action action) {
assert symbol != null;
@@ -31,5 +31,13 @@ public AliasSymbolChangedEvent(AliasSymbol symbol, Action action) {
public String toString() {
return "Alias symbol " + action.toString() + ": " + symbol.toString();
}
+
+ public AliasSymbol getSymbol() {
+ return this.symbol;
+ }
+
+ public Action getAction() {
+ return this.action;
+ }
}
diff --git a/src/main/java/seedu/savvytasker/commons/events/storage/DataSavingLocationChangedEvent.java b/src/main/java/seedu/savvytasker/commons/events/storage/DataSavingLocationChangedEvent.java
new file mode 100644
index 000000000000..6e92df0cf402
--- /dev/null
+++ b/src/main/java/seedu/savvytasker/commons/events/storage/DataSavingLocationChangedEvent.java
@@ -0,0 +1,27 @@
+package seedu.savvytasker.commons.events.storage;
+
+import seedu.savvytasker.commons.events.BaseEvent;
+import seedu.savvytasker.model.ReadOnlySavvyTasker;
+
+//@@author A0139915W
+/**
+ * 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;
+ }
+
+}
+//@@author
diff --git a/src/main/java/seedu/savvytasker/commons/events/ui/ChangeListRequestEvent.java b/src/main/java/seedu/savvytasker/commons/events/ui/ChangeListRequestEvent.java
new file mode 100644
index 000000000000..8f1f4f7fef28
--- /dev/null
+++ b/src/main/java/seedu/savvytasker/commons/events/ui/ChangeListRequestEvent.java
@@ -0,0 +1,26 @@
+package seedu.savvytasker.commons.events.ui;
+
+import seedu.savvytasker.commons.events.BaseEvent;
+
+/**
+ * Indicates a request to jump to the list of tasks
+ */
+public class ChangeListRequestEvent extends BaseEvent {
+
+ public enum DisplayedList {
+ Task,
+ Alias
+ }
+
+ public final DisplayedList displayedList;
+
+ public ChangeListRequestEvent(DisplayedList displayedList) {
+ this.displayedList = displayedList;
+ }
+
+ @Override
+ public String toString() {
+ return this.getClass().getSimpleName();
+ }
+
+}
diff --git a/src/main/java/seedu/savvytasker/commons/util/FileUtil.java b/src/main/java/seedu/savvytasker/commons/util/FileUtil.java
index f642a058f70a..f5eb599f2cfe 100644
--- a/src/main/java/seedu/savvytasker/commons/util/FileUtil.java
+++ b/src/main/java/seedu/savvytasker/commons/util/FileUtil.java
@@ -14,11 +14,11 @@ public static boolean isFileExists(File file) {
return file.exists() && file.isFile();
}
- public static void createIfMissing(File file) throws IOException {
- if (!isFileExists(file)) {
- createFile(file);
- }
+ //@@author A0139915W
+ public static boolean createIfMissing(File file) throws IOException {
+ return createFile(file);
}
+ //@@author
/**
* Creates a file if it does not exist along with its missing parent directories
diff --git a/src/main/java/seedu/savvytasker/commons/util/SmartDefaultDates.java b/src/main/java/seedu/savvytasker/commons/util/SmartDefaultDates.java
index cf6133f1c763..c7206ebdf7c7 100644
--- a/src/main/java/seedu/savvytasker/commons/util/SmartDefaultDates.java
+++ b/src/main/java/seedu/savvytasker/commons/util/SmartDefaultDates.java
@@ -66,6 +66,7 @@ public Date getEnd(InferredDate endDateTime) {
calendar.set(Calendar.HOUR_OF_DAY, 23);
calendar.set(Calendar.MINUTE, 59);
calendar.set(Calendar.SECOND, 59);
+ calendar.set(Calendar.MILLISECOND, 0);
}
return calendar.getTime();
}
@@ -85,7 +86,13 @@ private void parseEnd(InferredDate endDateTime) {
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
+ calendar.set(Calendar.MILLISECOND, 0);
this.startDateTime = calendar.getTime();
+
+ if (this.startDateTime.compareTo(this.endDateTime) > 0) {
+ // end date is before today, leave start date as null
+ this.startDateTime = null;
+ }
}
@@ -114,6 +121,7 @@ public Date getStart(InferredDate startDateTime) {
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
+ calendar.set(Calendar.MILLISECOND, 0);
}
return calendar.getTime();
}
@@ -134,6 +142,7 @@ private void parseStart(InferredDate startDateTime) {
calendar.set(Calendar.HOUR_OF_DAY, 23);
calendar.set(Calendar.MINUTE, 59);
calendar.set(Calendar.SECOND, 59);
+ calendar.set(Calendar.MILLISECOND, 0);
this.endDateTime = calendar.getTime();
}
@@ -149,11 +158,6 @@ private void parseStartAndEnd(InferredDate startDateTime, InferredDate endDateTi
Date end = getEnd(endDateTime);
this.startDateTime = start;
this.endDateTime = end;
- if (this.startDateTime.compareTo(this.endDateTime) > 0) {
- calendar.setTime(this.endDateTime);
- calendar.add(Calendar.DATE, 7);
- this.endDateTime = calendar.getTime();
- }
}
public Date getStartDate() {
diff --git a/src/main/java/seedu/savvytasker/commons/util/StringUtil.java b/src/main/java/seedu/savvytasker/commons/util/StringUtil.java
index 3c0fc9ea185e..115b96e7d353 100644
--- a/src/main/java/seedu/savvytasker/commons/util/StringUtil.java
+++ b/src/main/java/seedu/savvytasker/commons/util/StringUtil.java
@@ -9,7 +9,7 @@
* Helper functions for handling strings.
*/
public class StringUtil {
- //@@author A0139915W-reused
+ //@@author A0139915W
// reused original implementation of 'containsIgnoreCase' to find exact matches
public static boolean containsExactIgnoreCase(String source, String query) {
List strings = Arrays.asList(source);
diff --git a/src/main/java/seedu/savvytasker/logic/Logic.java b/src/main/java/seedu/savvytasker/logic/Logic.java
index db33308d66c6..bc55816f290a 100644
--- a/src/main/java/seedu/savvytasker/logic/Logic.java
+++ b/src/main/java/seedu/savvytasker/logic/Logic.java
@@ -2,6 +2,7 @@
import javafx.collections.ObservableList;
import seedu.savvytasker.logic.commands.CommandResult;
+import seedu.savvytasker.model.alias.AliasSymbol;
import seedu.savvytasker.model.task.ReadOnlyTask;
/**
@@ -17,6 +18,9 @@ public interface Logic {
/** Returns the filtered list of tasks */
ObservableList getFilteredTaskList();
+
+ /** Returns the filtered list of alias symbol */
+ ObservableList getAliasSymbolList();
/** */
boolean canParseHeader(String keyword);
diff --git a/src/main/java/seedu/savvytasker/logic/LogicManager.java b/src/main/java/seedu/savvytasker/logic/LogicManager.java
index 732bc14daebc..0225052f898d 100644
--- a/src/main/java/seedu/savvytasker/logic/LogicManager.java
+++ b/src/main/java/seedu/savvytasker/logic/LogicManager.java
@@ -7,11 +7,16 @@
import com.google.common.eventbus.Subscribe;
import javafx.collections.ObservableList;
+import seedu.savvytasker.MainApp;
import seedu.savvytasker.commons.core.ComponentManager;
+import seedu.savvytasker.commons.core.EventsCenter;
import seedu.savvytasker.commons.core.LogsCenter;
import seedu.savvytasker.commons.events.model.AliasSymbolChangedEvent;
+import seedu.savvytasker.commons.events.ui.ChangeListRequestEvent;
+import seedu.savvytasker.commons.events.ui.ChangeListRequestEvent.DisplayedList;
import seedu.savvytasker.logic.commands.Command;
import seedu.savvytasker.logic.commands.CommandResult;
+import seedu.savvytasker.logic.commands.ListCommand;
import seedu.savvytasker.logic.parser.AddCommandParser;
import seedu.savvytasker.logic.parser.AliasCommandParser;
import seedu.savvytasker.logic.parser.ClearCommandParser;
@@ -24,6 +29,7 @@
import seedu.savvytasker.logic.parser.MasterParser;
import seedu.savvytasker.logic.parser.ModifyCommandParser;
import seedu.savvytasker.logic.parser.RedoCommandParser;
+import seedu.savvytasker.logic.parser.StorageCommandParser;
import seedu.savvytasker.logic.parser.UnaliasCommandParser;
import seedu.savvytasker.logic.parser.UndoCommandParser;
import seedu.savvytasker.logic.parser.UnmarkCommandParser;
@@ -31,6 +37,7 @@
import seedu.savvytasker.model.alias.AliasSymbol;
import seedu.savvytasker.model.task.ReadOnlyTask;
import seedu.savvytasker.storage.Storage;
+import seedu.savvytasker.ui.Ui;
/**
* The main LogicManager of the app.
@@ -39,12 +46,14 @@ public class LogicManager extends ComponentManager implements Logic {
private final Logger logger = LogsCenter.getLogger(LogicManager.class);
private final Model model;
+ private final Storage storage;
private final MasterParser parser;
private final Stack undoStack;
private final Stack redoStack;
public LogicManager(Model model, Storage storage) {
this.model = model;
+ this.storage = storage;
this.parser = new MasterParser();
this.undoStack = new Stack();
this.redoStack = new Stack();
@@ -59,9 +68,15 @@ public CommandResult execute(String commandText) {
Command command = parser.parse(commandText);
command.setModel(model);
command.setLogic(this);
+ command.setStorage(storage);
CommandResult result = command.execute();
+ if (!(command instanceof ListCommand)) {
+ // forcefully show the task list instead
+ EventsCenter.getInstance().post(new ChangeListRequestEvent(DisplayedList.Task));
+ }
+
//@@author A0097627N
if (command.isUndo()){
if (!undo()) {
@@ -82,10 +97,17 @@ else if (command.canUndo()){
return result;
}
+ //@@author A0139915W
@Override
public ObservableList getFilteredTaskList() {
return model.getFilteredTaskList();
}
+
+ @Override
+ public ObservableList getAliasSymbolList() {
+ return parser.getAliasSymbolList();
+ }
+ //@@author
//@@author A0139916U
private void registerAllDefaultCommandParsers() {
@@ -103,6 +125,7 @@ private void registerAllDefaultCommandParsers() {
parser.registerCommandParser(new RedoCommandParser());
parser.registerCommandParser(new AliasCommandParser());
parser.registerCommandParser(new UnaliasCommandParser());
+ parser.registerCommandParser(new StorageCommandParser());
}
private void loadAllAliasSymbols() {
@@ -138,24 +161,42 @@ private boolean redo() {
return redone;
}
+ /**
+ * Log the result of adding/removing a symbol in the parser.
+ *
+ * @param success if the operation succeeded
+ * @param changedSymbol the symbol that was involved in the operation
+ * @param successMsgFormat the message to print if the operation succeeded. It should contain a single
+ * %s string format specifier, which will be replaced by the symbol's string representation.
+ * @param failureMsgFormat the message to print if the operation failed. It should contain a single
+ * %s string format specifier, which will be replaced by the symbol's string representation.
+ */
+ private void logParserSymbolChange(boolean success, AliasSymbol changedSymbol,
+ String successMsgFormat, String failureMsgFormat) {
+ if (success) {
+ logger.info(String.format(successMsgFormat, changedSymbol));
+ } else {
+ logger.warning(String.format(failureMsgFormat, changedSymbol));
+ }
+ }
+
@Subscribe
public void handleAliasSymbolChangedEvent(AliasSymbolChangedEvent event) {
logger.info(LogsCenter.getEventHandlingLogMessage(
- event, "Alias symbol " + event.action.toString().toLowerCase()));
- if (event.action.equals(AliasSymbolChangedEvent.Action.Added)) {
- boolean success = parser.addAliasSymbol(event.symbol);
- if (success) {
- logger.info("Added alias symbol '"+event.symbol.getKeyword()+"' to parser");
- } else {
- logger.warning("Failed to add alias symbol '"+event.symbol.getKeyword()+" to parser");
- }
- } else {
- boolean success = parser.removeAliasSymbol(event.symbol.getKeyword());
- if (success) {
- logger.info("Removed alias symbol '"+event.symbol.getKeyword()+"' from parser");
- } else {
- logger.warning("Failed to remove alias symbol '"+event.symbol.getKeyword()+" from parser");
- }
+ event, "Alias symbol " + event.getAction().toString().toLowerCase()));
+
+ if (event.getAction().equals(AliasSymbolChangedEvent.Action.Added)) {
+ logParserSymbolChange(
+ parser.addAliasSymbol(event.getSymbol()),
+ event.getSymbol(),
+ "Added alias symbol '%s' to parser",
+ "Failed to add alias symbol '%s' to parser");
+ } else if (event.getAction().equals(AliasSymbolChangedEvent.Action.Removed)) {
+ logParserSymbolChange(
+ parser.removeAliasSymbol(event.getSymbol().getKeyword()),
+ event.getSymbol(),
+ "Removed alias symbol '%s' from parser",
+ "Failed to remove alias symbol '%s' from parser");
}
}
diff --git a/src/main/java/seedu/savvytasker/logic/commands/AddCommand.java b/src/main/java/seedu/savvytasker/logic/commands/AddCommand.java
index 52343ea376a9..83f6fc639954 100644
--- a/src/main/java/seedu/savvytasker/logic/commands/AddCommand.java
+++ b/src/main/java/seedu/savvytasker/logic/commands/AddCommand.java
@@ -1,12 +1,16 @@
package seedu.savvytasker.logic.commands;
+import java.util.Iterator;
+import java.util.LinkedList;
+
+import seedu.savvytasker.commons.core.EventsCenter;
import seedu.savvytasker.commons.core.UnmodifiableObservableList;
+import seedu.savvytasker.commons.events.ui.JumpToListRequestEvent;
import seedu.savvytasker.logic.parser.DateParser.InferredDate;
import seedu.savvytasker.model.task.PriorityLevel;
import seedu.savvytasker.model.task.ReadOnlyTask;
import seedu.savvytasker.model.task.RecurrenceType;
import seedu.savvytasker.model.task.Task;
-import seedu.savvytasker.model.task.TaskList.DuplicateTaskException;
import seedu.savvytasker.model.task.TaskList.InvalidDateException;
import seedu.savvytasker.model.task.TaskList.TaskNotFoundException;
@@ -38,6 +42,7 @@ public class AddCommand extends ModelRequiringCommand {
private final String description;
private Task toAdd;
+ private LinkedList tasksAdded;
//@@author A0139915W
/**
@@ -55,16 +60,24 @@ public AddCommand(String taskName, InferredDate startDateTime, InferredDate endD
this.numberOfRecurrence = numberOfRecurrence;
this.category = category;
this.description = description;
+ tasksAdded = new LinkedList();
}
private void createTask() {
final boolean isArchived = false; // all tasks are first added as active tasks
final int taskId = 0; // taskId to be assigned by ModelManager, leave as 0
+ final int groupId = 0; // groupId to be assigned by ModelManager, leave as 0
- this.toAdd = new Task(taskId, taskName, startDateTime, endDateTime,
+ this.toAdd = new Task(taskId, groupId, taskName, startDateTime, endDateTime,
location, priority, recurringType, numberOfRecurrence,
category, description, isArchived);
}
+
+ private void addToListOfTasksAdded(Task... tasks) {
+ for (Task t : tasks) {
+ tasksAdded.add(t);
+ }
+ }
@Override
public CommandResult execute() {
@@ -72,15 +85,41 @@ public CommandResult execute() {
createTask();
try {
- model.addTask(toAdd);
+ Task taskAdded = null;
+ if (toAdd.getRecurringType() == RecurrenceType.None) {
+ // not a recurring task, add a single task
+ taskAdded = model.addTask(toAdd);
+ addToListOfTasksAdded(taskAdded);
+ } else {
+ // a recurring task, add a group of recurring tasks
+ LinkedList tasksAdded = model.addRecurringTask(toAdd);
+ taskAdded = tasksAdded.peekFirst();
+ addToListOfTasksAdded(tasksAdded.toArray(new Task[tasksAdded.size()]));
+ }
+
+ 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 (DuplicateTaskException e) {
- return new CommandResult(MESSAGE_DUPLICATE_TASK);
} catch (InvalidDateException ex) {
return new CommandResult(MESSAGE_INVALID_START_END);
}
}
+
+ /**
+ * Helper method to retrieve the index of the task in the tasklist that was added.
+ * @param task The task to find
+ * @return Returns the index of the task in the list, -1 if not found.
+ */
+ private int getIndexOfTask(Task task) {
+ model.updateFilteredListToShowActive(); //because newly added tasks are all active.
+ UnmodifiableObservableList lastShownList = model.getFilteredTaskList();
+ return lastShownList.indexOf(task);
+ }
//@@author
//@@author A0097627N
@@ -100,7 +139,7 @@ public boolean canUndo() {
@Override
public boolean redo() {
execute();
- return false;
+ return true;
}
/**
@@ -109,20 +148,18 @@ public boolean redo() {
*/
@Override
public boolean undo() {
-
- UnmodifiableObservableList lastShownList = model.getFilteredTaskListTask();
-
- for (int i = 0; i < lastShownList.size(); i++) {
- if (lastShownList.get(i) == toAdd){
- ReadOnlyTask taskToDelete = lastShownList.get(i);
- try {
- model.deleteTask(taskToDelete);
- } catch (TaskNotFoundException e) {
- e.printStackTrace();
- }
+ Iterator itr = tasksAdded.iterator();
+ while (itr.hasNext()) {
+ try {
+ model.deleteTask(itr.next());
+ } catch (TaskNotFoundException e) {
+ // do nothing.
}
- }
- return false;
+ }
+ // clears the list of tasks added.
+ // if redo is performed, the list will be populated again.
+ tasksAdded.clear();
+ return true;
}
/**
diff --git a/src/main/java/seedu/savvytasker/logic/commands/AliasCommand.java b/src/main/java/seedu/savvytasker/logic/commands/AliasCommand.java
index f5666df04465..fe751a23a821 100644
--- a/src/main/java/seedu/savvytasker/logic/commands/AliasCommand.java
+++ b/src/main/java/seedu/savvytasker/logic/commands/AliasCommand.java
@@ -62,7 +62,7 @@ public void setLogic(Logic logic) {
this.logic = logic;
}
- //@@author A0139916U
+ //@@author A0097627N
/**
* Checks if a command can perform undo operations
* @return true if the command supports undo, false otherwise
diff --git a/src/main/java/seedu/savvytasker/logic/commands/Command.java b/src/main/java/seedu/savvytasker/logic/commands/Command.java
index 9ef43c3dc2fa..db06165bb9b5 100644
--- a/src/main/java/seedu/savvytasker/logic/commands/Command.java
+++ b/src/main/java/seedu/savvytasker/logic/commands/Command.java
@@ -5,6 +5,7 @@
import seedu.savvytasker.commons.events.ui.IncorrectCommandAttemptedEvent;
import seedu.savvytasker.logic.Logic;
import seedu.savvytasker.model.Model;
+import seedu.savvytasker.storage.Storage;
/**
* Represents a command with hidden internal logic and the ability to be executed.
@@ -19,6 +20,15 @@ public abstract class Command {
public static String getMessageForTaskListShownSummary(int displaySize) {
return String.format(Messages.MESSAGE_TASKS_LISTED_OVERVIEW, displaySize);
}
+ /**
+ * Constructs a feedback message to summarise an operation that displayed a listing of aliases.
+ *
+ * @param displaySize used to generate summary
+ * @return summary message for tasks displayed
+ */
+ public static String getMessageForAliasListShownSummary(int displaySize) {
+ return String.format(Messages.MESSAGE_ALIASES_LISTED_OVERVIEW, displaySize);
+ }
/**
* Executes the command and returns the result message.
@@ -40,6 +50,13 @@ public void setModel(Model model) { /* Intentionally does nothing */ }
* access to the dependencies.
*/
public void setLogic(Logic logic) { /* Intentionally does nothing */ }
+
+ /**
+ * Provides any storage related dependencies to the command.
+ * Commands making use of any of these should override this method to gain
+ * access to the dependencies.
+ */
+ public void setStorage(Storage storage) { /* Intentionally does nothing */ }
/**
* Raises an event to indicate an attempt to execute an incorrect command
diff --git a/src/main/java/seedu/savvytasker/logic/commands/DeleteCommand.java b/src/main/java/seedu/savvytasker/logic/commands/DeleteCommand.java
index 418a864dfce2..40a64c594447 100644
--- a/src/main/java/seedu/savvytasker/logic/commands/DeleteCommand.java
+++ b/src/main/java/seedu/savvytasker/logic/commands/DeleteCommand.java
@@ -58,7 +58,7 @@ public CommandResult execute() {
//tasksToUndo.add((Task)taskToDelete);
resultSb.append(String.format(MESSAGE_DELETE_TASK_SUCCESS, taskToDelete));
}
- } catch (TaskNotFoundException pnfe) {
+ } catch (TaskNotFoundException tnfe) {
assert false : "The target task cannot be missing";
}
diff --git a/src/main/java/seedu/savvytasker/logic/commands/IncorrectCommand.java b/src/main/java/seedu/savvytasker/logic/commands/IncorrectCommand.java
index 71d5b895be83..b369336ba941 100644
--- a/src/main/java/seedu/savvytasker/logic/commands/IncorrectCommand.java
+++ b/src/main/java/seedu/savvytasker/logic/commands/IncorrectCommand.java
@@ -6,17 +6,17 @@
*/
public class IncorrectCommand extends Command {
public final String resolvedText;
- public final String feedbackToUser;
+ public final String errorFeedback;
- public IncorrectCommand(String resolvedText, String feedbackToUser){
+ public IncorrectCommand(String resolvedText, String errorFeedback){
this.resolvedText = resolvedText;
- this.feedbackToUser = feedbackToUser;
+ this.errorFeedback = errorFeedback;
}
@Override
public CommandResult execute() {
indicateAttemptToExecuteIncorrectCommand();
- return new CommandResult(feedbackToUser);
+ return new CommandResult("Input: " + resolvedText + "\n" + errorFeedback);
}
//@@author A0097627N
diff --git a/src/main/java/seedu/savvytasker/logic/commands/ListCommand.java b/src/main/java/seedu/savvytasker/logic/commands/ListCommand.java
index 9f297bb218f3..f8c39d9032af 100644
--- a/src/main/java/seedu/savvytasker/logic/commands/ListCommand.java
+++ b/src/main/java/seedu/savvytasker/logic/commands/ListCommand.java
@@ -1,6 +1,9 @@
package seedu.savvytasker.logic.commands;
-import seedu.savvytasker.model.task.ListType;
+import seedu.savvytasker.commons.core.EventsCenter;
+import seedu.savvytasker.commons.events.ui.ChangeListRequestEvent;
+import seedu.savvytasker.commons.events.ui.ChangeListRequestEvent.DisplayedList;
+import seedu.savvytasker.model.ListType;
/**
* Lists all tasks in the savvy tasker to the user.
@@ -35,6 +38,9 @@ public CommandResult execute() {
// use default, sort by due date
_listType = ListType.DueDate;
}
+
+ // shows the task list by default, unless user
+ // specifies to show the alias
switch (_listType)
{
case DueDate:
@@ -46,10 +52,19 @@ public CommandResult execute() {
case Archived:
model.updateFilteredListToShowArchived();
break;
+ case Alias:
+ EventsCenter.getInstance().post(new ChangeListRequestEvent(DisplayedList.Alias));
+ break;
default:
- assert false; // should not reach here
+ // nothing to do
+ break;
+ }
+ if (_listType != ListType.Alias) {
+ EventsCenter.getInstance().post(new ChangeListRequestEvent(DisplayedList.Task));
+ return new CommandResult(getMessageForTaskListShownSummary(model.getFilteredTaskList().size()));
+ } else {
+ return new CommandResult(getMessageForAliasListShownSummary(model.getAliasSymbolCount()));
}
- return new CommandResult(getMessageForTaskListShownSummary(model.getFilteredTaskList().size()));
}
//@@author
diff --git a/src/main/java/seedu/savvytasker/logic/commands/MarkCommand.java b/src/main/java/seedu/savvytasker/logic/commands/MarkCommand.java
index d20314e38d9f..88f2bac1d142 100644
--- a/src/main/java/seedu/savvytasker/logic/commands/MarkCommand.java
+++ b/src/main/java/seedu/savvytasker/logic/commands/MarkCommand.java
@@ -8,7 +8,6 @@
import seedu.savvytasker.model.SavvyTasker;
import seedu.savvytasker.model.task.ReadOnlyTask;
import seedu.savvytasker.model.task.Task;
-import seedu.savvytasker.model.task.TaskList.DuplicateTaskException;
import seedu.savvytasker.model.task.TaskList.InvalidDateException;
import seedu.savvytasker.model.task.TaskList.TaskNotFoundException;
@@ -54,8 +53,7 @@ public CommandResult execute() {
for(Task taskToMark : tasksToMark) {
if (!taskToMark.isArchived()){
taskToMark.setArchived(true);
- model.deleteTask(taskToMark);
- model.addTask(taskToMark);
+ model.modifyTask(taskToMark, taskToMark);
resultSb.append(String.format(MESSAGE_MARK_TASK_SUCCESS, taskToMark));
} else {
resultSb.append(String.format(MESSAGE_MARK_TASK_FAIL, taskToMark));
@@ -63,8 +61,6 @@ public CommandResult execute() {
}
} catch (TaskNotFoundException pnfe) {
assert false : "The target task cannot be missing";
- } catch (DuplicateTaskException e) {
- e.printStackTrace();
} catch (InvalidDateException e) {
assert false : "The target task should be valid, only the archived flag is set";
}
diff --git a/src/main/java/seedu/savvytasker/logic/commands/ModifyCommand.java b/src/main/java/seedu/savvytasker/logic/commands/ModifyCommand.java
index 87c09d0ca87f..02438849d7a4 100644
--- a/src/main/java/seedu/savvytasker/logic/commands/ModifyCommand.java
+++ b/src/main/java/seedu/savvytasker/logic/commands/ModifyCommand.java
@@ -1,7 +1,9 @@
package seedu.savvytasker.logic.commands;
+import seedu.savvytasker.commons.core.EventsCenter;
import seedu.savvytasker.commons.core.Messages;
import seedu.savvytasker.commons.core.UnmodifiableObservableList;
+import seedu.savvytasker.commons.events.ui.JumpToListRequestEvent;
import seedu.savvytasker.logic.parser.DateParser.InferredDate;
import seedu.savvytasker.model.task.PriorityLevel;
import seedu.savvytasker.model.task.ReadOnlyTask;
@@ -78,7 +80,13 @@ public CommandResult execute() {
try {
originalTask = (Task)taskToModify;
- model.modifyTask(taskToModify, replacement);
+ Task taskModified = model.modifyTask(taskToModify, replacement);
+ 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";
} catch (InvalidDateException ex) {
@@ -87,6 +95,16 @@ public CommandResult execute() {
return new CommandResult(String.format(MESSAGE_SUCCESS, replacement));
}
+
+ /**
+ * Helper method to retrieve the index of the task in the tasklist that was added.
+ * @param task The task to find
+ * @return Returns the index of the task in the list, -1 if not found.
+ */
+ private int getIndexOfTask(Task task) {
+ UnmodifiableObservableList lastShownList = model.getFilteredTaskList();
+ return lastShownList.indexOf(task);
+ }
//@@author
//@@author A0097627N
diff --git a/src/main/java/seedu/savvytasker/logic/commands/StorageAndModelRequiringCommand.java b/src/main/java/seedu/savvytasker/logic/commands/StorageAndModelRequiringCommand.java
new file mode 100644
index 000000000000..fd18f92fa260
--- /dev/null
+++ b/src/main/java/seedu/savvytasker/logic/commands/StorageAndModelRequiringCommand.java
@@ -0,0 +1,23 @@
+package seedu.savvytasker.logic.commands;
+
+import seedu.savvytasker.model.Model;
+import seedu.savvytasker.storage.Storage;
+
+//@@author A0139915W
+/**
+ * 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;
+ }
+}
diff --git a/src/main/java/seedu/savvytasker/logic/commands/StorageCommand.java b/src/main/java/seedu/savvytasker/logic/commands/StorageCommand.java
new file mode 100644
index 000000000000..45df445e3f37
--- /dev/null
+++ b/src/main/java/seedu/savvytasker/logic/commands/StorageCommand.java
@@ -0,0 +1,87 @@
+package seedu.savvytasker.logic.commands;
+
+import seedu.savvytasker.commons.core.EventsCenter;
+import seedu.savvytasker.commons.events.storage.DataSavingLocationChangedEvent;
+import seedu.savvytasker.model.ReadOnlySavvyTasker;
+
+/**
+ * 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));
+ }
+ }
+
+ //@@author A0097627N
+ /**
+ * Checks if a command can perform undo operations
+ * @return true if the command supports undo, false otherwise
+ */
+ @Override
+ public boolean canUndo() {
+ return false;
+ }
+
+ /**
+ * Redo the select command
+ * @return true if the operation completed successfully, false otherwise
+ */
+ @Override
+ public boolean redo() {
+ // nothing required to be done
+ return false;
+ }
+
+ /**
+ * Undo the select command
+ * @return true if the operation completed successfully, false otherwise
+ */
+ @Override
+ public boolean undo() {
+ // nothing required to be done
+ return false;
+ }
+
+ /**
+ * Check if command is an undo command
+ * @return true if the command is an undo operation, false otherwise
+ */
+ @Override
+ public boolean isUndo() {
+ return false;
+ }
+
+ /**
+ * Check if command is a redo command
+ * @return true if the command is a redo operation, false otherwise
+ */
+ @Override
+ public boolean isRedo(){
+ return false;
+ }
+ //@@author
+}
diff --git a/src/main/java/seedu/savvytasker/logic/commands/UnaliasCommand.java b/src/main/java/seedu/savvytasker/logic/commands/UnaliasCommand.java
index e8ed11152db5..380fc236cfdf 100644
--- a/src/main/java/seedu/savvytasker/logic/commands/UnaliasCommand.java
+++ b/src/main/java/seedu/savvytasker/logic/commands/UnaliasCommand.java
@@ -47,8 +47,10 @@ public CommandResult execute() {
}
try {
- if (toRemove == null)
+ if (toRemove == null) {
return new CommandResult(MESSAGE_UNREGOGNIZED_ALIAS);
+ }
+
toUndo = toRemove;
model.removeAliasSymbol(toRemove);
return new CommandResult(String.format(MESSAGE_SUCCESS, toRemove));
@@ -56,7 +58,6 @@ public CommandResult execute() {
return new CommandResult(MESSAGE_UNREGOGNIZED_ALIAS);
}
}
- //@@author
//@@author A0097627N
/**
diff --git a/src/main/java/seedu/savvytasker/logic/commands/UnmarkCommand.java b/src/main/java/seedu/savvytasker/logic/commands/UnmarkCommand.java
index f3d360b01793..cee98003b600 100644
--- a/src/main/java/seedu/savvytasker/logic/commands/UnmarkCommand.java
+++ b/src/main/java/seedu/savvytasker/logic/commands/UnmarkCommand.java
@@ -8,7 +8,6 @@
import seedu.savvytasker.model.SavvyTasker;
import seedu.savvytasker.model.task.ReadOnlyTask;
import seedu.savvytasker.model.task.Task;
-import seedu.savvytasker.model.task.TaskList.DuplicateTaskException;
import seedu.savvytasker.model.task.TaskList.InvalidDateException;
import seedu.savvytasker.model.task.TaskList.TaskNotFoundException;
@@ -54,8 +53,7 @@ public CommandResult execute() {
for(Task taskToUnmark : tasksToUnmark) {
if (taskToUnmark.isArchived()){
taskToUnmark.setArchived(false);
- model.deleteTask(taskToUnmark);
- model.addTask(taskToUnmark);
+ model.modifyTask(taskToUnmark, taskToUnmark);
model.updateFilteredListToShowArchived();
resultSb.append(String.format(MESSAGE_UNMARK_TASK_SUCCESS, taskToUnmark));
} else {
@@ -64,9 +62,7 @@ public CommandResult execute() {
}
} catch (TaskNotFoundException pnfe) {
assert false : "The target task cannot be missing";
- } catch (DuplicateTaskException e) {
- e.printStackTrace();
- }catch (InvalidDateException e) {
+ } catch (InvalidDateException e) {
assert false : "The target task should be valid, only the archived flag is set";
}
return new CommandResult(resultSb.toString());
diff --git a/src/main/java/seedu/savvytasker/logic/parser/AddCommandParser.java b/src/main/java/seedu/savvytasker/logic/parser/AddCommandParser.java
index 7301ce70e1e9..66dc288eeedf 100644
--- a/src/main/java/seedu/savvytasker/logic/parser/AddCommandParser.java
+++ b/src/main/java/seedu/savvytasker/logic/parser/AddCommandParser.java
@@ -10,22 +10,12 @@
import seedu.savvytasker.model.task.PriorityLevel;
import seedu.savvytasker.model.task.RecurrenceType;
-public class AddCommandParser implements CommandParser {
+public class AddCommandParser extends TaskFieldParser {
private static final String HEADER = "add";
private static final String READABLE_FORMAT = HEADER+" TASK_NAME [s/START_DATE] " +
"[e/END_DATE] [l/LOCATION] [p/PRIORITY_LEVEL] [r/RECURRING_TYPE] " +
"[n/NUMBER_OF_RECURRENCE] [c/CATEGORY] [d/DESCRIPTION]";
- private static final String REGEX_REF_TASK_NAME = "TaskName";
- private static final String REGEX_REF_START_DATE = "StartDate";
- private static final String REGEX_REF_END_DATE = "EndDate";
- private static final String REGEX_REF_LOCATION = "Location";
- private static final String REGEX_REF_PRIORITY_LEVEL = "Priority";
- private static final String REGEX_REF_RECURRING_TYPE = "RecurringType";
- private static final String REGEX_REF_NUMBER_OF_RECURRENCE = "RecurringNumber";
- private static final String REGEX_REF_CATEGORY = "Category";
- private static final String REGEX_REF_DESCRIPTION = "Description";
-
private static final Pattern REGEX_PATTERN = Pattern.compile(
HEADER+"\\s+(?<"+REGEX_REF_TASK_NAME+">([^/]+?(\\s+|$))+)((?<=\\s)(" +
"(s/(?<"+REGEX_REF_START_DATE+">[^/]+)(?!.*\\ss/))|" +
@@ -37,8 +27,6 @@ public class AddCommandParser implements CommandParser {
"(c/(?<"+REGEX_REF_CATEGORY+">[^/]+)(?!.*\\sc/))|" +
"(d/(?<"+REGEX_REF_DESCRIPTION+">[^/]+)(?!.*\\sd/))" +
")(\\s|$)){0,10}", Pattern.CASE_INSENSITIVE);
-
- private static final TaskFieldParser TASK_PARSER = new TaskFieldParser();
@Override
public String getHeader() {
@@ -54,15 +42,15 @@ public String getRequiredFormat() {
public AddCommand parse(String commandText) throws ParseException {
Matcher matcher = REGEX_PATTERN.matcher(commandText);
if (matcher.matches()) {
- InferredDate startDate = TASK_PARSER.parseStartDate(matcher.group(REGEX_REF_START_DATE));
- InferredDate endDate = TASK_PARSER.parseEndDate(matcher.group(REGEX_REF_END_DATE));
- String taskName = TASK_PARSER.parseTaskName(matcher.group(REGEX_REF_TASK_NAME));
- String location = TASK_PARSER.parseLocation(matcher.group(REGEX_REF_LOCATION));
- PriorityLevel priority = TASK_PARSER.parsePriorityLevel(matcher.group(REGEX_REF_PRIORITY_LEVEL));
- RecurrenceType recurrence = TASK_PARSER.parseRecurrenceType(matcher.group(REGEX_REF_RECURRING_TYPE));
- Integer nrOfRecurrence = TASK_PARSER.parseNumberOfRecurrence(matcher.group(REGEX_REF_NUMBER_OF_RECURRENCE));
- String category = TASK_PARSER.parseCategory(matcher.group(REGEX_REF_CATEGORY));
- String description = TASK_PARSER.parseDescription(matcher.group(REGEX_REF_DESCRIPTION));
+ InferredDate startDate = parseStartDate(matcher.group(REGEX_REF_START_DATE));
+ InferredDate endDate = parseEndDate(matcher.group(REGEX_REF_END_DATE));
+ String taskName = parseTaskName(matcher.group(REGEX_REF_TASK_NAME));
+ String location = parseLocation(matcher.group(REGEX_REF_LOCATION));
+ PriorityLevel priority = parsePriorityLevel(matcher.group(REGEX_REF_PRIORITY_LEVEL));
+ RecurrenceType recurrence = parseRecurrenceType(matcher.group(REGEX_REF_RECURRING_TYPE));
+ Integer nrOfRecurrence = parseNumberOfRecurrence(matcher.group(REGEX_REF_NUMBER_OF_RECURRENCE));
+ String category = parseCategory(matcher.group(REGEX_REF_CATEGORY));
+ String description = parseDescription(matcher.group(REGEX_REF_DESCRIPTION));
return new AddCommand(taskName, startDate,
endDate, location, priority,
diff --git a/src/main/java/seedu/savvytasker/logic/parser/AliasCommandParser.java b/src/main/java/seedu/savvytasker/logic/parser/AliasCommandParser.java
index c54280d6ed9c..2d5240d3534d 100644
--- a/src/main/java/seedu/savvytasker/logic/parser/AliasCommandParser.java
+++ b/src/main/java/seedu/savvytasker/logic/parser/AliasCommandParser.java
@@ -18,7 +18,8 @@ public class AliasCommandParser implements CommandParser {
HEADER+"\\s+((?<=\\s)(" +
"(r/(?<"+REGEX_REF_REPRESENTATION+">[^/]+)(?!.*\\sr/))|" +
"(k/(?<"+REGEX_REF_KEYWORD+">[^/]+)(?!.*\\sk/))" +
- ")(\\s|$)){2}"
+ ")(\\s|$)){2}",
+ Pattern.CASE_INSENSITIVE
);
@Override
diff --git a/src/main/java/seedu/savvytasker/logic/parser/ListCommandParser.java b/src/main/java/seedu/savvytasker/logic/parser/ListCommandParser.java
index af95bce78bff..ad2457b96f2f 100644
--- a/src/main/java/seedu/savvytasker/logic/parser/ListCommandParser.java
+++ b/src/main/java/seedu/savvytasker/logic/parser/ListCommandParser.java
@@ -6,16 +6,16 @@
import seedu.savvytasker.commons.core.Messages;
import seedu.savvytasker.logic.commands.ListCommand;
-import seedu.savvytasker.model.task.ListType;
+import seedu.savvytasker.model.ListType;
public class ListCommandParser implements CommandParser {
private static final String HEADER = "list";
- private static final String READABLE_FORMAT = HEADER+" [t/LIST_TYPE]";
+ private static final String READABLE_FORMAT = HEADER+" [LIST_TYPE]";
private static final String REGEX_REF_LIST_TYPE = "ListType";
private static final Pattern REGEX_PATTERN = Pattern.compile(
- HEADER+"\\s*((?<=\\s)t/(?<"+REGEX_REF_LIST_TYPE+">[^/]+))?",
+ HEADER+"\\s*((?<=\\s)(?<"+REGEX_REF_LIST_TYPE+">[^/]+))?",
Pattern.CASE_INSENSITIVE);
@Override
diff --git a/src/main/java/seedu/savvytasker/logic/parser/MasterParser.java b/src/main/java/seedu/savvytasker/logic/parser/MasterParser.java
index 753b62808fe3..271cb564acd5 100644
--- a/src/main/java/seedu/savvytasker/logic/parser/MasterParser.java
+++ b/src/main/java/seedu/savvytasker/logic/parser/MasterParser.java
@@ -9,45 +9,86 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
import seedu.savvytasker.logic.commands.Command;
import seedu.savvytasker.logic.commands.HelpCommand;
import seedu.savvytasker.logic.commands.IncorrectCommand;
import seedu.savvytasker.model.alias.AliasSymbol;
+/**
+ * Represents the master parser that is used by Logic. This is a parser containing
+ * all subparsers that will do the actual parsing to produce Command objects. This
+ * parser replaces keywords of the input with aliased representations before selecting
+ * a subparser to do the parsing. The selection of the subparser is based on the first
+ * word of the input, called the header, and matching it to the subparser that declares
+ * that it parses it.
+ */
public class MasterParser {
private static final Pattern KEYWORD_PATTERN =
- Pattern.compile("(\\S+)(\\s+|$)");
+ Pattern.compile("([^\\s/]+)([\\s/]+|$)");
private final Map> commandParsers;
private final Map aliasingSymbols;
+ private final ObservableList aliasList = FXCollections.observableArrayList();
+
public MasterParser() {
this.commandParsers = new HashMap>();
this.aliasingSymbols = new HashMap();
}
+ /**
+ * Parses the input text, selecting an appropriate registered parser to parse it.
+ * The parser selected is based on the first header word of the input text. The text
+ * is preprocessed, replacing any of its tokens that are keywords to an alias, before
+ * being passed to the parser.
+ *
+ * @param userInput the text to be parse
+ * @return the command that was parsed if successful, or IncorrectCommand if there is no
+ * parser that can parse the text or if there is a format error with the text.
+ */
public Command parse(String userInput) {
String[] pieces = preprocessInitial(userInput.trim());
- if (pieces == null)
- return new IncorrectCommand(userInput, String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE));
+ if (pieces == null) {
+ return new IncorrectCommand(userInput,
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE));
+ }
String header = pieces[0];
String body = pieces[1];
- String trueHeader = extractHeader(header);
- CommandParser extends Command> parser = commandParsers.get(trueHeader);
- if (parser == null)
- return new IncorrectCommand(header + body, String.format(MESSAGE_UNKNOWN_COMMAND, HelpCommand.MESSAGE_USAGE));
- if (parser.shouldPreprocess())
- body = preprocessBody(body);
+ CommandParser extends Command> parser = selectParser(extractTrueHeader(header));
+ if (parser == null) {
+ return new IncorrectCommand(header + body,
+ String.format(MESSAGE_UNKNOWN_COMMAND, HelpCommand.MESSAGE_USAGE));
+ }
- String combined = header + body;
+ if (parser.shouldPreprocess()) {
+ return makeParserParse(parser, header + preprocessBody(body));
+ } else {
+ return makeParserParse(parser, header + body);
+ }
+ }
+
+ /**
+ * Makes the parser parse the preprocessed text.
+ *
+ * @param parser the parser to use to parse
+ * @param preprocessedText the text to parse
+ * @return the output Command from the parsing, or IncorrectCommand object if the parse failed
+ */
+ private Command makeParserParse(CommandParser extends Command> parser, String preprocessedText) {
try {
- return parser.parse(combined);
+ return parser.parse(preprocessedText);
} catch (ParseException pe) {
- return new IncorrectCommand(combined, String.format(pe.getFailureDetails()));
+ return new IncorrectCommand(preprocessedText, String.format(pe.getFailureDetails()));
}
}
+ private CommandParser extends Command> selectParser(String header) {
+ return commandParsers.get(header);
+ }
+
/**
* Does an initial preprocessing of a command text in case the header is aliased.
* Returns a string array with 2 elements: the first is the header which is possibly aliased,
@@ -78,13 +119,13 @@ private String[] preprocessInitial(String commandText) {
}
/**
- * Gets the header from the preprocessed header as a preprocessed header may contain
+ * Gets the true header from the preprocessed header as a preprocessed header may contain
* several tokens.
*
* @param preprocessedHeader the preprocessed header
* @return the true header
*/
- private String extractHeader(String preprocessedHeader) {
+ private String extractTrueHeader(String preprocessedHeader) {
Matcher matcher = KEYWORD_PATTERN.matcher(preprocessedHeader);
if (matcher.find()) {
@@ -182,7 +223,8 @@ public boolean addAliasSymbol(AliasSymbol symbol) {
return false;
if (isCommandParserRegistered(symbol.getKeyword()))
return false;
-
+
+ aliasList.add(symbol);
aliasingSymbols.put(symbol.getKeyword(), symbol);
return true;
}
@@ -197,7 +239,12 @@ public boolean addAliasSymbol(AliasSymbol symbol) {
public boolean removeAliasSymbol(String symbolKeyword) {
assert symbolKeyword != null;
- return aliasingSymbols.remove(symbolKeyword) != null;
+ AliasSymbol symbol = aliasingSymbols.remove(symbolKeyword);
+ if (symbol != null) {
+ return aliasList.remove(symbol);
+ } else {
+ return false;
+ }
}
/**
@@ -216,6 +263,11 @@ public boolean doesAliasSymbolExist(String symbolKeyword) {
* @see #removeAliasSymbol
*/
public void clearAllAliasSymbols() {
+ aliasList.clear();
aliasingSymbols.clear();
}
+
+ public ObservableList getAliasSymbolList() {
+ return aliasList;
+ }
}
diff --git a/src/main/java/seedu/savvytasker/logic/parser/ModifyCommandParser.java b/src/main/java/seedu/savvytasker/logic/parser/ModifyCommandParser.java
index 4bb317bdbde2..6592d486ee0b 100644
--- a/src/main/java/seedu/savvytasker/logic/parser/ModifyCommandParser.java
+++ b/src/main/java/seedu/savvytasker/logic/parser/ModifyCommandParser.java
@@ -11,22 +11,13 @@
import seedu.savvytasker.model.task.PriorityLevel;
import seedu.savvytasker.model.task.RecurrenceType;
-public class ModifyCommandParser implements CommandParser {
+public class ModifyCommandParser extends TaskFieldParser {
private static final String HEADER = "modify";
private static final String READABLE_FORMAT = HEADER+" 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]";
private static final String REGEX_REF_INDEX = "Index";
- private static final String REGEX_REF_TASK_NAME = "TaskName";
- private static final String REGEX_REF_START_DATE = "StartDate";
- private static final String REGEX_REF_END_DATE = "EndDate";
- private static final String REGEX_REF_LOCATION = "Location";
- private static final String REGEX_REF_PRIORITY_LEVEL = "Priority";
- private static final String REGEX_REF_RECURRING_TYPE = "RecurringType";
- private static final String REGEX_REF_NUMBER_OF_RECURRENCE = "RecurringNumber";
- private static final String REGEX_REF_CATEGORY = "Category";
- private static final String REGEX_REF_DESCRIPTION = "Description";
private static final Pattern REGEX_PATTERN = Pattern.compile(
HEADER+"\\s+(?<"+REGEX_REF_INDEX+">([^/]+?(\\s+|$))+)((?<=\\s)(" +
@@ -41,7 +32,6 @@ public class ModifyCommandParser implements CommandParser {
"(d/(?<"+REGEX_REF_DESCRIPTION+">[^/]*)(?!.*\\sd/))" +
")(\\s|$)){0,11}", Pattern.CASE_INSENSITIVE);
- private static final TaskFieldParser TASK_PARSER = new TaskFieldParser();
private static final IndexParser INDEX_PARSER = new IndexParser();
@Override
@@ -62,13 +52,13 @@ public ModifyCommand parse(String commandText) throws ParseException {
int index = parseIndex(matcher.group(REGEX_REF_INDEX));
InferredDate startDate = parseDate(matcher.group(REGEX_REF_START_DATE));
InferredDate endDate = parseDate(matcher.group(REGEX_REF_END_DATE));
- String taskName = TASK_PARSER.parseTaskName(matcher.group(REGEX_REF_TASK_NAME));
- String location = TASK_PARSER.parseLocation(matcher.group(REGEX_REF_LOCATION));
- PriorityLevel priority = TASK_PARSER.parsePriorityLevel(matcher.group(REGEX_REF_PRIORITY_LEVEL));
- RecurrenceType recurrence = TASK_PARSER.parseRecurrenceType(matcher.group(REGEX_REF_RECURRING_TYPE));
- Integer nrOfRecurrence = TASK_PARSER.parseNumberOfRecurrence(matcher.group(REGEX_REF_NUMBER_OF_RECURRENCE));
- String category = TASK_PARSER.parseCategory(matcher.group(REGEX_REF_CATEGORY));
- String description = TASK_PARSER.parseDescription(matcher.group(REGEX_REF_DESCRIPTION));
+ String taskName = parseTaskName(matcher.group(REGEX_REF_TASK_NAME));
+ String location = parseLocation(matcher.group(REGEX_REF_LOCATION));
+ PriorityLevel priority = parsePriorityLevel(matcher.group(REGEX_REF_PRIORITY_LEVEL));
+ RecurrenceType recurrence = parseRecurrenceType(matcher.group(REGEX_REF_RECURRING_TYPE));
+ Integer nrOfRecurrence = parseNumberOfRecurrence(matcher.group(REGEX_REF_NUMBER_OF_RECURRENCE));
+ String category = parseCategory(matcher.group(REGEX_REF_CATEGORY));
+ String description = parseDescription(matcher.group(REGEX_REF_DESCRIPTION));
return new ModifyCommand(index, taskName, startDate,
endDate, location, priority,
@@ -90,9 +80,9 @@ private int parseIndex(String indexText) throws ParseException {
private InferredDate parseDate(String dateText) throws ParseException {
if (dateText != null && dateText.trim().isEmpty()) {
- return TASK_PARSER.dateParser.new InferredDate(new Date(), true, true);
+ return dateParser.new InferredDate(new Date(), true, true);
}
- return TASK_PARSER.parseStartDate(dateText);
+ return parseStartDate(dateText);
}
}
diff --git a/src/main/java/seedu/savvytasker/logic/parser/StorageCommandParser.java b/src/main/java/seedu/savvytasker/logic/parser/StorageCommandParser.java
new file mode 100644
index 000000000000..c97a391c1431
--- /dev/null
+++ b/src/main/java/seedu/savvytasker/logic/parser/StorageCommandParser.java
@@ -0,0 +1,45 @@
+//@@author A0139916U
+package seedu.savvytasker.logic.parser;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import seedu.savvytasker.commons.core.Messages;
+import seedu.savvytasker.logic.commands.StorageCommand;
+
+public class StorageCommandParser implements CommandParser {
+ private static final String HEADER = "storage";
+ private static final String READABLE_FORMAT = HEADER+" NEW_PATH";
+
+ private static final String REGEX_REF_PATH = "Path";
+
+ private static final Pattern REGEX_PATTERN = Pattern.compile(
+ HEADER+"\\s+(?<"+REGEX_REF_PATH+">.*)",
+ Pattern.CASE_INSENSITIVE);
+
+ @Override
+ public String getHeader() {
+ return HEADER;
+ }
+
+ @Override
+ public String getRequiredFormat() {
+ return READABLE_FORMAT;
+ }
+
+ @Override
+ public StorageCommand parse(String commandText) throws ParseException {
+ Matcher matcher = REGEX_PATTERN.matcher(commandText);
+ if (matcher.matches()) {
+ String path = matcher.group(REGEX_REF_PATH).trim();
+
+ if (!path.isEmpty()) {
+ return new StorageCommand(path);
+ }
+ }
+
+ throw new ParseException(commandText, String.format(
+ Messages.MESSAGE_INVALID_COMMAND_FORMAT, getRequiredFormat()));
+ }
+
+}
diff --git a/src/main/java/seedu/savvytasker/logic/parser/TaskFieldParser.java b/src/main/java/seedu/savvytasker/logic/parser/TaskFieldParser.java
index 4e981b3dd4ba..361ad6944576 100644
--- a/src/main/java/seedu/savvytasker/logic/parser/TaskFieldParser.java
+++ b/src/main/java/seedu/savvytasker/logic/parser/TaskFieldParser.java
@@ -1,31 +1,47 @@
//@@author A0139916U
package seedu.savvytasker.logic.parser;
+import seedu.savvytasker.logic.commands.Command;
import seedu.savvytasker.logic.parser.DateParser.InferredDate;
import seedu.savvytasker.model.task.PriorityLevel;
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.
*/
-public class TaskFieldParser {
+public abstract class TaskFieldParser implements CommandParser {
+ /*
+ * Provides standard regex ref names for various task fields that might be used by subclasses.
+ */
+ protected static final String REGEX_REF_TASK_NAME = "TaskName";
+ protected static final String REGEX_REF_START_DATE = "StartDate";
+ protected static final String REGEX_REF_END_DATE = "EndDate";
+ protected static final String REGEX_REF_LOCATION = "Location";
+ protected static final String REGEX_REF_PRIORITY_LEVEL = "Priority";
+ protected static final String REGEX_REF_RECURRING_TYPE = "RecurringType";
+ protected static final String REGEX_REF_NUMBER_OF_RECURRENCE = "RecurringNumber";
+ protected static final String REGEX_REF_CATEGORY = "Category";
+ protected static final String REGEX_REF_DESCRIPTION = "Description";
+
protected final DateParser dateParser;
- public TaskFieldParser() {
+ protected TaskFieldParser() {
this.dateParser = new DateParser();
}
- public String parseTaskName(String taskNameText) throws ParseException {
+ protected String parseTaskName(String taskNameText) throws ParseException {
if (taskNameText == null)
return null;
return taskNameText.trim();
}
- public InferredDate parseStartDate(String dateText) throws ParseException {
+ protected InferredDate parseStartDate(String dateText) throws ParseException {
return parseDate(dateText, "START_DATE: ");
}
- public InferredDate parseEndDate(String dateText) throws ParseException {
+ protected InferredDate parseEndDate(String dateText) throws ParseException {
return parseDate(dateText, "END_DATE: ");
}
@@ -41,13 +57,13 @@ private InferredDate parseDate(String dateText, String errorField) throws ParseE
}
}
- public String parseLocation(String locationText) throws ParseException {
+ protected String parseLocation(String locationText) throws ParseException {
if (locationText == null)
return null;
return locationText.trim();
}
- public PriorityLevel parsePriorityLevel(String priorityLevelText) throws ParseException {
+ protected PriorityLevel parsePriorityLevel(String priorityLevelText) throws ParseException {
if (priorityLevelText == null)
return null;
@@ -59,7 +75,7 @@ public PriorityLevel parsePriorityLevel(String priorityLevelText) throws ParseEx
}
}
- public RecurrenceType parseRecurrenceType(String recurrenceTypeText) throws ParseException {
+ protected RecurrenceType parseRecurrenceType(String recurrenceTypeText) throws ParseException {
if (recurrenceTypeText == null)
return null;
@@ -71,7 +87,7 @@ public RecurrenceType parseRecurrenceType(String recurrenceTypeText) throws Pars
}
}
- public Integer parseNumberOfRecurrence(String numRecurrenceText) throws ParseException {
+ protected Integer parseNumberOfRecurrence(String numRecurrenceText) throws ParseException {
if (numRecurrenceText == null)
return null;
@@ -93,13 +109,13 @@ public Integer parseNumberOfRecurrence(String numRecurrenceText) throws ParseExc
return numRecurrence;
}
- public String parseCategory(String categoryText) throws ParseException {
+ protected String parseCategory(String categoryText) throws ParseException {
if (categoryText == null)
return null;
return categoryText.trim();
}
- public String parseDescription(String descriptionText) throws ParseException {
+ protected String parseDescription(String descriptionText) throws ParseException {
if (descriptionText == null)
return null;
return descriptionText.trim();
diff --git a/src/main/java/seedu/savvytasker/logic/parser/UnaliasCommandParser.java b/src/main/java/seedu/savvytasker/logic/parser/UnaliasCommandParser.java
index 96e63e82adf2..809f57552b6e 100644
--- a/src/main/java/seedu/savvytasker/logic/parser/UnaliasCommandParser.java
+++ b/src/main/java/seedu/savvytasker/logic/parser/UnaliasCommandParser.java
@@ -14,7 +14,8 @@ public class UnaliasCommandParser implements CommandParser {
private static final String REGEX_REF_KEYWORD = "Keyword";
private static final Pattern REGEX_PATTERN = Pattern.compile(
- HEADER+"\\s+(?<"+REGEX_REF_KEYWORD+">[^/]+)"
+ HEADER+"\\s+(?<"+REGEX_REF_KEYWORD+">[^/]+)",
+ Pattern.CASE_INSENSITIVE
);
@Override
diff --git a/src/main/java/seedu/savvytasker/model/task/ListType.java b/src/main/java/seedu/savvytasker/model/ListType.java
similarity index 82%
rename from src/main/java/seedu/savvytasker/model/task/ListType.java
rename to src/main/java/seedu/savvytasker/model/ListType.java
index cca1a5d58472..2b7c9f244679 100644
--- a/src/main/java/seedu/savvytasker/model/task/ListType.java
+++ b/src/main/java/seedu/savvytasker/model/ListType.java
@@ -1,8 +1,8 @@
//@@author A0139916U
-package seedu.savvytasker.model.task;
+package seedu.savvytasker.model;
/**
- * This enum represents the different ways to list tasks.
+ * This enum represents what and how to list tasks/symbols.
*/
public enum ListType {
/**
@@ -18,7 +18,12 @@ public enum ListType {
/**
* List archived tasks.
*/
- Archived;
+ Archived,
+
+ /**
+ * List aliases.
+ */
+ Alias;
/**
* Gets a ListType enum object from its enum name, ignoring cases.
diff --git a/src/main/java/seedu/savvytasker/model/Model.java b/src/main/java/seedu/savvytasker/model/Model.java
index eaff64142432..4b081eb8ba34 100644
--- a/src/main/java/seedu/savvytasker/model/Model.java
+++ b/src/main/java/seedu/savvytasker/model/Model.java
@@ -1,5 +1,7 @@
package seedu.savvytasker.model;
+import java.util.LinkedList;
+
import seedu.savvytasker.commons.core.UnmodifiableObservableList;
import seedu.savvytasker.model.alias.AliasSymbol;
import seedu.savvytasker.model.alias.DuplicateSymbolKeywordException;
@@ -22,22 +24,37 @@ public interface Model {
ReadOnlySavvyTasker getSavvyTasker();
//@@author A0139915W
- /** Deletes the given Task. */
- void deleteTask(ReadOnlyTask target) throws TaskNotFoundException;
+ /**
+ * Deletes the given Task.
+ * @throws {@link TaskNotFoundException} if the task does not exist
+ * @return Returns a Task if the delete operation is successful, an exception is thrown otherwise.
+ * */
+ Task deleteTask(ReadOnlyTask target) throws TaskNotFoundException;
- /** Modifies the given Task. */
- void modifyTask(ReadOnlyTask target, Task replacement) throws TaskNotFoundException, InvalidDateException;
+ /**
+ * Modifies the given Task.
+ * @throws {@link TaskNotFoundException} if the task does not exist
+ * @throws {@link InvalidDateException} if the end date is earlier than the start date
+ * @return Returns a Task if the modify operation is successful, an exception is thrown otherwise.
+ * */
+ Task modifyTask(ReadOnlyTask target, Task replacement) throws TaskNotFoundException, InvalidDateException;
/** Adds the given Task.
* @throws {@link DuplicateTaskException} if a duplicate is found
+ * @throws {@link InvalidDateException} if the end date is earlier than the start date
+ * @return Returns a Task if the add operation is successful, an exception is thrown otherwise.
+ * */
+ Task addTask(Task task) throws InvalidDateException;
+
+ /** Adds the given Task as a recurring task. The task's recurrence type must not be null.
+ * @throws {@link DuplicateTaskException} if a duplicate is found
+ * @throws {@link InvalidDateException} if the end date is earlier than the start date
+ * @return Returns the list of Tasks added if the add operation is successful, an exception is thrown otherwise.
* */
- void addTask(Task task) throws DuplicateTaskException, InvalidDateException;
+ LinkedList addRecurringTask(Task task) throws InvalidDateException;
/** Returns the filtered task list as an {@code UnmodifiableObservableList} */
UnmodifiableObservableList getFilteredTaskList();
-
- /** Returns the filtered task list as an {@code UnmodifiableObservableList} */
- UnmodifiableObservableList getFilteredTaskListTask();
/** Updates the filter of the filtered task list to show all active tasks sorted by due date */
void updateFilteredListToShowActiveSortedByDueDate();
@@ -60,4 +77,7 @@ public interface Model {
/** Removes an the given AliasSymbol. */
void removeAliasSymbol(AliasSymbol symbol) throws SymbolKeywordNotFoundException;
+
+ /** Gets the number of aliases */
+ int getAliasSymbolCount();
}
diff --git a/src/main/java/seedu/savvytasker/model/ModelManager.java b/src/main/java/seedu/savvytasker/model/ModelManager.java
index 98c5fbb87b84..1551a6608316 100644
--- a/src/main/java/seedu/savvytasker/model/ModelManager.java
+++ b/src/main/java/seedu/savvytasker/model/ModelManager.java
@@ -4,6 +4,7 @@
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.logging.Logger;
@@ -22,7 +23,6 @@
import seedu.savvytasker.model.task.FindType;
import seedu.savvytasker.model.task.ReadOnlyTask;
import seedu.savvytasker.model.task.Task;
-import seedu.savvytasker.model.task.TaskList.DuplicateTaskException;
import seedu.savvytasker.model.task.TaskList.InvalidDateException;
import seedu.savvytasker.model.task.TaskList.TaskNotFoundException;
@@ -50,7 +50,7 @@ public ModelManager(SavvyTasker src) {
savvyTasker = new SavvyTasker(src);
filteredTasks = new FilteredList<>(savvyTasker.getTasks());
- sortedAndFilteredTasks = new SortedList<>(filteredTasks, new TaskSortedByDefault());
+ sortedAndFilteredTasks = new SortedList<>(filteredTasks, new TaskSortedByDueDate());
updateFilteredListToShowActive(); // shows only active tasks on start
}
@@ -61,7 +61,7 @@ public ModelManager() {
public ModelManager(ReadOnlySavvyTasker initialData) {
savvyTasker = new SavvyTasker(initialData);
filteredTasks = new FilteredList<>(savvyTasker.getTasks());
- sortedAndFilteredTasks = new SortedList<>(filteredTasks, new TaskSortedByDefault());
+ sortedAndFilteredTasks = new SortedList<>(filteredTasks, new TaskSortedByDueDate());
updateFilteredListToShowActive(); // shows only active tasks on start
}
//@@author
@@ -95,23 +95,33 @@ private void indicateAliasSymbolRemoved(AliasSymbol symbol) {
//@@author A0139915W
@Override
- public synchronized void deleteTask(ReadOnlyTask target) throws TaskNotFoundException {
- savvyTasker.removeTask(target);
+ public synchronized Task deleteTask(ReadOnlyTask target) throws TaskNotFoundException {
+ Task taskDeleted = savvyTasker.removeTask(target);
indicateSavvyTaskerChanged();
+ return taskDeleted;
}
@Override
- public void modifyTask(ReadOnlyTask target, Task replacement) throws TaskNotFoundException, InvalidDateException {
- savvyTasker.replaceTask(target, replacement);
+ public synchronized Task modifyTask(ReadOnlyTask target, Task replacement) throws TaskNotFoundException, InvalidDateException {
+ Task taskModified = savvyTasker.replaceTask(target, replacement);
indicateSavvyTaskerChanged();
+ return taskModified;
}
@Override
- public synchronized void addTask(Task t) throws DuplicateTaskException, InvalidDateException {
- t.setId(savvyTasker.getNextTaskId());
- savvyTasker.addTask(t);
+ public synchronized Task addTask(Task t) throws InvalidDateException {
+ Task taskAdded = savvyTasker.addTask(t);
updateFilteredListToShowActive();
indicateSavvyTaskerChanged();
+ return taskAdded;
+ }
+
+ @Override
+ public synchronized LinkedList addRecurringTask(Task recurringTask) throws InvalidDateException {
+ LinkedList recurringTasks = savvyTasker.addRecurringTasks(recurringTask);
+ updateFilteredListToShowActive();
+ indicateSavvyTaskerChanged();
+ return recurringTasks;
}
//@@author
@@ -129,6 +139,11 @@ public synchronized void removeAliasSymbol(AliasSymbol symbol) throws SymbolKeyw
indicateSavvyTaskerChanged();
indicateAliasSymbolRemoved(symbol);
}
+
+ @Override
+ public int getAliasSymbolCount() {
+ return savvyTasker.getAliasSymbolCount();
+ }
//@@author
//=========== Filtered/Sorted Task List Accessors ===============================================================
@@ -138,11 +153,6 @@ public synchronized void removeAliasSymbol(AliasSymbol symbol) throws SymbolKeyw
public UnmodifiableObservableList getFilteredTaskList() {
return new UnmodifiableObservableList(sortedAndFilteredTasks);
}
-
- @Override
- public UnmodifiableObservableList getFilteredTaskListTask() {
- return new UnmodifiableObservableList(sortedAndFilteredTasks);
- }
@Override
public void updateFilteredListToShowActiveSortedByDueDate() {
@@ -464,18 +474,7 @@ public int compare(Task task1, Task task2) {
else if (task1 == null) return 1;
else if (task2 == null) return -1;
else {
- // Priority Level can be nulls
- // Check for existence of priorityLevel before comparing
- if (task1.getPriority() == null &&
- task2.getPriority() == null) {
- return 0;
- } else if (task1.getPriority() == null) {
- return 1;
- } else if (task2.getPriority() == null) {
- return -1;
- } else {
- return task2.getPriority().compareTo(task1.getPriority());
- }
+ return task2.getPriority().compareTo(task1.getPriority());
}
}
diff --git a/src/main/java/seedu/savvytasker/model/SavvyTasker.java b/src/main/java/seedu/savvytasker/model/SavvyTasker.java
index a58381cf4ab5..7b32afb8635f 100644
--- a/src/main/java/seedu/savvytasker/model/SavvyTasker.java
+++ b/src/main/java/seedu/savvytasker/model/SavvyTasker.java
@@ -1,7 +1,11 @@
package seedu.savvytasker.model;
+import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
@@ -12,6 +16,7 @@
import seedu.savvytasker.model.alias.DuplicateSymbolKeywordException;
import seedu.savvytasker.model.alias.SymbolKeywordNotFoundException;
import seedu.savvytasker.model.task.ReadOnlyTask;
+import seedu.savvytasker.model.task.RecurrenceType;
import seedu.savvytasker.model.task.Task;
import seedu.savvytasker.model.task.TaskList;
import seedu.savvytasker.model.task.TaskList.DuplicateTaskException;
@@ -67,40 +72,162 @@ public void resetData(ReadOnlySavvyTasker newData) {
//// symbol/task-level operations
//@@author A0139915W
+
/**
- * Returns the next available id for use to uniquely identify a task.
- * @author A0139915W
- * @return The next available id.
+ * Adds a task to savvy tasker.
+ * @throws {@link InvalidDateException} if the end date is earlier than the start date
+ * @return Returns the task added if the operation succeeds, an exception is thrown otherwise.
*/
- public int getNextTaskId() {
- return tasks.getNextId();
+ public Task addTask(Task t) throws InvalidDateException {
+ // guarantees unique ID
+ t.setId(tasks.getNextId());
+ try {
+ return tasks.add(t);
+ } catch (DuplicateTaskException e) {
+ // should never get here.
+ return null;
+ }
}
/**
- * Adds a task to savvy tasker.
- * @throws TaskList.DuplicateTaskException if an equivalent task already exists.
+ * Adds a group of recurring tasks to savvy tasker.
+ * @throws {@link InvalidDateException} if the end date is earlier than the start date
+ * @return Returns the list of recurring tasks if the operation succeeds, an exception is thrown otherwise
+ */
+ public LinkedList addRecurringTasks(Task recurringTask) throws InvalidDateException {
+ LinkedList tasksToAdd =
+ createRecurringTasks(recurringTask, recurringTask.getRecurringType(),
+ recurringTask.getNumberOfRecurrence());
+ Iterator itr = tasksToAdd.iterator();
+
+ while(itr.hasNext()) {
+ // this will be an atomic operation
+ // guaranteed no duplicates
+ // if the start/end dates are invalid,
+ // the first task to be added will fail immediately,
+ // subsequent tasks will not be added
+ try {
+ tasks.add(itr.next());
+ } catch (DuplicateTaskException e) {
+ // should never get here.
+ return null;
+ }
+ }
+ return tasksToAdd;
+ }
+
+ /**
+ * Creates a list of recurring tasks to be added into savvy tasker.
+ * @param recurringTask the task that recurs
+ * @param recurringType the type of recurrence
+ * @param numberOfRecurrences the number of recurrences
+ * @return A list of tasks that represents a recurring task.
*/
- public void addTask(Task t) throws DuplicateTaskException, InvalidDateException {
- tasks.add(t);
+ private LinkedList createRecurringTasks(Task recurringTask, RecurrenceType recurringType, int numberOfRecurrences) {
+ assert recurringTask.getRecurringType() != null;
+ assert recurringTask.getNumberOfRecurrence() > 0;
+
+ LinkedList listOfTasks = new LinkedList();
+ recurringTask.setGroupId(tasks.getNextGroupId());
+
+ for (int i = 0; i < numberOfRecurrences; ++i) {
+ Task t = recurringTask.clone();
+ // guarantees uniqueness
+ t.setId(tasks.getNextId());
+ listOfTasks.add(setDatesForRecurringType(t, recurringType, i));
+ }
+
+ return listOfTasks;
+ }
+
+ /**
+ * Helper function for createRecurringTasks(). Sets the respective start/end datetime for the
+ * i-th recurring task to be added
+ * @param t The first recurring task
+ * @param recurringType the type of recurrence
+ * @param index the index of the loop
+ * @return A task with its respective datetime set.
+ */
+ private Task setDatesForRecurringType(Task t, RecurrenceType recurringType, int index) {
+ Date startDate = t.getStartDateTime();
+ Date endDate = t.getEndDateTime();
+ Calendar calendar = Calendar.getInstance();
+ switch (recurringType) {
+ case Daily: // add one day to the i-th task
+ if (startDate != null) {
+ calendar.setTime(startDate);
+ calendar.add(Calendar.DATE, 1 * index);
+ startDate = calendar.getTime();
+ }
+ if (endDate != null) {
+ calendar.setTime(endDate);
+ calendar.add(Calendar.DATE, 1 * index);
+ endDate = calendar.getTime();
+ }
+ break;
+ case Weekly: // add 7 days to the i-th task
+ if (startDate != null) {
+ calendar.setTime(startDate);
+ calendar.add(Calendar.DATE, 7 * index);
+ startDate = calendar.getTime();
+ }
+ if (endDate != null) {
+ calendar.setTime(endDate);
+ calendar.add(Calendar.DATE, 7 * index);
+ endDate = calendar.getTime();
+ }
+ break;
+ case Monthly: // add 1 month to the i-th task
+ if (startDate != null) {
+ calendar.setTime(startDate);
+ calendar.add(Calendar.MONTH, 1 * index);
+ startDate = calendar.getTime();
+ }
+ if (endDate != null) {
+ calendar.setTime(endDate);
+ calendar.add(Calendar.MONTH, 1 * index);
+ endDate = calendar.getTime();
+ }
+ break;
+ case Yearly: // add 1 year to the i-th task
+ if (startDate != null) {
+ calendar.setTime(startDate);
+ calendar.add(Calendar.YEAR, 1 * index);
+ startDate = calendar.getTime();
+ }
+ if (endDate != null) {
+ calendar.setTime(endDate);
+ calendar.add(Calendar.YEAR, 1 * index);
+ endDate = calendar.getTime();
+ }
+ break;
+ case None:
+ default:
+ assert false; // should not come here
+ }
+ t.setStartDateTime(startDate);
+ t.setEndDateTime(endDate);
+ return t;
}
/**
* Removes a task from savvy tasker.
* @param key the task to be removed
- * @return true if the task is removed successfully
- * @throws TaskNotFoundException if the task to be removed does not exist
+ * @throws {@link TaskNotFoundException} if the task does not exist
+ * @return Returns a Task if the remove operation is successful, an exception is thrown otherwise.
*/
- public boolean removeTask(ReadOnlyTask key) throws TaskNotFoundException {
+ public Task removeTask(ReadOnlyTask key) throws TaskNotFoundException {
return tasks.remove(key);
}
/**
* Replaces a task from savvy tasker.
* @param key the task to be replaced
+ * @throws {@link TaskNotFoundException} if the task does not exist
+ * @throws {@link InvalidDateException} if the end date is earlier than the start date
* @return true if the task is removed successfully
- * @throws TaskNotFoundException if the task to be removed does not exist
*/
- public boolean replaceTask(ReadOnlyTask key, Task replacement) throws TaskNotFoundException, InvalidDateException {
+ public Task replaceTask(ReadOnlyTask key, Task replacement) throws TaskNotFoundException, InvalidDateException {
return tasks.replace(key, replacement);
}
//@@author
@@ -125,6 +252,10 @@ public void removeAliasSymbol(AliasSymbol symbol) throws SymbolKeywordNotFoundEx
}
//@@author
+ public int getAliasSymbolCount() {
+ return symbols.size();
+ }
+
//// util methods
@Override
diff --git a/src/main/java/seedu/savvytasker/model/alias/AliasSymbol.java b/src/main/java/seedu/savvytasker/model/alias/AliasSymbol.java
index afd67350f3b1..52fbaddfc592 100644
--- a/src/main/java/seedu/savvytasker/model/alias/AliasSymbol.java
+++ b/src/main/java/seedu/savvytasker/model/alias/AliasSymbol.java
@@ -24,7 +24,7 @@ public AliasSymbol(String keyword, String representation) {
assert keyword != null && !keyword.matches(".*\\s+.*");
assert representation != null && !representation.isEmpty();
- this.keyword = keyword;
+ this.keyword = keyword.toLowerCase();
this.representation = representation;
}
diff --git a/src/main/java/seedu/savvytasker/model/task/ReadOnlyTask.java b/src/main/java/seedu/savvytasker/model/task/ReadOnlyTask.java
index 7b0c9d7b3444..9b4df673008c 100644
--- a/src/main/java/seedu/savvytasker/model/task/ReadOnlyTask.java
+++ b/src/main/java/seedu/savvytasker/model/task/ReadOnlyTask.java
@@ -10,6 +10,7 @@
public interface ReadOnlyTask {
int getId();
+ int getGroupId();
boolean isMarked();
boolean isArchived();
String getTaskName();
@@ -39,23 +40,68 @@ default String getAsText() {
.append(" Task Name: ")
.append(getTaskName())
.append(" Archived: ")
- .append(isArchived())
- .append(" Start: ")
- .append(getStartDateTime())
- .append(" End: ")
- .append(getEndDateTime())
- .append(" Location: ")
- .append(getLocation())
- .append(" Priority: ")
+ .append(isArchived());
+ if (getStartDateTime() != null) {
+ builder.append(" Start: ")
+ .append(getStartDateTime());
+ }
+ if (getEndDateTime() != null) {
+ builder.append(" End: ")
+ .append(getEndDateTime());
+ }
+ if (getLocation() != null && !getLocation().isEmpty()) {
+ builder.append(" Location: ")
+ .append(getLocation());
+ }
+ builder.append(" Priority: ")
+ .append(getPriority());
+ if (getCategory() != null && !getCategory().isEmpty()) {
+ builder.append(" Category: ")
+ .append(getCategory());
+ }
+ if (getDescription() != null && !getDescription().isEmpty()) {
+ builder.append(" Description: ")
+ . append(getDescription());
+ }
+ return builder.toString();
+ }
+
+
+ /**
+ * Formats the task as text, showing all task details, formatted for the UI.
+ */
+ 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())
+ .append("\n");
+ }
+ if (getLocation() != null && !getLocation().isEmpty()) {
+ builder.append(" Location: ")
+ .append(getLocation())
+ .append("\n");
+ }
+ builder.append(" Priority: ")
.append(getPriority())
- .append(" Recurring Type: ")
- .append(getRecurringType())
- .append(" Nr. Recurrence: ")
- .append(getNumberOfRecurrence())
- .append(" Category: ")
- .append(getCategory())
- .append(" Description: ")
- .append(getDescription());
+ .append("\n");
+ if (getCategory() != null && !getCategory().isEmpty()) {
+ builder.append(" Category: ")
+ .append(getCategory())
+ .append("\n");
+ }
+ if (getDescription() != null && !getDescription().isEmpty()) {
+ builder.append(" Description: ")
+ .append(getDescription())
+ .append("\n");
+ }
+ builder.append(" Archived: ")
+ .append(isArchived());
return builder.toString();
}
diff --git a/src/main/java/seedu/savvytasker/model/task/Task.java b/src/main/java/seedu/savvytasker/model/task/Task.java
index e70d8763336c..593822c9bf31 100644
--- a/src/main/java/seedu/savvytasker/model/task/Task.java
+++ b/src/main/java/seedu/savvytasker/model/task/Task.java
@@ -13,6 +13,7 @@
public class Task implements ReadOnlyTask {
private int id;
+ private int groupId;
private String taskName;
private Date startDateTime;
private Date endDateTime;
@@ -27,12 +28,13 @@ public class Task implements ReadOnlyTask {
/**
* Constructor with smart defaults
*/
- public Task(int id, String taskName, InferredDate startDateTime, InferredDate endDateTime, String location,
+ public Task(int id, int groupId, String taskName, InferredDate startDateTime, InferredDate endDateTime, String location,
PriorityLevel priority, RecurrenceType recurringType, Integer numberOfRecurrence,
String category, String description, boolean isArchived) {
SmartDefaultDates sdd = new SmartDefaultDates(startDateTime, endDateTime);
this.id = id;
+ this.groupId = groupId;
this.taskName = taskName;
this.startDateTime = sdd.getStartDate();
this.endDateTime = sdd.getEndDate();
@@ -48,7 +50,7 @@ public Task(int id, String taskName, InferredDate startDateTime, InferredDate en
this.recurringType = recurringType;
}
if (numberOfRecurrence == null) {
- this.numberOfRecurrence = 0;
+ this.numberOfRecurrence = 1;
} else {
this.numberOfRecurrence = numberOfRecurrence.intValue();
}
@@ -60,11 +62,12 @@ public Task(int id, String taskName, InferredDate startDateTime, InferredDate en
/**
* Constructor without smart defaults
*/
- public Task(int id, String taskName, Date startDateTime, Date endDateTime, String location,
+ public Task(int id, int groupId, String taskName, Date startDateTime, Date endDateTime, String location,
PriorityLevel priority, RecurrenceType recurringType, Integer numberOfRecurrence,
String category, String description, boolean isArchived) {
this.id = id;
+ this.groupId = groupId;
this.taskName = taskName;
this.startDateTime = startDateTime;
this.endDateTime = endDateTime;
@@ -80,7 +83,7 @@ public Task(int id, String taskName, Date startDateTime, Date endDateTime, Strin
this.recurringType = recurringType;
}
if (numberOfRecurrence == null) {
- this.numberOfRecurrence = 0;
+ this.numberOfRecurrence = 1;
} else {
this.numberOfRecurrence = numberOfRecurrence.intValue();
}
@@ -93,15 +96,13 @@ public Task(String taskName) {
this.taskName = taskName;
// sets initial default values
this.priority = PriorityLevel.Medium;
- this.recurringType = RecurrenceType.None;
- this.numberOfRecurrence = 0;
}
/**
* Copy constructor.
*/
public Task(ReadOnlyTask source) {
- this(source.getId(), source.getTaskName(), source.getStartDateTime(),
+ this(source.getId(), source.getGroupId(), source.getTaskName(), source.getStartDateTime(),
source.getEndDateTime(), source.getLocation(), source.getPriority(),
source.getRecurringType(), source.getNumberOfRecurrence(),
source.getCategory(), source.getDescription(), source.isArchived());
@@ -113,12 +114,13 @@ public Task(ReadOnlyTask source) {
public Task(ReadOnlyTask source, String taskName, InferredDate startDateTime, InferredDate endDateTime, String location,
PriorityLevel priority, RecurrenceType recurringType, Integer numberOfRecurrence, String category,
String description) {
- this(source.getId(), source.getTaskName(), source.getStartDateTime(),
+ this(source.getId(), source.getGroupId(), source.getTaskName(), source.getStartDateTime(),
source.getEndDateTime(), source.getLocation(), source.getPriority(),
source.getRecurringType(), source.getNumberOfRecurrence(),
source.getCategory(), source.getDescription(), source.isArchived());
//this.id should follow that of the source.
+ //this.groupId should follow that of the source.
//this.isArchived should follow that of the source.
this.taskName = taskName == null ? this.taskName : taskName;
setStartDate(startDateTime);
@@ -172,6 +174,11 @@ public int getId() {
return this.id;
}
+ @Override
+ public int getGroupId() {
+ return this.groupId;
+ }
+
@Override
public boolean isMarked() {
return isArchived(); // all marked tasks are archived
@@ -231,6 +238,10 @@ public void setId(int id) {
this.id = id;
}
+ public void setGroupId(int groupId) {
+ this.groupId = groupId;
+ }
+
public void setTaskName(String taskName) {
this.taskName = taskName;
}
@@ -309,6 +320,17 @@ public int hashCode() {
public String toString() {
return getAsText();
}
+
+ /**
+ * Creates a deep copy of this object.
+ */
+ public Task clone() {
+ Task t = new Task(id, groupId, taskName,
+ (Date)startDateTime.clone(), (Date)endDateTime.clone(),
+ location, priority, recurringType, numberOfRecurrence,
+ category, description, isArchived);
+ return t;
+ }
}
//@@author
diff --git a/src/main/java/seedu/savvytasker/model/task/TaskList.java b/src/main/java/seedu/savvytasker/model/task/TaskList.java
index e56a2a0e2502..6c68eab70ae7 100644
--- a/src/main/java/seedu/savvytasker/model/task/TaskList.java
+++ b/src/main/java/seedu/savvytasker/model/task/TaskList.java
@@ -1,7 +1,6 @@
package seedu.savvytasker.model.task;
import java.util.Iterator;
-import java.util.LinkedList;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
@@ -63,6 +62,8 @@ public static class TaskNotFoundException extends Exception {
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.
@@ -76,10 +77,8 @@ public TaskList() {}
*/
public int getNextId() {
if (!isNextIdInitialized) {
- int nextLowest = -1; // first id to be used is 0. Start finding with -1
- LinkedList usedIds = new LinkedList();
+ int nextLowest = 0; // first id to be used is 1. Start finding with 0
for (Task t : internalList) {
- usedIds.add(t.getId());
if (t.getId() > nextLowest) {
nextLowest = t.getId();
}
@@ -93,6 +92,29 @@ public int getNextId() {
nextId++;
return nextId;
}
+
+ /**
+ * Gets the next available group id for uniquely identifying a group of recurring tasks in
+ * Savvy Tasker.
+ * @return The next available group id;
+ */
+ public int getNextGroupId() {
+ if (!isNextGroupIdInitialized) {
+ int nextLowest = 0; // first id to be used is 1. Start finding with 0
+ for (Task t : internalList) {
+ if (t.getId() > nextLowest) {
+ nextLowest = t.getGroupId();
+ }
+ }
+ // assumption that the number of tasks < 2^31
+ // implementation will be buggy if nextId exceeds 2^31
+ nextGroupId = nextLowest;
+ assert nextGroupId < Integer.MAX_VALUE;
+ isNextGroupIdInitialized = true;
+ }
+ nextGroupId++;
+ return nextGroupId;
+ }
/**
* Returns true if the list contains an equivalent task as the given argument.
@@ -116,10 +138,11 @@ public boolean isValidStartEnd(ReadOnlyTask toCheck) {
/**
* Adds a task to the list.
- *
- * @throws DuplicateTaskException if the person to add is a duplicate of an existing task in the list.
+ * @throws {@link DuplicateTaskException} if a duplicate is found
+ * @throws {@link InvalidDateException} if the end date is earlier than the start date
+ * @return Returns the Task added if the add is successful, an exception is thrown otherwise.
*/
- public void add(Task toAdd) throws DuplicateTaskException, InvalidDateException {
+ public Task add(Task toAdd) throws DuplicateTaskException, InvalidDateException {
assert toAdd != null;
if (contains(toAdd)) {
throw new DuplicateTaskException();
@@ -128,28 +151,36 @@ public void add(Task toAdd) throws DuplicateTaskException, InvalidDateException
throw new InvalidDateException();
}
internalList.add(toAdd);
+ return toAdd;
}
/**
* Removes the equivalent task from the list.
- *
- * @throws TaskNotFoundException if no such task could be found in the list.
+ * @throws {@link TaskNotFoundException} if the task does not exist
+ * @return Returns a Task if the delete operation is successful, an exception is thrown otherwise.
*/
- public boolean remove(ReadOnlyTask toRemove) throws TaskNotFoundException {
+ public Task remove(ReadOnlyTask toRemove) throws TaskNotFoundException {
assert toRemove != null;
- final boolean taskFoundAndDeleted = internalList.remove(toRemove);
- if (!taskFoundAndDeleted) {
+ int index = internalList.indexOf(toRemove);
+ if (index >= 0) {
+ final Task taskToDelete = internalList.get(index);
+ final boolean taskFoundAndDeleted = internalList.remove(toRemove);
+ if (!taskFoundAndDeleted) {
+ throw new TaskNotFoundException();
+ }
+ return taskToDelete;
+ } else {
throw new TaskNotFoundException();
}
- return taskFoundAndDeleted;
}
/**
* Replaces the equivalent task from the list.
- *
- * @throws TaskNotFoundException if no such task could be found in the list.
+ * @throws {@link TaskNotFoundException} if the task does not exist
+ * @throws {@link InvalidDateException} if the end date is earlier than the start date
+ * @return Returns the Task replaced if the replace is successful, an exception is thrown otherwise.
*/
- public boolean replace(ReadOnlyTask toReplace, Task replacement) throws TaskNotFoundException, InvalidDateException {
+ public Task replace(ReadOnlyTask toReplace, Task replacement) throws TaskNotFoundException, InvalidDateException {
assert toReplace != null;
assert replacement != null;
if (internalList.contains(toReplace)) {
@@ -157,7 +188,7 @@ public boolean replace(ReadOnlyTask toReplace, Task replacement) throws TaskNotF
throw new InvalidDateException();
}
internalList.set(internalList.indexOf(toReplace), replacement);
- return true;
+ return replacement;
}
else {
throw new TaskNotFoundException();
diff --git a/src/main/java/seedu/savvytasker/storage/SavvyTaskerStorage.java b/src/main/java/seedu/savvytasker/storage/SavvyTaskerStorage.java
index 2346201925f4..60a25ac03ea6 100644
--- a/src/main/java/seedu/savvytasker/storage/SavvyTaskerStorage.java
+++ b/src/main/java/seedu/savvytasker/storage/SavvyTaskerStorage.java
@@ -16,6 +16,13 @@ public interface SavvyTaskerStorage {
*/
String getSavvyTaskerFilePath();
+ //@@author A0139915W
+ /**
+ * Sets the file path of the data file. Returns true if successful, false otherwise
+ */
+ boolean setSavvyTaskerFilePath(String path);
+ //@@author
+
/**
* Returns SavvyTasker data as a {@link ReadOnlySavvyTasker}.
* Returns {@code Optional.empty()} if storage file is not found.
diff --git a/src/main/java/seedu/savvytasker/storage/Storage.java b/src/main/java/seedu/savvytasker/storage/Storage.java
index b52ea243a253..4ccbb1b5e76a 100644
--- a/src/main/java/seedu/savvytasker/storage/Storage.java
+++ b/src/main/java/seedu/savvytasker/storage/Storage.java
@@ -5,6 +5,7 @@
import seedu.savvytasker.commons.events.model.SavvyTaskerChangedEvent;
import seedu.savvytasker.commons.events.storage.DataSavingExceptionEvent;
+import seedu.savvytasker.commons.events.storage.DataSavingLocationChangedEvent;
import seedu.savvytasker.commons.exceptions.DataConversionException;
import seedu.savvytasker.model.ReadOnlySavvyTasker;
import seedu.savvytasker.model.UserPrefs;
@@ -22,15 +23,25 @@ public interface Storage extends SavvyTaskerStorage, UserPrefsStorage {
@Override
String getSavvyTaskerFilePath();
+
+ @Override
+ boolean setSavvyTaskerFilePath(String path);
@Override
Optional readSavvyTasker() throws DataConversionException, IOException;
@Override
void saveSavvyTasker(ReadOnlySavvyTasker savvyTasker) throws IOException;
+
+ /**
+ * Changes the storage location as requested
+ * Creates the data file at the new location.
+ * Raises {@link DataSavingExceptionEvent} if there was an error during saving.
+ */
+ void handleSavvyTaskerSaveLocationChangedEvent(DataSavingLocationChangedEvent dslce);
/**
- * Saves the current version of the Address Book to the hard disk.
+ * Saves the current version of the Savvy Tasker to the hard disk.
* Creates the data file if it is missing.
* Raises {@link DataSavingExceptionEvent} if there was an error during saving.
*/
diff --git a/src/main/java/seedu/savvytasker/storage/StorageManager.java b/src/main/java/seedu/savvytasker/storage/StorageManager.java
index 5117af6e555e..a9d463a690b4 100644
--- a/src/main/java/seedu/savvytasker/storage/StorageManager.java
+++ b/src/main/java/seedu/savvytasker/storage/StorageManager.java
@@ -10,6 +10,7 @@
import seedu.savvytasker.commons.core.LogsCenter;
import seedu.savvytasker.commons.events.model.SavvyTaskerChangedEvent;
import seedu.savvytasker.commons.events.storage.DataSavingExceptionEvent;
+import seedu.savvytasker.commons.events.storage.DataSavingLocationChangedEvent;
import seedu.savvytasker.commons.exceptions.DataConversionException;
import seedu.savvytasker.model.ReadOnlySavvyTasker;
import seedu.savvytasker.model.UserPrefs;
@@ -47,13 +48,20 @@ public void saveUserPrefs(UserPrefs userPrefs) throws IOException {
}
- // ================ AddressBook methods ==============================
+ // ================ SavvyTasker methods ==============================
@Override
public String getSavvyTaskerFilePath() {
return savvyTaskerStorage.getSavvyTaskerFilePath();
}
+ //@@author A0139915W
+ @Override
+ public boolean setSavvyTaskerFilePath(String path) {
+ return savvyTaskerStorage.setSavvyTaskerFilePath(path);
+ }
+ //@@author
+
@Override
public Optional readSavvyTasker() throws DataConversionException, IOException {
return readSavvyTasker(savvyTaskerStorage.getSavvyTaskerFilePath());
@@ -76,6 +84,18 @@ public void saveSavvyTasker(ReadOnlySavvyTasker savvyTasker, String filePath) th
savvyTaskerStorage.saveSavvyTasker(savvyTasker, filePath);
}
+ //@@author A0139915W
+ @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));
+ }
+ }
+ //@@author
@Override
@Subscribe
diff --git a/src/main/java/seedu/savvytasker/storage/XmlAdaptedTask.java b/src/main/java/seedu/savvytasker/storage/XmlAdaptedTask.java
index 2598075ab531..7df5aab8cf31 100644
--- a/src/main/java/seedu/savvytasker/storage/XmlAdaptedTask.java
+++ b/src/main/java/seedu/savvytasker/storage/XmlAdaptedTask.java
@@ -7,7 +7,6 @@
import seedu.savvytasker.commons.exceptions.IllegalValueException;
import seedu.savvytasker.model.task.PriorityLevel;
import seedu.savvytasker.model.task.ReadOnlyTask;
-import seedu.savvytasker.model.task.RecurrenceType;
import seedu.savvytasker.model.task.Task;
//@@author A0139915W
@@ -18,6 +17,8 @@ public class XmlAdaptedTask {
@XmlElement(required = true)
private int id;
+ @XmlElement(required = false)
+ private int groupId;
@XmlElement(required = true)
private String taskName;
@XmlElement(required = false)
@@ -29,10 +30,6 @@ public class XmlAdaptedTask {
@XmlElement(required = false)
private PriorityLevel priority;
@XmlElement(required = false)
- private RecurrenceType recurringType;
- @XmlElement(required = false)
- private int numberOfRecurrence;
- @XmlElement(required = false)
private String category;
@XmlElement(required = false)
private String description;
@@ -52,13 +49,12 @@ public XmlAdaptedTask() {}
*/
public XmlAdaptedTask(ReadOnlyTask source) {
id = source.getId();
+ groupId = source.getGroupId();
taskName = source.getTaskName();
startDateTime = source.getStartDateTime();
endDateTime = source.getEndDateTime();
location = source.getLocation();
priority = source.getPriority();
- recurringType = source.getRecurringType();
- numberOfRecurrence = source.getNumberOfRecurrence();
category = source.getCategory();
description = source.getDescription();
isArchived = source.isArchived();
@@ -76,13 +72,11 @@ public Task toModelType() throws IllegalValueException {
final Date endDateTime = this.endDateTime;
final String location = this.location;
final PriorityLevel priority = this.priority;
- final RecurrenceType recurringType = this.recurringType;
- final int numberOfRecurrence = this.numberOfRecurrence;
final String category = this.category;
final String description = this.description;
final boolean isArchived = this.isArchived;
- return new Task(id, taskName, startDateTime, endDateTime, location, priority,
- recurringType, numberOfRecurrence, category, description, isArchived);
+ return new Task(id, groupId, taskName, startDateTime, endDateTime, location, priority,
+ null, null, category, description, isArchived);
}
}
//@@author
diff --git a/src/main/java/seedu/savvytasker/storage/XmlSavvyTaskerStorage.java b/src/main/java/seedu/savvytasker/storage/XmlSavvyTaskerStorage.java
index 2afdb822eb47..29092ceb7cc6 100644
--- a/src/main/java/seedu/savvytasker/storage/XmlSavvyTaskerStorage.java
+++ b/src/main/java/seedu/savvytasker/storage/XmlSavvyTaskerStorage.java
@@ -29,6 +29,27 @@ public String getSavvyTaskerFilePath() {
return filePath;
}
+ //@@author A0139915W
+ @Override
+ /**
+ * Changes the path of the storage location if the file at newPath can be successfully created.
+ */
+ public boolean setSavvyTaskerFilePath(String newPath) {
+ try {
+ File file = new File(newPath);
+ if (FileUtil.createIfMissing(file)) {
+ this.filePath = newPath;
+ return true;
+ } else {
+ return false;
+ }
+ } catch (IOException e) {
+ // do nothing, can't set the path to new path
+ }
+ return false;
+ }
+ //@@author
+
/**
* Similar to {@link #readSavvyTasker()}
* @param filePath location of the data. Cannot be null
diff --git a/src/main/java/seedu/savvytasker/ui/AliasSymbolCard.java b/src/main/java/seedu/savvytasker/ui/AliasSymbolCard.java
new file mode 100644
index 000000000000..32d272f2be63
--- /dev/null
+++ b/src/main/java/seedu/savvytasker/ui/AliasSymbolCard.java
@@ -0,0 +1,56 @@
+package seedu.savvytasker.ui;
+
+import javafx.fxml.FXML;
+import javafx.scene.Node;
+import javafx.scene.control.Label;
+import javafx.scene.layout.HBox;
+import seedu.savvytasker.model.alias.AliasSymbol;
+
+public class AliasSymbolCard extends UiPart{
+
+ private static final String FXML = "AliasSymbolListCard.fxml";
+
+ @FXML
+ private HBox cardPane;
+ @FXML
+ private Label aliasName;
+ @FXML
+ private Label id;
+ @FXML
+ private Label details;
+
+ private AliasSymbol symbol;
+ private int displayedIndex;
+
+ public AliasSymbolCard(){
+
+ }
+
+ public static AliasSymbolCard load(AliasSymbol symbol, int displayedIndex){
+ AliasSymbolCard card = new AliasSymbolCard();
+ card.symbol = symbol;
+ card.displayedIndex = displayedIndex;
+ return UiPartLoader.loadUiPart(card);
+ }
+
+ @FXML
+ public void initialize() {
+ aliasName.setText(symbol.getKeyword());
+ id.setText(displayedIndex + ". ");
+ details.setText(symbol.getRepresentation());
+ }
+
+ public HBox getLayout() {
+ return cardPane;
+ }
+
+ @Override
+ public void setNode(Node node) {
+ cardPane = (HBox)node;
+ }
+
+ @Override
+ public String getFxmlPath() {
+ return FXML;
+ }
+}
diff --git a/src/main/java/seedu/savvytasker/ui/AliasSymbolListPanel.java b/src/main/java/seedu/savvytasker/ui/AliasSymbolListPanel.java
new file mode 100644
index 000000000000..001aa10b1c50
--- /dev/null
+++ b/src/main/java/seedu/savvytasker/ui/AliasSymbolListPanel.java
@@ -0,0 +1,111 @@
+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.model.alias.AliasSymbol;
+
+/**
+ * Panel containing the list of persons.
+ */
+public class AliasSymbolListPanel extends UiPart {
+ private final Logger logger = LogsCenter.getLogger(AliasSymbolListPanel.class);
+ private static final String FXML = "AliasSymbolListPanel.fxml";
+ private VBox panel;
+ private AnchorPane placeHolderPane;
+
+ @FXML
+ private ListView aliasSymbolListView;
+
+ public AliasSymbolListPanel() {
+ super();
+ }
+
+ @Override
+ public void setNode(Node node) {
+ panel = (VBox) node;
+ }
+
+ public Node getNode() {
+ return panel;
+ }
+
+ @Override
+ public String getFxmlPath() {
+ return FXML;
+ }
+
+ @Override
+ public void setPlaceholder(AnchorPane pane) {
+ this.placeHolderPane = pane;
+ }
+
+ public static AliasSymbolListPanel load(Stage primaryStage, AnchorPane aliasSymbolListPlaceholder,
+ ObservableList aliasList) {
+ AliasSymbolListPanel aliasListPanel =
+ UiPartLoader.loadUiPart(primaryStage, aliasSymbolListPlaceholder, new AliasSymbolListPanel());
+ aliasListPanel.configure(aliasList);
+ return aliasListPanel;
+ }
+
+ private void configure(ObservableList aliasList) {
+ setConnections(aliasList);
+ addToPlaceholder();
+ }
+
+ private void setConnections(ObservableList aliasList) {
+ aliasSymbolListView.setItems(aliasList);
+ aliasSymbolListView.setCellFactory(listView -> new AliasSymbolListViewCell());
+ setEventHandlerForSelectionChangeEvent();
+ }
+
+ private void addToPlaceholder() {
+ SplitPane.setResizableWithParent(placeHolderPane, false);
+ placeHolderPane.getChildren().add(panel);
+ }
+
+ private void setEventHandlerForSelectionChangeEvent() {
+ aliasSymbolListView.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
+ if (newValue != null) {
+ logger.fine("Selection in alias list panel changed to : '" + newValue + "'");
+ //raise(new TaskPanelSelectionChangedEvent(newValue));
+ }
+ });
+ }
+
+ public void scrollTo(int index) {
+ Platform.runLater(() -> {
+ aliasSymbolListView.scrollTo(index);
+ aliasSymbolListView.getSelectionModel().clearAndSelect(index);
+ });
+ }
+
+ class AliasSymbolListViewCell extends ListCell {
+
+ public AliasSymbolListViewCell() {
+ }
+
+ @Override
+ protected void updateItem(AliasSymbol symbol, boolean empty) {
+ super.updateItem(symbol, empty);
+
+ if (empty || symbol == null) {
+ setGraphic(null);
+ setText(null);
+ } else {
+ setGraphic(AliasSymbolCard.load(symbol, getIndex() + 1).getLayout());
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/seedu/savvytasker/ui/MainWindow.java b/src/main/java/seedu/savvytasker/ui/MainWindow.java
index 426f6a7e0bf5..1974651a4ecc 100644
--- a/src/main/java/seedu/savvytasker/ui/MainWindow.java
+++ b/src/main/java/seedu/savvytasker/ui/MainWindow.java
@@ -31,6 +31,7 @@ public class MainWindow extends UiPart {
// 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;
@@ -53,13 +54,19 @@ public class MainWindow extends UiPart {
private MenuItem helpMenuItem;
@FXML
- private AnchorPane personListPanelPlaceholder;
+ private AnchorPane taskListPanelPlaceholder;
+
+ @FXML
+ private AnchorPane aliasSymbolListPanelPlaceholder;
@FXML
private AnchorPane resultDisplayPlaceholder;
@FXML
private AnchorPane statusbarPlaceholder;
+
+ @FXML
+ private VBox listPanel;
public MainWindow() {
@@ -79,7 +86,7 @@ public String getFxmlPath() {
public static MainWindow load(Stage primaryStage, Config config, UserPrefs prefs, Logic logic) {
MainWindow mainWindow = UiPartLoader.loadUiPart(primaryStage, new MainWindow());
- mainWindow.configure(config.getAppTitle(), config.getAddressBookName(), config, prefs, logic);
+ mainWindow.configure(config.getAppTitle(), config.getSavvyTaskerListName(), config, prefs, logic);
return mainWindow;
}
@@ -109,11 +116,41 @@ private void setAccelerators() {
void fillInnerParts() {
browserPanel = BrowserPanel.load(browserPlaceholder);
- taskListPanel = TaskListPanel.load(primaryStage, getPersonListPlaceholder(), logic.getFilteredTaskList());
+ 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.getAddressBookFilePath());
+ statusBarFooter = StatusBarFooter.load(primaryStage, getStatusbarPlaceholder(), config.getSavvyTaskerFilePath());
commandBox = CommandBox.load(primaryStage, getCommandBoxPlaceholder(), resultDisplay, logic);
}
+
+ /**
+ * 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 AnchorPane getCommandBoxPlaceholder() {
return commandBoxPlaceholder;
@@ -127,8 +164,12 @@ private AnchorPane getResultDisplayPlaceholder() {
return resultDisplayPlaceholder;
}
- public AnchorPane getPersonListPlaceholder() {
- return personListPanelPlaceholder;
+ public AnchorPane getTaskListPlaceholder() {
+ return taskListPanelPlaceholder;
+ }
+
+ public AnchorPane getAliasSymbolPlaceholder() {
+ return aliasSymbolListPanelPlaceholder;
}
public void hide() {
@@ -181,8 +222,12 @@ public void show() {
private void handleExit() {
raise(new ExitAppRequestEvent());
}
+
+ public AliasSymbolListPanel getAliasSymbolListPanel() {
+ return this.aliasSymbolListPanel;
+ }
- public TaskListPanel getPersonListPanel() {
+ public TaskListPanel getTaskListPanel() {
return this.taskListPanel;
}
diff --git a/src/main/java/seedu/savvytasker/ui/StatusBarFooter.java b/src/main/java/seedu/savvytasker/ui/StatusBarFooter.java
index 4d927f84f101..482171f30520 100644
--- a/src/main/java/seedu/savvytasker/ui/StatusBarFooter.java
+++ b/src/main/java/seedu/savvytasker/ui/StatusBarFooter.java
@@ -14,6 +14,7 @@
import javafx.stage.Stage;
import seedu.savvytasker.commons.core.LogsCenter;
import seedu.savvytasker.commons.events.model.SavvyTaskerChangedEvent;
+import seedu.savvytasker.commons.events.storage.DataSavingLocationChangedEvent;
import seedu.savvytasker.commons.util.FxViewUtil;
/**
@@ -47,7 +48,7 @@ public void configure(String saveLocation) {
addSyncStatus();
setSyncStatus("Not updated yet in this session");
addSaveLocation();
- setSaveLocation("./" + saveLocation);
+ setSaveLocation(saveLocation);
registerAsAnEventHandler(this);
}
@@ -91,8 +92,15 @@ public String getFxmlPath() {
return FXML;
}
+ //@@author A0139915W
@Subscribe
- public void handleAddressBookChangedEvent(SavvyTaskerChangedEvent stce) {
+ public void handleSavvyTaskerSaveLocationChangedEvent(DataSavingLocationChangedEvent dslce) {
+ setSaveLocation(dslce.newPath);
+ }
+ //@@author
+
+ @Subscribe
+ public void handleSavvyTaskerChangedEvent(SavvyTaskerChangedEvent stce) {
String lastUpdated = (new Date()).toString();
logger.info(LogsCenter.getEventHandlingLogMessage(stce, "Setting last updated status to " + lastUpdated));
setSyncStatus("Last Updated: " + lastUpdated);
diff --git a/src/main/java/seedu/savvytasker/ui/TaskCard.java b/src/main/java/seedu/savvytasker/ui/TaskCard.java
index b3cc0f963fce..5d3512c8b5de 100644
--- a/src/main/java/seedu/savvytasker/ui/TaskCard.java
+++ b/src/main/java/seedu/savvytasker/ui/TaskCard.java
@@ -1,7 +1,5 @@
package seedu.savvytasker.ui;
-import java.util.Date;
-
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.Label;
@@ -10,8 +8,7 @@
public class TaskCard extends UiPart{
- private static final String FXML = "PersonListCard.fxml";
- private static final String EMPTY_FIELD = " - ";
+ private static final String FXML = "TaskListCard.fxml";
@FXML
private HBox cardPane;
@@ -20,13 +17,7 @@ public class TaskCard extends UiPart{
@FXML
private Label id;
@FXML
- private Label startDate;
- @FXML
- private Label endDate;
- @FXML
- private Label description;
- @FXML
- private Label tags;
+ private Label details;
private ReadOnlyTask task;
private int displayedIndex;
@@ -45,25 +36,8 @@ public static TaskCard load(ReadOnlyTask task, int displayedIndex){
@FXML
public void initialize() {
taskName.setText(task.getTaskName());
- Date startDate = task.getStartDateTime();
- if (startDate != null) {
- this.startDate.setText(startDate.toString());
- } else {
- this.startDate.setText(EMPTY_FIELD);
- }
- Date endDate = task.getEndDateTime();
- if (endDate != null) {
- this.endDate.setText(endDate.toString());
- } else {
- this.endDate.setText(EMPTY_FIELD);
- }
- String description = task.getDescription();
- if (description != null) {
- this.description.setText(description);
- } else {
- this.description.setText(EMPTY_FIELD);
- }
id.setText(displayedIndex + ". ");
+ details.setText(task.getTextForUi());
}
public HBox getLayout() {
diff --git a/src/main/java/seedu/savvytasker/ui/TaskListPanel.java b/src/main/java/seedu/savvytasker/ui/TaskListPanel.java
index 9b10bf105c42..f90ea46f78fd 100644
--- a/src/main/java/seedu/savvytasker/ui/TaskListPanel.java
+++ b/src/main/java/seedu/savvytasker/ui/TaskListPanel.java
@@ -17,11 +17,11 @@
import seedu.savvytasker.model.task.ReadOnlyTask;
/**
- * Panel containing the list of persons.
+ * Panel containing the list of tasks.
*/
public class TaskListPanel extends UiPart {
private final Logger logger = LogsCenter.getLogger(TaskListPanel.class);
- private static final String FXML = "PersonListPanel.fxml";
+ private static final String FXML = "TaskListPanel.fxml";
private VBox panel;
private AnchorPane placeHolderPane;
@@ -36,6 +36,10 @@ public TaskListPanel() {
public void setNode(Node node) {
panel = (VBox) node;
}
+
+ public Node getNode() {
+ return panel;
+ }
@Override
public String getFxmlPath() {
@@ -74,7 +78,7 @@ private void addToPlaceholder() {
private void setEventHandlerForSelectionChangeEvent() {
taskListView.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
if (newValue != null) {
- logger.fine("Selection in person list panel changed to : '" + newValue + "'");
+ logger.fine("Selection in task list panel changed to : '" + newValue + "'");
raise(new TaskPanelSelectionChangedEvent(newValue));
}
});
diff --git a/src/main/java/seedu/savvytasker/ui/UiManager.java b/src/main/java/seedu/savvytasker/ui/UiManager.java
index cd41d3a82aa1..f5b5835b2868 100644
--- a/src/main/java/seedu/savvytasker/ui/UiManager.java
+++ b/src/main/java/seedu/savvytasker/ui/UiManager.java
@@ -14,6 +14,8 @@
import seedu.savvytasker.commons.core.Config;
import seedu.savvytasker.commons.core.LogsCenter;
import seedu.savvytasker.commons.events.storage.DataSavingExceptionEvent;
+import seedu.savvytasker.commons.events.ui.ChangeListRequestEvent;
+import seedu.savvytasker.commons.events.ui.ChangeListRequestEvent.DisplayedList;
import seedu.savvytasker.commons.events.ui.JumpToListRequestEvent;
import seedu.savvytasker.commons.events.ui.ShowHelpRequestEvent;
import seedu.savvytasker.commons.events.ui.TaskPanelSelectionChangedEvent;
@@ -112,10 +114,20 @@ private void handleShowHelpEvent(ShowHelpRequestEvent event) {
mainWindow.handleHelp();
}
+ @Subscribe
+ private void handleChangeListRequestEvent(ChangeListRequestEvent event) {
+ logger.info(LogsCenter.getEventHandlingLogMessage(event));
+ if (event.displayedList == DisplayedList.Task) {
+ mainWindow.showTaskList(true);
+ } else {
+ mainWindow.showTaskList(false);
+ }
+ }
+
@Subscribe
private void handleJumpToListRequestEvent(JumpToListRequestEvent event) {
logger.info(LogsCenter.getEventHandlingLogMessage(event));
- mainWindow.getPersonListPanel().scrollTo(event.targetIndex);
+ mainWindow.getTaskListPanel().scrollTo(event.targetIndex);
}
@Subscribe
diff --git a/src/main/resources/view/PersonListCard.fxml b/src/main/resources/view/AliasSymbolListCard.fxml
similarity index 74%
rename from src/main/resources/view/PersonListCard.fxml
rename to src/main/resources/view/AliasSymbolListCard.fxml
index 9953ce588beb..7f205ec4b5b1 100644
--- a/src/main/resources/view/PersonListCard.fxml
+++ b/src/main/resources/view/AliasSymbolListCard.fxml
@@ -12,7 +12,7 @@
-
+
@@ -26,14 +26,14 @@
-
+
+
+
-
-
-
+
diff --git a/src/main/resources/view/AliasSymbolListPanel.fxml b/src/main/resources/view/AliasSymbolListPanel.fxml
new file mode 100644
index 000000000000..9149a98c6ab4
--- /dev/null
+++ b/src/main/resources/view/AliasSymbolListPanel.fxml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/view/MainWindow.fxml b/src/main/resources/view/MainWindow.fxml
index 4eeb2d392bab..e2567ee9ad65 100644
--- a/src/main/resources/view/MainWindow.fxml
+++ b/src/main/resources/view/MainWindow.fxml
@@ -36,12 +36,13 @@
-
+
-
+
+
diff --git a/src/main/resources/view/TaskListCard.fxml b/src/main/resources/view/TaskListCard.fxml
new file mode 100644
index 000000000000..2df104257f29
--- /dev/null
+++ b/src/main/resources/view/TaskListCard.fxml
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/view/PersonListPanel.fxml b/src/main/resources/view/TaskListPanel.fxml
similarity index 100%
rename from src/main/resources/view/PersonListPanel.fxml
rename to src/main/resources/view/TaskListPanel.fxml
diff --git a/src/test/java/guitests/AddCommandTest.java b/src/test/java/guitests/AddCommandTest.java
index 41984bea99f6..becd062d5121 100644
--- a/src/test/java/guitests/AddCommandTest.java
+++ b/src/test/java/guitests/AddCommandTest.java
@@ -4,7 +4,7 @@
import org.junit.Test;
-import seedu.savvytasker.commons.core.Messages;
+import seedu.savvytasker.logic.commands.AddCommand;
import seedu.savvytasker.logic.commands.HelpCommand;
import seedu.savvytasker.testutil.TestTask;
import seedu.savvytasker.testutil.TestUtil;
@@ -12,6 +12,11 @@
import static org.junit.Assert.assertTrue;
import static seedu.savvytasker.commons.core.Messages.MESSAGE_UNKNOWN_COMMAND;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+
//@@author A0139915W
public class AddCommandTest extends SavvyTaskerGuiTest {
@@ -34,7 +39,15 @@ public void add() {
//invalid command
commandBox.runCommand("adds Bad Command Task");
- assertResultMessage(String.format(MESSAGE_UNKNOWN_COMMAND, HelpCommand.MESSAGE_USAGE));
+ assertResultMessage("Input: adds Bad Command Task\n" +
+ String.format(MESSAGE_UNKNOWN_COMMAND, HelpCommand.MESSAGE_USAGE));
+
+ //invalid start end date
+ Date start = getDate("31/12/2015");
+ Date end = getDate("30/12/2015");
+ commandBox.runCommand("add bad start-end pair s/" + getLocaleDateString(start) +
+ " e/" + getLocaleDateString(end));
+ assertResultMessage(String.format(AddCommand.MESSAGE_INVALID_START_END));
}
private void assertAddSuccess(TestTask taskToAdd, TestTask... currentList) {
@@ -44,10 +57,29 @@ private void assertAddSuccess(TestTask taskToAdd, TestTask... currentList) {
TaskCardHandle addedCard = taskListPanel.navigateToTask(taskToAdd.getTaskName());
assertMatching(taskToAdd, addedCard);
- //confirm the list now contains all previous persons plus the new person
+ //confirm the list now contains all previous tasks plus the new task
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);
+ } catch (Exception e) {
+ assert false; //should not get an invalid date....
+ }
+ return null;
+ }
+
+ private SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy");
+ private Date getDate(String ddmmyyyy) {
+ try {
+ return format.parse(ddmmyyyy);
+ } catch (Exception e) {
+ assert false; //should not get an invalid date....
+ }
+ return null;
+ }
}
//@@author
diff --git a/src/test/java/guitests/FindCommandTest.java b/src/test/java/guitests/FindCommandTest.java
index fc884bb9e436..8183ef85bc17 100644
--- a/src/test/java/guitests/FindCommandTest.java
+++ b/src/test/java/guitests/FindCommandTest.java
@@ -2,7 +2,6 @@
import org.junit.Test;
-import seedu.savvytasker.commons.core.Messages;
import seedu.savvytasker.logic.commands.HelpCommand;
import seedu.savvytasker.testutil.TestTask;
@@ -37,6 +36,11 @@ public void find_nonEmptyList_byFullMatch() {
public void find_nonEmptyList_byExactMatch() {
assertFindResult("find t/exact Nearer Due Task", td.nearerDue); // one matching result only
}
+
+ @Test
+ public void find_nonEmptyList_byCategory() {
+ assertFindResult("find t/category priority", td.highPriority, td.medPriority, td.lowPriority); // matching 3 results
+ }
@Test
public void find_emptyList(){
@@ -47,7 +51,7 @@ public void find_emptyList(){
@Test
public void find_invalidCommand_fail() {
commandBox.runCommand("findmyring");
- assertResultMessage(String.format(MESSAGE_UNKNOWN_COMMAND, HelpCommand.MESSAGE_USAGE));
+ assertResultMessage("Input: findmyring\n" + String.format(MESSAGE_UNKNOWN_COMMAND, HelpCommand.MESSAGE_USAGE));
}
private void assertFindResult(String command, TestTask... expectedHits) {
diff --git a/src/test/java/guitests/ListCommandTest.java b/src/test/java/guitests/ListCommandTest.java
index 990f475711c9..c8989ee4d9f6 100644
--- a/src/test/java/guitests/ListCommandTest.java
+++ b/src/test/java/guitests/ListCommandTest.java
@@ -2,7 +2,6 @@
import org.junit.Test;
-import seedu.savvytasker.commons.core.Messages;
import seedu.savvytasker.logic.commands.HelpCommand;
import seedu.savvytasker.testutil.TestTask;
@@ -23,6 +22,12 @@ public void list_nonEmptyList() {
td.highPriority, td.medPriority, td.lowPriority);
}
+ @Test
+ public void list_nonEmptyList_byInvalidSwitch() {
+ commandBox.runCommand("list badswitch");
+ assertResultMessage("Input: list badswitch\nLIST_TYPE: Unknown type \'badswitch\'");
+ }
+
@Test
public void list_nonEmptyList_byDueDate() {
// covered by list_nonEmptyList()
@@ -30,13 +35,13 @@ public void list_nonEmptyList_byDueDate() {
@Test
public void list_nonEmptyList_byPriority() {
- assertListResult("list t/PriorityLevel", td.highPriority, td.medPriority,
+ assertListResult("list PriorityLevel", td.highPriority, td.medPriority,
td.furthestDue, td.nearerDue, td.notSoNearerDue, td.earliestDue, td.lowPriority); //multiple results
}
@Test
public void list_nonEmptyList_byArchived() {
- assertListResult("list t/Archived", td.longDue); // one matching result only
+ assertListResult("list Archived", td.longDue); // one matching result only
}
@Test
@@ -48,7 +53,7 @@ public void list_emptyList(){
@Test
public void find_invalidCommand_fail() {
commandBox.runCommand("listmytasks");
- assertResultMessage(String.format(MESSAGE_UNKNOWN_COMMAND, HelpCommand.MESSAGE_USAGE));
+ assertResultMessage("Input: listmytasks\n" + String.format(MESSAGE_UNKNOWN_COMMAND, HelpCommand.MESSAGE_USAGE));
}
private void assertListResult(String command, TestTask... expectedHits ) {
diff --git a/src/test/java/guitests/ModifyCommandTest.java b/src/test/java/guitests/ModifyCommandTest.java
new file mode 100644
index 000000000000..fddc833fe95e
--- /dev/null
+++ b/src/test/java/guitests/ModifyCommandTest.java
@@ -0,0 +1,84 @@
+package guitests;
+
+import guitests.guihandles.TaskCardHandle;
+
+import org.junit.Test;
+
+import seedu.savvytasker.commons.core.Messages;
+import seedu.savvytasker.testutil.TestTask;
+import seedu.savvytasker.testutil.TestUtil;
+
+import static org.junit.Assert.assertTrue;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+
+//@@author A0139915W
+public class ModifyCommandTest extends SavvyTaskerGuiTest {
+
+ @Test
+ public void add() {
+ //modify task
+ TestTask[] currentList = td.getTypicalTasks();
+ TestTask taskToModify = currentList[0];
+ Date start = getDate("30/12/2016");
+ Date end = getDate("31/12/2016");
+ taskToModify.setStartDateTime(start);
+ taskToModify.setEndDateTime(end);
+ assertModifySuccess("modify 1 s/" + getLocaleDateString(start) +
+ " e/" + getLocaleDateString(end), taskToModify, currentList);
+ currentList = TestUtil.replaceTaskFromList(currentList, taskToModify);
+
+ taskToModify.setStartDateTime(null);
+ taskToModify.setEndDateTime(null);
+ assertModifySuccess("modify 1 s/ e/", taskToModify, currentList);
+ currentList = TestUtil.replaceTaskFromList(currentList, taskToModify);
+
+ //modify invalid index
+ commandBox.runCommand("modify " + currentList.length + "1" + " s/sat");
+ assertResultMessage(String.format(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX));
+
+ //modify with invalid end date
+ start = getDate("31/12/2016");
+ end = getDate("30/12/2016");
+ commandBox.runCommand("modify 1 s/" + getLocaleDateString(start) +
+ " e/" + getLocaleDateString(end));
+ assertResultMessage(String.format(Messages.MESSAGE_INVALID_START_END));
+ }
+
+ private void assertModifySuccess(String command, TestTask taskToModify, TestTask... currentList) {
+ commandBox.runCommand(command);
+
+ //confirm the new card contains the right data
+ TaskCardHandle modifiedCard = taskListPanel.navigateToTask(taskToModify.getTaskName());
+ assertMatching(taskToModify, modifiedCard);
+
+ //confirm the list now contains all previous persons plus the new person
+ TestTask[] expectedList = TestUtil.replaceTaskFromList(currentList, taskToModify);
+ assertTrue(taskListPanel.isListMatching(expectedList));
+ }
+
+ private DateFormat formatter = DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.getDefault());
+ private String getLocaleDateString(Date date) {
+ try {
+ return formatter.format(date);
+ } catch (Exception e) {
+ assert false; //should not get an invalid date....
+ }
+ return null;
+ }
+
+ private SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy");
+ private Date getDate(String ddmmyyyy) {
+ try {
+ return format.parse(ddmmyyyy);
+ } catch (Exception e) {
+ assert false; //should not get an invalid date....
+ }
+ return null;
+ }
+
+}
+//@@author
diff --git a/src/test/java/guitests/guihandles/TaskCardHandle.java b/src/test/java/guitests/guihandles/TaskCardHandle.java
index fe32021d1b5f..58771f3d2091 100644
--- a/src/test/java/guitests/guihandles/TaskCardHandle.java
+++ b/src/test/java/guitests/guihandles/TaskCardHandle.java
@@ -11,6 +11,7 @@
*/
public class TaskCardHandle extends GuiHandle {
private static final String TASKNAME_FIELD_ID = "#taskName";
+ private static final String DETAILS_FIELD_ID = "#details";
private Node node;
@@ -26,16 +27,21 @@ protected String getTextFromLabel(String fieldId) {
public String getTaskName() {
return getTextFromLabel(TASKNAME_FIELD_ID);
}
+
+ public String getDetails() {
+ return getTextFromLabel(DETAILS_FIELD_ID);
+ }
public boolean isSameTask(ReadOnlyTask task) {
- return getTaskName().equals(task.getTaskName());
+ return getTaskName().equals(task.getTaskName()) && getDetails().equals(task.getTextForUi());
}
@Override
public boolean equals(Object obj) {
if(obj instanceof TaskCardHandle) {
TaskCardHandle handle = (TaskCardHandle) obj;
- return getTaskName().equals(handle.getTaskName()); //TODO: compare the rest
+ return getTaskName().equals(handle.getTaskName()) &&
+ getDetails().equals(handle.getDetails());
}
return super.equals(obj);
}
diff --git a/src/test/java/seedu/savvytasker/TestApp.java b/src/test/java/seedu/savvytasker/TestApp.java
index f29428ea4944..ad08171828b1 100644
--- a/src/test/java/seedu/savvytasker/TestApp.java
+++ b/src/test/java/seedu/savvytasker/TestApp.java
@@ -45,9 +45,9 @@ public TestApp(Supplier initialDataSupplier, String saveFil
protected Config initConfig(String configFilePath) {
Config config = super.initConfig(configFilePath);
config.setAppTitle(APP_TITLE);
- config.setAddressBookFilePath(saveFileLocation);
+ config.setSavvyTaskerFilePath(saveFileLocation);
config.setUserPrefsFilePath(DEFAULT_PREF_FILE_LOCATION_FOR_TESTING);
- config.setAddressBookName(ADDRESS_BOOK_NAME);
+ config.setSavvyTaskerName(ADDRESS_BOOK_NAME);
return config;
}
diff --git a/src/test/java/seedu/savvytasker/commons/core/ConfigTest.java b/src/test/java/seedu/savvytasker/commons/core/ConfigTest.java
index f1c820ab9b2c..3f0c0642d746 100644
--- a/src/test/java/seedu/savvytasker/commons/core/ConfigTest.java
+++ b/src/test/java/seedu/savvytasker/commons/core/ConfigTest.java
@@ -20,7 +20,7 @@ public void toString_defaultObject_stringReturned() {
"Current log level : INFO\n" +
"Preference file Location : preferences.json\n" +
"Local data file location : data/savvytasker.xml\n" +
- "AddressBook name : MyTaskList";
+ "Savvy Tasker List name : MyTaskList";
assertEquals(defaultConfigAsString, new Config().toString());
}
diff --git a/src/test/java/seedu/savvytasker/commons/util/ConfigUtilTest.java b/src/test/java/seedu/savvytasker/commons/util/ConfigUtilTest.java
index f3fa7414459e..0e853b22d958 100644
--- a/src/test/java/seedu/savvytasker/commons/util/ConfigUtilTest.java
+++ b/src/test/java/seedu/savvytasker/commons/util/ConfigUtilTest.java
@@ -79,8 +79,8 @@ private Config getTypicalConfig() {
config.setAppTitle("Typical App Title");
config.setLogLevel(Level.INFO);
config.setUserPrefsFilePath("C:\\preferences.json");
- config.setAddressBookFilePath("addressbook.xml");
- config.setAddressBookName("TypicalAddressBookName");
+ config.setSavvyTaskerFilePath("data/savvytasker.xml");
+ config.setSavvyTaskerName("MyTaskList");
return config;
}
diff --git a/src/test/java/seedu/savvytasker/commons/util/SmartDefaultDatesTest.java b/src/test/java/seedu/savvytasker/commons/util/SmartDefaultDatesTest.java
new file mode 100644
index 000000000000..6fe7ca6fc358
--- /dev/null
+++ b/src/test/java/seedu/savvytasker/commons/util/SmartDefaultDatesTest.java
@@ -0,0 +1,247 @@
+package seedu.savvytasker.commons.util;
+
+import org.junit.Test;
+
+import seedu.savvytasker.logic.parser.DateParser;
+import seedu.savvytasker.logic.parser.DateParser.InferredDate;
+import seedu.savvytasker.logic.parser.ParseException;
+
+import static org.junit.Assert.assertEquals;
+
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+
+//@@author A0139915W
+public class SmartDefaultDatesTest {
+
+ @Test
+ public void smartDefaultDates_parseStart() {
+ DateParser dateParser = new DateParser();
+ InferredDate inferredStart = null;
+ try {
+ //use MM-dd-yyyy
+ inferredStart = dateParser.parseSingle("12/31/2016");
+ } catch (ParseException e) {
+ assert false; //won't get here
+ }
+ InferredDate inferredEnd = null;
+ 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());
+
+ SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
+ Date today = today(0, 0);
+ try {
+ //use MM-dd-yyyy
+ inferredStart = dateParser.parseSingle("3pm");
+ } catch (ParseException e) {
+ assert false; //won't get here
+ }
+ 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());
+ }
+
+ @Test
+ public void smartDefaultDates_parseEnd() {
+ SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
+ Date today = today(0, 0);
+ DateParser dateParser = new DateParser();
+ InferredDate inferredEnd = null;
+ try {
+ //use MM-dd-yyyy
+ inferredEnd = dateParser.parseSingle("12/31/2016");
+ } catch (ParseException e) {
+ assert false; //won't get here
+ }
+ InferredDate inferredStart = null;
+ 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());
+
+ try {
+ //use MM-dd-yyyy
+ inferredEnd = dateParser.parseSingle("3pm");
+ } catch (ParseException e) {
+ assert false; //won't get here
+ }
+ 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());
+
+
+ try {
+ //use MM-dd-yyyy
+ inferredEnd = dateParser.parseSingle("12/31/2000");
+ } catch (ParseException e) {
+ assert false; //won't get here
+ }
+ 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());
+ }
+
+ @Test
+ public void smartDefaultDates_parseStartEnd() {
+ // START_TIME
+ // date not supplied -> today
+ // time not supplied -> 0000
+ // END_TIME
+ // date not supplied -> today
+ // time not supplied -> 2359
+ SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
+ Date today = today(0, 0);
+ DateParser dateParser = new DateParser();
+ InferredDate inferredStart = null;
+ InferredDate inferredEnd = null;
+ try {
+ //use MM-dd-yyyy
+ inferredStart = dateParser.parseSingle("12/31/2016");
+ inferredEnd = dateParser.parseSingle("12/31/2016");
+ } catch (ParseException e) {
+ assert false; //won't get here
+ }
+ SmartDefaultDates sdd = new SmartDefaultDates(inferredStart, inferredEnd);
+ // 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());
+
+ inferredStart = null;
+ inferredEnd = null;
+ try {
+ //use MM-dd-yyyy
+ inferredStart = dateParser.parseSingle("12/31/2016");
+ inferredEnd = dateParser.parseSingle("12/30/2016");
+ } catch (ParseException e) {
+ assert false; //won't get here
+ }
+ sdd = new SmartDefaultDates(inferredStart, inferredEnd);
+ // no time supplied for start and end, end date earlier than start
+ // 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());
+
+ inferredStart = null;
+ inferredEnd = null;
+ try {
+ //use MM-dd-yyyy
+ inferredStart = dateParser.parseSingle("10am");
+ inferredEnd = dateParser.parseSingle("10pm");
+ } catch (ParseException e) {
+ assert false; //won't get here
+ }
+ 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());
+
+ inferredStart = null;
+ inferredEnd = null;
+ try {
+ //use MM-dd-yyyy
+ inferredStart = dateParser.parseSingle("10pm");
+ inferredEnd = dateParser.parseSingle("10am");
+ } catch (ParseException e) {
+ assert false; //won't get here
+ }
+ sdd = new SmartDefaultDates(inferredStart, inferredEnd);
+ // 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());
+ }
+
+ @Test
+ public void smartDefaultDates_defaultParse() {
+ SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
+ Date today = today(0, 0);
+ DateParser dateParser = new DateParser();
+ 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);
+
+ try {
+ //use MM-dd-yyyy
+ actualStart = sdd.getStart(dateParser.parseSingle("10pm"));
+ actualEnd = sdd.getEnd(dateParser.parseSingle("10am"));
+ } 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);
+
+ try {
+ //use MM-dd-yyyy
+ actualStart = sdd.getStart(dateParser.parseSingle("12/31/2016"));
+ actualEnd = sdd.getEnd(dateParser.parseSingle("12/31/2016"));
+ } catch (ParseException e) {
+ assert false; //won't get here
+ }
+ expectedStart = getDate("31/12/2016 000000");
+ expectedEnd = getDate("31/12/2016 235959");
+ 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);
+ } catch (Exception e) {
+ assert false; //should not get an invalid date....
+ }
+ return null;
+ }
+
+ private Date today(int hours_24, int minute_60) {
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(new Date());
+ calendar.set(Calendar.HOUR_OF_DAY, hours_24);
+ calendar.set(Calendar.MINUTE, minute_60);
+ calendar.set(Calendar.SECOND, 0);
+ calendar.set(Calendar.MILLISECOND, 0);
+ return calendar.getTime();
+ }
+}
+//@@author
diff --git a/src/test/java/seedu/savvytasker/logic/LogicManagerTest.java b/src/test/java/seedu/savvytasker/logic/LogicManagerTest.java
index eec2e4ca6fd3..9b59af423a5e 100644
--- a/src/test/java/seedu/savvytasker/logic/LogicManagerTest.java
+++ b/src/test/java/seedu/savvytasker/logic/LogicManagerTest.java
@@ -88,6 +88,7 @@ public void teardown() {
public void execute_invalid() throws Exception {
String invalidCommand = " ";
assertCommandBehavior(invalidCommand,
+ "Input: \n" +
String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE));
}
@@ -128,7 +129,7 @@ private void assertCommandBehavior(String inputCommand, String expectedMessage,
@Test
public void execute_unknownCommandWord() throws Exception {
String unknownCommand = "uicfhmowqewca";
- assertCommandBehavior(unknownCommand, String.format(MESSAGE_UNKNOWN_COMMAND, HelpCommand.MESSAGE_USAGE));
+ assertCommandBehavior(unknownCommand, "Input: uicfhmowqewca\n" + String.format(MESSAGE_UNKNOWN_COMMAND, HelpCommand.MESSAGE_USAGE));
}
@Test
@@ -195,10 +196,11 @@ private void assertIncorrectIndexFormatBehaviorForCommand(String commandWord, St
// the following commands outputs a different expected message dealing with
// invalid indices.
- expectedMessage = String.format(Messages.MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.COMMAND_FORMAT) + ": " + IndexParser.INDEX_MUST_BE_POSITIVE;
- //assertCommandBehavior(commandWord + " +1", expectedMessage); //index should be unsigned [NOT SUPPORTED]
+ expectedMessage = "Input: delete -1\n" + String.format(Messages.MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.COMMAND_FORMAT) + ": " + IndexParser.INDEX_MUST_BE_POSITIVE;
assertCommandBehavior(commandWord + " -1", expectedMessage); //index should be unsigned
+ expectedMessage = "Input: delete 0\n" + String.format(Messages.MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.COMMAND_FORMAT) + ": " + IndexParser.INDEX_MUST_BE_POSITIVE;
assertCommandBehavior(commandWord + " 0", expectedMessage); //index cannot be 0
+ expectedMessage = "Input: delete not_a_number\n" + String.format(Messages.MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.COMMAND_FORMAT) + ": " + IndexParser.INDEX_MUST_BE_POSITIVE;
assertCommandBehavior(commandWord + " not_a_number", expectedMessage);
}
@@ -253,7 +255,7 @@ public void execute_select_jumpsToCorrectPerson() throws Exception {
@Test
public void execute_deleteInvalidArgsFormat_errorMessageShown() throws Exception {
- String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.COMMAND_FORMAT);
+ String expectedMessage = "Input: delete\n" + String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.COMMAND_FORMAT);
assertIncorrectIndexFormatBehaviorForCommand("delete", expectedMessage);
}
@@ -280,7 +282,7 @@ public void execute_delete_removesCorrectTask() throws Exception {
@Test
public void execute_find_invalidArgsFormat() throws Exception {
- String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.COMMAND_FORMAT);
+ String expectedMessage = "Input: find\n" + String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.COMMAND_FORMAT);
assertCommandBehavior("find ", expectedMessage);
}
diff --git a/src/test/java/seedu/savvytasker/logic/parser/ParserTest.java b/src/test/java/seedu/savvytasker/logic/parser/ParserTest.java
index 13c9bbd30247..a1856f5245ba 100644
--- a/src/test/java/seedu/savvytasker/logic/parser/ParserTest.java
+++ b/src/test/java/seedu/savvytasker/logic/parser/ParserTest.java
@@ -32,6 +32,7 @@ public class ParserTest {
private RedoCommandParser redoParser;
private AliasCommandParser aliasParser;
private UnaliasCommandParser unaliasParser;
+ private StorageCommandParser storageParser;
@Rule
public ExpectedException thrown = ExpectedException.none();
@@ -52,49 +53,50 @@ public void setup() {
redoParser = new RedoCommandParser();
aliasParser = new AliasCommandParser();
unaliasParser = new UnaliasCommandParser();
+ storageParser = new StorageCommandParser();
}
@Test
- public void parse_add_reorder() throws ParseException {
+ public void parseAdd_reorder() throws ParseException {
assertNotNull(addParser.parse("add task l/ comp e/ tomorrow, 3pm s/ today, 2pm n/ 2"));
}
@Test
- public void parse_add_multipleSpaces() throws ParseException {
+ public void parseAdd_multipleSpaces() throws ParseException {
assertNotNull(addParser.parse("add Multiple Spaces s/ 2pm"));
}
@Test
- public void parse_add_sameOptionMultipleTimes() throws ParseException {
+ public void parseAdd_sameOptionMultipleTimes_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
addParser.parse("add task s/ tomorrow 3pm s/ tomorrow 10pm");
}
@Test
- public void parse_add_missingTaskName() throws ParseException {
+ public void parseAdd_missingTaskName_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
addParser.parse("add s/ tomorrow 3pm");
}
@Test
- public void parse_add_arbitrarySlash() throws ParseException {
+ public void parseAdd_arbitrarySlash_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
addParser.parse("add task s/ tomorrow 2pm/3pm e/ sunday");
}
@Test
- public void parse_add_fullValid() throws ParseException {
+ public void parseAdd_fullValid() throws ParseException {
assertNotNull(addParser.parse("add task s/wednesday e/thursday l/ comp p/ high r/ none n/ 1 c/ test d/ test"));
}
@Test
- public void parse_add_invalidRecurrenceType() throws ParseException {
+ public void parseAdd_invalidRecurrenceType_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
addParser.parse("add task r/ Error ");
}
@Test
- public void parse_add_invalidPriorityLevel() throws ParseException {
+ public void parseAdd_invalidPriorityLevel_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
addParser.parse("add task p/ Error ");
}
@@ -102,34 +104,34 @@ public void parse_add_invalidPriorityLevel() throws ParseException {
//==================================================================================
@Test
- public void parse_delete_noIndexSpecified() throws ParseException {
+ public void parseDelete_noIndexSpecified_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
deleteParser.parse("delete");
}
@Test
- public void parse_delete_oneIndex() throws ParseException {
+ public void parseDelete_oneIndex() throws ParseException {
assertNotNull(deleteParser.parse("delete 1"));
}
@Test
- public void parse_delete_multipleIndices() throws ParseException {
+ public void parseDelete_multipleIndices() throws ParseException {
assertNotNull(deleteParser.parse("delete 1 2 3"));
}
@Test
- public void parse_delete_multipleSpacesIndices() throws ParseException {
+ public void parseDelete_multipleSpacesIndices() throws ParseException {
assertNotNull(deleteParser.parse("delete 1 2 3"));
}
@Test
- public void parse_delete_negativeIndex() throws ParseException {
+ public void parseDelete_negativeIndex_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
deleteParser.parse("delete -1");
}
@Test
- public void parse_delete_zeroIndex() throws ParseException {
+ public void parseDelete_zeroIndex_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
deleteParser.parse("delete 0");
}
@@ -137,198 +139,198 @@ public void parse_delete_zeroIndex() throws ParseException {
//==================================================================================
@Test
- public void parse_modify_noIndex() throws ParseException {
+ public void parseModify_noIndex_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
modifyParser.parse("modify t/ newtask");
}
@Test
- public void parse_modify_multipleIndex() throws ParseException {
+ public void parseModify_multipleIndex_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
modifyParser.parse("modify 1 2 3 t/ newtask");
}
@Test
- public void parse_modify_negativeIndex() throws ParseException {
+ public void parseModify_negativeIndex_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
modifyParser.parse("modify -1 t/ newtask");
}
@Test
- public void parse_modify_zeroIndex() throws ParseException {
+ public void parseModify_zeroIndex_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
modifyParser.parse("modify 0 t/ newtask");
}
@Test
- public void parse_modify_onlySpecifyIndex() throws ParseException {
+ public void parseModify_onlySpecifyIndex() throws ParseException {
assertNotNull(modifyParser.parse("modify 1"));
}
@Test
- public void parse_modify_fullValid() throws ParseException {
+ public void parseModify_fullValid() throws ParseException {
assertNotNull(modifyParser.parse("modify 3 t/ newtask s/wednesday e/thursday l/ comp p/ high r/ none n/ 1 c/ test d/ test"));
}
@Test
- public void parse_modify_reorder() throws ParseException {
+ public void parseModify_reorder() throws ParseException {
assertNotNull(modifyParser.parse("modify 1 l/ comp e/ tomorrow, 3pm s/ today, 2pm n/ 2"));
}
@Test
- public void parse_modify_multipleSpaces() throws ParseException {
+ public void parseModify_multipleSpaces() throws ParseException {
assertNotNull(modifyParser.parse("modify 1 t/ Multiple Spaces s/ 2pm"));
}
//==================================================================================
@Test
- public void parse_clear_spaces() throws ParseException {
+ public void parseClear_spaces() throws ParseException {
assertNotNull(clearParser.parse("clear "));
}
@Test
- public void parse_clear_invalid() throws ParseException {
+ public void parseClear_invalid_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
clearParser.parse("clear 1");
}
@Test
- public void parse_clear_valid() throws ParseException {
+ public void parseClear_valid() throws ParseException {
assertNotNull(clearParser.parse("clear"));
}
//==================================================================================
@Test
- public void parse_list_noParameters() throws ParseException {
+ public void parseList_noParameters() throws ParseException {
assertNotNull(listParser.parse("list"));
}
@Test
- public void parse_list_noParametersSpaces() throws ParseException {
+ public void parseList_noParametersSpaces() throws ParseException {
assertNotNull(listParser.parse("list "));
}
@Test
public void parse_list_valid() throws ParseException {
- assertNotNull(listParser.parse("list t/ Priority Level "));
+ assertNotNull(listParser.parse("list Priority Level "));
}
@Test
- public void parse_list_invalidType() throws ParseException {
+ public void parseList_invalidType_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
- listParser.parse("list t/ Error ");
+ listParser.parse("list Error ");
}
//==================================================================================
@Test
- public void parse_find_noKeywords() throws ParseException {
+ public void parseFind_noKeywords_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
findParser.parse("find");
}
@Test
- public void parse_find_noKeywordsSpaces() throws ParseException {
+ public void parseFind_noKeywordsSpaces_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
findParser.parse("find ");
}
@Test
- public void parse_find_noKeywordsButWithType() throws ParseException {
+ public void parseFind_noKeywordsButWithType_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
findParser.parse("find t/ Exact ");
}
@Test
- public void parse_find_invalidType() throws ParseException {
+ public void parseFind_invalidType_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
findParser.parse("find t/ Error some words");
}
@Test
- public void parse_find_validAfter() throws ParseException {
+ public void parseFind_validAfter() throws ParseException {
assertNotNull(findParser.parse("find t/ Exact this word "));
}
@Test
- public void parse_find_validBefore() throws ParseException {
+ public void parseFind_validBefore() throws ParseException {
assertNotNull(findParser.parse("find some words t/ Partial "));
}
@Test
- public void parse_find_validBeforeAndAfter() throws ParseException {
+ public void parseFind_validBeforeAndAfter() throws ParseException {
assertNotNull(findParser.parse("find some words t/ Full some words after "));
}
//==================================================================================
@Test
- public void parse_help_spaces() throws ParseException {
+ public void parseHelp_spaces() throws ParseException {
assertNotNull(helpParser.parse("help "));
}
@Test
- public void parse_help_invalid() throws ParseException {
+ public void parseHelp_invalid_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
helpParser.parse("help 1");
}
@Test
- public void parse_help_valid() throws ParseException {
+ public void parseHelp_valid() throws ParseException {
assertNotNull(helpParser.parse("help"));
}
//==================================================================================
@Test
- public void parse_exit_spaces() throws ParseException {
+ public void parseExit_spaces() throws ParseException {
assertNotNull(exitParser.parse("exit "));
}
@Test
- public void parse_exit_invalid() throws ParseException {
+ public void parseExit_invalid_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
helpParser.parse("exit 1");
}
@Test
- public void parse_exit_valid() throws ParseException {
+ public void parseExit_valid() throws ParseException {
assertNotNull(exitParser.parse("exit"));
}
//==================================================================================
@Test
- public void parse_mark_noIndexSpecified() throws ParseException {
+ public void parseMark_noIndexSpecified_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
markParser.parse("mark");
}
@Test
- public void parse_mark_oneIndex() throws ParseException {
+ public void parseMark_oneIndex() throws ParseException {
assertNotNull(markParser.parse("mark 1"));
}
@Test
- public void parse_mark_multipleIndices() throws ParseException {
+ public void parseMark_multipleIndices() throws ParseException {
assertNotNull(markParser.parse("mark 1 2 3"));
}
@Test
- public void parse_mark_multipleSpacesIndices() throws ParseException {
+ public void parseMark_multipleSpacesIndices() throws ParseException {
assertNotNull(markParser.parse("mark 1 2 3"));
}
@Test
- public void parse_mark_negativeIndex() throws ParseException {
+ public void parseMark_negativeIndex_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
markParser.parse("mark -1");
}
@Test
- public void parse_mark_zeroIndex() throws ParseException {
+ public void parseMark_zeroIndex_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
markParser.parse("mark 0");
}
@@ -336,34 +338,34 @@ public void parse_mark_zeroIndex() throws ParseException {
//==================================================================================
@Test
- public void parse_unmark_noIndexSpecified() throws ParseException {
+ public void parseUnmark_noIndexSpecified_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
unmarkParser.parse("unmark");
}
@Test
- public void parse_unmark_oneIndex() throws ParseException {
+ public void parseUnmark_oneIndex() throws ParseException {
assertNotNull(unmarkParser.parse("unmark 1"));
}
@Test
- public void parse_unmark_multipleIndices() throws ParseException {
+ public void parseUnmark_multipleIndices() throws ParseException {
assertNotNull(unmarkParser.parse("unmark 1 2 3"));
}
@Test
- public void parse_unmark_multipleSpacesIndices() throws ParseException {
+ public void parseUnmark_multipleSpacesIndices() throws ParseException {
assertNotNull(unmarkParser.parse("unmark 1 2 3"));
}
@Test
- public void parse_unmark_negativeIndex() throws ParseException {
+ public void parseUnmark_negativeIndex_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
unmarkParser.parse("unmark -1");
}
@Test
- public void parse_unmark_zeroIndex() throws ParseException {
+ public void parseUnmark_zeroIndex_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
unmarkParser.parse("unmark 0");
}
@@ -371,106 +373,118 @@ public void parse_unmark_zeroIndex() throws ParseException {
//==================================================================================
@Test
- public void parse_undo_spaces() throws ParseException {
+ public void parseUndo_spaces() throws ParseException {
assertNotNull(undoParser.parse("undo "));
}
@Test
- public void parse_undo_invalid() throws ParseException {
+ public void parseUndo_invalid() throws ParseException {
thrown.expect(ParseException.class);
helpParser.parse("undo 1");
}
@Test
- public void parse_undo_valid() throws ParseException {
+ public void parseUndo_valid() throws ParseException {
assertNotNull(undoParser.parse("undo"));
}
//==================================================================================
@Test
- public void parse_redo_spaces() throws ParseException {
+ public void parseRedo_spaces() throws ParseException {
assertNotNull(redoParser.parse("redo "));
}
@Test
- public void parse_redo_invalid() throws ParseException {
+ public void parseRedo_invalid_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
helpParser.parse("redo 1");
}
@Test
- public void parse_redo_valid() throws ParseException {
+ public void parseRedo_valid() throws ParseException {
assertNotNull(redoParser.parse("redo"));
}
//==================================================================================
@Test
- public void parse_alias_keywordUnspecified() throws ParseException {
+ public void parseAlias_keywordUnspecified_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
aliasParser.parse("alias r/ a string of things");
}
@Test
- public void parse_alias_textUnspecified() throws ParseException {
+ public void parseAlias_textUnspecified_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
aliasParser.parse("alias k/ xyz");
}
@Test
- public void parse_alias_noSwitchesSpecified() throws ParseException {
+ public void parseAlias_noSwitchesSpecified_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
aliasParser.parse("alias power overwhelming");
}
@Test
- public void parse_alias_keywordTooLong() throws ParseException {
+ public void parseAlias_keywordNotSingleWord_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
aliasParser.parse("alias k/ not a single word r/ project management");
}
@Test
- public void parse_alias_keywordEmpty() throws ParseException {
+ public void parseAlias_keywordEmpty_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
aliasParser.parse("alias k/ r/ project management");
}
@Test
- public void parse_alias_textEmpty() throws ParseException {
+ public void parseAlias_textEmpty_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
aliasParser.parse("alias k/ pjm r/ ");
}
@Test
- public void parse_alias_fullValid() throws ParseException {
+ public void parseAlias_fullValid() throws ParseException {
assertNotNull(aliasParser.parse("alias k/ pjm r/ project management "));
}
//==================================================================================
@Test
- public void parse_unalias_emptyKeyword() throws ParseException {
+ public void parseUnalias_emptyKeyword_exceptionThrown() throws ParseException {
thrown.expect(ParseException.class);
unaliasParser.parse("unalias ");
}
@Test
- public void parse_unalias_valid() throws ParseException {
+ public void parseUnalias_valid() throws ParseException {
assertNotNull(unaliasParser.parse("unalias something "));
}
//==================================================================================
-
+
+ @Test
+ public void parseStorage_invalid_exceptionThrown() throws ParseException {
+ thrown.expect(ParseException.class);
+ storageParser.parse("storage ");
+ }
+
+ @Test
+ public void parseStorage_valid() throws ParseException {
+ assertNotNull(storageParser.parse("storage C:/Users/Brown/Desktop/file.xml "));
+ }
+
+ //==================================================================================
@Test
- public void parse_master_subparser() throws ParseException {
+ public void masterParser_subparserParsing_returnParsedCommand() throws ParseException {
MasterParser parser = new MasterParser();
parser.registerCommandParser(new AddCommandParser());
assertTrue(parser.parse(" add A New Task s/ tomorrow e/ the day after tomorrow, l/ SR10 ") instanceof AddCommand);
}
@Test
- public void parse_master_subparserRemoved() throws ParseException {
+ public void masterParser_subparserRemoved_returnIncorrectCommand() throws ParseException {
MasterParser parser = new MasterParser();
parser.registerCommandParser(new AddCommandParser());
parser.unregisterCommandParser("add");
@@ -478,7 +492,7 @@ public void parse_master_subparserRemoved() throws ParseException {
}
@Test
- public void parse_master_alias() throws ParseException {
+ public void masterParser_alias_returnParsedCommand() throws ParseException {
MasterParser parser = new MasterParser();
parser.registerCommandParser(new AddCommandParser());
parser.addAliasSymbol(new AliasSymbol("xyz", "add A New Task"));
@@ -487,14 +501,14 @@ public void parse_master_alias() throws ParseException {
}
@Test
- public void parse_master_invalidAlias() throws ParseException {
+ public void masterParser_invalidAlias_returnFalse() throws ParseException {
MasterParser parser = new MasterParser();
parser.registerCommandParser(new AddCommandParser());
assertFalse(parser.addAliasSymbol(new AliasSymbol("add", "add A New Task")));
}
@Test
- public void parse_master_removedAlias() throws ParseException {
+ public void masterParser_removedAlias_returnIncorrectCommand() throws ParseException {
MasterParser parser = new MasterParser();
parser.registerCommandParser(new AddCommandParser());
parser.addAliasSymbol(new AliasSymbol("xyz", "add A New Task"));
diff --git a/src/test/java/seedu/savvytasker/model/task/TaskListTest.java b/src/test/java/seedu/savvytasker/model/task/TaskListTest.java
new file mode 100644
index 000000000000..eac412d95d72
--- /dev/null
+++ b/src/test/java/seedu/savvytasker/model/task/TaskListTest.java
@@ -0,0 +1,92 @@
+package seedu.savvytasker.model.task;
+
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import seedu.savvytasker.model.task.TaskList;
+import seedu.savvytasker.model.task.TaskList.DuplicateTaskException;
+import seedu.savvytasker.model.task.TaskList.InvalidDateException;
+import seedu.savvytasker.model.task.TaskList.TaskNotFoundException;
+
+import static org.junit.Assert.assertEquals;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import org.junit.Rule;
+
+
+//@@author A0139915W
+public class TaskListTest {
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Test
+ public void taskList_addDuplicate() throws DuplicateTaskException, InvalidDateException {
+ thrown.expect(DuplicateTaskException.class);
+ TaskList tasks = new TaskList();
+ Task t = new Task("Test Task");
+ t.setId(1);
+ tasks.add(t); // passes
+ assertEquals(1, tasks.getInternalList().size());
+ tasks.add(t); // fails
+ }
+
+ @Test
+ public void taskList_addInvalidDate() throws DuplicateTaskException, InvalidDateException {
+ thrown.expect(InvalidDateException.class);
+ TaskList tasks = new TaskList();
+ Task t = new Task("Test Task");
+ t.setId(1);
+ t.setStartDateTime(getDate("31/12/2016"));
+ t.setEndDateTime(getDate("31/12/2015"));
+ tasks.add(t); // fails, end date earlier than start date
+ }
+
+ @Test
+ public void taskList_removeNonExistent() throws TaskNotFoundException {
+ thrown.expect(TaskNotFoundException.class);
+ TaskList tasks = new TaskList();
+ Task t = new Task("Test Task");
+ t.setId(1);
+ assertEquals(0, tasks.getInternalList().size());
+ tasks.remove(t); // fails
+ }
+
+ @Test
+ public void taskList_replaceNonExistent() throws TaskNotFoundException, InvalidDateException {
+ thrown.expect(TaskNotFoundException.class);
+ TaskList tasks = new TaskList();
+ Task t = new Task("Test Task");
+ t.setId(1);
+ assertEquals(0, tasks.getInternalList().size());
+ tasks.replace(t, t); // fails
+ }
+
+ @Test
+ public void taskList_replaceInvalidDate() throws TaskNotFoundException, InvalidDateException, DuplicateTaskException {
+ thrown.expect(InvalidDateException.class);
+ TaskList tasks = new TaskList();
+ Task t = new Task("Test Task");
+ t.setId(1);
+ t.setStartDateTime(getDate("30/12/2016"));
+ t.setEndDateTime(getDate("31/12/2016"));
+ tasks.add(t);
+ assertEquals(1, tasks.getInternalList().size());
+ t.setStartDateTime(getDate("31/12/2016"));
+ t.setEndDateTime(getDate("31/12/2015"));
+ tasks.replace(t, t); // fails, end date earlier than start date
+ }
+
+ private SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy");
+ private Date getDate(String ddmmyyyy) {
+ try {
+ return format.parse(ddmmyyyy);
+ } catch (Exception e) {
+ assert false; //should not get an invalid date....
+ }
+ return null;
+ }
+}
+//@@author
diff --git a/src/test/java/seedu/savvytasker/testutil/TestTask.java b/src/test/java/seedu/savvytasker/testutil/TestTask.java
index 56f03a4e97cb..40b75a26f5da 100644
--- a/src/test/java/seedu/savvytasker/testutil/TestTask.java
+++ b/src/test/java/seedu/savvytasker/testutil/TestTask.java
@@ -1,5 +1,6 @@
package seedu.savvytasker.testutil;
+import java.text.SimpleDateFormat;
import java.util.Date;
import seedu.savvytasker.model.task.PriorityLevel;
@@ -13,6 +14,7 @@
public class TestTask implements ReadOnlyTask {
private int id;
+ private int groupId;
private String taskName;
private Date startDateTime;
private Date endDateTime;
@@ -31,10 +33,16 @@ public TestTask() {
this.numberOfRecurrence = 0;
}
+ @Override
public int getId() {
return id;
}
+ @Override
+ public int getGroupId() {
+ return groupId;
+ }
+
@Override
public String getTaskName() {
return taskName;
@@ -93,6 +101,10 @@ public boolean isArchived() {
public void setId(int id) {
this.id = id;
}
+
+ public void setGroupId(int groupId) {
+ this.groupId = groupId;
+ }
public void setTaskName(String taskName) {
this.taskName = taskName;
@@ -140,8 +152,32 @@ public String toString() {
}
public String getAddCommand() {
+ SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy HHmm");
StringBuilder sb = new StringBuilder();
sb.append("add " + this.getTaskName());
+ if (startDateTime != null) {
+ sb.append(" s/ ").append(sdf.format(startDateTime));
+ }
+ if (endDateTime != null) {
+ sb.append(" e/ ").append(sdf.format(endDateTime));
+ }
+ if (location != null && !location.isEmpty()) {
+ sb.append(" l/ ").append(location);
+ }
+ if (priority != null && priority != PriorityLevel.Medium) {
+ // p/ defaults to medium, if set to medium, take as non-existent
+ sb.append(" p/ ").append(priority.toString());
+ }
+ if (recurringType != null && recurringType != RecurrenceType.None) {
+ // r/ defaults to none, if set to none, take as non-existent
+ sb.append(" r/ ").append(recurringType.toString());
+ }
+ if (category != null && !category.isEmpty()) {
+ sb.append(" c/ ").append(category);
+ }
+ if (description != null && !description.isEmpty()) {
+ sb.append(" d/ ").append(description);
+ }
return sb.toString();
}
}
diff --git a/src/test/java/seedu/savvytasker/testutil/TestUtil.java b/src/test/java/seedu/savvytasker/testutil/TestUtil.java
index a6ca044f7c42..348a28c5e37b 100644
--- a/src/test/java/seedu/savvytasker/testutil/TestUtil.java
+++ b/src/test/java/seedu/savvytasker/testutil/TestUtil.java
@@ -280,8 +280,13 @@ public static TestTask[] removeTaskFromList(final TestTask[] list, int targetInd
* @param index The index of the task to be replaced.
* @return
*/
- public static TestTask[] replaceTaskFromList(TestTask[] tasks, TestTask task, int index) {
- tasks[index] = task;
+ public static TestTask[] replaceTaskFromList(TestTask[] tasks, TestTask task) {
+ for (int i = 0; i < tasks.length; ++i) {
+ if (tasks[i].getId() == task.getId()) {
+ tasks[i] = task;
+ break;
+ }
+ }
return tasks;
}
diff --git a/src/test/java/seedu/savvytasker/testutil/TypicalTestTasks.java b/src/test/java/seedu/savvytasker/testutil/TypicalTestTasks.java
index da6b3a91cb1e..31f80cda0527 100644
--- a/src/test/java/seedu/savvytasker/testutil/TypicalTestTasks.java
+++ b/src/test/java/seedu/savvytasker/testutil/TypicalTestTasks.java
@@ -7,7 +7,6 @@
import seedu.savvytasker.model.SavvyTasker;
import seedu.savvytasker.model.task.PriorityLevel;
import seedu.savvytasker.model.task.Task;
-import seedu.savvytasker.model.task.TaskList.DuplicateTaskException;
import seedu.savvytasker.model.task.TaskList.InvalidDateException;
//@@author A0139915W
@@ -22,26 +21,26 @@ public class TypicalTestTasks {
public TypicalTestTasks() {
try {
- highPriority = new TaskBuilder().withId(0).withTaskName("High Priority Task")
- .withPriority(PriorityLevel.High).build();
- medPriority = new TaskBuilder().withId(1).withTaskName("Medium Priority Task")
- .withPriority(PriorityLevel.Medium).build();
- lowPriority = new TaskBuilder().withId(2).withTaskName("Low Priority Task")
- .withPriority(PriorityLevel.Low).build();
- furthestDue = new TaskBuilder().withId(3).withTaskName("Furthest Due Task")
+ highPriority = new TaskBuilder().withId(1).withTaskName("High Priority Task")
+ .withPriority(PriorityLevel.High).withCategory("priority").build();
+ medPriority = new TaskBuilder().withId(2).withTaskName("Medium Priority Task")
+ .withPriority(PriorityLevel.Medium).withCategory("priority").build();
+ lowPriority = new TaskBuilder().withId(3).withTaskName("Low Priority Task")
+ .withPriority(PriorityLevel.Low).withCategory("priority").build();
+ furthestDue = new TaskBuilder().withId(4).withTaskName("Furthest Due Task")
.withEndDateTime(getDate("01/12/2016")).build();
- nearerDue = new TaskBuilder().withId(4).withTaskName("Nearer Due Task")
+ nearerDue = new TaskBuilder().withId(5).withTaskName("Nearer Due Task")
.withEndDateTime(getDate("01/11/2016")).build();
- notSoNearerDue = new TaskBuilder().withId(5).withTaskName("Not So Nearer Due Task")
+ notSoNearerDue = new TaskBuilder().withId(6).withTaskName("Not So Nearer Due Task")
.withEndDateTime(getDate("02/11/2016")).build();
- earliestDue = new TaskBuilder().withId(6).withTaskName("Earliest Due Task")
+ earliestDue = new TaskBuilder().withId(7).withTaskName("Earliest Due Task")
.withEndDateTime(getDate("01/10/2016")).build();
- longDue = new TaskBuilder().withId(7).withTaskName("Long Due Task")
+ longDue = new TaskBuilder().withId(8).withTaskName("Long Due Task")
.withEndDateTime(getDate("01/1/2016")).withArchived(true).build();
//Manually added
- happy = new TaskBuilder().withId(8).withTaskName("Happy Task").build();
- haloween = new TaskBuilder().withId(9).withTaskName("Haloween Task").build();
+ happy = new TaskBuilder().withId(9).withTaskName("Happy Task").build();
+ haloween = new TaskBuilder().withId(10).withTaskName("Haloween Task").build();
} catch (IllegalValueException e) {
e.printStackTrace();
assert false : "not possible";
@@ -59,8 +58,6 @@ public static void loadSavvyTaskerWithSampleData(SavvyTasker st) {
st.addTask(new Task(td.notSoNearerDue));
st.addTask(new Task(td.earliestDue));
st.addTask(new Task(td.longDue));
- } catch (DuplicateTaskException e) {
- assert false : "not possible";
} catch (InvalidDateException e) {
assert false : "not possible";
}