diff --git a/config/travis/check-eof-newline.sh b/config/travis/check-eof-newline.sh index b771f3988dd8..9dd231bbfe94 100755 --- a/config/travis/check-eof-newline.sh +++ b/config/travis/check-eof-newline.sh @@ -3,14 +3,14 @@ ret=0 -# Preserve filename with spaces by only splitting on newlines. +# Preserve csvFile with spaces by only splitting on newlines. IFS=' ' -for filename in $(git grep --cached -I -l -e '' -- ':/'); do - if [ "$(tail -c 1 "./$filename")" != '' ]; then - line="$(wc -l "./$filename" | cut -d' ' -f1)" - echo "ERROR:$filename:$line: no newline at EOF." +for csvFile in $(git grep --cached -I -l -e '' -- ':/'); do + if [ "$(tail -c 1 "./$csvFile")" != '' ]; then + line="$(wc -l "./$csvFile" | cut -d' ' -f1)" + echo "ERROR:$csvFile:$line: no newline at EOF." ret=1 fi done diff --git a/docs/DeveloperGuide.adoc b/docs/DeveloperGuide.adoc index d1105fc17b1d..751106d9126f 100755 --- a/docs/DeveloperGuide.adoc +++ b/docs/DeveloperGuide.adoc @@ -399,7 +399,7 @@ CsvManager's API’s are exposed in the model interface as `Model#ExportCardFol [discrete] ==== Example Usage -1. User wants to export folders `Human Anatomy` and `Nervous System`. User inputs the following folders and the filename specified that he wants to export the folders to. +1. User wants to export folders `Human Anatomy` and `Nervous System`. User inputs the following folders and the csvFile specified that he wants to export the folders to. picture of command box with user inputs diff --git a/docs/UserGuide.adoc b/docs/UserGuide.adoc index 2dee1bc9f183..f5cf3687da30 100755 --- a/docs/UserGuide.adoc +++ b/docs/UserGuide.adoc @@ -327,7 +327,7 @@ Format: `search KEYWORDS [MORE_KEYWORDS]` ==== Import flashcards : `import` -Searches for a json file with the specified filename in the program directory and parses the file to generate a flashcard folder. +Searches for a json file with the specified csvFile in the program directory and parses the file to generate a flashcard folder. Format: `import FILENAME` diff --git a/src/main/java/seedu/address/commons/core/Messages.java b/src/main/java/seedu/address/commons/core/Messages.java index 5bfcca6d2e9e..e7292eece738 100755 --- a/src/main/java/seedu/address/commons/core/Messages.java +++ b/src/main/java/seedu/address/commons/core/Messages.java @@ -16,14 +16,27 @@ public class Messages { + " session"; public static final String MESSAGE_INVALID_COMMAND_INSIDE_TEST_SESSION = "This command is valid only outside a test" + " session"; - public static final String MESSAGE_INVALID_COMMAND_INSIDE_REPORT = "This command is not valid while displaying a " - + "report"; + public static final String MESSAGE_INVALID_ANSWER_COMMAND = "Answer command is valid only when a question is " + "displayed"; + public static final String MESSAGE_NO_NEGATIVE_INDEX = "Negative index not allowed !"; + public static final String MESSAGE_ILLEGAL_COMMAND_NOT_IN_FOLDER = "Command can only be executed in folder"; + public static final String MESSAGE_ILLEGAL_COMMAND_NOT_IN_HOME = "Command can only be executed in home directory"; + + + public static final String MESSAGE_INVALID_COMMAND_INSIDE_REPORT = "This command is not valid while displaying a " + + "report"; + + public static final String MESSAGE_INVALID_COMMAND_ON_EMPTY_FOLDER = "This command is not valid on an empty" + " folder"; public static final String MESSAGE_INVALID_NEXT_COMMAND = "Next command is valid only when this question has been" + " answered"; + public static final String MESSAGE_INVALID_COMMAND_OUTSIDE_FOLDER = "Command can only be executed in folder"; public static final String MESSAGE_INVALID_COMMAND_INSIDE_FOLDER = "Command can only be executed in home directory"; + public static final String MESSAGE_CSV_MANAGER_NOT_INITIALIZED = "Unable to carry out import and export commands"; + public static final String MESSAGE_INCORRECT_CSV_FILE_HEADER = "Incorrect Csv file headers. Check that the\n" + + "csv file contains question,answer,options,hints header"; + } diff --git a/src/main/java/seedu/address/commons/core/index/Index.java b/src/main/java/seedu/address/commons/core/index/Index.java index 19536439c099..d9ab470a2177 100644 --- a/src/main/java/seedu/address/commons/core/index/Index.java +++ b/src/main/java/seedu/address/commons/core/index/Index.java @@ -51,4 +51,9 @@ public boolean equals(Object other) { || (other instanceof Index // instanceof handles nulls && zeroBasedIndex == ((Index) other).zeroBasedIndex); // state check } + + + public String displayIndex() { + return Integer.toString(getOneBased()); + } } diff --git a/src/main/java/seedu/address/logic/commands/ExportCommand.java b/src/main/java/seedu/address/logic/commands/ExportCommand.java index 0befd3949edb..d62cbd07375f 100644 --- a/src/main/java/seedu/address/logic/commands/ExportCommand.java +++ b/src/main/java/seedu/address/logic/commands/ExportCommand.java @@ -1,65 +1,65 @@ package seedu.address.logic.commands; -import static seedu.address.logic.parser.CliSyntax.PREFIX_FILENAME; -import static seedu.address.logic.parser.CliSyntax.PREFIX_FOLDERNAME; - import java.io.IOException; -import java.util.Set; +import java.util.List; +import seedu.address.commons.core.Messages; import seedu.address.logic.CommandHistory; import seedu.address.logic.commands.exceptions.CommandException; import seedu.address.model.CardFolderNotFoundException; import seedu.address.model.Model; -import seedu.address.storage.csvmanager.CardFolderExport; -import seedu.address.storage.csvmanager.CsvFile; +import seedu.address.storage.csvmanager.exceptions.CsvManagerNotInitialized; + /** - * Exports single or multiple card folders into a .json file. Users must specify file name to export card folders to. + * Exports single or multiple card folders into a .csv file. */ public class ExportCommand extends Command { public static final String COMMAND_WORD = "export"; public static final String MESSAGE_USAGE = COMMAND_WORD + ": exports single or multiple card folders into" - + "a .csv file. " - + "Users must include the .csv extension.\n" - + "Parameters: " - + PREFIX_FOLDERNAME + "CARD_FOLDER_NAME [MORE CARD_FOLDER_NAMES]..." - + PREFIX_FILENAME + "Filename.csv\n" - + "Example: " + COMMAND_WORD + "f/Human_anatomy f/Bone_structure n/myfilename.csv"; + + "their respective .csv files." + + "Parameters: INDEX (Index specifies the card folder index to export) \n" + + "Can specify more than one card folder index to export" + + "Example: " + COMMAND_WORD + "1 3 5 7"; - public static final String MESSAGE_SUCCESS = "Successfully exported card folders to: $1%s"; + public static final String MESSAGE_SUCCESS = "Successfully exported card folders"; - public static final String MESSAGE_MISSING_CARD_FOLDERS = "Could not find the specified folder: "; + public static final String MESSAGE_MISSING_CARD_FOLDERS = "Could not find the specified folder index: "; public static final String MESSAGE_FILE_OPS_FAILURE = "Could not export to specified file"; - private Set cardFolders; - private CsvFile filename; + private List cardFolderIndexes; - public ExportCommand(Set cardFolders, CsvFile filename) { - this.cardFolders = cardFolders; - this.filename = filename; + public ExportCommand(List cardFolderIndexes) { + this.cardFolderIndexes = cardFolderIndexes; } @Override public CommandResult execute(Model model, CommandHistory history) throws CommandException { // check whether model contains the card folders desired. Catch exception thrown + + if (model.isInFolder()) { + throw new CommandException(Messages.MESSAGE_INVALID_COMMAND_INSIDE_FOLDER); + } try { - model.exportCardFolders(cardFolders, filename); + model.exportCardFolders(cardFolderIndexes); } catch (CardFolderNotFoundException e) { throw new CommandException(MESSAGE_MISSING_CARD_FOLDERS + e.getMessage()); } catch (IOException e) { throw new CommandException(MESSAGE_FILE_OPS_FAILURE); + } catch (CsvManagerNotInitialized e) { + throw new CommandException(Messages.MESSAGE_CSV_MANAGER_NOT_INITIALIZED); } - return new CommandResult(String.format(MESSAGE_SUCCESS, filename)); + return new CommandResult(MESSAGE_SUCCESS); } + @Override public boolean equals(Object other) { return other == this // short circuit if same object || other instanceof ExportCommand // instanceof handles nulls - && (cardFolders.containsAll(((ExportCommand) other).cardFolders) - && filename.equals(((ExportCommand) other).filename)); + && cardFolderIndexes.containsAll(((ExportCommand) other).cardFolderIndexes); } } diff --git a/src/main/java/seedu/address/logic/commands/ImportCommand.java b/src/main/java/seedu/address/logic/commands/ImportCommand.java index 93e47eccc0b2..9eeaa769b6a0 100644 --- a/src/main/java/seedu/address/logic/commands/ImportCommand.java +++ b/src/main/java/seedu/address/logic/commands/ImportCommand.java @@ -2,6 +2,7 @@ import java.io.IOException; +import seedu.address.commons.core.Messages; import seedu.address.logic.CommandHistory; import seedu.address.logic.commands.exceptions.CommandException; import seedu.address.model.Model; @@ -19,34 +20,45 @@ public class ImportCommand extends Command { + "card folders information.\n" + "File imported must have a .csv extension.\n" + "Default file path if not specified will be in the root folder of this application\n" - + "Parameters: JSON_FILE_NAME\n" + + "Parameters: CSV_FILE_NAME\n" + "Example: " + COMMAND_WORD + "alice.csv"; public static final String MESSAGE_FILE_OPS_FAILURE = "Could not import from specified file. Check that it exists " + "in root directory"; + public static final String MESSAGE_SUCCESS = "Successfully imported: %1$s"; - private CsvFile filename; + private CsvFile csvFile; - public ImportCommand(CsvFile filename) { - this.filename = filename; + public ImportCommand(CsvFile csvFile) { + this.csvFile = csvFile; } @Override public CommandResult execute(Model model, CommandHistory history) throws CommandException { + + if (model.isInFolder()) { + throw new CommandException(Messages.MESSAGE_INVALID_COMMAND_INSIDE_FOLDER); + } + try { - model.importCardFolders(filename); + model.importCardFolders(csvFile); } catch (IOException e) { throw new CommandException(MESSAGE_FILE_OPS_FAILURE); } - return null; + return new CommandResult(String.format(MESSAGE_SUCCESS, csvFile.filename)); } - - /** * Returns true if file extension is of .json format. */ private boolean isCorrectFileExtension(String filename) { return filename.split("\\.(?=[^\\.]+$)")[1].equals("csv"); } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || other instanceof ImportCommand // instanceof handles nulls + && csvFile.filename.equals(((ImportCommand) other).csvFile.filename); + } } diff --git a/src/main/java/seedu/address/logic/parser/ExportCommandParser.java b/src/main/java/seedu/address/logic/parser/ExportCommandParser.java index 927776afe84a..e2fd6a10b0f2 100644 --- a/src/main/java/seedu/address/logic/parser/ExportCommandParser.java +++ b/src/main/java/seedu/address/logic/parser/ExportCommandParser.java @@ -1,15 +1,14 @@ package seedu.address.logic.parser; import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; -import static seedu.address.logic.parser.CliSyntax.PREFIX_FILENAME; -import static seedu.address.logic.parser.CliSyntax.PREFIX_FOLDERNAME; +import static seedu.address.commons.core.Messages.MESSAGE_NO_NEGATIVE_INDEX; -import java.util.Set; +import java.util.List; +import seedu.address.commons.exceptions.IllegalValueException; import seedu.address.logic.commands.ExportCommand; import seedu.address.logic.parser.exceptions.ParseException; -import seedu.address.storage.csvmanager.CardFolderExport; -import seedu.address.storage.csvmanager.CsvFile; + /** * Parses input for export command arguments and creates a new export command object @@ -18,14 +17,13 @@ public class ExportCommandParser implements Parser { @Override public ExportCommand parse(String userInput) throws ParseException { - ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize( - userInput, PREFIX_FILENAME, PREFIX_FOLDERNAME); - if (!ParserUtil.arePrefixesPresent(argMultimap, PREFIX_FOLDERNAME, PREFIX_FILENAME) - || !argMultimap.getPreamble().isEmpty()) { - throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, ExportCommand.MESSAGE_USAGE)); + try { + List folderIndexes = ParserUtil.parseFolderIndex(userInput); + return new ExportCommand(folderIndexes); + } catch (NumberFormatException e) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, ExportCommand.MESSAGE_USAGE), e); + } catch (IllegalValueException e) { + throw new ParseException(MESSAGE_NO_NEGATIVE_INDEX); } - Set folderNames = ParserUtil.parseFolders(argMultimap.getAllValues(PREFIX_FOLDERNAME)); - CsvFile filename = ParserUtil.parseFileName(argMultimap.getValue(PREFIX_FILENAME).get()); - return new ExportCommand(folderNames, filename); } } diff --git a/src/main/java/seedu/address/logic/parser/ParserUtil.java b/src/main/java/seedu/address/logic/parser/ParserUtil.java index 89ed7138821e..c71832421173 100644 --- a/src/main/java/seedu/address/logic/parser/ParserUtil.java +++ b/src/main/java/seedu/address/logic/parser/ParserUtil.java @@ -3,20 +3,23 @@ import static java.util.Objects.requireNonNull; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.stream.Collectors; import java.util.stream.Stream; +import seedu.address.commons.core.Messages; import seedu.address.commons.core.index.Index; +import seedu.address.commons.exceptions.IllegalValueException; import seedu.address.commons.util.StringUtil; import seedu.address.logic.parser.exceptions.ParseException; import seedu.address.model.card.Answer; import seedu.address.model.card.Option; import seedu.address.model.card.Question; import seedu.address.model.hint.Hint; -import seedu.address.storage.csvmanager.CardFolderExport; import seedu.address.storage.csvmanager.CsvFile; /** @@ -25,8 +28,10 @@ public class ParserUtil { public static final String MESSAGE_INVALID_INDEX = "Index is not a non-zero unsigned integer."; + public static final String MESSAGE_INDEX_LESS_THAN_ZERO = "Index is less than zero"; public static final String HOME_SYMBOL = ".."; + /** * Parses {@code oneBasedIndex} into an {@code Index} and returns it. Leading and trailing whitespaces will be * trimmed. @@ -134,30 +139,26 @@ public static Set