Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add user prompting feature (#150) #21

Merged
merged 1 commit into from
Oct 31, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/main/java/tagline/logic/Logic.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package tagline.logic;

import java.nio.file.Path;
import java.util.List;

import javafx.collections.ObservableList;
import tagline.commons.core.GuiSettings;
import tagline.logic.commands.CommandResult;
import tagline.logic.commands.exceptions.CommandException;
import tagline.logic.parser.Prompt;
import tagline.logic.parser.exceptions.ParseException;
import tagline.model.contact.Contact;
import tagline.model.contact.ReadOnlyAddressBook;
Expand All @@ -30,6 +32,13 @@ public interface Logic {
*/
CommandResult execute(String commandText) throws CommandException, ParseException;

/**
* Executes the command with some additional prompts.
*
* @see Logic#execute(String).
*/
CommandResult execute(String commandText, List<Prompt> filledPrompts) throws CommandException, ParseException;

/**
* Returns the address book.
*
Expand Down
22 changes: 22 additions & 0 deletions src/main/java/tagline/logic/LogicManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.io.IOException;
import java.nio.file.Path;
import java.util.List;
import java.util.logging.Logger;

import javafx.collections.ObservableList;
Expand All @@ -10,6 +11,7 @@
import tagline.logic.commands.Command;
import tagline.logic.commands.CommandResult;
import tagline.logic.commands.exceptions.CommandException;
import tagline.logic.parser.Prompt;
import tagline.logic.parser.TaglineParser;
import tagline.logic.parser.exceptions.ParseException;
import tagline.model.Model;
Expand Down Expand Up @@ -60,6 +62,26 @@ public CommandResult execute(String commandText) throws CommandException, ParseE
return commandResult;
}

@Override
public CommandResult execute(String commandText, List<Prompt> filledPrompts)
throws CommandException, ParseException {
logger.info("----------------[USER COMMAND][" + commandText + "]");

CommandResult commandResult;
Command command = taglineParser.parseCommand(commandText, filledPrompts);
commandResult = command.execute(model);

try {
storage.saveAddressBook(model.getAddressBook());
storage.saveNoteBook(model.getNoteBook());
storage.saveGroupBook(model.getGroupBook());
} catch (IOException ioe) {
throw new CommandException(FILE_OPS_ERROR_MESSAGE + ioe, ioe);
}

return commandResult;
}

@Override
public ReadOnlyAddressBook getAddressBook() {
return model.getAddressBook();
Expand Down
44 changes: 44 additions & 0 deletions src/main/java/tagline/logic/parser/ParserPromptHandlerUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package tagline.logic.parser;

import java.util.List;
import java.util.Optional;

/**
* A class containing utility static functions for parser classes when handling prompts.
*/
public class ParserPromptHandlerUtil {
/**
* Parses an argument {@code String} and a {@code List} of {@code Prompt} objects, to produce
* a {@code String} including the prompt responses.
*/
public static String getArgsWithFilledPrompts(String args, List<Prompt> filledPrompts) {
StringBuilder argsBuilder = new StringBuilder(args);
for (Prompt prompt : filledPrompts) {
if (prompt.getArgumentPrefix().isEmpty()) {
argsBuilder.insert(0, " ").insert(0, prompt.getPromptResponse());
} else {
argsBuilder.append(" ").append(prompt.getArgumentPrefix())
.append(" ").append(prompt.getPromptResponse());
}
}

return argsBuilder.toString();
}

/**
* Gets the response corresponding to an argument prefix from a list of {@code Prompt} objects.
* If no such prompt exists, returns an empty string.
*/
public static String getPromptResponseFromPrefix(String prefix, List<Prompt> filledPrompts) {
Optional<Prompt> promptWithPrefix = filledPrompts.stream()
.filter(prompt -> prompt.getArgumentPrefix().equals(prefix))
.findFirst();

//If empty, no prompt was given
if (!promptWithPrefix.isPresent()) {
return "";
}

return promptWithPrefix.get().getPromptResponse();
}
}
57 changes: 57 additions & 0 deletions src/main/java/tagline/logic/parser/Prompt.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package tagline.logic.parser;

import static tagline.commons.util.CollectionUtil.requireAllNonNull;

/**
* Represents a prompt requested by the parser for the user.
*/
public class Prompt {
private final String argumentPrefix;
private final String promptQuestion;
private String promptResponse;

public Prompt(String argumentPrefix, String promptQuestion) {
requireAllNonNull(argumentPrefix, promptQuestion);
this.argumentPrefix = argumentPrefix;
this.promptQuestion = promptQuestion;
this.promptResponse = ""; //default empty response
}

public String getPromptQuestion() {
return promptQuestion;
}

public String getPromptResponse() {
return promptResponse;
}

public String getArgumentPrefix() {
return argumentPrefix;
}

public void setPromptResponse(String promptResponse) {
this.promptResponse = promptResponse;
}

@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}

if (other instanceof Prompt) {
return argumentPrefix.equals(((Prompt) other).argumentPrefix)
&& promptQuestion.equals(((Prompt) other).promptQuestion)
&& promptResponse.equals(((Prompt) other).promptResponse);
}

return false;
}

@Override
public String toString() {
return new StringBuilder("Prefix: ").append(argumentPrefix)
.append(", Question: ").append(promptQuestion)
.append(", Response: ").append(promptResponse).toString();
}
}
40 changes: 40 additions & 0 deletions src/main/java/tagline/logic/parser/TaglineParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static tagline.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
import static tagline.commons.core.Messages.MESSAGE_UNKNOWN_COMMAND;

import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

Expand Down Expand Up @@ -69,4 +70,43 @@ public Command parseCommand(String userInput) throws ParseException {
}
}

/**
* Parses user input into command for execution, with a list of filled prompts.
*
* @param userInput full user input string
* @param filledPrompts list of filled prompts from the user
* @return the command based on the user input
* @throws ParseException if the user input does not conform the expected format
*/
public Command parseCommand(String userInput, List<Prompt> filledPrompts) throws ParseException {
final Matcher matcher = BASIC_COMMAND_FORMAT.matcher(userInput.trim());
if (!matcher.matches()) {
throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE));
}

final String commandKey = matcher.group("commandKey");
final String commandStr = matcher.group("commandStr");

switch (commandKey) {

case ContactCommand.COMMAND_KEY:
return new ContactCommandParser().parseCommand(commandStr, filledPrompts);

case NoteCommand.COMMAND_KEY:
return new NoteCommandParser().parseCommand(commandStr, filledPrompts);

case GroupCommand.COMMAND_KEY:
//Currently doesn't support prompts
return new GroupCommandParser().parseCommand(commandStr);

case ExitCommand.COMMAND_KEY:
return new ExitCommand();

case HelpCommand.COMMAND_KEY:
return new HelpCommand();

default:
throw new ParseException(MESSAGE_UNKNOWN_COMMAND);
}
}
}
16 changes: 16 additions & 0 deletions src/main/java/tagline/logic/parser/contact/AddContactParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,17 @@
import static tagline.logic.parser.contact.ContactCliSyntax.PREFIX_NAME;
import static tagline.logic.parser.contact.ContactCliSyntax.PREFIX_PHONE;

import java.util.Arrays;
import java.util.stream.Stream;

import tagline.logic.commands.contact.CreateContactCommand;
import tagline.logic.parser.ArgumentMultimap;
import tagline.logic.parser.ArgumentTokenizer;
import tagline.logic.parser.Parser;
import tagline.logic.parser.Prefix;
import tagline.logic.parser.Prompt;
import tagline.logic.parser.exceptions.ParseException;
import tagline.logic.parser.exceptions.PromptRequestException;
import tagline.model.contact.Address;
import tagline.model.contact.Contact;
import tagline.model.contact.Description;
Expand All @@ -37,6 +40,8 @@ public CreateContactCommand parse(String args) throws ParseException {
ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL,
PREFIX_ADDRESS, PREFIX_DESCRIPTION);

checkCompulsoryFields(argMultimap);

Name name;
Phone phone;
Email email;
Expand Down Expand Up @@ -78,6 +83,17 @@ public CreateContactCommand parse(String args) throws ParseException {
return new CreateContactCommand(contact);
}

/**
* Checks the compulsory fields of the command (i.e. name).
* @throws PromptRequestException if name is missing
*/
private void checkCompulsoryFields(ArgumentMultimap argMultimap) throws PromptRequestException {
if (!argMultimap.getValue(PREFIX_NAME).isPresent()) {
throw new PromptRequestException(Arrays.asList(new Prompt(PREFIX_NAME.getPrefix(),
"Please enter a name.")));
}
}

/**
* Returns true if none of the prefixes contains empty {@code Optional} values in the given
* {@code ArgumentMultimap}.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import static tagline.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
import static tagline.commons.core.Messages.MESSAGE_UNKNOWN_COMMAND;

import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

Expand All @@ -15,20 +17,27 @@
import tagline.logic.commands.contact.FindContactCommand;
import tagline.logic.commands.contact.ListContactCommand;
import tagline.logic.commands.contact.ShowContactCommand;
import tagline.logic.parser.ParserPromptHandlerUtil;
import tagline.logic.parser.Prompt;
import tagline.logic.parser.exceptions.ParseException;
import tagline.logic.parser.exceptions.PromptRequestException;

/**
* Parses user input.
*/
public class ContactCommandParser {
public static final String CONTACT_CLEAR_COMMAND_CONFIRM_STRING = "Are you sure you want to clear your contact"
+ " list? Enter 'Y' to continue.";
public static final String CONTACT_CLEAR_COMMAND_ABORTED_STRING = "The current command has been aborted.";
public static final String CONTACT_CLEAR_CONFIRM_CHARACTER = "Y";

/**
* Used for initial separation of command word and args.
*/
private static final Pattern BASIC_COMMAND_FORMAT = Pattern.compile("(?<commandWord>\\S+)(?<arguments>.*)");

/**
* Parses user input into command for execution.
* Parses user input into a contact command for execution.
*
* @param userInput full user input string
* @return the command based on the user input
Expand Down Expand Up @@ -57,7 +66,8 @@ public Command parseCommand(String userInput) throws ParseException {
return new DeleteContactParser().parse(arguments);

case ClearContactCommand.COMMAND_WORD:
return new ClearContactCommand();
throw new PromptRequestException(Arrays.asList(
new Prompt("", CONTACT_CLEAR_COMMAND_CONFIRM_STRING)));

case FindContactCommand.COMMAND_WORD:
return new FindContactParser().parse(arguments);
Expand All @@ -70,4 +80,51 @@ public Command parseCommand(String userInput) throws ParseException {
}
}

//@author tanlk99
/**
* Parses user input into a contact command for execution, using a list of filled prompts.
*
* @param userInput full user input string
* @return the command based on the user input
* @throws ParseException if the user input does not conform the expected format
*/
public Command parseCommand(String userInput, List<Prompt> promptList) throws ParseException {
final Matcher matcher = BASIC_COMMAND_FORMAT.matcher(userInput.trim());
if (!matcher.matches()) {
throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE));
}

final String commandWord = matcher.group("commandWord");
final String arguments = matcher.group("arguments");
final String filledArguments = ParserPromptHandlerUtil.getArgsWithFilledPrompts(arguments, promptList);

switch (commandWord) {

case CreateContactCommand.COMMAND_WORD:
return new AddContactParser().parse(filledArguments);

case EditContactCommand.COMMAND_WORD:
return new EditCommandParser().parse(filledArguments);

case DeleteContactCommand.COMMAND_WORD:
return new DeleteContactParser().parse(filledArguments);

case FindContactCommand.COMMAND_WORD:
return new FindContactParser().parse(filledArguments);

case ListContactCommand.COMMAND_WORD:
return new ListContactCommand();

case ClearContactCommand.COMMAND_WORD:
if (ParserPromptHandlerUtil.getPromptResponseFromPrefix("", promptList)
.equals(CONTACT_CLEAR_CONFIRM_CHARACTER)) {
return new ClearContactCommand();
} else {
throw new ParseException(CONTACT_CLEAR_COMMAND_ABORTED_STRING);
}

default:
throw new ParseException(MESSAGE_UNKNOWN_COMMAND);
}
}
}
Loading