diff --git a/README.md b/README.md index c651f00724d0..f2b87a75bc0d 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ [![Build Status](https://travis-ci.org/se-edu/addressbook-level4.svg?branch=master)](https://travis-ci.org/se-edu/addressbook-level4) [![Coverage Status](https://coveralls.io/repos/github/CS2103AUG2016-F10-C3/main/badge.svg?branch=master)](https://coveralls.io/github/CS2103AUG2016-F10-C3/main?branch=master) +[![Codacy Badge](https://api.codacy.com/project/badge/Grade/72e712e19dd241cfa8820139dbab0bef)](https://www.codacy.com/app/shwetha-ravi3/main?utm_source=github.com&utm_medium=referral&utm_content=CS2103AUG2016-F10-C3/main&utm_campaign=Badge_Grade) # Tary diff --git a/docs/AboutUs.md b/docs/AboutUs.md index c640ee153033..fefc2d366cc4 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -4,18 +4,22 @@ We are a team based in the [School of Computing, National University of Singapor ## Project Team -#### [Joshua Lee](http://github.com/lejolly) -
-Role: Developer
-Responsibilities: UI - ------ - #### [Ravi Shwetha](http://github.com/ravishwetha)
-Role: Developer
-Responsibilities: Storage and Testing +* Components in charge of: [Storage and Testing](https://github.com/se-edu/addressbook-level4/blob/master/docs/DeveloperGuide.md#storage-component) +* Aspects/tools in charge of: Testing, Git +* Features implemented: + * [Basic undo and multiple undo](https://github.com/se-edu/addressbook-level4/blob/master/docs/UserGuide.md#listing-all-persons--list) + * [Edit task](https://github.com/se-edu/addressbook-level4/blob/master/docs/UserGuide.md#deleting-a-person--delete) + * [Find searches for exact keywords first](https://github.com/se-edu/addressbook-level4/blob/master/docs/UserGuide.md#deleting-a-person--delete) + * [Natural language processing for dates using Natty API](https://github.com/se-edu/addressbook-level4/blob/master/docs/UserGuide.md#deleting-a-person--delete) +* Code written: [[functional code](A0146130W.md)][[test code](A0146130W.md)][[docs](A0146130W.md)] +* Other major contributions: + * Did the initial refactoring from Person model to Task model [[#133](https://github.com/se-edu/addressbook-level4/pull/152) ] + * Set up Coveralls and Collate + * Change browser to search task location on google maps + ----- #### [Tan Shao Yun](http://github.com/shaocloud) @@ -23,7 +27,6 @@ Responsibilities: Storage and Testing Role: Developer
Responsibilities: UI - ----- #### [Voon Soo Yin](http://github.com/tessav) @@ -37,6 +40,6 @@ Responsibilities: UI #### [Chan Jun Wei](http://github.com/chanjunweimy)
- Role: Module Tutor
+ Role: Module Tutor and Project Supervisor
Code modified from : https://github.com/nus-cs2103-AY1617S1/addressbook-level4 diff --git a/libs/A0146130W.md b/libs/A0146130W.md index 73c5ea897901..f7882e9c3111 100644 --- a/libs/A0146130W.md +++ b/libs/A0146130W.md @@ -73,11 +73,13 @@ ###### /src/main/java/seedu/gtd/logic/commands/FindCommand.java ``` java private final String keywords; - private final Set keywordSet; + private Set keywordSet; + private final String cmd; - public FindCommand(String keywords, Set keywordSet) { + public FindCommand(String keywords, Set keywordSet, String cmd) { this.keywords = keywords; this.keywordSet = keywordSet; + this.cmd = cmd; } private String getMessageForTaskListShownSummaryIfExactPhraseNotFound(int displaySize) { @@ -86,20 +88,68 @@ String MESSAGE_IF_EXACT_PHRASE_NOT_FOUND = "The exact phrase '" + keywords + "' was not found. Listing " + displaySize + " " + task_tasks + " containing the keywords entered instead."; return String.format(MESSAGE_IF_EXACT_PHRASE_NOT_FOUND); } + + private String getMessageForTaskListShownSummaryIfExactFieldNotFound(int displaySize) { + String task_tasks = (displaySize == 1) ? "task" : "tasks"; + + String MESSAGE_IF_EXACT_PHRASE_NOT_FOUND = "The exact phrase '" + keywords + "' was not found in the specified field type. Listing " + displaySize + " " + task_tasks + " containing the keywords entered instead."; + return String.format(MESSAGE_IF_EXACT_PHRASE_NOT_FOUND); + } @Override public CommandResult execute() { - model.updateFilteredTaskList(keywords, keywordSet); - - if(model.getFilteredTaskList().isEmpty()) { - model.updateFilteredTaskList(keywordSet); - if(!model.getFilteredTaskList().isEmpty()) return new CommandResult(getMessageForTaskListShownSummaryIfExactPhraseNotFound(model.getFilteredTaskList().size())); - } - + System.out.println("command: " + cmd); + + // search by parameter if specified + if (cmd != "nil") { + model.updateFilteredTaskList(keywords, cmd); + } else { + // search by exact name + model.updateFilteredTaskList(keywords, keywordSet); + } + if (!model.getFilteredTaskList().isEmpty()) { + return new CommandResult(getMessageForTaskListShownSummary(model.getFilteredTaskList().size())); + } + + // search by keywords + model.updateFilteredTaskList(keywords, "nil"); + + if (!model.getFilteredTaskList().isEmpty()) { + if (cmd == "nil") { + return new CommandResult(getMessageForTaskListShownSummaryIfExactPhraseNotFound(model.getFilteredTaskList().size())); + } else { + return new CommandResult(getMessageForTaskListShownSummaryIfExactFieldNotFound(model.getFilteredTaskList().size())); + } + } + return new CommandResult(getMessageForTaskListShownSummary(model.getFilteredTaskList().size())); } } ``` +###### /src/main/java/seedu/gtd/logic/commands/UndoCommand.java +``` java + +package seedu.gtd.logic.commands; + +/** + * Deletes a task identified using it's last displayed index from the address book. + */ +public class UndoCommand extends Command { + + public static final String COMMAND_WORD = "undo"; + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Un-does the most recent modification of the task list."; + public static final String MESSAGE_SUCCESS = "Undo change"; + + public UndoCommand() {} + + @Override + public CommandResult execute() { + model.undoAddressBookChange(); + return new CommandResult(MESSAGE_SUCCESS); + } + +} +``` ###### /src/main/java/seedu/gtd/logic/parser/DateNaturalLanguageProcessor.java ``` java @@ -109,7 +159,7 @@ public class DateNaturalLanguageProcessor implements NaturalLanguageProcessor { private static final com.joestelmach.natty.Parser parser = new com.joestelmach.natty.Parser(); - private static final String DATE_FORMAT = "dd/MM/yyyy HH:mm:ss"; + private static final String DATE_FORMAT = "dd/MM/yyyy HH:mm"; @Override public String formatString(String naturalLanguageDate) { @@ -165,6 +215,12 @@ public interface NaturalLanguageProcessor { return nlp.formatString(dueDateRaw); } + // remove time on date parsed to improve search results + private String removeTimeOnDate(String dueDateRaw) { + String[] dateTime = dueDateRaw.split(" "); + return dateTime[0]; + } + ``` ###### /src/main/java/seedu/gtd/logic/parser/Parser.java ``` java @@ -237,11 +293,19 @@ public interface NaturalLanguageProcessor { ``` java @Override public synchronized void editTask(int targetIndex, Task task) throws TaskNotFoundException { + savePreviousAddressBook(); + System.out.println("editing task.."); addressBook.editTask(targetIndex, task); updateFilteredListToShowAll(); indicateAddressBookChanged(); } + @Override + public void clearTaskList() { + savePreviousAddressBook(); + resetData(AddressBook.getEmptyAddressBook()); + } + ``` ###### /src/main/java/seedu/gtd/model/task/UniqueTaskList.java ``` java @@ -258,6 +322,18 @@ public interface NaturalLanguageProcessor { internalList.set(targetIndex, toEdit); } + public void done(int targetIndex, Task taskdone) throws TaskNotFoundException { + System.out.println("in uniquetasklist"); + System.out.println(taskdone.getName() + " " + taskdone.getisDone()); + System.out.println("index at final:" + targetIndex); + assert taskdone != null; + if (invalidIndex(targetIndex)) { + throw new TaskNotFoundException(); + } + System.out.println("marked done in model"); + internalList.set(targetIndex, taskdone); + } + private boolean invalidIndex(int i) { if(i < 0 || i >= internalList.size()) return true; return false; @@ -312,9 +388,9 @@ public class EditCommandTest extends AddressBookGuiTest { } /** - * Runs the delete command to delete the task at specified index and confirms the result is correct. - * @param targetIndexOneIndexed e.g. to delete the first task in the list, 1 should be given as the target index. - * @param currentList A copy of the current list of tasks (before deletion). + * Runs the edit command to edit the task at specified index and confirms the result is correct. + * @param targetIndexOneIndexed e.g. to edit the first task in the list, 1 should be given as the target index. + * @param currentList A copy of the current list of tasks (before editing). */ private void assertEditSuccess(int targetIndexOneIndexed, String change, final TestTask[] currentList) { TestTask taskToEdit = currentList[targetIndexOneIndexed-1]; //-1 because array uses zero indexing @@ -328,6 +404,69 @@ public class EditCommandTest extends AddressBookGuiTest { assertResultMessage(String.format(MESSAGE_EDIT_TASK_SUCCESS, expectedRemainder[targetIndexOneIndexed-1])); } +} +``` +###### /src/test/java/guitests/UndoCommandTest.java +``` java + +package guitests; + +import org.junit.Test; + +import seedu.gtd.testutil.TestTask; +import seedu.gtd.testutil.TestUtil; + +import static org.junit.Assert.assertTrue; +import static seedu.gtd.logic.commands.UndoCommand.MESSAGE_SUCCESS;; + +public class UndoCommandTest extends AddressBookGuiTest { + + @Test + public void undo() { + + //undo the addition of the first task + TestTask[] currentList = td.getTypicalTasks(); + TestTask[] previousList = currentList; + commandBox.runCommand(td.george.getAddCommand()); + assertUndoSuccess(previousList); + + //undo editing the dueDate of the last task in the list + int targetIndex = currentList.length; + String change = "d/2"; + previousList = currentList; + commandBox.runCommand("edit " + targetIndex + " " + change); + assertUndoSuccess(previousList); + + //undo deleting a task from the middle of the list + targetIndex = currentList.length/2; + previousList = currentList; + commandBox.runCommand("delete " + targetIndex); + assertUndoSuccess(previousList); + + //undo clearing list + previousList = currentList; + commandBox.runCommand("clear"); + assertUndoSuccess(previousList); + + //undo marking the middle task as done + previousList = currentList; + commandBox.runCommand("done " + targetIndex); + assertUndoSuccess(previousList); + } + + /** + * Runs the undo command to undo the last change to the task list + */ + private void assertUndoSuccess(final TestTask[] previousList) { + commandBox.runCommand("undo"); + + //confirm the list now contains all previous tasks except the deleted task + assertTrue(taskListPanel.isListMatching(previousList)); + + //confirm the result message is correct + assertResultMessage(String.format(MESSAGE_SUCCESS)); + } + } ``` ###### /src/test/java/seedu/gtd/testutil/TestUtil.java diff --git a/libs/addressbooklevel4.md b/libs/addressbooklevel4.md index 6743ab4432a1..75c99362d388 100644 --- a/libs/addressbooklevel4.md +++ b/libs/addressbooklevel4.md @@ -3,10 +3,11 @@ ``` java public static final String COMMAND_WORD = "find"; - public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all tasks whose names contain any of " + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all tasks whose name, date, address, tags and priority contain any of " + "the specified keywords (case-sensitive) and displays them as a list with index numbers.\n" - + "Parameters: KEYWORD [MORE_KEYWORDS]...\n" - + "Example: " + COMMAND_WORD + " alice bob charlie"; + + "To search by one particular field type, use t/ for tags, a/ for address, d/ for duedate and p/ for priority.\n" + + "Parameters: [FIELDTYPE] KEYWORD [MORE_KEYWORDS]...\n" + + "Example: " + COMMAND_WORD + " cs2103, " + COMMAND_WORD + " d/today"; ``` ###### /src/main/java/seedu/gtd/logic/parser/Parser.java @@ -30,19 +31,19 @@ // + "(?(?: t/[^/]+)*)"); // variable number of tags private static final Pattern NAME_TASK_DATA_ARGS_FORMAT = - Pattern.compile("(?[^/]+) (t|p|a|d|e)/.*"); + Pattern.compile("(?[^/]+) (t|p|a|d|z)/.*"); private static final Pattern PRIORITY_TASK_DATA_ARGS_FORMAT = - Pattern.compile(".* p/(?[^/]+) (t|a|d|e)/.*"); + Pattern.compile(".* p/(?[^/]+) (t|a|d|z)/.*"); private static final Pattern ADDRESS_TASK_DATA_ARGS_FORMAT = - Pattern.compile(".* a/(?
[^/]+) (t|p|d|e)/.*"); + Pattern.compile(".* a/(?
[^/]+) (t|p|d|z)/.*"); private static final Pattern DUEDATE_TASK_DATA_ARGS_FORMAT = - Pattern.compile(".* d/(?[^/]+) (t|a|p|e)/.*"); + Pattern.compile(".* d/(?[^/]+) (t|a|p|z)/.*"); private static final Pattern TAGS_TASK_DATA_ARGS_FORMAT = - Pattern.compile(".* t/(?[^/]+) (d|a|p|e)/.*"); + Pattern.compile(".* t/(?[^/]+) (d|a|p|z)/.*"); private static final Pattern EDIT_DATA_ARGS_FORMAT = Pattern.compile("(?\\S+)" @@ -77,6 +78,9 @@ case DeleteCommand.COMMAND_WORD: return prepareDelete(arguments); + + case DoneCommand.COMMAND_WORD: + return prepareDone(arguments); case ClearCommand.COMMAND_WORD: return new ClearCommand(); @@ -85,13 +89,16 @@ return prepareFind(arguments); case ListCommand.COMMAND_WORD: - return new ListCommand(); + return prepareList(arguments); case ExitCommand.COMMAND_WORD: return new ExitCommand(); case HelpCommand.COMMAND_WORD: return prepareHelp(arguments); + + case UndoCommand.COMMAND_WORD: + return new UndoCommand(); default: return new IncorrectCommand(MESSAGE_UNKNOWN_COMMAND); @@ -149,7 +156,7 @@ } private String appendEnd(String args) { - return args + " e/"; + return args + " z/"; } private String checkEmptyAndAddDefault(Matcher matcher, String groupName, String defaultValue) { @@ -196,6 +203,18 @@ return new DeleteCommand(index.get()); } + + private Command prepareDone(String args) { + + Optional index = parseIndex(args); + System.out.println("index at preparedone:" + index.get()); + if(!index.isPresent()){ + return new IncorrectCommand( + String.format(MESSAGE_INVALID_COMMAND_FORMAT, DoneCommand.MESSAGE_USAGE)); + } + + return new DoneCommand(index.get()); + } /** * Parses arguments in the context of the select task command. @@ -238,6 +257,37 @@ * @return the prepared command */ private Command prepareFind(String args) { + + // check if parameters are specified and pass specified field to FindCommand + + String preprocessedArgs = " " + appendEnd(args.trim()); + final Matcher addressMatcher = ADDRESS_TASK_DATA_ARGS_FORMAT.matcher(preprocessedArgs); + final Matcher priorityMatcher = PRIORITY_TASK_DATA_ARGS_FORMAT.matcher(preprocessedArgs); + final Matcher dueDateMatcher = DUEDATE_TASK_DATA_ARGS_FORMAT.matcher(preprocessedArgs); + final Matcher tagsMatcher = TAGS_TASK_DATA_ARGS_FORMAT.matcher(preprocessedArgs); + + Set defaultSet = new HashSet(); + + if (addressMatcher.matches()) { + String addressToBeFound = addressMatcher.group("address"); + return new FindCommand(addressToBeFound, defaultSet,"address"); + } + if (priorityMatcher.matches()) { + String priorityToBeFound = priorityMatcher.group("priority"); + return new FindCommand(priorityToBeFound, defaultSet, "priority"); + } + if (dueDateMatcher.matches()) { + String dueDateToBeFound = dueDateMatcher.group("dueDate"); + String parsedDueDateToBeFound = removeTimeOnDate(parseDueDate(dueDateToBeFound)); + return new FindCommand(parsedDueDateToBeFound, defaultSet, "dueDate"); + } + if (tagsMatcher.matches()) { + String tagsToBeFound = tagsMatcher.group("tagArguments"); + return new FindCommand(tagsToBeFound, defaultSet,"tagArguments"); + } + + // free-form search by keywords + final Matcher matcher = KEYWORDS_ARGS_FORMAT.matcher(args.trim()); if (!matcher.matches()) { return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, @@ -249,8 +299,16 @@ final Set keywordSet = new HashSet<>(Arrays.asList(splitKeywords)); final String keywords = matcher.group("keywords"); - return new FindCommand(keywords, keywordSet); + return new FindCommand(keywords, keywordSet, "nil"); } + +private Command prepareList(String args) { + + // check if parameters are specified and pass specified field to FindCommand + + //String preprocessedArgs = " " + appendEnd(args.trim()); + return new ListCommand(args); +} /** * Parses arguments in the context of the help command. @@ -451,6 +509,7 @@ public class MainApp extends Application { */ public AddressBook(ReadOnlyAddressBook toBeCopied) { this(toBeCopied.getUniqueTaskList(), toBeCopied.getUniqueTagList()); + System.out.println("start with first method"); } /** @@ -458,6 +517,7 @@ public class MainApp extends Application { */ public AddressBook(UniqueTaskList tasks, UniqueTagList tags) { resetData(tasks.getInternalList(), tags.getInternalList()); + System.out.println("start with second method"); } public static ReadOnlyAddressBook getEmptyAddressBook() { @@ -534,6 +594,11 @@ public class MainApp extends Application { throw new UniqueTaskList.TaskNotFoundException(); } } + + public void doneTask(int index, Task target) throws TaskNotFoundException { + System.out.println("in addressbook"); + tasks.done(index, target); + } //// tag-level operations @@ -553,7 +618,7 @@ public class MainApp extends Application { public List getTaskList() { return Collections.unmodifiableList(tasks.getInternalList()); } - + @Override public List getTagList() { return Collections.unmodifiableList(tags.getInternalList()); @@ -590,8 +655,9 @@ public class MainApp extends Application { private static final Logger logger = LogsCenter.getLogger(ModelManager.class); - private final AddressBook addressBook; + private AddressBook addressBook; private final FilteredList filteredTasks; + private AddressBook previousAddressBook; /** * Initializes a ModelManager with the given AddressBook @@ -606,6 +672,7 @@ public class MainApp extends Application { addressBook = new AddressBook(src); filteredTasks = new FilteredList<>(addressBook.getTasks()); + previousAddressBook = new AddressBook(addressBook); } public ModelManager() { @@ -615,14 +682,14 @@ public class MainApp extends Application { public ModelManager(ReadOnlyAddressBook initialData, UserPrefs userPrefs) { addressBook = new AddressBook(initialData); filteredTasks = new FilteredList<>(addressBook.getTasks()); + previousAddressBook = new AddressBook(addressBook); } - @Override - public void resetData(ReadOnlyAddressBook newData) { + private void resetData(ReadOnlyAddressBook newData) { addressBook.resetData(newData); indicateAddressBookChanged(); } - + @Override public ReadOnlyAddressBook getAddressBook() { return addressBook; @@ -632,15 +699,35 @@ public class MainApp extends Application { private void indicateAddressBookChanged() { raise(new AddressBookChangedEvent(addressBook)); } + + private void savePreviousAddressBook() { + previousAddressBook = new AddressBook(addressBook); + } + + @Override + public void undoAddressBookChange() { + resetData(previousAddressBook); + } @Override public synchronized void deleteTask(ReadOnlyTask target) throws TaskNotFoundException { + savePreviousAddressBook(); addressBook.removeTask(target); indicateAddressBookChanged(); } - + + @Override + public synchronized void doneTask(int targetIndex, Task task) throws TaskNotFoundException { + savePreviousAddressBook(); + System.out.println("in model manager"); + addressBook.doneTask(targetIndex, task); + updateFilteredListToShowAll(); + indicateAddressBookChanged(); + } + @Override public synchronized void addTask(Task task) throws UniqueTaskList.DuplicateTaskException { + savePreviousAddressBook(); addressBook.addTask(task); updateFilteredListToShowAll(); indicateAddressBookChanged(); @@ -658,7 +745,27 @@ public class MainApp extends Application { @Override public void updateFilteredListToShowAll() { - filteredTasks.setPredicate(null); + updateFilteredListToShowAll(new PredicateExpression(new RemoveDoneQualifier())); + System.out.println("show all"); + } + + private void updateFilteredListToShowAll(Expression expression) { + filteredTasks.setPredicate(expression::satisfies); + } + + @Override + public void updateFilteredListToShowRemoved() { + updateFilteredListToShowRemoved(new PredicateExpression(new DoneQualifier())); + System.out.println("show done list"); + } + + private void updateFilteredListToShowRemoved(Expression expression) { + filteredTasks.setPredicate(expression::satisfies); + } + + @Override + public void updateFilteredTaskList(Set keywordSet) { + updateFilteredTaskList(new PredicateExpression(new NameQualifier(keywordSet))); } @Override @@ -667,8 +774,8 @@ public class MainApp extends Application { } @Override - public void updateFilteredTaskList(Set keywordSet) { - updateFilteredTaskList(new PredicateExpression(new NameQualifier(keywordSet))); + public void updateFilteredTaskList(String keywords, String cmd) { + updateFilteredTaskList(new PredicateExpression(new otherFieldsQualifier(keywords, cmd))); } private void updateFilteredTaskList(Expression expression) { @@ -715,10 +822,10 @@ public class MainApp extends Application { @Override public boolean run(ReadOnlyTask task) { - return keywordSet.stream() - .filter(keyword -> StringUtil.containsIgnoreCase(task.getName().fullName, keyword)) - .findAny() - .isPresent(); + return keywordSet.stream() + .filter(keyword -> StringUtil.containsIgnoreCase(task.getName().fullName, keyword)) + .findAny() + .isPresent(); } @Override @@ -727,6 +834,64 @@ public class MainApp extends Application { } } + private class otherFieldsQualifier implements Qualifier { + protected String nameKeyWords; + protected String cmd; + + otherFieldsQualifier(String keywords, String cmd) { + this.nameKeyWords = keywords; + this.cmd = cmd; + } + + @Override + public boolean run(ReadOnlyTask task) { + if (cmd == "address") { + System.out.println("finding address.."); + String address = task.getAddress().toString().toLowerCase(); + boolean addressMatch = address.contains(nameKeyWords.toLowerCase()); + return addressMatch; + } else if (cmd == "priority") { + System.out.println("finding priority.."); + String priority = task.getPriority().toString(); + boolean priorityMatch = priority.contains(nameKeyWords); + return priorityMatch; + } else if (cmd == "dueDate") { + System.out.println("finding dueDate.."); + String dueDate = task.getDueDate().toString(); + boolean dueDateMatch = dueDate.contains(nameKeyWords); + return dueDateMatch; + } else if (cmd == "tagArguments") { + System.out.println("finding tags.. "); + UniqueTagList tagsList = task.getTags(); + boolean tagsMatch = tagsList.containSearch(nameKeyWords.toLowerCase()); + return tagsMatch; + } + + // cmd == "nil" + + String taskFullNameLowerCase = task.getName().fullName.toLowerCase(); + String priority = task.getPriority().toString(); + String address = task.getAddress().toString().toLowerCase(); + String dueDate = task.getDueDate().toString(); + UniqueTagList tagsList = task.getTags(); + + boolean nameMatch = taskFullNameLowerCase.contains(nameKeyWords.toLowerCase()); + boolean addressMatch = address.contains(nameKeyWords.toLowerCase()); + boolean priorityMatch = priority.contains(nameKeyWords); + boolean dueDateMatch = dueDate.contains(nameKeyWords); + boolean tagsMatch = tagsList.containSearch(nameKeyWords.toLowerCase()); + boolean eachWordMatch = false; + + String[] eachWord = nameKeyWords.split(" "); + for (String word : eachWord) { + System.out.println("each: " + word); + eachWordMatch = eachWordMatch || taskFullNameLowerCase.contains(word.toLowerCase()); + } + + return eachWordMatch || nameMatch || addressMatch || priorityMatch || dueDateMatch || tagsMatch; + } + } + private class orderedNameQualifier extends NameQualifier implements Qualifier { private String nameKeyWords; @@ -738,14 +903,36 @@ public class MainApp extends Application { @Override public boolean run(ReadOnlyTask task) { String taskFullNameLowerCase = task.getName().fullName.toLowerCase(); - boolean orderMatch = taskFullNameLowerCase.contains(nameKeyWords.toLowerCase()); + boolean nameMatch = taskFullNameLowerCase.contains(nameKeyWords.toLowerCase()); boolean eachWordMatch = keywordSet.stream() .filter(keyword -> StringUtil.containsIgnoreCase(task.getName().fullName, keyword)) .findAny() .isPresent(); - - return eachWordMatch && orderMatch; + return eachWordMatch && nameMatch; + } + } + + // to check and return a list of tasks that are already done + private class DoneQualifier implements Qualifier { + + DoneQualifier() {} + + @Override + public boolean run(ReadOnlyTask task) { + return task.getisDone(); + } + } + + // default display tasks that are not yet done + private class RemoveDoneQualifier implements Qualifier { + + RemoveDoneQualifier() {} + + @Override + public boolean run(ReadOnlyTask task) { + System.out.println(task.getName()); + return !task.getisDone(); } } } @@ -1088,7 +1275,7 @@ public class MainApp extends Application { List taskList = helper.generateTaskList(2); // set AB state to 2 tasks - model.resetData(new AddressBook()); + model.clearTaskList(); for (Task p : taskList) { model.addTask(p); } diff --git a/src/main/java/seedu/gtd/commons/core/ComponentManager.java b/src/main/java/seedu/gtd/commons/core/ComponentManager.java index b060116d9461..1b0561e20d5c 100644 --- a/src/main/java/seedu/gtd/commons/core/ComponentManager.java +++ b/src/main/java/seedu/gtd/commons/core/ComponentManager.java @@ -27,4 +27,9 @@ public ComponentManager(EventsCenter eventsCenter) { protected void raise(BaseEvent event){ eventsCenter.post(event); } + + public void updateFilteredListToShowRemoved() { + // TODO Auto-generated method stub + + } } diff --git a/src/main/java/seedu/gtd/logic/commands/ClearCommand.java b/src/main/java/seedu/gtd/logic/commands/ClearCommand.java index 91ec6ad13767..7689aeadc00c 100644 --- a/src/main/java/seedu/gtd/logic/commands/ClearCommand.java +++ b/src/main/java/seedu/gtd/logic/commands/ClearCommand.java @@ -17,7 +17,7 @@ public ClearCommand() {} @Override public CommandResult execute() { assert model != null; - model.resetData(AddressBook.getEmptyAddressBook()); + model.clearTaskList(); return new CommandResult(MESSAGE_SUCCESS); } } diff --git a/src/main/java/seedu/gtd/logic/commands/DoneCommand.java b/src/main/java/seedu/gtd/logic/commands/DoneCommand.java new file mode 100644 index 000000000000..03fc01b26c9c --- /dev/null +++ b/src/main/java/seedu/gtd/logic/commands/DoneCommand.java @@ -0,0 +1,70 @@ +package seedu.gtd.logic.commands; + +import seedu.gtd.commons.core.Messages; +import seedu.gtd.commons.core.UnmodifiableObservableList; +import seedu.gtd.commons.exceptions.IllegalValueException; +import seedu.gtd.model.task.ReadOnlyTask; +import seedu.gtd.model.task.Task; +import seedu.gtd.model.task.UniqueTaskList.TaskNotFoundException; + +/** + * Mark a task as done, identified using it's last displayed index from the address book. + */ +public class DoneCommand extends Command { + + public static final String COMMAND_WORD = "done"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + + ": Marks a task as done, by the index number used in the last task listing.\n" + + "Parameters: INDEX (must be a positive integer)\n" + + "Example: " + COMMAND_WORD + " 1"; + + public static final String MESSAGE_DONE_TASK_SUCCESS = "Done Task: %1$s"; + + public final int targetIndex; + + public DoneCommand(int targetIndex) { + this.targetIndex = targetIndex; + } + + + @Override + public CommandResult execute() { + + UnmodifiableObservableList lastShownList = model.getFilteredTaskList(); + + if (lastShownList.size() < targetIndex) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX); + } + + ReadOnlyTask toEdit = lastShownList.get(targetIndex-1); + Task taskToUpdate = new Task(toEdit); + + try { + taskToUpdate = updateTask(taskToUpdate, "done", "true"); + System.out.println("IS IT DONE? " + taskToUpdate.getisDone()); + } catch (IllegalValueException ive) { + return new CommandResult(ive.getMessage()); + } + + assert model != null; + try { + System.out.println("in donecommand.java"); + System.out.println(taskToUpdate.getName() + " " + taskToUpdate.getisDone()); + System.out.println("index at donecommand:" + targetIndex); + model.doneTask(targetIndex-1, taskToUpdate); + + } catch (TaskNotFoundException e) { + assert false : "The target task cannot be missing"; + } + return new CommandResult(String.format(MESSAGE_DONE_TASK_SUCCESS, taskToUpdate)); + + } + + private Task updateTask(Task taskToUpdate, String detailType, String newDetail) throws IllegalValueException { + taskToUpdate.edit(detailType, newDetail); + return taskToUpdate; + } + +} diff --git a/src/main/java/seedu/gtd/logic/commands/ListCommand.java b/src/main/java/seedu/gtd/logic/commands/ListCommand.java index c887f37c3849..62a8fdd111ab 100644 --- a/src/main/java/seedu/gtd/logic/commands/ListCommand.java +++ b/src/main/java/seedu/gtd/logic/commands/ListCommand.java @@ -9,12 +9,21 @@ public class ListCommand extends Command { public static final String COMMAND_WORD = "list"; public static final String MESSAGE_USAGE = COMMAND_WORD + ": Shows a list of all tasks in the task list."; public static final String MESSAGE_SUCCESS = "Listed all tasks"; - - public ListCommand() {} + private String arg; + + public ListCommand(String arg) { + this.arg = arg; + } @Override public CommandResult execute() { - model.updateFilteredListToShowAll(); + System.out.println("args:" + arg); + if (arg.equals(" done")) { + System.out.println("in done"); + model.updateFilteredListToShowRemoved(); + } else { + model.updateFilteredListToShowAll(); + } return new CommandResult(MESSAGE_SUCCESS); } } diff --git a/src/main/java/seedu/gtd/logic/commands/UndoCommand.java b/src/main/java/seedu/gtd/logic/commands/UndoCommand.java new file mode 100644 index 000000000000..48cb8fe8b1d6 --- /dev/null +++ b/src/main/java/seedu/gtd/logic/commands/UndoCommand.java @@ -0,0 +1,23 @@ +//@@author A0146130W + +package seedu.gtd.logic.commands; + +/** + * Deletes a task identified using it's last displayed index from the address book. + */ +public class UndoCommand extends Command { + + public static final String COMMAND_WORD = "undo"; + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Un-does the most recent modification of the task list."; + public static final String MESSAGE_SUCCESS = "Undo change"; + public static final String MESSAGE_UNDO_LIMIT_REACHED = "Undo limit reached!"; + + public UndoCommand() {} + + @Override + public CommandResult execute() { + if(model.undoAddressBookChange()) return new CommandResult(MESSAGE_SUCCESS); + else return new CommandResult(MESSAGE_UNDO_LIMIT_REACHED); + } + +} \ No newline at end of file diff --git a/src/main/java/seedu/gtd/logic/parser/Parser.java b/src/main/java/seedu/gtd/logic/parser/Parser.java index df231533d940..ef24c3577d7d 100644 --- a/src/main/java/seedu/gtd/logic/parser/Parser.java +++ b/src/main/java/seedu/gtd/logic/parser/Parser.java @@ -35,19 +35,19 @@ public class Parser { // + "(?(?: t/[^/]+)*)"); // variable number of tags private static final Pattern NAME_TASK_DATA_ARGS_FORMAT = - Pattern.compile("(?[^/]+) (t|p|a|d|e)/.*"); + Pattern.compile("(?[^/]+) (t|p|a|d|z)/.*"); private static final Pattern PRIORITY_TASK_DATA_ARGS_FORMAT = - Pattern.compile(".* p/(?[^/]+) (t|a|d|e)/.*"); + Pattern.compile(".* p/(?[^/]+) (t|a|d|z)/.*"); private static final Pattern ADDRESS_TASK_DATA_ARGS_FORMAT = - Pattern.compile(".* a/(?
[^/]+) (t|p|d|e)/.*"); + Pattern.compile(".* a/(?
[^/]+) (t|p|d|z)/.*"); private static final Pattern DUEDATE_TASK_DATA_ARGS_FORMAT = - Pattern.compile(".* d/(?[^/]+) (t|a|p|e)/.*"); + Pattern.compile(".* d/(?[^/]+) (t|a|p|z)/.*"); private static final Pattern TAGS_TASK_DATA_ARGS_FORMAT = - Pattern.compile(".* t/(?[^/]+) (d|a|p|e)/.*"); + Pattern.compile(".* t/(?[^/]+) (d|a|p|z)/.*"); private static final Pattern EDIT_DATA_ARGS_FORMAT = Pattern.compile("(?\\S+)" @@ -82,6 +82,9 @@ public Command parseCommand(String userInput) { case DeleteCommand.COMMAND_WORD: return prepareDelete(arguments); + + case DoneCommand.COMMAND_WORD: + return prepareDone(arguments); case ClearCommand.COMMAND_WORD: return new ClearCommand(); @@ -90,13 +93,16 @@ public Command parseCommand(String userInput) { return prepareFind(arguments); case ListCommand.COMMAND_WORD: - return new ListCommand(); + return prepareList(arguments); case ExitCommand.COMMAND_WORD: return new ExitCommand(); case HelpCommand.COMMAND_WORD: return prepareHelp(arguments); + + case UndoCommand.COMMAND_WORD: + return new UndoCommand(); default: return new IncorrectCommand(MESSAGE_UNKNOWN_COMMAND); @@ -154,7 +160,7 @@ private Command prepareAdd(String args){ } private String appendEnd(String args) { - return args + " e/"; + return args + " z/"; } private String checkEmptyAndAddDefault(Matcher matcher, String groupName, String defaultValue) { @@ -260,6 +266,18 @@ private Command prepareDelete(String args) { return new DeleteCommand(index.get()); } + + private Command prepareDone(String args) { + + Optional index = parseIndex(args); + System.out.println("index at preparedone:" + index.get()); + if(!index.isPresent()){ + return new IncorrectCommand( + String.format(MESSAGE_INVALID_COMMAND_FORMAT, DoneCommand.MESSAGE_USAGE)); + } + + return new DoneCommand(index.get()); + } /** * Parses arguments in the context of the select task command. @@ -346,6 +364,14 @@ private Command prepareFind(String args) { final String keywords = matcher.group("keywords"); return new FindCommand(keywords, keywordSet, "nil"); } + +private Command prepareList(String args) { + + // check if parameters are specified and pass specified field to FindCommand + + //String preprocessedArgs = " " + appendEnd(args.trim()); + return new ListCommand(args); +} /** * Parses arguments in the context of the help command. diff --git a/src/main/java/seedu/gtd/model/AddressBook.java b/src/main/java/seedu/gtd/model/AddressBook.java index 7a3870ad77fa..0679722d8926 100644 --- a/src/main/java/seedu/gtd/model/AddressBook.java +++ b/src/main/java/seedu/gtd/model/AddressBook.java @@ -6,6 +6,7 @@ import seedu.gtd.model.task.ReadOnlyTask; import seedu.gtd.model.task.Task; import seedu.gtd.model.task.UniqueTaskList; +import seedu.gtd.model.task.UniqueTaskList.TaskNotFoundException; import java.util.*; import java.util.stream.Collectors; @@ -32,6 +33,7 @@ public AddressBook() {} */ public AddressBook(ReadOnlyAddressBook toBeCopied) { this(toBeCopied.getUniqueTaskList(), toBeCopied.getUniqueTagList()); + System.out.println("start with first method"); } /** @@ -39,6 +41,7 @@ public AddressBook(ReadOnlyAddressBook toBeCopied) { */ public AddressBook(UniqueTaskList tasks, UniqueTagList tags) { resetData(tasks.getInternalList(), tags.getInternalList()); + System.out.println("start with second method"); } public static ReadOnlyAddressBook getEmptyAddressBook() { @@ -126,6 +129,11 @@ public boolean removeTask(ReadOnlyTask key) throws UniqueTaskList.TaskNotFoundEx throw new UniqueTaskList.TaskNotFoundException(); } } + + public void doneTask(int index, Task target) throws TaskNotFoundException { + System.out.println("in addressbook"); + tasks.done(index, target); + } //// tag-level operations @@ -145,7 +153,7 @@ public String toString() { public List getTaskList() { return Collections.unmodifiableList(tasks.getInternalList()); } - + @Override public List getTagList() { return Collections.unmodifiableList(tags.getInternalList()); diff --git a/src/main/java/seedu/gtd/model/Model.java b/src/main/java/seedu/gtd/model/Model.java index 543e8bc4c1bc..80d2d050f0d0 100644 --- a/src/main/java/seedu/gtd/model/Model.java +++ b/src/main/java/seedu/gtd/model/Model.java @@ -11,14 +11,14 @@ * The API of the Model component. */ public interface Model { - /** Clears existing backing model and replaces with the provided new data. */ - void resetData(ReadOnlyAddressBook newData); - /** Returns the AddressBook */ ReadOnlyAddressBook getAddressBook(); /** Deletes the given task. */ void deleteTask(ReadOnlyTask target) throws UniqueTaskList.TaskNotFoundException; + + /** Marks the given task as done. */ + void doneTask(int targetIndex, Task target) throws UniqueTaskList.TaskNotFoundException; /** Adds the given task */ void addTask(Task task) throws UniqueTaskList.DuplicateTaskException; @@ -31,6 +31,9 @@ public interface Model { /** Updates the filter of the filtered task list to show all tasks */ void updateFilteredListToShowAll(); + + /** Updates the filter of the filtered task list to show all tasks */ + void updateFilteredListToShowRemoved(); /** Updates the filter of the filtered task list to filter by the given exact phrase * @param keywordSet */ @@ -41,4 +44,11 @@ public interface Model { /** Updates the filter of the filtered task list to filter by the right parameter*/ void updateFilteredTaskList(String keywords, String cmd); + + /** Un-does a change to the AddressBook + * @return true if undo command was effective or false if undo is not possible, i.e the stack of previous task list states is empty */ + boolean undoAddressBookChange(); + + /** Clears all tasks */ + void clearTaskList(); } diff --git a/src/main/java/seedu/gtd/model/ModelManager.java b/src/main/java/seedu/gtd/model/ModelManager.java index 7262ebfaf20a..c9b07f935eea 100644 --- a/src/main/java/seedu/gtd/model/ModelManager.java +++ b/src/main/java/seedu/gtd/model/ModelManager.java @@ -15,6 +15,7 @@ import java.util.Arrays; import java.util.Set; +import java.util.Stack; import java.util.logging.Logger; /** @@ -26,8 +27,9 @@ public class ModelManager extends ComponentManager implements Model { private static final Logger logger = LogsCenter.getLogger(ModelManager.class); - private final AddressBook addressBook; + private AddressBook addressBook; private final FilteredList filteredTasks; + private Stack previousAddressBook; /** * Initializes a ModelManager with the given AddressBook @@ -42,6 +44,8 @@ public ModelManager(AddressBook src, UserPrefs userPrefs) { addressBook = new AddressBook(src); filteredTasks = new FilteredList<>(addressBook.getTasks()); + previousAddressBook = new Stack(); + previousAddressBook.push(new AddressBook(addressBook)); } public ModelManager() { @@ -51,14 +55,15 @@ public ModelManager() { public ModelManager(ReadOnlyAddressBook initialData, UserPrefs userPrefs) { addressBook = new AddressBook(initialData); filteredTasks = new FilteredList<>(addressBook.getTasks()); + previousAddressBook = new Stack(); + previousAddressBook.push(new AddressBook(addressBook)); } - @Override - public void resetData(ReadOnlyAddressBook newData) { + private void resetData(ReadOnlyAddressBook newData) { addressBook.resetData(newData); indicateAddressBookChanged(); } - + @Override public ReadOnlyAddressBook getAddressBook() { return addressBook; @@ -68,15 +73,41 @@ public ReadOnlyAddressBook getAddressBook() { private void indicateAddressBookChanged() { raise(new AddressBookChangedEvent(addressBook)); } + + private void savePreviousAddressBook() { + previousAddressBook.push(new AddressBook(addressBook)); + } + + @Override + public boolean undoAddressBookChange() { + if(previousAddressBook.isEmpty()) { + return false; + } + else{ + resetData(previousAddressBook.pop()); + return true; + } + } @Override public synchronized void deleteTask(ReadOnlyTask target) throws TaskNotFoundException { + savePreviousAddressBook(); addressBook.removeTask(target); indicateAddressBookChanged(); } - + + @Override + public synchronized void doneTask(int targetIndex, Task task) throws TaskNotFoundException { + savePreviousAddressBook(); + System.out.println("in model manager"); + addressBook.doneTask(targetIndex, task); + updateFilteredListToShowAll(); + indicateAddressBookChanged(); + } + @Override public synchronized void addTask(Task task) throws UniqueTaskList.DuplicateTaskException { + savePreviousAddressBook(); addressBook.addTask(task); updateFilteredListToShowAll(); indicateAddressBookChanged(); @@ -85,11 +116,19 @@ public synchronized void addTask(Task task) throws UniqueTaskList.DuplicateTaskE //@@author A0146130W @Override public synchronized void editTask(int targetIndex, Task task) throws TaskNotFoundException { + savePreviousAddressBook(); + System.out.println("editing task.."); addressBook.editTask(targetIndex, task); updateFilteredListToShowAll(); indicateAddressBookChanged(); } + @Override + public void clearTaskList() { + savePreviousAddressBook(); + resetData(AddressBook.getEmptyAddressBook()); + } + //@@author addressbook-level4 //=========== Filtered Task List Accessors =============================================================== @@ -100,7 +139,22 @@ public UnmodifiableObservableList getFilteredTaskList() { @Override public void updateFilteredListToShowAll() { - filteredTasks.setPredicate(null); + updateFilteredListToShowAll(new PredicateExpression(new RemoveDoneQualifier())); + System.out.println("show all"); + } + + private void updateFilteredListToShowAll(Expression expression) { + filteredTasks.setPredicate(expression::satisfies); + } + + @Override + public void updateFilteredListToShowRemoved() { + updateFilteredListToShowRemoved(new PredicateExpression(new DoneQualifier())); + System.out.println("show done list"); + } + + private void updateFilteredListToShowRemoved(Expression expression) { + filteredTasks.setPredicate(expression::satisfies); } @Override @@ -252,4 +306,27 @@ public boolean run(ReadOnlyTask task) { return eachWordMatch && nameMatch; } } + + // to check and return a list of tasks that are already done + private class DoneQualifier implements Qualifier { + + DoneQualifier() {} + + @Override + public boolean run(ReadOnlyTask task) { + return task.getisDone(); + } + } + + // default display tasks that are not yet done + private class RemoveDoneQualifier implements Qualifier { + + RemoveDoneQualifier() {} + + @Override + public boolean run(ReadOnlyTask task) { + System.out.println(task.getName()); + return !task.getisDone(); + } + } } diff --git a/src/main/java/seedu/gtd/model/task/ReadOnlyTask.java b/src/main/java/seedu/gtd/model/task/ReadOnlyTask.java index 90a2a3b5aba6..6f18661b506c 100644 --- a/src/main/java/seedu/gtd/model/task/ReadOnlyTask.java +++ b/src/main/java/seedu/gtd/model/task/ReadOnlyTask.java @@ -12,6 +12,7 @@ public interface ReadOnlyTask { DueDate getDueDate(); Address getAddress(); Priority getPriority(); + boolean getisDone(); /** * The returned TagList is a deep copy of the internal TagList, @@ -55,4 +56,5 @@ default String tagsString() { return buffer.substring(0, buffer.length() - separator.length()); } } + } diff --git a/src/main/java/seedu/gtd/model/task/Task.java b/src/main/java/seedu/gtd/model/task/Task.java index 97b0121d0c64..c0a6dfc0e68f 100644 --- a/src/main/java/seedu/gtd/model/task/Task.java +++ b/src/main/java/seedu/gtd/model/task/Task.java @@ -15,14 +15,27 @@ public class Task implements ReadOnlyTask { private Name name; private DueDate dueDate; + private DueDate startDate; + private DueDate endDate; private Address address; private Priority priority; + private boolean isDone; private UniqueTagList tags; /** * Every field must be present and not null. */ + public Task(Name name, DueDate dueDate, Address address, Priority priority, UniqueTagList tags, boolean isDone) { + assert !CollectionUtil.isAnyNull(name, dueDate, address, priority, tags); + this.name = name; + this.dueDate = dueDate; + this.address = address; + this.priority = priority; + this.tags = new UniqueTagList(tags); // protect internal tags from changes in the arg list + this.isDone = isDone; + } + public Task(Name name, DueDate dueDate, Address address, Priority priority, UniqueTagList tags) { assert !CollectionUtil.isAnyNull(name, dueDate, address, priority, tags); this.name = name; @@ -30,6 +43,7 @@ public Task(Name name, DueDate dueDate, Address address, Priority priority, Uniq this.address = address; this.priority = priority; this.tags = new UniqueTagList(tags); // protect internal tags from changes in the arg list + this.isDone = false; } /** @@ -58,6 +72,11 @@ public Address getAddress() { public Priority getPriority() { return priority; } + + @Override + public boolean getisDone() { + return isDone; + } @Override public UniqueTagList getTags() { @@ -80,12 +99,17 @@ public void setPriority(Priority priority) { this.priority = priority; } + public void setisDone(boolean isdone) { + this.isDone = isdone; + } + public void edit(String detailType, String newDetail) throws IllegalValueException { switch(detailType) { case "dueDate": setDueDate(new DueDate(newDetail)); break; case "address": setAddress(new Address(newDetail)); break; case "priority": setPriority(new Priority(newDetail)); break; + case "done": setisDone(true); break; default: setName(new Name(newDetail)); } } diff --git a/src/main/java/seedu/gtd/model/task/UniqueTaskList.java b/src/main/java/seedu/gtd/model/task/UniqueTaskList.java index f0e977f275ee..76645f087dc7 100644 --- a/src/main/java/seedu/gtd/model/task/UniqueTaskList.java +++ b/src/main/java/seedu/gtd/model/task/UniqueTaskList.java @@ -74,6 +74,18 @@ public void edit(int targetIndex, Task toEdit) throws TaskNotFoundException { internalList.set(targetIndex, toEdit); } + public void done(int targetIndex, Task taskdone) throws TaskNotFoundException { + System.out.println("in uniquetasklist"); + System.out.println(taskdone.getName() + " " + taskdone.getisDone()); + System.out.println("index at final:" + targetIndex); + assert taskdone != null; + if (invalidIndex(targetIndex)) { + throw new TaskNotFoundException(); + } + System.out.println("marked done in model"); + internalList.set(targetIndex, taskdone); + } + private boolean invalidIndex(int i) { if(i < 0 || i >= internalList.size()) return true; return false; diff --git a/src/main/java/seedu/gtd/storage/XmlAdaptedTask.java b/src/main/java/seedu/gtd/storage/XmlAdaptedTask.java index 48117b44e48e..9c041c345ee5 100644 --- a/src/main/java/seedu/gtd/storage/XmlAdaptedTask.java +++ b/src/main/java/seedu/gtd/storage/XmlAdaptedTask.java @@ -23,6 +23,8 @@ public class XmlAdaptedTask { private String address; @XmlElement(required = true) private String priority; + @XmlElement(required = true) + private boolean isDone; @XmlElement private List tagged = new ArrayList<>(); @@ -43,6 +45,7 @@ public XmlAdaptedTask(ReadOnlyTask source) { dueDate = source.getDueDate().value; address = source.getAddress().value; priority = source.getPriority().value; + isDone = source.getisDone(); tagged = new ArrayList<>(); for (Tag tag : source.getTags()) { tagged.add(new XmlAdaptedTag(tag)); @@ -63,7 +66,8 @@ public Task toModelType() throws IllegalValueException { final DueDate dueDate = new DueDate(this.dueDate); final Address address = new Address(this.address); final Priority priority = new Priority(this.priority); + final boolean isDone = this.isDone; final UniqueTagList tags = new UniqueTagList(taskTags); - return new Task(name, dueDate, address, priority, tags); + return new Task(name, dueDate, address, priority, tags, isDone); } } diff --git a/src/test/java/guitests/EditCommandTest.java b/src/test/java/guitests/EditCommandTest.java index f2eb71b15f29..bf16e9083dad 100644 --- a/src/test/java/guitests/EditCommandTest.java +++ b/src/test/java/guitests/EditCommandTest.java @@ -45,9 +45,9 @@ public void edit() { } /** - * Runs the delete command to delete the task at specified index and confirms the result is correct. - * @param targetIndexOneIndexed e.g. to delete the first task in the list, 1 should be given as the target index. - * @param currentList A copy of the current list of tasks (before deletion). + * Runs the edit command to edit the task at specified index and confirms the result is correct. + * @param targetIndexOneIndexed e.g. to edit the first task in the list, 1 should be given as the target index. + * @param currentList A copy of the current list of tasks (before editing). */ private void assertEditSuccess(int targetIndexOneIndexed, String change, final TestTask[] currentList) { TestTask taskToEdit = currentList[targetIndexOneIndexed-1]; //-1 because array uses zero indexing diff --git a/src/test/java/guitests/UndoCommandTest.java b/src/test/java/guitests/UndoCommandTest.java new file mode 100644 index 000000000000..2e691df10c31 --- /dev/null +++ b/src/test/java/guitests/UndoCommandTest.java @@ -0,0 +1,93 @@ +//@@author A0146130W + +package guitests; + +import org.junit.Test; + +import seedu.gtd.testutil.TestTask; + +import static org.junit.Assert.assertTrue; +import static seedu.gtd.logic.commands.UndoCommand.MESSAGE_SUCCESS; +import static seedu.gtd.logic.commands.UndoCommand.MESSAGE_UNDO_LIMIT_REACHED; + +import java.util.Stack;; + +public class UndoCommandTest extends AddressBookGuiTest { + + @Test + public void undo() { + + //undo the addition of the first task + TestTask[] currentList = td.getTypicalTasks(); + Stack previousList = new Stack(); + previousList.push(currentList); + commandBox.runCommand(td.george.getAddCommand()); + assertUndoSuccess(previousList.pop()); + + //undo editing the dueDate of the last task in the list + int targetIndex = currentList.length; + String change = "d/2"; + previousList.push(currentList); + commandBox.runCommand("edit " + targetIndex + " " + change); + assertUndoSuccess(previousList.pop()); + + //undo deleting a task from the middle of the list + targetIndex = currentList.length/2; + previousList.push(currentList); + commandBox.runCommand("delete " + targetIndex); + assertUndoSuccess(previousList.pop()); + + //undo clearing list + previousList.push(currentList); + commandBox.runCommand("clear"); + assertUndoSuccess(previousList.pop()); + + //undo marking the middle task as done + previousList.push(currentList); + commandBox.runCommand("done " + targetIndex); + assertUndoSuccess(previousList.pop()); + + /* + //undo multiple times + previousList.push(currentList); + commandBox.runCommand("edit " + targetIndex + " " + change); + previousList.push(currentList); + commandBox.runCommand(td.george.getAddCommand()); + previousList.push(currentList); + commandBox.runCommand("delete " + targetIndex); + previousList.push(currentList); + commandBox.runCommand("done " + targetIndex); + previousList.push(currentList); + commandBox.runCommand("clear"); + assertMultipleUndoSuccess(previousList); + */ + } + + /** + * Runs the undo command to undo the last change to the task list + */ + private void assertUndoSuccess(final TestTask[] previousList) { + commandBox.runCommand("undo"); + + //confirm the list now contains all previous tasks except the deleted task + assertTrue(taskListPanel.isListMatching(previousList)); + + //confirm the result message is correct + assertResultMessage(String.format(MESSAGE_SUCCESS)); + } + + private void assertMultipleUndoSuccess(final Stack previousList) { + + //run undo multiple times and verify list each time + for(int i=1; i < previousList.size(); i++) { + commandBox.runCommand("undo"); + assertTrue(taskListPanel.isListMatching(previousList.pop())); + assertResultMessage(String.format(MESSAGE_SUCCESS)); + } + + //verify that the undo limit message is shown when undo limit is reached + commandBox.runCommand("undo"); + assertResultMessage(String.format(MESSAGE_UNDO_LIMIT_REACHED)); + } + +} diff --git a/src/test/java/seedu/gtd/logic/LogicManagerTest.java b/src/test/java/seedu/gtd/logic/LogicManagerTest.java index 71889d47fe0c..57d476796a59 100644 --- a/src/test/java/seedu/gtd/logic/LogicManagerTest.java +++ b/src/test/java/seedu/gtd/logic/LogicManagerTest.java @@ -303,7 +303,7 @@ private void assertIndexNotFoundBehaviorForCommand(String commandWord) throws Ex List taskList = helper.generateTaskList(2); // set AB state to 2 tasks - model.resetData(new AddressBook()); + model.clearTaskList(); for (Task p : taskList) { model.addTask(p); } diff --git a/src/test/java/seedu/gtd/testutil/TestTask.java b/src/test/java/seedu/gtd/testutil/TestTask.java index a983ef564eff..2736b4090271 100644 --- a/src/test/java/seedu/gtd/testutil/TestTask.java +++ b/src/test/java/seedu/gtd/testutil/TestTask.java @@ -13,6 +13,7 @@ public class TestTask implements ReadOnlyTask { private Address address; private Priority priority; private UniqueTagList tags; + private boolean isDone; public TestTask() { tags = new UniqueTagList(); @@ -23,6 +24,7 @@ public TestTask(Name name, DueDate dueDate, Address address, Priority priority, this.dueDate = dueDate; this.address = address; this.priority = priority; + this.isDone = false; this.tags = new UniqueTagList(tags); // protect internal tags from changes in the arg list } @@ -51,6 +53,11 @@ public Name getName() { public DueDate getDueDate() { return dueDate; } + + @Override + public boolean getisDone() { + return isDone; + } @Override public Address getAddress() {