From 3b19ba1790d6035a9e246f5d4ae627bf68778606 Mon Sep 17 00:00:00 2001 From: damithc Date: Mon, 25 May 2020 00:58:18 +0800 Subject: [PATCH 01/92] Add Gradle support --- build.gradle | 46 ++++++ gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 58695 bytes gradle/wrapper/gradle-wrapper.properties | 5 + gradlew | 183 +++++++++++++++++++++++ gradlew.bat | 103 +++++++++++++ text-ui-test/runtest.sh | 0 6 files changed, 337 insertions(+) create mode 100644 build.gradle create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100755 gradlew create mode 100644 gradlew.bat mode change 100644 => 100755 text-ui-test/runtest.sh diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000000..b0c5528fb5 --- /dev/null +++ b/build.gradle @@ -0,0 +1,46 @@ +plugins { + id 'java' + id 'application' + id 'checkstyle' + id 'com.github.johnrengelman.shadow' version '5.1.0' +} + +repositories { + mavenCentral() +} + +dependencies { + testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.5.0' + testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.5.0' +} + +test { + useJUnitPlatform() + + testLogging { + events "passed", "skipped", "failed" + + showExceptions true + exceptionFormat "full" + showCauses true + showStackTraces true + showStandardStreams = false + } +} + +application { + mainClassName = "seedu.duke.Duke" +} + +shadowJar { + archiveBaseName = "duke" + archiveClassifier = null +} + +checkstyle { + toolVersion = '8.23' +} + +run{ + standardInput = System.in +} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..f3d88b1c2faf2fc91d853cd5d4242b5547257070 GIT binary patch literal 58695 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 literal 0 HcmV?d00001 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000000..b7c8c5dbf5 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.2-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 0000000000..2fe81a7d95 --- /dev/null +++ b/gradlew @@ -0,0 +1,183 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000000..62bd9b9cce --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,103 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/text-ui-test/runtest.sh b/text-ui-test/runtest.sh old mode 100644 new mode 100755 From a75fceeb74708da6ac524c08ef526d38e60ee56b Mon Sep 17 00:00:00 2001 From: damithc <> Date: Sun, 30 Aug 2020 00:37:24 +0800 Subject: [PATCH 02/92] build.gradle: Update version to 8.29 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index b0c5528fb5..20c0521cc7 100644 --- a/build.gradle +++ b/build.gradle @@ -38,7 +38,7 @@ shadowJar { } checkstyle { - toolVersion = '8.23' + toolVersion = '8.29' } run{ From d518a02e112e147a1403e1a4d90596355d89e537 Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Wed, 20 Jan 2021 23:20:16 +0800 Subject: [PATCH 03/92] Done Level-1 --- src/main/java/Duke.java | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index 5d313334cc..4f5c298a83 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -1,10 +1,24 @@ +import java.util.Locale; +import java.util.Scanner; + public class Duke { public static void main(String[] args) { - String logo = " ____ _ \n" + String logo = + " ____ _ \n" + "| _ \\ _ _| | _____ \n" + "| | | | | | | |/ / _ \\\n" + "| |_| | |_| | < __/\n" + "|____/ \\__,_|_|\\_\\___|\n"; + String seperator = "------------------\n"; System.out.println("Hello from\n" + logo); + System.out.println("Parrot mode engaged"); + Scanner in = new Scanner(System.in); + String command = ""; + do{ + System.out.print(seperator + "Listening to your input: "); + command = in.nextLine(); + System.out.println("Echo: "+command); + }while(!command.equals("bye")); + System.out.println(seperator + "Goodbye from\n" + logo); } } From bcd127598d3926ecf6a9b04ca3c18220af7d691c Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Thu, 21 Jan 2021 01:06:57 +0800 Subject: [PATCH 04/92] Done Level-2 --- src/main/java/Duke.java | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index 4f5c298a83..274aa713da 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -1,3 +1,5 @@ +import java.util.ArrayList; +import java.util.List; import java.util.Locale; import java.util.Scanner; @@ -14,11 +16,23 @@ public static void main(String[] args) { System.out.println("Parrot mode engaged"); Scanner in = new Scanner(System.in); String command = ""; + List store = new ArrayList<>(); do{ System.out.print(seperator + "Listening to your input: "); command = in.nextLine(); - System.out.println("Echo: "+command); + switch(command){ + case "bye": + System.out.println(seperator + "Goodbye from\n" + logo); + break; + case "list": + for (int i = 0; i < store.size(); i++) { + System.out.println("Entry " + String.valueOf(i+1) + ": " + store.get(i)); + } + break; + default: + store.add(command); + System.out.println("Added: " + command); + } }while(!command.equals("bye")); - System.out.println(seperator + "Goodbye from\n" + logo); } } From f4d6f0f1ce97e614a352fa94fc723d3bb6ead33f Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Thu, 21 Jan 2021 01:19:07 +0800 Subject: [PATCH 05/92] Added Task class, and cleaned up the code of warnings --- src/main/java/Duke.java | 17 ++++++++--------- src/main/java/Task.java | 25 +++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 9 deletions(-) create mode 100644 src/main/java/Task.java diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index 274aa713da..56bf25d332 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -1,6 +1,5 @@ import java.util.ArrayList; import java.util.List; -import java.util.Locale; import java.util.Scanner; public class Duke { @@ -11,26 +10,26 @@ public static void main(String[] args) { + "| | | | | | | |/ / _ \\\n" + "| |_| | |_| | < __/\n" + "|____/ \\__,_|_|\\_\\___|\n"; - String seperator = "------------------\n"; + String separator = "------------------\n"; System.out.println("Hello from\n" + logo); System.out.println("Parrot mode engaged"); Scanner in = new Scanner(System.in); - String command = ""; - List store = new ArrayList<>(); + String command; + List store = new ArrayList<>(); do{ - System.out.print(seperator + "Listening to your input: "); + System.out.print(separator + "Listening to your input: "); command = in.nextLine(); switch(command){ case "bye": - System.out.println(seperator + "Goodbye from\n" + logo); + System.out.println(separator + "Goodbye from\n" + logo); break; case "list": - for (int i = 0; i < store.size(); i++) { - System.out.println("Entry " + String.valueOf(i+1) + ": " + store.get(i)); + for (Task t: store) { + System.out.println(t.toString()); } break; default: - store.add(command); + store.add(new Task(command,store.size())); System.out.println("Added: " + command); } }while(!command.equals("bye")); diff --git a/src/main/java/Task.java b/src/main/java/Task.java new file mode 100644 index 0000000000..b0cea79ee3 --- /dev/null +++ b/src/main/java/Task.java @@ -0,0 +1,25 @@ +public class Task { + protected String description; + protected boolean isDone; + protected int number; + + public Task(String description, int number) { + this.description = description; + this.isDone = false; + this.number = number; + } + + public String getStatusIcon() { + return (isDone ? "\u2713" : "\u2718"); //return tick or X symbols + } + + @Override + public String toString() { + return "Entry " + + (number+1) + + "|["+ this.getStatusIcon()+"]: " + + description; + } + + //... +} \ No newline at end of file From 179b869a94aea9fdc7b98481246812cd02c89611 Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Thu, 21 Jan 2021 01:36:37 +0800 Subject: [PATCH 06/92] Done Level-3 --- src/main/java/Duke.java | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index 56bf25d332..cf12618947 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -14,12 +14,14 @@ public static void main(String[] args) { System.out.println("Hello from\n" + logo); System.out.println("Parrot mode engaged"); Scanner in = new Scanner(System.in); - String command; + String line; List store = new ArrayList<>(); + String tokens[]; do{ System.out.print(separator + "Listening to your input: "); - command = in.nextLine(); - switch(command){ + line = in.nextLine(); + tokens = line.split(" "); + switch(tokens[0]){ case "bye": System.out.println(separator + "Goodbye from\n" + logo); break; @@ -28,10 +30,16 @@ public static void main(String[] args) { System.out.println(t.toString()); } break; + case "done": + int index = Integer.valueOf(tokens[1]) - 1; + Task t = store.get(index); + t.isDone = true; + System.out.println("The following task is now marked as done:\n" + t.toString()); + break; default: - store.add(new Task(command,store.size())); - System.out.println("Added: " + command); + store.add(new Task(line,store.size())); + System.out.println("Added: " + line); } - }while(!command.equals("bye")); + }while(!tokens[0].equals("bye")); } } From e70781223b7f0c7279510a9d58c45e10b8a743ee Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Thu, 21 Jan 2021 01:46:42 +0800 Subject: [PATCH 07/92] Refactored Task --- src/main/java/Duke.java | 2 +- src/main/java/Task.java | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index cf12618947..febdf9991e 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -37,7 +37,7 @@ public static void main(String[] args) { System.out.println("The following task is now marked as done:\n" + t.toString()); break; default: - store.add(new Task(line,store.size())); + store.add(new Task(line)); System.out.println("Added: " + line); } }while(!tokens[0].equals("bye")); diff --git a/src/main/java/Task.java b/src/main/java/Task.java index b0cea79ee3..4ac882683a 100644 --- a/src/main/java/Task.java +++ b/src/main/java/Task.java @@ -1,12 +1,13 @@ public class Task { - protected String description; + private final String description; protected boolean isDone; - protected int number; + private final int number; + private static int counter = 0; - public Task(String description, int number) { + public Task(String description) { this.description = description; this.isDone = false; - this.number = number; + this.number = Task.counter++; } public String getStatusIcon() { From c7cdb7887fa1af73ecc56e16ad73666eba122b22 Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Thu, 21 Jan 2021 01:50:40 +0800 Subject: [PATCH 08/92] Further refactored Task to not deal with numbering --- src/main/java/Duke.java | 4 ++-- src/main/java/Task.java | 6 +----- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index febdf9991e..28647cbb4b 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -26,8 +26,8 @@ public static void main(String[] args) { System.out.println(separator + "Goodbye from\n" + logo); break; case "list": - for (Task t: store) { - System.out.println(t.toString()); + for (int i = 0 ; i < store.size(); i++) { + System.out.println("Entry " + (i+1) + "|" + store.get(i).toString()); } break; case "done": diff --git a/src/main/java/Task.java b/src/main/java/Task.java index 4ac882683a..4664f1c64e 100644 --- a/src/main/java/Task.java +++ b/src/main/java/Task.java @@ -1,13 +1,11 @@ public class Task { private final String description; protected boolean isDone; - private final int number; private static int counter = 0; public Task(String description) { this.description = description; this.isDone = false; - this.number = Task.counter++; } public String getStatusIcon() { @@ -16,9 +14,7 @@ public String getStatusIcon() { @Override public String toString() { - return "Entry " + - (number+1) + - "|["+ this.getStatusIcon()+"]: " + + return "["+ this.getStatusIcon()+"]: " + description; } From a171f30bd2897b0624255fd61c3cc63a9f92ceab Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Thu, 21 Jan 2021 02:58:47 +0800 Subject: [PATCH 09/92] Done A-Inheritance --- src/main/java/Deadline.java | 13 +++++++++++++ src/main/java/Events.java | 13 +++++++++++++ src/main/java/Task.java | 2 +- src/main/java/ToDos.java | 10 ++++++++++ 4 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 src/main/java/Deadline.java create mode 100644 src/main/java/Events.java create mode 100644 src/main/java/ToDos.java diff --git a/src/main/java/Deadline.java b/src/main/java/Deadline.java new file mode 100644 index 0000000000..32d37c1a27 --- /dev/null +++ b/src/main/java/Deadline.java @@ -0,0 +1,13 @@ +public class Deadline extends Task { + protected String by; + + public Deadline(String description, String by) { + super(description); + this.by = by; + } + + @Override + public String toString() { + return "[D]" + super.toString() + " (Deadline: " + by + ")"; + } +} \ No newline at end of file diff --git a/src/main/java/Events.java b/src/main/java/Events.java new file mode 100644 index 0000000000..6d10dcd7e5 --- /dev/null +++ b/src/main/java/Events.java @@ -0,0 +1,13 @@ +public class Events extends Task{ + private String eventPeriod; + + public Events(String description, String eventPeriod) { + super(description); + this.eventPeriod = eventPeriod; + } + + @Override + public String toString() { + return "[E]" + super.toString() + " (Event Time: " + eventPeriod + ")"; + } +} diff --git a/src/main/java/Task.java b/src/main/java/Task.java index 4664f1c64e..20cad66d3f 100644 --- a/src/main/java/Task.java +++ b/src/main/java/Task.java @@ -1,4 +1,4 @@ -public class Task { +public abstract class Task { private final String description; protected boolean isDone; private static int counter = 0; diff --git a/src/main/java/ToDos.java b/src/main/java/ToDos.java new file mode 100644 index 0000000000..f48936d938 --- /dev/null +++ b/src/main/java/ToDos.java @@ -0,0 +1,10 @@ +public class ToDos extends Task{ + public ToDos(String description) { + super(description); + } + + @Override + public String toString() { + return "[T]" + super.toString(); + } +} From d8b325f5c7848cc18ca4c85c1ebf98d684d26942 Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Thu, 21 Jan 2021 03:00:00 +0800 Subject: [PATCH 10/92] Done Level-4, with some refactoring --- src/main/java/Duke.java | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index 28647cbb4b..8b29eab468 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -20,26 +20,53 @@ public static void main(String[] args) { do{ System.out.print(separator + "Listening to your input: "); line = in.nextLine(); - tokens = line.split(" "); + tokens = line.split(" ",2); switch(tokens[0]){ case "bye": System.out.println(separator + "Goodbye from\n" + logo); break; case "list": for (int i = 0 ; i < store.size(); i++) { - System.out.println("Entry " + (i+1) + "|" + store.get(i).toString()); + System.out.println(formatOrderedPrint(store,i)); } break; case "done": int index = Integer.valueOf(tokens[1]) - 1; Task t = store.get(index); t.isDone = true; - System.out.println("The following task is now marked as done:\n" + t.toString()); + System.out.println("The following task is now marked as done:\n" + + formatOrderedPrint(store,-1)); + break; + case "todo": + store.add(new ToDos(tokens[0])); + System.out.println("The following todo item has been added:\n" + + formatOrderedPrint(store,-1)); + break; + case "deadline": + tokens = tokens[1].split(" /by ",2); + store.add(new Deadline(tokens[0],tokens[1])); + System.out.println("The following deadline item has been added:\n" + + formatOrderedPrint(store,-1)); + break; + case "event": + tokens = tokens[1].split(" /at ",2); + store.add(new Deadline(tokens[0],tokens[1])); + System.out.println("The following event item has been added:\n" + + formatOrderedPrint(store,-1)); break; default: - store.add(new Task(line)); - System.out.println("Added: " + line); + break; } }while(!tokens[0].equals("bye")); } + private static String formatOrderedPrint(List tasks, int i){ + final int size = tasks.size(); + while (i < 0){ + i += size; + } + while (i >= size){ + i -= size; + } + return "Entry " + (i+1) + "|" + tasks.get(i).toString(); + } } From 557f98c7093ff72002a9728da156c650b4ce35ae Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Thu, 21 Jan 2021 03:06:55 +0800 Subject: [PATCH 11/92] Whoops, renamed Events to Event and actually include Event as creation. Good time for automated testing --- src/main/java/Duke.java | 2 +- src/main/java/{Events.java => Event.java} | 4 ++-- text-ui-test/input.txt | 3 +++ 3 files changed, 6 insertions(+), 3 deletions(-) rename src/main/java/{Events.java => Event.java} (71%) diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index 8b29eab468..2794e2ac5f 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -50,7 +50,7 @@ public static void main(String[] args) { break; case "event": tokens = tokens[1].split(" /at ",2); - store.add(new Deadline(tokens[0],tokens[1])); + store.add(new Event(tokens[0],tokens[1])); System.out.println("The following event item has been added:\n" + formatOrderedPrint(store,-1)); break; diff --git a/src/main/java/Events.java b/src/main/java/Event.java similarity index 71% rename from src/main/java/Events.java rename to src/main/java/Event.java index 6d10dcd7e5..11e629390a 100644 --- a/src/main/java/Events.java +++ b/src/main/java/Event.java @@ -1,7 +1,7 @@ -public class Events extends Task{ +public class Event extends Task{ private String eventPeriod; - public Events(String description, String eventPeriod) { + public Event(String description, String eventPeriod) { super(description); this.eventPeriod = eventPeriod; } diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index e69de29bb2..c837b8f971 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -0,0 +1,3 @@ +deadline do homework /by no idea :-p +todo Dab on Homies +event \ No newline at end of file From 7f652e59a0d384010ece11e0261cbd2a27eca249 Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Thu, 21 Jan 2021 03:27:47 +0800 Subject: [PATCH 12/92] Added test data, found bugs immediately in need of testing, unicode does not render --- text-ui-test/EXPECTED.TXT | 41 +++++++++++++++++++++++++++++++++++++++ text-ui-test/input.txt | 7 ++++++- 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 657e74f6e7..67ba8d9266 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -5,3 +5,44 @@ Hello from | |_| | |_| | < __/ |____/ \__,_|_|\_\___| +Parrot mode engaged +------------------ +Listening to your input: deadline do homework /by no idea :-p +The following deadline item has been added: +Entry 1|[D][✘]: do homework (Deadline: no idea :-p) +------------------ +Listening to your input: todo Dab on Homies +The following todo item has been added: +Entry 2|[T][✘]: todo +------------------ +Listening to your input: event Ninja_0 /at 3pm EST +The following event item has been added: +Entry 3|[E][✘]: Ninja_0 (Event Time: 3pm EST) +------------------ +Listening to your input:Entry 1|[D][✘]: do homework (Deadline: no idea :-p) +Entry 2|[T][✘]: todo +Entry 3|[E][✘]: Ninja_0 (Event Time: 3pm EST) +------------------ +Listening to your input: done 3 +The following task is now marked as done: +Entry 3|[E][✓]: Ninja_0 (Event Time: 3pm EST) +------------------ +Listening to your input: done 1 +The following task is now marked as done: +Entry 3|[E][✓]: Ninja_0 (Event Time: 3pm EST) +------------------ +Listening to your input: list +Entry 1|[D][✓]: do homework (Deadline: no idea :-p) +Entry 2|[T][✘]: todo +Entry 3|[E][✓]: Ninja_0 (Event Time: 3pm EST) +------------------ +Listening to your input: bye +------------------ +Goodbye from + ____ _ +| _ \ _ _| | _____ +| | | | | | | |/ / _ \ +| |_| | |_| | < __/ +|____/ \__,_|_|\_\___| + + diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index c837b8f971..073cefb5a3 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -1,3 +1,8 @@ deadline do homework /by no idea :-p todo Dab on Homies -event \ No newline at end of file +event Ninja_0 /at 3pm EST +list +done 3 +done 1 +list +bye From 558f9b7733a845bdd810b33ae2414069d89c369e Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Thu, 21 Jan 2021 03:37:51 +0800 Subject: [PATCH 13/92] Somewhat fixed unicode, probably need to fix how files are compared cause line endings shouldn't matter --- src/main/java/Duke.java | 2 +- src/main/java/Task.java | 2 +- text-ui-test/EXPECTED.TXT | 48 ++++++++++++++++----------------------- 3 files changed, 22 insertions(+), 30 deletions(-) diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index 2794e2ac5f..6f6a16904f 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -12,7 +12,7 @@ public static void main(String[] args) { + "|____/ \\__,_|_|\\_\\___|\n"; String separator = "------------------\n"; System.out.println("Hello from\n" + logo); - System.out.println("Parrot mode engaged"); + System.out.println("No unicode allowed"); Scanner in = new Scanner(System.in); String line; List store = new ArrayList<>(); diff --git a/src/main/java/Task.java b/src/main/java/Task.java index 20cad66d3f..508eb7dd8d 100644 --- a/src/main/java/Task.java +++ b/src/main/java/Task.java @@ -9,7 +9,7 @@ public Task(String description) { } public String getStatusIcon() { - return (isDone ? "\u2713" : "\u2718"); //return tick or X symbols + return (isDone ? "*" : " "); //Don't use unicode, cause it can't test properly } @Override diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 67ba8d9266..1938474923 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -5,44 +5,36 @@ Hello from | |_| | |_| | < __/ |____/ \__,_|_|\_\___| -Parrot mode engaged +No unicode allowed ------------------ -Listening to your input: deadline do homework /by no idea :-p -The following deadline item has been added: -Entry 1|[D][✘]: do homework (Deadline: no idea :-p) +Listening to your input: The following deadline item has been added: +Entry 1|[D][ ]: do homework (Deadline: no idea :-p) ------------------ -Listening to your input: todo Dab on Homies -The following todo item has been added: -Entry 2|[T][✘]: todo +Listening to your input: The following todo item has been added: +Entry 2|[T][ ]: todo ------------------ -Listening to your input: event Ninja_0 /at 3pm EST -The following event item has been added: -Entry 3|[E][✘]: Ninja_0 (Event Time: 3pm EST) +Listening to your input: The following event item has been added: +Entry 3|[E][ ]: Ninja_0 (Event Time: 3pm EST) ------------------ -Listening to your input:Entry 1|[D][✘]: do homework (Deadline: no idea :-p) -Entry 2|[T][✘]: todo -Entry 3|[E][✘]: Ninja_0 (Event Time: 3pm EST) +Listening to your input: Entry 1|[D][ ]: do homework (Deadline: no idea :-p) +Entry 2|[T][ ]: todo +Entry 3|[E][ ]: Ninja_0 (Event Time: 3pm EST) ------------------ -Listening to your input: done 3 -The following task is now marked as done: -Entry 3|[E][✓]: Ninja_0 (Event Time: 3pm EST) +Listening to your input: The following task is now marked as done: +Entry 3|[E][*]: Ninja_0 (Event Time: 3pm EST) ------------------ -Listening to your input: done 1 -The following task is now marked as done: -Entry 3|[E][✓]: Ninja_0 (Event Time: 3pm EST) +Listening to your input: The following task is now marked as done: +Entry 3|[E][*]: Ninja_0 (Event Time: 3pm EST) ------------------ -Listening to your input: list -Entry 1|[D][✓]: do homework (Deadline: no idea :-p) -Entry 2|[T][✘]: todo -Entry 3|[E][✓]: Ninja_0 (Event Time: 3pm EST) ------------------- -Listening to your input: bye +Listening to your input: Entry 1|[D][*]: do homework (Deadline: no idea :-p) +Entry 2|[T][ ]: todo +Entry 3|[E][*]: Ninja_0 (Event Time: 3pm EST) ------------------ +Listening to your input: ------------------ Goodbye from - ____ _ -| _ \ _ _| | _____ + ____ _ +| _ \ _ _| | _____ | | | | | | | |/ / _ \ | |_| | |_| | < __/ |____/ \__,_|_|\_\___| - From 691306e479b98cec691a1174bf267f2a7b48688c Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Thu, 21 Jan 2021 03:42:25 +0800 Subject: [PATCH 14/92] Removed rendundant line --- src/main/java/Task.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/Task.java b/src/main/java/Task.java index 508eb7dd8d..5c498a7ff6 100644 --- a/src/main/java/Task.java +++ b/src/main/java/Task.java @@ -1,7 +1,6 @@ public abstract class Task { private final String description; protected boolean isDone; - private static int counter = 0; public Task(String description) { this.description = description; From 4856b15f9763ee56dee9fa91af63b3ef460d2f54 Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Thu, 21 Jan 2021 03:55:58 +0800 Subject: [PATCH 15/92] Fixed another bug I missed --- src/main/java/Duke.java | 5 ++++- text-ui-test/EXPECTED.TXT | 6 +++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index 6f6a16904f..daa5850f62 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -38,12 +38,15 @@ public static void main(String[] args) { formatOrderedPrint(store,-1)); break; case "todo": - store.add(new ToDos(tokens[0])); + store.add(new ToDos(tokens[1])); System.out.println("The following todo item has been added:\n" + formatOrderedPrint(store,-1)); break; case "deadline": tokens = tokens[1].split(" /by ",2); + if (tokens.length < 2){ + + } store.add(new Deadline(tokens[0],tokens[1])); System.out.println("The following deadline item has been added:\n" + formatOrderedPrint(store,-1)); diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 1938474923..98805db07b 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -11,13 +11,13 @@ Listening to your input: The following deadline item has been added: Entry 1|[D][ ]: do homework (Deadline: no idea :-p) ------------------ Listening to your input: The following todo item has been added: -Entry 2|[T][ ]: todo +Entry 2|[T][ ]: Dab on Homies ------------------ Listening to your input: The following event item has been added: Entry 3|[E][ ]: Ninja_0 (Event Time: 3pm EST) ------------------ Listening to your input: Entry 1|[D][ ]: do homework (Deadline: no idea :-p) -Entry 2|[T][ ]: todo +Entry 2|[T][ ]: Dab on Homies Entry 3|[E][ ]: Ninja_0 (Event Time: 3pm EST) ------------------ Listening to your input: The following task is now marked as done: @@ -27,7 +27,7 @@ Listening to your input: The following task is now marked as done: Entry 3|[E][*]: Ninja_0 (Event Time: 3pm EST) ------------------ Listening to your input: Entry 1|[D][*]: do homework (Deadline: no idea :-p) -Entry 2|[T][ ]: todo +Entry 2|[T][ ]: Dab on Homies Entry 3|[E][*]: Ninja_0 (Event Time: 3pm EST) ------------------ Listening to your input: ------------------ From 819aea77b72e08f798815e83abd4f58008123c07 Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Thu, 21 Jan 2021 05:00:05 +0800 Subject: [PATCH 16/92] Added some error checking --- src/main/java/Duke.java | 100 ++++++++++++--------- src/main/java/InvalidCommandException.java | 15 ++++ 2 files changed, 75 insertions(+), 40 deletions(-) create mode 100644 src/main/java/InvalidCommandException.java diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index daa5850f62..fdba3794ef 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -1,3 +1,4 @@ +import java.text.ParseException; import java.util.ArrayList; import java.util.List; import java.util.Scanner; @@ -16,49 +17,53 @@ public static void main(String[] args) { Scanner in = new Scanner(System.in); String line; List store = new ArrayList<>(); - String tokens[]; + String tokens[] = {"invalid"}; do{ System.out.print(separator + "Listening to your input: "); line = in.nextLine(); - tokens = line.split(" ",2); - switch(tokens[0]){ - case "bye": - System.out.println(separator + "Goodbye from\n" + logo); - break; - case "list": - for (int i = 0 ; i < store.size(); i++) { - System.out.println(formatOrderedPrint(store,i)); - } - break; - case "done": - int index = Integer.valueOf(tokens[1]) - 1; - Task t = store.get(index); - t.isDone = true; - System.out.println("The following task is now marked as done:\n" + - formatOrderedPrint(store,-1)); - break; - case "todo": - store.add(new ToDos(tokens[1])); - System.out.println("The following todo item has been added:\n" + - formatOrderedPrint(store,-1)); - break; - case "deadline": - tokens = tokens[1].split(" /by ",2); - if (tokens.length < 2){ - - } - store.add(new Deadline(tokens[0],tokens[1])); - System.out.println("The following deadline item has been added:\n" + - formatOrderedPrint(store,-1)); - break; - case "event": - tokens = tokens[1].split(" /at ",2); - store.add(new Event(tokens[0],tokens[1])); - System.out.println("The following event item has been added:\n" + - formatOrderedPrint(store,-1)); - break; - default: - break; + try { + tokens = splitTokenIntoTwo(line," ", "bye"); + switch(tokens[0]){ + case "bye": + System.out.println(separator + "Goodbye from\n" + logo); + break; + case "list": + for (int i = 0 ; i < store.size(); i++) { + System.out.println(formatOrderedPrint(store,i)); + } + break; + case "done": + int index = Integer.valueOf(tokens[1]) - 1; + Task t = store.get(index); + t.isDone = true; + System.out.println("The following task is now marked as done:\n" + + formatOrderedPrint(store,-1)); + break; + case "todo": + store.add(new ToDos(tokens[1])); + System.out.println("The following todo item has been added:\n" + + formatOrderedPrint(store,-1)); + break; + case "deadline": + tokens = splitTokenIntoTwo(tokens[1]," /by "); + store.add(new Deadline(tokens[0],tokens[1])); + System.out.println("The following deadline item has been added:\n" + + formatOrderedPrint(store,-1)); + break; + case "event": + tokens = splitTokenIntoTwo(tokens[1]," /by "); + store.add(new Event(tokens[0],tokens[1])); + System.out.println("The following event item has been added:\n" + + formatOrderedPrint(store,-1)); + break; + default: + throw new InvalidCommandException(tokens[0]); + } + } catch (ParseException e) { + System.out.println("Command has invalid parsing."); + System.out.println(e.getMessage()); + } catch (InvalidCommandException e){ + System.out.println(e.getMessage()); } }while(!tokens[0].equals("bye")); } @@ -72,4 +77,19 @@ private static String formatOrderedPrint(List tasks, int i){ } return "Entry " + (i+1) + "|" + tasks.get(i).toString(); } + private static String[] splitTokenIntoTwo(String parseTarget,String delimiter) throws ParseException{ + String[] tokens = parseTarget.split(delimiter,2); + if (tokens.length < 2){ + throw new ParseException("Expected deliminter '"+ delimiter +"'", tokens[0].length()); + } + return tokens; + } + + private static String[] splitTokenIntoTwo(String parseTarget,String delimiter, String exception) throws ParseException{ + String[] tokens = parseTarget.split(delimiter,2); + if (!tokens[0].equals(exception) && tokens.length < 2){ + throw new ParseException("Expected deliminter '"+ delimiter +"'", tokens[0].length()); + } + return tokens; + } } diff --git a/src/main/java/InvalidCommandException.java b/src/main/java/InvalidCommandException.java new file mode 100644 index 0000000000..5ebb0d615e --- /dev/null +++ b/src/main/java/InvalidCommandException.java @@ -0,0 +1,15 @@ +public class InvalidCommandException extends Exception { + + private String badCommand; + + public InvalidCommandException(String badCommand) { + this.badCommand = badCommand; + } + + private static final long serialVersionUID = 1L; + + @Override + public String getMessage() { + return "Command '" + badCommand + "' is not recognized."; + } +} \ No newline at end of file From dec65f380f636807d994985cb6b8fc2df8c70692 Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Thu, 21 Jan 2021 05:00:53 +0800 Subject: [PATCH 17/92] Minor bugfix on leakage --- src/main/java/Duke.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index fdba3794ef..5b44fc2932 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -66,6 +66,7 @@ public static void main(String[] args) { System.out.println(e.getMessage()); } }while(!tokens[0].equals("bye")); + in.close(); } private static String formatOrderedPrint(List tasks, int i){ final int size = tasks.size(); From 945ec43e6c44d8e4f75bb38cb95717ae9640ab06 Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Thu, 21 Jan 2021 05:09:51 +0800 Subject: [PATCH 18/92] Added Empty Argument Handling --- src/main/java/Deadline.java | 6 +++++- src/main/java/Duke.java | 2 ++ src/main/java/EmptyArgument.java | 8 ++++++++ src/main/java/Event.java | 6 +++++- src/main/java/Task.java | 6 +++++- src/main/java/ToDos.java | 2 +- 6 files changed, 26 insertions(+), 4 deletions(-) create mode 100644 src/main/java/EmptyArgument.java diff --git a/src/main/java/Deadline.java b/src/main/java/Deadline.java index 32d37c1a27..ee2c20f5da 100644 --- a/src/main/java/Deadline.java +++ b/src/main/java/Deadline.java @@ -1,8 +1,12 @@ public class Deadline extends Task { protected String by; - public Deadline(String description, String by) { + public Deadline(String description, String by) throws EmptyArgument { super(description); + by = by.trim(); + if (by.isEmpty()){ + throw new EmptyArgument(); + } this.by = by; } diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index 5b44fc2932..ea9cdf74c1 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -64,6 +64,8 @@ public static void main(String[] args) { System.out.println(e.getMessage()); } catch (InvalidCommandException e){ System.out.println(e.getMessage()); + } catch(EmptyArgument e){ + System.out.println("Cannot have empty argument"); } }while(!tokens[0].equals("bye")); in.close(); diff --git a/src/main/java/EmptyArgument.java b/src/main/java/EmptyArgument.java new file mode 100644 index 0000000000..10b7ae55aa --- /dev/null +++ b/src/main/java/EmptyArgument.java @@ -0,0 +1,8 @@ +public class EmptyArgument extends Exception{ + + /** + * + */ + private static final long serialVersionUID = 1L; + +} diff --git a/src/main/java/Event.java b/src/main/java/Event.java index 11e629390a..b0ed9e06b6 100644 --- a/src/main/java/Event.java +++ b/src/main/java/Event.java @@ -1,8 +1,12 @@ public class Event extends Task{ private String eventPeriod; - public Event(String description, String eventPeriod) { + public Event(String description, String eventPeriod) throws EmptyArgument { super(description); + eventPeriod = eventPeriod.trim(); + if (eventPeriod.isEmpty()){ + throw new EmptyArgument(); + } this.eventPeriod = eventPeriod; } diff --git a/src/main/java/Task.java b/src/main/java/Task.java index 5c498a7ff6..96fdb989d2 100644 --- a/src/main/java/Task.java +++ b/src/main/java/Task.java @@ -2,7 +2,11 @@ public abstract class Task { private final String description; protected boolean isDone; - public Task(String description) { + public Task(String description) throws EmptyArgument { + description = description.trim(); + if (description.isEmpty()){ + throw new EmptyArgument(); + } this.description = description; this.isDone = false; } diff --git a/src/main/java/ToDos.java b/src/main/java/ToDos.java index f48936d938..71318c8edf 100644 --- a/src/main/java/ToDos.java +++ b/src/main/java/ToDos.java @@ -1,5 +1,5 @@ public class ToDos extends Task{ - public ToDos(String description) { + public ToDos(String description) throws EmptyArgument { super(description); } From 7fb940aa18b1b39206106d36a34791ad5181c54e Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Thu, 21 Jan 2021 05:26:51 +0800 Subject: [PATCH 19/92] Fixed bug to do with single arg commands --- src/main/java/Duke.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index ea9cdf74c1..eb85292036 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -1,5 +1,6 @@ import java.text.ParseException; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Scanner; @@ -22,7 +23,8 @@ public static void main(String[] args) { System.out.print(separator + "Listening to your input: "); line = in.nextLine(); try { - tokens = splitTokenIntoTwo(line," ", "bye"); + String singleTokens[] = {"bye","list"}; + tokens = splitTokenIntoTwo(line," ", singleTokens); switch(tokens[0]){ case "bye": System.out.println(separator + "Goodbye from\n" + logo); @@ -88,9 +90,10 @@ private static String[] splitTokenIntoTwo(String parseTarget,String delimiter) t return tokens; } - private static String[] splitTokenIntoTwo(String parseTarget,String delimiter, String exception) throws ParseException{ + private static String[] splitTokenIntoTwo(String parseTarget,String delimiter, String[] exception) throws ParseException{ + List exceptionList = Arrays.asList(exception); String[] tokens = parseTarget.split(delimiter,2); - if (!tokens[0].equals(exception) && tokens.length < 2){ + if (!exceptionList.contains(tokens[0]) && tokens.length < 2){ throw new ParseException("Expected deliminter '"+ delimiter +"'", tokens[0].length()); } return tokens; From 6db18be72de45b6b0368ef0c1f875da184bd82cc Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Thu, 21 Jan 2021 05:28:26 +0800 Subject: [PATCH 20/92] Implemented Delete --- src/main/java/Duke.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index eb85292036..c8ee8bedb3 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -58,6 +58,13 @@ public static void main(String[] args) { System.out.println("The following event item has been added:\n" + formatOrderedPrint(store,-1)); break; + case "delete": + int deleteIndex = Integer.valueOf(tokens[1]) - 1; + System.out.println("Deleting the following Task:"); + System.out.println(formatOrderedPrint(store, deleteIndex)); + store.remove(deleteIndex); + System.out.println("Done"); + break; default: throw new InvalidCommandException(tokens[0]); } From 6563d2c7af8f2d99cb8e68c2b959c336c8e44d50 Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Thu, 28 Jan 2021 08:16:46 +0800 Subject: [PATCH 21/92] Fixed bug with event deliminator --- src/main/java/Duke.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index c8ee8bedb3..d95b0ccaa6 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -53,7 +53,7 @@ public static void main(String[] args) { formatOrderedPrint(store,-1)); break; case "event": - tokens = splitTokenIntoTwo(tokens[1]," /by "); + tokens = splitTokenIntoTwo(tokens[1]," /at "); store.add(new Event(tokens[0],tokens[1])); System.out.println("The following event item has been added:\n" + formatOrderedPrint(store,-1)); From 6d3e2d1ac04b02ddae3d453cbbb96a15cabfc462 Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Fri, 29 Jan 2021 02:27:55 +0800 Subject: [PATCH 22/92] Add minimal code to implement saving. Code does not implement saving Need to persist the change across runs Let's: * Add and call code to load and save data * Add file safe string functions to tasks --- data/duke.txt | 5 ++ src/main/java/Deadline.java | 5 ++ src/main/java/Duke.java | 35 ++++++++-- src/main/java/Event.java | 5 ++ src/main/java/Task.java | 6 +- src/main/java/TaskListFileUtils.java | 95 ++++++++++++++++++++++++++++ src/main/java/ToDos.java | 5 ++ 7 files changed, 150 insertions(+), 6 deletions(-) create mode 100644 data/duke.txt create mode 100644 src/main/java/TaskListFileUtils.java diff --git a/data/duke.txt b/data/duke.txt new file mode 100644 index 0000000000..bec87e2018 --- /dev/null +++ b/data/duke.txt @@ -0,0 +1,5 @@ +D,0,11,do homework,11,no idea :-p +T,0,13,Dab on Homies +E,0,7,Ninja_0,7,3pm EST +T,0,13,Dab on Homies +E,0,7,Ninja_0,7,3pm EST diff --git a/src/main/java/Deadline.java b/src/main/java/Deadline.java index ee2c20f5da..0fa12979d4 100644 --- a/src/main/java/Deadline.java +++ b/src/main/java/Deadline.java @@ -14,4 +14,9 @@ public Deadline(String description, String by) throws EmptyArgument { public String toString() { return "[D]" + super.toString() + " (Deadline: " + by + ")"; } + + @Override + public String toFileString() { + return "D," + super.toBaseFileString() + "," + by.length() + "," + by; + } } \ No newline at end of file diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index d95b0ccaa6..e99502b850 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -1,5 +1,5 @@ +import java.io.IOException; import java.text.ParseException; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Scanner; @@ -15,13 +15,22 @@ public static void main(String[] args) { String separator = "------------------\n"; System.out.println("Hello from\n" + logo); System.out.println("No unicode allowed"); + List store = null; + try { + System.out.println("Loading From File..."); + store = TaskListFileUtils.LoadTaskList(); + System.out.println("Loaded"); + } catch (IOException e) { + System.out.println("Failed to Load file. Aborting."); + return; + } Scanner in = new Scanner(System.in); String line; - List store = new ArrayList<>(); String tokens[] = {"invalid"}; do{ System.out.print(separator + "Listening to your input: "); line = in.nextLine(); + int hash = store.hashCode(); //To detect changes later. try { String singleTokens[] = {"bye","list"}; tokens = splitTokenIntoTwo(line," ", singleTokens); @@ -30,9 +39,7 @@ public static void main(String[] args) { System.out.println(separator + "Goodbye from\n" + logo); break; case "list": - for (int i = 0 ; i < store.size(); i++) { - System.out.println(formatOrderedPrint(store,i)); - } + printList(store); break; case "done": int index = Integer.valueOf(tokens[1]) - 1; @@ -75,10 +82,28 @@ public static void main(String[] args) { System.out.println(e.getMessage()); } catch(EmptyArgument e){ System.out.println("Cannot have empty argument"); + } finally { + int x = store.hashCode(); + if(store.hashCode() != hash){ + try { + TaskListFileUtils.saveTaskList(store); + } catch (IOException e) { + System.out.println("Unable to save list. Dumping ..."); + printList(store); + System.out.println("Continuing Normal operation"); + } + } } }while(!tokens[0].equals("bye")); in.close(); } + + private static void printList(List store){ + for (int i = 0 ; i < store.size(); i++) { + System.out.println(formatOrderedPrint(store,i)); + } + } + private static String formatOrderedPrint(List tasks, int i){ final int size = tasks.size(); while (i < 0){ diff --git a/src/main/java/Event.java b/src/main/java/Event.java index b0ed9e06b6..5184d7dabf 100644 --- a/src/main/java/Event.java +++ b/src/main/java/Event.java @@ -14,4 +14,9 @@ public Event(String description, String eventPeriod) throws EmptyArgument { public String toString() { return "[E]" + super.toString() + " (Event Time: " + eventPeriod + ")"; } + + @Override + public String toFileString() { + return "E," + super.toBaseFileString() + "," + eventPeriod.length() + "," + eventPeriod; + } } diff --git a/src/main/java/Task.java b/src/main/java/Task.java index 96fdb989d2..d7c92d8e14 100644 --- a/src/main/java/Task.java +++ b/src/main/java/Task.java @@ -21,5 +21,9 @@ public String toString() { description; } - //... + abstract String toFileString(); + + String toBaseFileString(){ + return (isDone ? "1" : "0") + "," + description.length() + "," + description; + } } \ No newline at end of file diff --git a/src/main/java/TaskListFileUtils.java b/src/main/java/TaskListFileUtils.java new file mode 100644 index 0000000000..e179fd645e --- /dev/null +++ b/src/main/java/TaskListFileUtils.java @@ -0,0 +1,95 @@ +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class TaskListFileUtils { + public static final String FILE_DIR = "data"; + public static final String FILE_NAME = "duke.txt"; + static int badLines = 0;//Last call bad lines + + public static List LoadTaskList() throws IOException { + badLines = 0; + List store = new ArrayList<>(); + File file = getOrCreateFile(); + Scanner s = new Scanner(file); + generateLines: //TODO: Whats the code style for this. + while(s.hasNextLine()){ + Task t; + String line = s.nextLine(); + String pattern = "([TED]),([01]),(\\d*),(.*)"; + Pattern r = Pattern.compile(pattern); + Matcher m = r.matcher(line); + if(!m.find()){ + badLines++; + break; + } + String type = m.group(1); + boolean isDone = m.group(2).equals("1"); + int taskLength = Integer.parseInt(m.group(3)); + String task = m.group(4).substring(0,taskLength); + String leftover = m.group(4).substring(taskLength); + try { + if (type.equals("E") || type.equals("D") ) { + line = leftover.substring(1); + pattern = "(\\d*),(.*)"; + r = Pattern.compile(pattern); + m = r.matcher(line); + if (!m.find()) { + badLines++; + break; + } + int timeLength = Integer.parseInt(m.group(1)); + String timeData = m.group(2).substring(0, timeLength); + + switch (type) { + case "E": + t = new Event(task, timeData); + break; + case "D": + t = new Deadline(task, timeData); + break; + default: + badLines++; + break generateLines; + } + } else { + t = new ToDos(task); + } + }catch(EmptyArgument e){ + badLines++; + break; + } + t.isDone = isDone; + store.add(t); + } + s.close(); + return store; + } + + public static void saveTaskList(List store) throws IOException { + StringBuilder saveText = new StringBuilder(); + for (Task t: store){ + saveText.append(t.toFileString()); + saveText.append('\n'); + } + File f = getOrCreateFile(); + FileWriter writer = new FileWriter(f); + writer.write(saveText.toString()); + writer.close(); + } + + private static File getOrCreateFile() throws IOException { + Files.createDirectories(Paths.get(FILE_DIR)); + File file = new File(FILE_DIR, FILE_NAME); // create a File for the given file path + file.createNewFile(); + return file; + } +} diff --git a/src/main/java/ToDos.java b/src/main/java/ToDos.java index 71318c8edf..5d89e1f5cc 100644 --- a/src/main/java/ToDos.java +++ b/src/main/java/ToDos.java @@ -7,4 +7,9 @@ public ToDos(String description) throws EmptyArgument { public String toString() { return "[T]" + super.toString(); } + + @Override + String toFileString() { + return "T," + super.toBaseFileString(); + } } From eab039037fe0e0ea1afbff7ff27874a0c51d123b Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Fri, 29 Jan 2021 02:47:08 +0800 Subject: [PATCH 23/92] Fix hash calculation of CheckList for better saving --- src/main/java/Duke.java | 4 ++-- src/main/java/Task.java | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index e99502b850..18ae35fac8 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -83,8 +83,8 @@ public static void main(String[] args) { } catch(EmptyArgument e){ System.out.println("Cannot have empty argument"); } finally { - int x = store.hashCode(); - if(store.hashCode() != hash){ + int newHash = store.hashCode(); + if(newHash != hash){ try { TaskListFileUtils.saveTaskList(store); } catch (IOException e) { diff --git a/src/main/java/Task.java b/src/main/java/Task.java index d7c92d8e14..32386ccd8c 100644 --- a/src/main/java/Task.java +++ b/src/main/java/Task.java @@ -23,6 +23,11 @@ public String toString() { abstract String toFileString(); + @Override + public int hashCode(){ + return this.toString().hashCode(); + } + String toBaseFileString(){ return (isDone ? "1" : "0") + "," + description.length() + "," + description; } From b985269c989e7022dabf35f84769049a6e76dbe5 Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Fri, 29 Jan 2021 03:17:49 +0800 Subject: [PATCH 24/92] Remove duke.txt from tracking --- data/.gitignore | 3 +++ data/duke.txt | 5 ----- 2 files changed, 3 insertions(+), 5 deletions(-) create mode 100644 data/.gitignore delete mode 100644 data/duke.txt diff --git a/data/.gitignore b/data/.gitignore new file mode 100644 index 0000000000..e7a210ec7d --- /dev/null +++ b/data/.gitignore @@ -0,0 +1,3 @@ +* +*/ +!.gitignore \ No newline at end of file diff --git a/data/duke.txt b/data/duke.txt deleted file mode 100644 index bec87e2018..0000000000 --- a/data/duke.txt +++ /dev/null @@ -1,5 +0,0 @@ -D,0,11,do homework,11,no idea :-p -T,0,13,Dab on Homies -E,0,7,Ninja_0,7,3pm EST -T,0,13,Dab on Homies -E,0,7,Ninja_0,7,3pm EST From 100297eca2cb50a572c55e498866f9a0a40dd11b Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Fri, 29 Jan 2021 03:48:26 +0800 Subject: [PATCH 25/92] Add date time parsing to Deadline --- src/main/java/Deadline.java | 14 +++++++------- src/main/java/Duke.java | 6 +++++- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/main/java/Deadline.java b/src/main/java/Deadline.java index ee2c20f5da..13761b11b4 100644 --- a/src/main/java/Deadline.java +++ b/src/main/java/Deadline.java @@ -1,17 +1,17 @@ +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; + public class Deadline extends Task { - protected String by; + protected LocalDate by; - public Deadline(String description, String by) throws EmptyArgument { + public Deadline(String description, LocalDate by) throws EmptyArgument { super(description); - by = by.trim(); - if (by.isEmpty()){ - throw new EmptyArgument(); - } this.by = by; } @Override public String toString() { - return "[D]" + super.toString() + " (Deadline: " + by + ")"; + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMMM dd, yyyy"); + return "[D]" + super.toString() + " (Deadline: " + by.format(formatter) + ")"; } } \ No newline at end of file diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index d95b0ccaa6..e8c0311cdf 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -1,4 +1,6 @@ import java.text.ParseException; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -48,7 +50,9 @@ public static void main(String[] args) { break; case "deadline": tokens = splitTokenIntoTwo(tokens[1]," /by "); - store.add(new Deadline(tokens[0],tokens[1])); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd MM yyyy"); + LocalDate data = LocalDate.parse(tokens[1], formatter); + store.add(new Deadline(tokens[0],data)); System.out.println("The following deadline item has been added:\n" + formatOrderedPrint(store,-1)); break; From a66f65a7b73b7eae61cb47db0bd02f83bf48859d Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Fri, 29 Jan 2021 04:13:57 +0800 Subject: [PATCH 26/92] Add graceful handling of badly formatted date input --- src/main/java/BadDateArgumentException.java | 7 +++++++ src/main/java/Deadline.java | 11 ++++++++--- src/main/java/Duke.java | 2 ++ src/main/java/TaskListFileUtils.java | 3 +++ 4 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 src/main/java/BadDateArgumentException.java diff --git a/src/main/java/BadDateArgumentException.java b/src/main/java/BadDateArgumentException.java new file mode 100644 index 0000000000..b51a3494c0 --- /dev/null +++ b/src/main/java/BadDateArgumentException.java @@ -0,0 +1,7 @@ +public class BadDateArgumentException extends Exception{ + + /** + * + */ + private static final long serialVersionUID = 1L; +} diff --git a/src/main/java/Deadline.java b/src/main/java/Deadline.java index 8de528c389..0820a431af 100644 --- a/src/main/java/Deadline.java +++ b/src/main/java/Deadline.java @@ -1,14 +1,19 @@ import java.time.LocalDate; import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; public class Deadline extends Task { protected LocalDate by; - public Deadline(String description, String by) throws EmptyArgument { + public Deadline(String description, String by) throws EmptyArgument, BadDateArgumentException { super(description); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd MM yyyy"); - LocalDate date = LocalDate.parse(by, formatter); - this.by = date; + try { + LocalDate date = LocalDate.parse(by, formatter); + this.by = date; + }catch(DateTimeParseException e){ + throw new BadDateArgumentException(); + } } @Override diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index 18ae35fac8..50943e067c 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -82,6 +82,8 @@ public static void main(String[] args) { System.out.println(e.getMessage()); } catch(EmptyArgument e){ System.out.println("Cannot have empty argument"); + } catch (BadDateArgumentException e) { + System.out.println("Date must be of format 'dd MM yyyy'; Eg: 27 08 2044"); } finally { int newHash = store.hashCode(); if(newHash != hash){ diff --git a/src/main/java/TaskListFileUtils.java b/src/main/java/TaskListFileUtils.java index e179fd645e..3a7bc54efe 100644 --- a/src/main/java/TaskListFileUtils.java +++ b/src/main/java/TaskListFileUtils.java @@ -66,6 +66,9 @@ public static List LoadTaskList() throws IOException { }catch(EmptyArgument e){ badLines++; break; + }catch(BadDateArgumentException e){ + badLines++; + break; } t.isDone = isDone; store.add(t); From 494dc331bba82d781b6f2ed90cc3bf3972dd532a Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Fri, 29 Jan 2021 04:17:57 +0800 Subject: [PATCH 27/92] Fix bug where feedback on done item was absent --- src/main/java/Duke.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index 50943e067c..df075b520c 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -46,7 +46,7 @@ public static void main(String[] args) { Task t = store.get(index); t.isDone = true; System.out.println("The following task is now marked as done:\n" + - formatOrderedPrint(store,-1)); + formatOrderedPrint(store,index)); break; case "todo": store.add(new ToDos(tokens[1])); From 1edba8d5da3d03ab6210a3646ddec68184247e40 Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Fri, 29 Jan 2021 12:54:40 +0800 Subject: [PATCH 28/92] Add some Class needed for the increment A-MoreOOP --- src/main/java/AddCommand.java | 17 ++++++ src/main/java/Command.java | 4 ++ src/main/java/DeleteCommand.java | 10 ++++ src/main/java/DoneCommand.java | 10 ++++ src/main/java/IndexedCommand.java | 11 ++++ src/main/java/ListCommand.java | 12 +++++ src/main/java/Parser.java | 55 +++++++++++++++++++ src/main/java/TaskList.java | 87 +++++++++++++++++++++++++++++++ 8 files changed, 206 insertions(+) create mode 100644 src/main/java/AddCommand.java create mode 100644 src/main/java/Command.java create mode 100644 src/main/java/DeleteCommand.java create mode 100644 src/main/java/DoneCommand.java create mode 100644 src/main/java/IndexedCommand.java create mode 100644 src/main/java/ListCommand.java create mode 100644 src/main/java/Parser.java create mode 100644 src/main/java/TaskList.java diff --git a/src/main/java/AddCommand.java b/src/main/java/AddCommand.java new file mode 100644 index 0000000000..726a51700b --- /dev/null +++ b/src/main/java/AddCommand.java @@ -0,0 +1,17 @@ +public class AddCommand extends Command{ + String[] args; + + public AddCommand(String[] args){ + this.args = args; + } + + @Override + String[] run() { + return args; + } + + @Override + TaskList.Action getType() { + return TaskList.Action.ADD; + } +} diff --git a/src/main/java/Command.java b/src/main/java/Command.java new file mode 100644 index 0000000000..2ce7c347d6 --- /dev/null +++ b/src/main/java/Command.java @@ -0,0 +1,4 @@ +public abstract class Command { + abstract String[] run(); + abstract TaskList.Action getType(); +} diff --git a/src/main/java/DeleteCommand.java b/src/main/java/DeleteCommand.java new file mode 100644 index 0000000000..393202a284 --- /dev/null +++ b/src/main/java/DeleteCommand.java @@ -0,0 +1,10 @@ +public class DeleteCommand extends IndexedCommand{ + public DeleteCommand(int position) { + super(position); + } + + @Override + TaskList.Action getType() { + return TaskList.Action.DELETE; + } +} diff --git a/src/main/java/DoneCommand.java b/src/main/java/DoneCommand.java new file mode 100644 index 0000000000..534b99a341 --- /dev/null +++ b/src/main/java/DoneCommand.java @@ -0,0 +1,10 @@ +public class DoneCommand extends IndexedCommand{ + public DoneCommand(int position) { + super(position); + } + + @Override + TaskList.Action getType() { + return TaskList.Action.DONE; + } +} diff --git a/src/main/java/IndexedCommand.java b/src/main/java/IndexedCommand.java new file mode 100644 index 0000000000..ae2171a057 --- /dev/null +++ b/src/main/java/IndexedCommand.java @@ -0,0 +1,11 @@ +abstract class IndexedCommand extends Command{ + private final int index; + public IndexedCommand(int position){ + this.index = position - 1; + } + + @Override + String[] run() { + return new String[]{String.valueOf(index)}; + } +} diff --git a/src/main/java/ListCommand.java b/src/main/java/ListCommand.java new file mode 100644 index 0000000000..5b1c900059 --- /dev/null +++ b/src/main/java/ListCommand.java @@ -0,0 +1,12 @@ +public class ListCommand extends Command { + + @Override + String[] run() { + return new String[0]; + } + + @Override + TaskList.Action getType() { + return TaskList.Action.LIST; + } +} diff --git a/src/main/java/Parser.java b/src/main/java/Parser.java new file mode 100644 index 0000000000..bab59c5aad --- /dev/null +++ b/src/main/java/Parser.java @@ -0,0 +1,55 @@ +import java.text.ParseException; +import java.util.Arrays; +import java.util.List; + +public class Parser { + public static Command parse(String line) throws ParseException, InvalidCommandException { + Command c = null; + String singleTokens[] = {"bye", "list"}; + String[] tokens = splitTokenIntoTwo(line, " ", singleTokens); + switch (tokens[0]) { + case "bye": + //Leave as null + break; + case "list": + c = new ListCommand(); + break; + case "done": + c = new DoneCommand(Integer.parseInt(tokens[1])); + break; + case "todo": + c = new AddCommand(new String[]{"T", tokens[1]}); + break; + case "deadline": + tokens = splitTokenIntoTwo(tokens[1], " /by "); + c = new AddCommand(new String[]{"D", tokens[0], tokens[1]}); + break; + case "event": + tokens = splitTokenIntoTwo(tokens[1], " /at "); + c = new AddCommand(new String[]{"E", tokens[0], tokens[1]}); + break; + case "delete": + c = new DeleteCommand(Integer.parseInt(tokens[1])); + break; + default: + throw new InvalidCommandException(tokens[0]); + } + return c; + } + private static String[] splitTokenIntoTwo(String parseTarget,String delimiter) throws ParseException { + String[] tokens = parseTarget.split(delimiter,2); + if (tokens.length < 2){ + throw new ParseException("Expected deliminter '"+ delimiter +"'", tokens[0].length()); + } + return tokens; + } + + private static String[] splitTokenIntoTwo(String parseTarget,String delimiter, String[] exception) throws ParseException{ + List exceptionList = Arrays.asList(exception); + String[] tokens = parseTarget.split(delimiter,2); + if (!exceptionList.contains(tokens[0]) && tokens.length < 2){ + throw new ParseException("Expected deliminter '"+ delimiter +"'", tokens[0].length()); + } + return tokens; + } +} diff --git a/src/main/java/TaskList.java b/src/main/java/TaskList.java new file mode 100644 index 0000000000..9c741b73c8 --- /dev/null +++ b/src/main/java/TaskList.java @@ -0,0 +1,87 @@ +import java.util.ArrayList; +import java.util.List; + +public class TaskList { + public enum Action{ + ADD, + LIST, + DONE, + DELETE, + } + List store; + public TaskList(String[][] tokens) throws EmptyArgument, BadDateArgumentException { + store = new ArrayList<>(); + for(String[] args: tokens){ + addTask(args); + } + } + private String addTask(String[] tokens) throws EmptyArgument, BadDateArgumentException { + Task t; + switch(tokens[0]){ + case "D": + t = new Deadline(tokens[1], tokens[2]); + break; + case "E": + t = new Event(tokens[1], tokens[2]); + break; + case "T": + //Fall through + default: //More fault tolerant + t = new ToDos(tokens[1]); + break; + } + store.add(t); + return formatOrderedPrint(-1); + } + public String run(Command c) throws EmptyArgument, BadDateArgumentException { + String[] args = c.run(); + String results; + switch(c.getType()){ + case ADD: + results = addTask(args); + break; + case DONE: + results = setDone(Integer.parseInt(args[0])); + break; + case DELETE: + results = delete(Integer.parseInt(args[0])); + break; + case LIST: + results = getList(); + break; + default: + results = ""; + break; + } + return results; + } + private String setDone(int doneIndex){ + Task t = store.get(doneIndex); + t.isDone = true; + return formatOrderedPrint(doneIndex); + } + private String delete(int deleteIndex){ + String returnValue = formatOrderedPrint(deleteIndex); + store.remove(deleteIndex); + return returnValue; + } + private String getList(){ + StringBuilder builder = new StringBuilder(); + for (int i = 0 ; i < store.size(); i++) { + builder.append(formatOrderedPrint(i)); + builder.append('\n'); + } + return builder.toString(); + } + + private String formatOrderedPrint(int i){ + final int size = store.size(); + while (i < 0){ + i += size; + } + while (i >= size){ + i -= size; + } + return "Entry " + (i+1) + "|" + store.get(i).toString() + "\n"; + } +} From 079455b93190236658a3c21ed833eaee124ae353 Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Fri, 29 Jan 2021 12:58:25 +0800 Subject: [PATCH 29/92] Add flag to detect edits --- src/main/java/TaskList.java | 43 +++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/src/main/java/TaskList.java b/src/main/java/TaskList.java index 9c741b73c8..d0214051b7 100644 --- a/src/main/java/TaskList.java +++ b/src/main/java/TaskList.java @@ -8,6 +8,7 @@ public enum Action{ DONE, DELETE, } + boolean edited = false; List store; public TaskList(String[][] tokens) throws EmptyArgument, BadDateArgumentException { store = new ArrayList<>(); @@ -15,36 +16,21 @@ public TaskList(String[][] tokens) throws EmptyArgument, BadDateArgumentExceptio addTask(args); } } - private String addTask(String[] tokens) throws EmptyArgument, BadDateArgumentException { - Task t; - switch(tokens[0]){ - case "D": - t = new Deadline(tokens[1], tokens[2]); - break; - case "E": - t = new Event(tokens[1], tokens[2]); - break; - case "T": - //Fall through - default: //More fault tolerant - t = new ToDos(tokens[1]); - break; - } - store.add(t); - return formatOrderedPrint(-1); - } public String run(Command c) throws EmptyArgument, BadDateArgumentException { String[] args = c.run(); String results; switch(c.getType()){ case ADD: results = addTask(args); + edited = true; break; case DONE: results = setDone(Integer.parseInt(args[0])); + edited = true; break; case DELETE: results = delete(Integer.parseInt(args[0])); + edited = true; break; case LIST: results = getList(); @@ -55,6 +41,27 @@ public String run(Command c) throws EmptyArgument, BadDateArgumentException { } return results; } + private void markSaved(){ + edited = false; + } + private String addTask(String[] tokens) throws EmptyArgument, BadDateArgumentException { + Task t; + switch(tokens[0]){ + case "D": + t = new Deadline(tokens[1], tokens[2]); + break; + case "E": + t = new Event(tokens[1], tokens[2]); + break; + case "T": + //Fall through + default: //More fault tolerant + t = new ToDos(tokens[1]); + break; + } + store.add(t); + return formatOrderedPrint(-1); + } private String setDone(int doneIndex){ Task t = store.get(doneIndex); t.isDone = true; From 69d2fb319907a7f6f3e15ef0c4569d860aa0f7ef Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Sun, 31 Jan 2021 19:23:05 +0800 Subject: [PATCH 30/92] Move some Ui code into its own class --- src/main/java/Duke.java | 13 +++---------- src/main/java/Ui.java | 17 +++++++++++++++++ 2 files changed, 20 insertions(+), 10 deletions(-) create mode 100644 src/main/java/Ui.java diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index df075b520c..e945f34098 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -6,15 +6,9 @@ public class Duke { public static void main(String[] args) { - String logo = - " ____ _ \n" - + "| _ \\ _ _| | _____ \n" - + "| | | | | | | |/ / _ \\\n" - + "| |_| | |_| | < __/\n" - + "|____/ \\__,_|_|\\_\\___|\n"; + Ui ui = new Ui(); String separator = "------------------\n"; - System.out.println("Hello from\n" + logo); - System.out.println("No unicode allowed"); + ui.startUpMessage(); List store = null; try { System.out.println("Loading From File..."); @@ -36,8 +30,7 @@ public static void main(String[] args) { tokens = splitTokenIntoTwo(line," ", singleTokens); switch(tokens[0]){ case "bye": - System.out.println(separator + "Goodbye from\n" + logo); - break; + ui.goodByeMessage(); break; case "list": printList(store); break; diff --git a/src/main/java/Ui.java b/src/main/java/Ui.java new file mode 100644 index 0000000000..eae5a44d6e --- /dev/null +++ b/src/main/java/Ui.java @@ -0,0 +1,17 @@ +public class Ui { + String logo = + " ____ _ \n" //TODO: Figure out if this is allowed by style + + "| _ \\ _ _| | _____ \n" + + "| | | | | | | |/ / _ \\\n" + + "| |_| | |_| | < __/\n" + + "|____/ \\__,_|_|\\_\\___|\n"; + String separator = "------------------\n"; + + public void startUpMessage(){ + System.out.println("Hello from\n" + logo); + System.out.println("No unicode allowed"); + } + public void goodByeMessage(){ + System.out.println(separator + "Goodbye from\n" + logo); + } +} From 52ab2afce0a06c195f02b4051e82d77d49498e2d Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Sun, 31 Jan 2021 20:04:11 +0800 Subject: [PATCH 31/92] Refactor java files into packages Currently, the project src files are all in one single src folder. This makes it very unclear what files are logically together and clutter the folder view. Let's * Create a top level package 'duke' * Create the sub-packages 'command', 'exception' and 'task' * Leave the files; 'Duke', 'Parser', 'TaskList', 'TaskListFileUtils' and 'Ui' in the top level package 'duke'. Note that I only place files that will have more than one related file into packages. I currently do not have any packages with only one file for now. Whether that is best practice or not is unknown, and may change in the future. --- src/main/java/Command.java | 4 ---- src/main/java/ListCommand.java | 12 ------------ src/main/java/{ => duke}/Duke.java | 16 +++++++++++++--- src/main/java/{ => duke}/Parser.java | 5 +++++ src/main/java/{ => duke}/TaskList.java | 16 +++++++++++++--- src/main/java/{ => duke}/TaskListFileUtils.java | 12 ++++++++++-- src/main/java/{ => duke}/Ui.java | 2 ++ src/main/java/{ => duke/command}/AddCommand.java | 11 ++++++++--- src/main/java/duke/command/Command.java | 8 ++++++++ .../java/{ => duke/command}/DeleteCommand.java | 8 ++++++-- .../java/{ => duke/command}/DoneCommand.java | 8 ++++++-- .../java/{ => duke/command}/IndexedCommand.java | 4 +++- src/main/java/duke/command/ListCommand.java | 16 ++++++++++++++++ .../exception}/BadDateArgumentException.java | 2 ++ .../exception/EmptyArgumentException.java} | 4 +++- .../exception}/InvalidCommandException.java | 4 +++- src/main/java/{ => duke/task}/Deadline.java | 9 +++++++-- src/main/java/{ => duke/task}/Event.java | 10 +++++++--- src/main/java/{ => duke/task}/Task.java | 12 ++++++++---- src/main/java/{ => duke/task}/ToDos.java | 8 ++++++-- 20 files changed, 126 insertions(+), 45 deletions(-) delete mode 100644 src/main/java/Command.java delete mode 100644 src/main/java/ListCommand.java rename src/main/java/{ => duke}/Duke.java (93%) rename src/main/java/{ => duke}/Parser.java (96%) rename src/main/java/{ => duke}/TaskList.java (83%) rename src/main/java/{ => duke}/TaskListFileUtils.java (92%) rename src/main/java/{ => duke}/Ui.java (97%) rename src/main/java/{ => duke/command}/AddCommand.java (55%) create mode 100644 src/main/java/duke/command/Command.java rename src/main/java/{ => duke/command}/DeleteCommand.java (56%) rename src/main/java/{ => duke/command}/DoneCommand.java (56%) rename src/main/java/{ => duke/command}/IndexedCommand.java (82%) create mode 100644 src/main/java/duke/command/ListCommand.java rename src/main/java/{ => duke/exception}/BadDateArgumentException.java (84%) rename src/main/java/{EmptyArgument.java => duke/exception/EmptyArgumentException.java} (51%) rename src/main/java/{ => duke/exception}/InvalidCommandException.java (75%) rename src/main/java/{ => duke/task}/Deadline.java (79%) rename src/main/java/{ => duke/task}/Event.java (68%) rename src/main/java/{ => duke/task}/Task.java (70%) rename src/main/java/{ => duke/task}/ToDos.java (57%) diff --git a/src/main/java/Command.java b/src/main/java/Command.java deleted file mode 100644 index 2ce7c347d6..0000000000 --- a/src/main/java/Command.java +++ /dev/null @@ -1,4 +0,0 @@ -public abstract class Command { - abstract String[] run(); - abstract TaskList.Action getType(); -} diff --git a/src/main/java/ListCommand.java b/src/main/java/ListCommand.java deleted file mode 100644 index 5b1c900059..0000000000 --- a/src/main/java/ListCommand.java +++ /dev/null @@ -1,12 +0,0 @@ -public class ListCommand extends Command { - - @Override - String[] run() { - return new String[0]; - } - - @Override - TaskList.Action getType() { - return TaskList.Action.LIST; - } -} diff --git a/src/main/java/Duke.java b/src/main/java/duke/Duke.java similarity index 93% rename from src/main/java/Duke.java rename to src/main/java/duke/Duke.java index e945f34098..de21373943 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/duke/Duke.java @@ -1,3 +1,13 @@ +package duke; + +import duke.exception.BadDateArgumentException; +import duke.exception.EmptyArgumentException; +import duke.exception.InvalidCommandException; +import duke.task.Deadline; +import duke.task.Event; +import duke.task.Task; +import duke.task.ToDos; + import java.io.IOException; import java.text.ParseException; import java.util.Arrays; @@ -60,7 +70,7 @@ public static void main(String[] args) { break; case "delete": int deleteIndex = Integer.valueOf(tokens[1]) - 1; - System.out.println("Deleting the following Task:"); + System.out.println("Deleting the following duke.task.Task:"); System.out.println(formatOrderedPrint(store, deleteIndex)); store.remove(deleteIndex); System.out.println("Done"); @@ -69,11 +79,11 @@ public static void main(String[] args) { throw new InvalidCommandException(tokens[0]); } } catch (ParseException e) { - System.out.println("Command has invalid parsing."); + System.out.println("Command.Command has invalid parsing."); System.out.println(e.getMessage()); } catch (InvalidCommandException e){ System.out.println(e.getMessage()); - } catch(EmptyArgument e){ + } catch(EmptyArgumentException e){ System.out.println("Cannot have empty argument"); } catch (BadDateArgumentException e) { System.out.println("Date must be of format 'dd MM yyyy'; Eg: 27 08 2044"); diff --git a/src/main/java/Parser.java b/src/main/java/duke/Parser.java similarity index 96% rename from src/main/java/Parser.java rename to src/main/java/duke/Parser.java index bab59c5aad..a897c638b7 100644 --- a/src/main/java/Parser.java +++ b/src/main/java/duke/Parser.java @@ -1,3 +1,8 @@ +package duke; + +import duke.command.*; +import duke.exception.InvalidCommandException; + import java.text.ParseException; import java.util.Arrays; import java.util.List; diff --git a/src/main/java/TaskList.java b/src/main/java/duke/TaskList.java similarity index 83% rename from src/main/java/TaskList.java rename to src/main/java/duke/TaskList.java index d0214051b7..5d8ead15a5 100644 --- a/src/main/java/TaskList.java +++ b/src/main/java/duke/TaskList.java @@ -1,3 +1,13 @@ +package duke; + +import duke.command.Command; +import duke.exception.BadDateArgumentException; +import duke.exception.EmptyArgumentException; +import duke.task.Deadline; +import duke.task.Event; +import duke.task.Task; +import duke.task.ToDos; + import java.util.ArrayList; import java.util.List; @@ -10,13 +20,13 @@ public enum Action{ } boolean edited = false; List store; - public TaskList(String[][] tokens) throws EmptyArgument, BadDateArgumentException { + public TaskList(String[][] tokens) throws EmptyArgumentException, BadDateArgumentException { store = new ArrayList<>(); for(String[] args: tokens){ addTask(args); } } - public String run(Command c) throws EmptyArgument, BadDateArgumentException { + public String run(Command c) throws EmptyArgumentException, BadDateArgumentException { String[] args = c.run(); String results; switch(c.getType()){ @@ -44,7 +54,7 @@ public String run(Command c) throws EmptyArgument, BadDateArgumentException { private void markSaved(){ edited = false; } - private String addTask(String[] tokens) throws EmptyArgument, BadDateArgumentException { + private String addTask(String[] tokens) throws EmptyArgumentException, BadDateArgumentException { Task t; switch(tokens[0]){ case "D": diff --git a/src/main/java/TaskListFileUtils.java b/src/main/java/duke/TaskListFileUtils.java similarity index 92% rename from src/main/java/TaskListFileUtils.java rename to src/main/java/duke/TaskListFileUtils.java index 3a7bc54efe..cdec1dce1c 100644 --- a/src/main/java/TaskListFileUtils.java +++ b/src/main/java/duke/TaskListFileUtils.java @@ -1,8 +1,16 @@ +package duke; + +import duke.exception.BadDateArgumentException; +import duke.exception.EmptyArgumentException; +import duke.task.Deadline; +import duke.task.Event; +import duke.task.Task; +import duke.task.ToDos; + import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.nio.file.Files; -import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; @@ -63,7 +71,7 @@ public static List LoadTaskList() throws IOException { } else { t = new ToDos(task); } - }catch(EmptyArgument e){ + }catch(EmptyArgumentException e){ badLines++; break; }catch(BadDateArgumentException e){ diff --git a/src/main/java/Ui.java b/src/main/java/duke/Ui.java similarity index 97% rename from src/main/java/Ui.java rename to src/main/java/duke/Ui.java index eae5a44d6e..b4dd2db80d 100644 --- a/src/main/java/Ui.java +++ b/src/main/java/duke/Ui.java @@ -1,3 +1,5 @@ +package duke; + public class Ui { String logo = " ____ _ \n" //TODO: Figure out if this is allowed by style diff --git a/src/main/java/AddCommand.java b/src/main/java/duke/command/AddCommand.java similarity index 55% rename from src/main/java/AddCommand.java rename to src/main/java/duke/command/AddCommand.java index 726a51700b..69f4a3822e 100644 --- a/src/main/java/AddCommand.java +++ b/src/main/java/duke/command/AddCommand.java @@ -1,3 +1,8 @@ +package duke.command; + +import duke.TaskList; +import duke.TaskList.Action; + public class AddCommand extends Command{ String[] args; @@ -6,12 +11,12 @@ public AddCommand(String[] args){ } @Override - String[] run() { + public String[] run() { return args; } @Override - TaskList.Action getType() { - return TaskList.Action.ADD; + public Action getType() { + return Action.ADD; } } diff --git a/src/main/java/duke/command/Command.java b/src/main/java/duke/command/Command.java new file mode 100644 index 0000000000..3ac304d79a --- /dev/null +++ b/src/main/java/duke/command/Command.java @@ -0,0 +1,8 @@ +package duke.command; + +import duke.TaskList; + +public abstract class Command { + public abstract String[] run(); + public abstract TaskList.Action getType(); +} diff --git a/src/main/java/DeleteCommand.java b/src/main/java/duke/command/DeleteCommand.java similarity index 56% rename from src/main/java/DeleteCommand.java rename to src/main/java/duke/command/DeleteCommand.java index 393202a284..8074733fda 100644 --- a/src/main/java/DeleteCommand.java +++ b/src/main/java/duke/command/DeleteCommand.java @@ -1,10 +1,14 @@ +package duke.command; + +import duke.TaskList.Action; + public class DeleteCommand extends IndexedCommand{ public DeleteCommand(int position) { super(position); } @Override - TaskList.Action getType() { - return TaskList.Action.DELETE; + public Action getType() { + return Action.DELETE; } } diff --git a/src/main/java/DoneCommand.java b/src/main/java/duke/command/DoneCommand.java similarity index 56% rename from src/main/java/DoneCommand.java rename to src/main/java/duke/command/DoneCommand.java index 534b99a341..6b2ac87ac7 100644 --- a/src/main/java/DoneCommand.java +++ b/src/main/java/duke/command/DoneCommand.java @@ -1,10 +1,14 @@ +package duke.command; + +import duke.TaskList.Action; + public class DoneCommand extends IndexedCommand{ public DoneCommand(int position) { super(position); } @Override - TaskList.Action getType() { - return TaskList.Action.DONE; + public Action getType() { + return Action.DONE; } } diff --git a/src/main/java/IndexedCommand.java b/src/main/java/duke/command/IndexedCommand.java similarity index 82% rename from src/main/java/IndexedCommand.java rename to src/main/java/duke/command/IndexedCommand.java index ae2171a057..cbeb5aa574 100644 --- a/src/main/java/IndexedCommand.java +++ b/src/main/java/duke/command/IndexedCommand.java @@ -1,3 +1,5 @@ +package duke.command; + abstract class IndexedCommand extends Command{ private final int index; public IndexedCommand(int position){ @@ -5,7 +7,7 @@ public IndexedCommand(int position){ } @Override - String[] run() { + public String[] run() { return new String[]{String.valueOf(index)}; } } diff --git a/src/main/java/duke/command/ListCommand.java b/src/main/java/duke/command/ListCommand.java new file mode 100644 index 0000000000..420c7f640b --- /dev/null +++ b/src/main/java/duke/command/ListCommand.java @@ -0,0 +1,16 @@ +package duke.command; + +import duke.TaskList.Action; + +public class ListCommand extends Command { + + @Override + public String[] run() { + return new String[0]; + } + + @Override + public Action getType() { + return Action.LIST; + } +} diff --git a/src/main/java/BadDateArgumentException.java b/src/main/java/duke/exception/BadDateArgumentException.java similarity index 84% rename from src/main/java/BadDateArgumentException.java rename to src/main/java/duke/exception/BadDateArgumentException.java index b51a3494c0..d3c3607429 100644 --- a/src/main/java/BadDateArgumentException.java +++ b/src/main/java/duke/exception/BadDateArgumentException.java @@ -1,3 +1,5 @@ +package duke.exception; + public class BadDateArgumentException extends Exception{ /** diff --git a/src/main/java/EmptyArgument.java b/src/main/java/duke/exception/EmptyArgumentException.java similarity index 51% rename from src/main/java/EmptyArgument.java rename to src/main/java/duke/exception/EmptyArgumentException.java index 10b7ae55aa..c9d8c55814 100644 --- a/src/main/java/EmptyArgument.java +++ b/src/main/java/duke/exception/EmptyArgumentException.java @@ -1,4 +1,6 @@ -public class EmptyArgument extends Exception{ +package duke.exception; + +public class EmptyArgumentException extends Exception{ /** * diff --git a/src/main/java/InvalidCommandException.java b/src/main/java/duke/exception/InvalidCommandException.java similarity index 75% rename from src/main/java/InvalidCommandException.java rename to src/main/java/duke/exception/InvalidCommandException.java index 5ebb0d615e..076845f125 100644 --- a/src/main/java/InvalidCommandException.java +++ b/src/main/java/duke/exception/InvalidCommandException.java @@ -1,3 +1,5 @@ +package duke.exception; + public class InvalidCommandException extends Exception { private String badCommand; @@ -10,6 +12,6 @@ public InvalidCommandException(String badCommand) { @Override public String getMessage() { - return "Command '" + badCommand + "' is not recognized."; + return "Command.Command '" + badCommand + "' is not recognized."; } } \ No newline at end of file diff --git a/src/main/java/Deadline.java b/src/main/java/duke/task/Deadline.java similarity index 79% rename from src/main/java/Deadline.java rename to src/main/java/duke/task/Deadline.java index 0820a431af..4dc6db2331 100644 --- a/src/main/java/Deadline.java +++ b/src/main/java/duke/task/Deadline.java @@ -1,3 +1,8 @@ +package duke.task; + +import duke.exception.EmptyArgumentException; +import duke.exception.BadDateArgumentException; + import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; @@ -5,7 +10,7 @@ public class Deadline extends Task { protected LocalDate by; - public Deadline(String description, String by) throws EmptyArgument, BadDateArgumentException { + public Deadline(String description, String by) throws EmptyArgumentException, BadDateArgumentException { super(description); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd MM yyyy"); try { @@ -19,7 +24,7 @@ public Deadline(String description, String by) throws EmptyArgument, BadDateArgu @Override public String toString() { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMMM dd, yyyy"); - return "[D]" + super.toString() + " (Deadline: " + by.format(formatter) + ")"; + return "[D]" + super.toString() + " (duke.task.Deadline: " + by.format(formatter) + ")"; } @Override diff --git a/src/main/java/Event.java b/src/main/java/duke/task/Event.java similarity index 68% rename from src/main/java/Event.java rename to src/main/java/duke/task/Event.java index 5184d7dabf..179cc2c401 100644 --- a/src/main/java/Event.java +++ b/src/main/java/duke/task/Event.java @@ -1,18 +1,22 @@ +package duke.task; + +import duke.exception.EmptyArgumentException; + public class Event extends Task{ private String eventPeriod; - public Event(String description, String eventPeriod) throws EmptyArgument { + public Event(String description, String eventPeriod) throws EmptyArgumentException { super(description); eventPeriod = eventPeriod.trim(); if (eventPeriod.isEmpty()){ - throw new EmptyArgument(); + throw new EmptyArgumentException(); } this.eventPeriod = eventPeriod; } @Override public String toString() { - return "[E]" + super.toString() + " (Event Time: " + eventPeriod + ")"; + return "[E]" + super.toString() + " (duke.task.Event Time: " + eventPeriod + ")"; } @Override diff --git a/src/main/java/Task.java b/src/main/java/duke/task/Task.java similarity index 70% rename from src/main/java/Task.java rename to src/main/java/duke/task/Task.java index 32386ccd8c..5d5b15a787 100644 --- a/src/main/java/Task.java +++ b/src/main/java/duke/task/Task.java @@ -1,11 +1,15 @@ +package duke.task; + +import duke.exception.EmptyArgumentException; + public abstract class Task { private final String description; - protected boolean isDone; + public boolean isDone; //TODO: Figure out if I can restrict access - public Task(String description) throws EmptyArgument { + public Task(String description) throws EmptyArgumentException { description = description.trim(); if (description.isEmpty()){ - throw new EmptyArgument(); + throw new EmptyArgumentException(); } this.description = description; this.isDone = false; @@ -21,7 +25,7 @@ public String toString() { description; } - abstract String toFileString(); + public abstract String toFileString(); @Override public int hashCode(){ diff --git a/src/main/java/ToDos.java b/src/main/java/duke/task/ToDos.java similarity index 57% rename from src/main/java/ToDos.java rename to src/main/java/duke/task/ToDos.java index 5d89e1f5cc..231a4225c5 100644 --- a/src/main/java/ToDos.java +++ b/src/main/java/duke/task/ToDos.java @@ -1,5 +1,9 @@ +package duke.task; + +import duke.exception.EmptyArgumentException; + public class ToDos extends Task{ - public ToDos(String description) throws EmptyArgument { + public ToDos(String description) throws EmptyArgumentException { super(description); } @@ -9,7 +13,7 @@ public String toString() { } @Override - String toFileString() { + public String toFileString() { return "T," + super.toBaseFileString(); } } From 893c5e7ce6ca214ac34601eede78b8b36bf38a8d Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Sun, 31 Jan 2021 20:17:30 +0800 Subject: [PATCH 32/92] Rename TaskListFileUtils to Storage for Class req --- src/main/java/duke/Duke.java | 4 ++-- src/main/java/duke/{TaskListFileUtils.java => Storage.java} | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) rename src/main/java/duke/{TaskListFileUtils.java => Storage.java} (99%) diff --git a/src/main/java/duke/Duke.java b/src/main/java/duke/Duke.java index de21373943..2fa693fe13 100644 --- a/src/main/java/duke/Duke.java +++ b/src/main/java/duke/Duke.java @@ -22,7 +22,7 @@ public static void main(String[] args) { List store = null; try { System.out.println("Loading From File..."); - store = TaskListFileUtils.LoadTaskList(); + store = Storage.LoadTaskList(); System.out.println("Loaded"); } catch (IOException e) { System.out.println("Failed to Load file. Aborting."); @@ -91,7 +91,7 @@ public static void main(String[] args) { int newHash = store.hashCode(); if(newHash != hash){ try { - TaskListFileUtils.saveTaskList(store); + Storage.saveTaskList(store); } catch (IOException e) { System.out.println("Unable to save list. Dumping ..."); printList(store); diff --git a/src/main/java/duke/TaskListFileUtils.java b/src/main/java/duke/Storage.java similarity index 99% rename from src/main/java/duke/TaskListFileUtils.java rename to src/main/java/duke/Storage.java index cdec1dce1c..f801a0e954 100644 --- a/src/main/java/duke/TaskListFileUtils.java +++ b/src/main/java/duke/Storage.java @@ -18,7 +18,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -public class TaskListFileUtils { +public class Storage { public static final String FILE_DIR = "data"; public static final String FILE_NAME = "duke.txt"; static int badLines = 0;//Last call bad lines From cfefbd8a4ce461f41ee52770532629e82c251260 Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Sun, 31 Jan 2021 20:58:12 +0800 Subject: [PATCH 33/92] Made isDone only changable via a setter function to true. --- src/main/java/duke/Duke.java | 2 +- src/main/java/duke/Storage.java | 4 +++- src/main/java/duke/TaskList.java | 2 +- src/main/java/duke/task/Task.java | 6 +++++- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/main/java/duke/Duke.java b/src/main/java/duke/Duke.java index 2fa693fe13..424e74b5cc 100644 --- a/src/main/java/duke/Duke.java +++ b/src/main/java/duke/Duke.java @@ -47,7 +47,7 @@ public static void main(String[] args) { case "done": int index = Integer.valueOf(tokens[1]) - 1; Task t = store.get(index); - t.isDone = true; + t.setDone(); System.out.println("The following task is now marked as done:\n" + formatOrderedPrint(store,index)); break; diff --git a/src/main/java/duke/Storage.java b/src/main/java/duke/Storage.java index f801a0e954..ef958fada5 100644 --- a/src/main/java/duke/Storage.java +++ b/src/main/java/duke/Storage.java @@ -78,7 +78,9 @@ public static List LoadTaskList() throws IOException { badLines++; break; } - t.isDone = isDone; + if (isDone){ + t.setDone(); + } store.add(t); } s.close(); diff --git a/src/main/java/duke/TaskList.java b/src/main/java/duke/TaskList.java index 5d8ead15a5..a49253164a 100644 --- a/src/main/java/duke/TaskList.java +++ b/src/main/java/duke/TaskList.java @@ -74,7 +74,7 @@ private String addTask(String[] tokens) throws EmptyArgumentException, BadDateAr } private String setDone(int doneIndex){ Task t = store.get(doneIndex); - t.isDone = true; + t.setDone(); return formatOrderedPrint(doneIndex); } private String delete(int deleteIndex){ diff --git a/src/main/java/duke/task/Task.java b/src/main/java/duke/task/Task.java index 5d5b15a787..3efcf76678 100644 --- a/src/main/java/duke/task/Task.java +++ b/src/main/java/duke/task/Task.java @@ -4,7 +4,7 @@ public abstract class Task { private final String description; - public boolean isDone; //TODO: Figure out if I can restrict access + private boolean isDone; //TODO: Figure out if I can restrict access public Task(String description) throws EmptyArgumentException { description = description.trim(); @@ -15,6 +15,10 @@ public Task(String description) throws EmptyArgumentException { this.isDone = false; } + public void setDone(){ + this.isDone = true; + } + public String getStatusIcon() { return (isDone ? "*" : " "); //Don't use unicode, cause it can't test properly } From e32afc4f4a12e4d18d6ec11280248bd5dce1e024 Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Mon, 1 Feb 2021 00:46:16 +0800 Subject: [PATCH 34/92] Intergrate previously disconnected Object Oriented classes The created object oriented classes is disconnected from the actual Duke main function There is a requirement for OOP to be used extentively by CS2103T Let's * Remove ill-formatted strings due to indiscriminate package refactoring * Properly flesh out Ui class functionality * Intergrate prevously created class into Duke * Edit TaskList and Storage to accomidate each other * Edit TaskList and Ui to accomidate error printing --- src/main/java/duke/Duke.java | 106 ++++---------------------- src/main/java/duke/Storage.java | 7 +- src/main/java/duke/TaskList.java | 26 ++++--- src/main/java/duke/Ui.java | 33 +++++++- src/main/java/duke/task/Deadline.java | 2 +- src/main/java/duke/task/Event.java | 2 +- 6 files changed, 66 insertions(+), 110 deletions(-) diff --git a/src/main/java/duke/Duke.java b/src/main/java/duke/Duke.java index 424e74b5cc..4b7e804d0e 100644 --- a/src/main/java/duke/Duke.java +++ b/src/main/java/duke/Duke.java @@ -1,25 +1,19 @@ package duke; +import duke.command.Command; import duke.exception.BadDateArgumentException; import duke.exception.EmptyArgumentException; import duke.exception.InvalidCommandException; -import duke.task.Deadline; -import duke.task.Event; -import duke.task.Task; -import duke.task.ToDos; import java.io.IOException; import java.text.ParseException; -import java.util.Arrays; -import java.util.List; import java.util.Scanner; public class Duke { public static void main(String[] args) { Ui ui = new Ui(); - String separator = "------------------\n"; ui.startUpMessage(); - List store = null; + TaskList store = null; try { System.out.println("Loading From File..."); store = Storage.LoadTaskList(); @@ -30,56 +24,18 @@ public static void main(String[] args) { } Scanner in = new Scanner(System.in); String line; - String tokens[] = {"invalid"}; do{ - System.out.print(separator + "Listening to your input: "); + ui.prompt(); line = in.nextLine(); - int hash = store.hashCode(); //To detect changes later. try { - String singleTokens[] = {"bye","list"}; - tokens = splitTokenIntoTwo(line," ", singleTokens); - switch(tokens[0]){ - case "bye": - ui.goodByeMessage(); break; - case "list": - printList(store); - break; - case "done": - int index = Integer.valueOf(tokens[1]) - 1; - Task t = store.get(index); - t.setDone(); - System.out.println("The following task is now marked as done:\n" + - formatOrderedPrint(store,index)); - break; - case "todo": - store.add(new ToDos(tokens[1])); - System.out.println("The following todo item has been added:\n" + - formatOrderedPrint(store,-1)); - break; - case "deadline": - tokens = splitTokenIntoTwo(tokens[1]," /by "); - store.add(new Deadline(tokens[0],tokens[1])); - System.out.println("The following deadline item has been added:\n" + - formatOrderedPrint(store,-1)); - break; - case "event": - tokens = splitTokenIntoTwo(tokens[1]," /at "); - store.add(new Event(tokens[0],tokens[1])); - System.out.println("The following event item has been added:\n" + - formatOrderedPrint(store,-1)); - break; - case "delete": - int deleteIndex = Integer.valueOf(tokens[1]) - 1; - System.out.println("Deleting the following duke.task.Task:"); - System.out.println(formatOrderedPrint(store, deleteIndex)); - store.remove(deleteIndex); - System.out.println("Done"); - break; - default: - throw new InvalidCommandException(tokens[0]); + Command c = Parser.parse(line); + if (c==null){ //Bye command + break; } + String data = store.run(c); + ui.commandMessage(c,data); } catch (ParseException e) { - System.out.println("Command.Command has invalid parsing."); + System.out.println("Command has invalid parsing."); System.out.println(e.getMessage()); } catch (InvalidCommandException e){ System.out.println(e.getMessage()); @@ -88,51 +44,17 @@ public static void main(String[] args) { } catch (BadDateArgumentException e) { System.out.println("Date must be of format 'dd MM yyyy'; Eg: 27 08 2044"); } finally { - int newHash = store.hashCode(); - if(newHash != hash){ + if(store.isEdited()){ try { Storage.saveTaskList(store); + store.markSaved(); } catch (IOException e) { - System.out.println("Unable to save list. Dumping ..."); - printList(store); - System.out.println("Continuing Normal operation"); + ui.dumpState(store); } } } - }while(!tokens[0].equals("bye")); + }while(true); + ui.goodByeMessage(); in.close(); } - - private static void printList(List store){ - for (int i = 0 ; i < store.size(); i++) { - System.out.println(formatOrderedPrint(store,i)); - } - } - - private static String formatOrderedPrint(List tasks, int i){ - final int size = tasks.size(); - while (i < 0){ - i += size; - } - while (i >= size){ - i -= size; - } - return "Entry " + (i+1) + "|" + tasks.get(i).toString(); - } - private static String[] splitTokenIntoTwo(String parseTarget,String delimiter) throws ParseException{ - String[] tokens = parseTarget.split(delimiter,2); - if (tokens.length < 2){ - throw new ParseException("Expected deliminter '"+ delimiter +"'", tokens[0].length()); - } - return tokens; - } - - private static String[] splitTokenIntoTwo(String parseTarget,String delimiter, String[] exception) throws ParseException{ - List exceptionList = Arrays.asList(exception); - String[] tokens = parseTarget.split(delimiter,2); - if (!exceptionList.contains(tokens[0]) && tokens.length < 2){ - throw new ParseException("Expected deliminter '"+ delimiter +"'", tokens[0].length()); - } - return tokens; - } } diff --git a/src/main/java/duke/Storage.java b/src/main/java/duke/Storage.java index ef958fada5..a2c7c9f7d0 100644 --- a/src/main/java/duke/Storage.java +++ b/src/main/java/duke/Storage.java @@ -23,7 +23,7 @@ public class Storage { public static final String FILE_NAME = "duke.txt"; static int badLines = 0;//Last call bad lines - public static List LoadTaskList() throws IOException { + public static TaskList LoadTaskList() throws IOException { badLines = 0; List store = new ArrayList<>(); File file = getOrCreateFile(); @@ -84,10 +84,11 @@ public static List LoadTaskList() throws IOException { store.add(t); } s.close(); - return store; + return new TaskList(store); } - public static void saveTaskList(List store) throws IOException { + public static void saveTaskList(TaskList data) throws IOException { + List store = data.getRawData(); StringBuilder saveText = new StringBuilder(); for (Task t: store){ saveText.append(t.toFileString()); diff --git a/src/main/java/duke/TaskList.java b/src/main/java/duke/TaskList.java index a49253164a..35d9ff4c5c 100644 --- a/src/main/java/duke/TaskList.java +++ b/src/main/java/duke/TaskList.java @@ -8,7 +8,6 @@ import duke.task.Task; import duke.task.ToDos; -import java.util.ArrayList; import java.util.List; public class TaskList { @@ -18,14 +17,16 @@ public enum Action{ DONE, DELETE, } - boolean edited = false; - List store; - public TaskList(String[][] tokens) throws EmptyArgumentException, BadDateArgumentException { - store = new ArrayList<>(); - for(String[] args: tokens){ - addTask(args); - } + private boolean edited = false; + private List store; + public TaskList(List store) { + this.store = store; + } + + public List getRawData(){ + return this.store; } + public String run(Command c) throws EmptyArgumentException, BadDateArgumentException { String[] args = c.run(); String results; @@ -51,9 +52,12 @@ public String run(Command c) throws EmptyArgumentException, BadDateArgumentExcep } return results; } - private void markSaved(){ + public void markSaved(){ edited = false; } + public boolean isEdited(){ + return this.edited; + } private String addTask(String[] tokens) throws EmptyArgumentException, BadDateArgumentException { Task t; switch(tokens[0]){ @@ -82,7 +86,7 @@ private String delete(int deleteIndex){ store.remove(deleteIndex); return returnValue; } - private String getList(){ + public String getList(){ StringBuilder builder = new StringBuilder(); for (int i = 0 ; i < store.size(); i++) { builder.append(formatOrderedPrint(i)); @@ -99,6 +103,6 @@ private String formatOrderedPrint(int i){ while (i >= size){ i -= size; } - return "Entry " + (i+1) + "|" + store.get(i).toString() + "\n"; + return "Entry " + (i+1) + "|" + store.get(i).toString(); } } diff --git a/src/main/java/duke/Ui.java b/src/main/java/duke/Ui.java index b4dd2db80d..14bef4dcb2 100644 --- a/src/main/java/duke/Ui.java +++ b/src/main/java/duke/Ui.java @@ -1,13 +1,15 @@ package duke; +import duke.command.Command; + public class Ui { - String logo = + private String logo = " ____ _ \n" //TODO: Figure out if this is allowed by style + "| _ \\ _ _| | _____ \n" + "| | | | | | | |/ / _ \\\n" + "| |_| | |_| | < __/\n" + "|____/ \\__,_|_|\\_\\___|\n"; - String separator = "------------------\n"; + private String separator = "------------------\n"; public void startUpMessage(){ System.out.println("Hello from\n" + logo); @@ -16,4 +18,31 @@ public void startUpMessage(){ public void goodByeMessage(){ System.out.println(separator + "Goodbye from\n" + logo); } + public void prompt(){ + System.out.print(separator + "Listening to your input: "); + } + public void dumpState(TaskList store){ + System.out.println("Unable to save list. Dumping ..."); + System.out.print(store.getList()); + System.out.println("Continuing Normal operation"); + } + public void commandMessage(Command command, String data){ + switch(command.getType()){ + case LIST: + System.out.print(data); + break; + case DONE: + System.out.println("The following task is now marked as done:\n" + + data); + break; + case ADD: + System.out.println("The following task has been added:\n" + + data); + break; + case DELETE: + System.out.println("The following Task has been deleted:"); + System.out.println(data); + break; + } + } } diff --git a/src/main/java/duke/task/Deadline.java b/src/main/java/duke/task/Deadline.java index 4dc6db2331..320c3714e6 100644 --- a/src/main/java/duke/task/Deadline.java +++ b/src/main/java/duke/task/Deadline.java @@ -24,7 +24,7 @@ public Deadline(String description, String by) throws EmptyArgumentException, Ba @Override public String toString() { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMMM dd, yyyy"); - return "[D]" + super.toString() + " (duke.task.Deadline: " + by.format(formatter) + ")"; + return "[D]" + super.toString() + " (Deadline: " + by.format(formatter) + ")"; } @Override diff --git a/src/main/java/duke/task/Event.java b/src/main/java/duke/task/Event.java index 179cc2c401..e9779973de 100644 --- a/src/main/java/duke/task/Event.java +++ b/src/main/java/duke/task/Event.java @@ -16,7 +16,7 @@ public Event(String description, String eventPeriod) throws EmptyArgumentExcepti @Override public String toString() { - return "[E]" + super.toString() + " (duke.task.Event Time: " + eventPeriod + ")"; + return "[E]" + super.toString() + " (Event Time: " + eventPeriod + ")"; } @Override From c1cf9f339aa4f1218d886afd7c7e57ed1a48ecea Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Mon, 1 Feb 2021 00:59:00 +0800 Subject: [PATCH 35/92] Allow more relaxed parsing rules --- src/main/java/duke/Parser.java | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/main/java/duke/Parser.java b/src/main/java/duke/Parser.java index a897c638b7..24bdbcfbee 100644 --- a/src/main/java/duke/Parser.java +++ b/src/main/java/duke/Parser.java @@ -9,13 +9,18 @@ public class Parser { public static Command parse(String line) throws ParseException, InvalidCommandException { + line = line.trim(); Command c = null; - String singleTokens[] = {"bye", "list"}; + String singleTokens[] = {"bye", "list", "exit", "ls"}; String[] tokens = splitTokenIntoTwo(line, " ", singleTokens); - switch (tokens[0]) { + switch (tokens[0].toLowerCase()) { + case "exit": + //Fall-through case "bye": //Leave as null break; + case "ls": + //Fall-through case "list": c = new ListCommand(); break; @@ -33,6 +38,12 @@ public static Command parse(String line) throws ParseException, InvalidCommandEx tokens = splitTokenIntoTwo(tokens[1], " /at "); c = new AddCommand(new String[]{"E", tokens[0], tokens[1]}); break; + case "rm": + //Fall-through + case "remove": + //Fall-through + case "del": + //Fall-through case "delete": c = new DeleteCommand(Integer.parseInt(tokens[1])); break; From eb5747d4c3ddfeaf22e464e97609e04942db8353 Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Mon, 1 Feb 2021 01:09:02 +0800 Subject: [PATCH 36/92] Move Error printing into Ui Class --- src/main/java/duke/Duke.java | 9 ++++----- src/main/java/duke/Ui.java | 21 +++++++++++++++++++++ 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/main/java/duke/Duke.java b/src/main/java/duke/Duke.java index 4b7e804d0e..6117c180b1 100644 --- a/src/main/java/duke/Duke.java +++ b/src/main/java/duke/Duke.java @@ -35,14 +35,13 @@ public static void main(String[] args) { String data = store.run(c); ui.commandMessage(c,data); } catch (ParseException e) { - System.out.println("Command has invalid parsing."); - System.out.println(e.getMessage()); + ui.handleException(e); } catch (InvalidCommandException e){ - System.out.println(e.getMessage()); + ui.handleException(e); } catch(EmptyArgumentException e){ - System.out.println("Cannot have empty argument"); + ui.handleException(e); } catch (BadDateArgumentException e) { - System.out.println("Date must be of format 'dd MM yyyy'; Eg: 27 08 2044"); + ui.handleException(e); } finally { if(store.isEdited()){ try { diff --git a/src/main/java/duke/Ui.java b/src/main/java/duke/Ui.java index 14bef4dcb2..756be2b7d9 100644 --- a/src/main/java/duke/Ui.java +++ b/src/main/java/duke/Ui.java @@ -1,6 +1,11 @@ package duke; import duke.command.Command; +import duke.exception.BadDateArgumentException; +import duke.exception.EmptyArgumentException; +import duke.exception.InvalidCommandException; + +import java.text.ParseException; public class Ui { private String logo = @@ -45,4 +50,20 @@ public void commandMessage(Command command, String data){ break; } } + //TODO: Figure out if this overloading is acceptable from a coding style perspective. + public void handleException(ParseException e){ + System.out.println("Command has invalid parsing."); + System.out.println(e.getMessage()); + } + public void handleException(InvalidCommandException e){ + System.out.println(e.getMessage()); + } + public void handleException(EmptyArgumentException e){ + System.out.println("Cannot have empty argument"); + System.out.println(e.getMessage()); + } + public void handleException(BadDateArgumentException e) { + System.out.println("Date must be of format 'dd MM yyyy'; Eg: 27 08 2044"); + System.out.println(e.getMessage()); + } } From 5e0abc5b043012a02d311deaa103426e81a5faea Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Mon, 1 Feb 2021 01:18:27 +0800 Subject: [PATCH 37/92] Move last ui elements to Ui class --- src/main/java/duke/Duke.java | 8 ++++---- src/main/java/duke/Ui.java | 9 +++++++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/main/java/duke/Duke.java b/src/main/java/duke/Duke.java index 6117c180b1..1256b3e15b 100644 --- a/src/main/java/duke/Duke.java +++ b/src/main/java/duke/Duke.java @@ -13,13 +13,13 @@ public class Duke { public static void main(String[] args) { Ui ui = new Ui(); ui.startUpMessage(); - TaskList store = null; + TaskList store; try { - System.out.println("Loading From File..."); + ui.loadStart(); store = Storage.LoadTaskList(); - System.out.println("Loaded"); + ui.loadSuccess(); } catch (IOException e) { - System.out.println("Failed to Load file. Aborting."); + ui.loadFail(); return; } Scanner in = new Scanner(System.in); diff --git a/src/main/java/duke/Ui.java b/src/main/java/duke/Ui.java index 756be2b7d9..2705a90c46 100644 --- a/src/main/java/duke/Ui.java +++ b/src/main/java/duke/Ui.java @@ -26,6 +26,15 @@ public void goodByeMessage(){ public void prompt(){ System.out.print(separator + "Listening to your input: "); } + public void loadStart(){ + System.out.println("Loading From File..."); + } + public void loadSuccess(){ + System.out.println("Loaded"); + } + public void loadFail(){ + System.out.println("Failed to Load file. Aborting."); + } public void dumpState(TaskList store){ System.out.println("Unable to save list. Dumping ..."); System.out.print(store.getList()); From d5405aa738917cb45339dbf4297f2d3da6248dcf Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Mon, 1 Feb 2021 02:49:00 +0800 Subject: [PATCH 38/92] Add Skeleton Test Code --- src/test/java/duke/DukeTest.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 src/test/java/duke/DukeTest.java diff --git a/src/test/java/duke/DukeTest.java b/src/test/java/duke/DukeTest.java new file mode 100644 index 0000000000..23746ef9b9 --- /dev/null +++ b/src/test/java/duke/DukeTest.java @@ -0,0 +1,12 @@ +package duke; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class DukeTest { + @Test + public void dummyTest(){ + assertEquals(2, 2); + } +} From f1e59d5ce5f5f481009ff7b80ef55d43011dc005 Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Tue, 2 Feb 2021 16:36:59 +0800 Subject: [PATCH 39/92] Add minimal Test Code to satisfy req --- src/test/java/duke/ParserTest.java | 42 +++++++++++++++++++++++ src/test/java/duke/task/DeadlineTest.java | 36 +++++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 src/test/java/duke/ParserTest.java create mode 100644 src/test/java/duke/task/DeadlineTest.java diff --git a/src/test/java/duke/ParserTest.java b/src/test/java/duke/ParserTest.java new file mode 100644 index 0000000000..0a8b9ae726 --- /dev/null +++ b/src/test/java/duke/ParserTest.java @@ -0,0 +1,42 @@ +package duke; + +import duke.command.AddCommand; +import duke.command.Command; +import duke.command.ListCommand; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.fail; + +public class ParserTest { + @Test + public void exitTest(){ + try { + Assertions.assertNull(Parser.parse("bye")); + Assertions.assertNull(Parser.parse("exit")); + } catch (Exception e) { + fail("Should not throw Exception"); + } + } + @Test + public void listTest(){ + try { + Assertions.assertTrue(Parser.parse("list") instanceof ListCommand); + Assertions.assertTrue(Parser.parse(" ls ") instanceof ListCommand); + } catch (Exception e) { + fail("Should not throw Exception"); + } + } + @Test + public void todoTest(){ + try { + Command c = Parser.parse("TODO blow up the moon"); + Assertions.assertTrue(c instanceof AddCommand); + Assertions.assertEquals(2, c.run().length); + Assertions.assertEquals("T", c.run()[0]); + Assertions.assertEquals("blow up the moon", c.run()[1]); + } catch (Exception e) { + fail("Should not throw Exception"); + } + } +} diff --git a/src/test/java/duke/task/DeadlineTest.java b/src/test/java/duke/task/DeadlineTest.java new file mode 100644 index 0000000000..6efbcfd351 --- /dev/null +++ b/src/test/java/duke/task/DeadlineTest.java @@ -0,0 +1,36 @@ +package duke.task; + +import duke.exception.BadDateArgumentException; +import duke.exception.EmptyArgumentException; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.fail; + +public class DeadlineTest { + @Test + public void incorrectParseTest(){ + String[] badList = {"2202 10 31", "May 20 2421", "11 30 2020", "13 8 2000"}; + for(String badString: badList) { + try { + new Deadline("Dud Desc.", badString); + fail("Exception not thrown"); + } catch (EmptyArgumentException e) { + fail("Wrong Exception Thrown"); + } catch (BadDateArgumentException e) { + } + } + } + @Test + public void basicToStringTest(){ + try { + Deadline d = new Deadline("Dud Desc.", "13 08 2020"); + Assertions.assertEquals("[D][ ]: Dud Desc. (Deadline: August 13, 2020)",d.toString()); + d.setDone(); + Assertions.assertEquals("[D][*]: Dud Desc. (Deadline: August 13, 2020)",d.toString()); + } catch (Exception e) { + e.printStackTrace(); + fail("Should not have exception"); + } + } +} From abb945f42d87cb0773848e4f5cfdf29e43d2b95c Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Thu, 4 Feb 2021 08:10:09 +0800 Subject: [PATCH 40/92] Add Basic search framework code --- src/main/java/duke/Parser.java | 5 +++++ src/main/java/duke/TaskList.java | 15 +++++++++++++ src/main/java/duke/Ui.java | 7 ++++++ src/main/java/duke/command/SearchCommand.java | 22 +++++++++++++++++++ src/main/java/duke/task/Task.java | 4 ++++ 5 files changed, 53 insertions(+) create mode 100644 src/main/java/duke/command/SearchCommand.java diff --git a/src/main/java/duke/Parser.java b/src/main/java/duke/Parser.java index 24bdbcfbee..6d0e6d00f3 100644 --- a/src/main/java/duke/Parser.java +++ b/src/main/java/duke/Parser.java @@ -47,6 +47,11 @@ public static Command parse(String line) throws ParseException, InvalidCommandEx case "delete": c = new DeleteCommand(Integer.parseInt(tokens[1])); break; + case "find": + //Fall-through + case "search": + c = new SearchCommand(tokens[1]); + break; default: throw new InvalidCommandException(tokens[0]); } diff --git a/src/main/java/duke/TaskList.java b/src/main/java/duke/TaskList.java index 35d9ff4c5c..1b9f0acca7 100644 --- a/src/main/java/duke/TaskList.java +++ b/src/main/java/duke/TaskList.java @@ -16,6 +16,7 @@ public enum Action{ LIST, DONE, DELETE, + SEARCH, } private boolean edited = false; private List store; @@ -46,6 +47,9 @@ public String run(Command c) throws EmptyArgumentException, BadDateArgumentExcep case LIST: results = getList(); break; + case SEARCH: + results = getFilteredList(args[0]); + break; default: results = ""; break; @@ -95,6 +99,17 @@ public String getList(){ return builder.toString(); } + public String getFilteredList(String searchTerm){ + StringBuilder builder = new StringBuilder(); + for (int i = 0 ; i < store.size(); i++) { + if(store.get(i).containsSearch(searchTerm)) { + builder.append(formatOrderedPrint(i)); + builder.append('\n'); + } + } + return builder.toString(); + } + private String formatOrderedPrint(int i){ final int size = store.size(); while (i < 0){ diff --git a/src/main/java/duke/Ui.java b/src/main/java/duke/Ui.java index 2705a90c46..252bb41902 100644 --- a/src/main/java/duke/Ui.java +++ b/src/main/java/duke/Ui.java @@ -57,6 +57,13 @@ public void commandMessage(Command command, String data){ System.out.println("The following Task has been deleted:"); System.out.println(data); break; + case SEARCH: + if (data.length() > 0){ + System.out.println("Matching Task(s):"); + System.out.println(data); + }else{ + System.out.println("No Matching Task has been found"); + } } } //TODO: Figure out if this overloading is acceptable from a coding style perspective. diff --git a/src/main/java/duke/command/SearchCommand.java b/src/main/java/duke/command/SearchCommand.java new file mode 100644 index 0000000000..fc7dcf4525 --- /dev/null +++ b/src/main/java/duke/command/SearchCommand.java @@ -0,0 +1,22 @@ +package duke.command; + +import duke.TaskList; + +public class SearchCommand extends Command{ + private String searchTerm; + + public SearchCommand(String searchTerm){ + this.searchTerm = searchTerm; + } + + @Override + public String[] run() { + String[] searchTerm = {this.searchTerm}; + return searchTerm; + } + + @Override + public TaskList.Action getType() { + return TaskList.Action.SEARCH; + } +} diff --git a/src/main/java/duke/task/Task.java b/src/main/java/duke/task/Task.java index 3efcf76678..634df6765c 100644 --- a/src/main/java/duke/task/Task.java +++ b/src/main/java/duke/task/Task.java @@ -39,4 +39,8 @@ public int hashCode(){ String toBaseFileString(){ return (isDone ? "1" : "0") + "," + description.length() + "," + description; } + + public boolean containsSearch(String search){ + return description.contains(search); + } } \ No newline at end of file From 7a7c782067bc00e5526795052e9a970206455e5e Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Thu, 4 Feb 2021 08:27:57 +0800 Subject: [PATCH 41/92] Make search more intuitive Search is currently only a wrapper on contains() This is bad because this breaks intuition (At least my intuition) about how searching should be done. For example: "in" should not match "Beating Minecraft" and "minecraft" should match it, but both of those cases are unfulfilled. Let's: * Attempt to check description on a per word basis from the start of the word ** Allow this to be overriden by the presence of multiple spaces * Do lowercase matching for everything by default ** Allow capital letters in the search to override this. The reason we allow exceptions is because we sometimes want more specific searching rules. --- src/main/java/duke/task/Task.java | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/main/java/duke/task/Task.java b/src/main/java/duke/task/Task.java index 634df6765c..1135e6cb73 100644 --- a/src/main/java/duke/task/Task.java +++ b/src/main/java/duke/task/Task.java @@ -2,6 +2,8 @@ import duke.exception.EmptyArgumentException; +import java.util.Locale; + public abstract class Task { private final String description; private boolean isDone; //TODO: Figure out if I can restrict access @@ -41,6 +43,22 @@ String toBaseFileString(){ } public boolean containsSearch(String search){ - return description.contains(search); + String targetString = description; + boolean isCaseSensitive = search.toLowerCase().contains(search); + if (isCaseSensitive){ + targetString = targetString.toLowerCase(); + } + if (search.contains(" ")){//Literal multi word matching + return targetString.contains(search); + } else {//Smart per word start matching + String[] words = targetString.split(" "); + for(String word: words){ + String subWord = word.substring(0, search.length()); + if (subWord.equals(search)){ + return true; + } + } + return false; + } } } \ No newline at end of file From 568e9016e8d0549cd6dc62a834f6a1683f5ddb4c Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Thu, 4 Feb 2021 08:39:51 +0800 Subject: [PATCH 42/92] Minor spelling correction, from overeager refactor --- src/main/java/duke/exception/InvalidCommandException.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/duke/exception/InvalidCommandException.java b/src/main/java/duke/exception/InvalidCommandException.java index 076845f125..a5b79a3868 100644 --- a/src/main/java/duke/exception/InvalidCommandException.java +++ b/src/main/java/duke/exception/InvalidCommandException.java @@ -12,6 +12,6 @@ public InvalidCommandException(String badCommand) { @Override public String getMessage() { - return "Command.Command '" + badCommand + "' is not recognized."; + return "Command '" + badCommand + "' is not recognized."; } } \ No newline at end of file From 4f536302d089eb7517fcf6d5b46b344512cc08c2 Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Fri, 5 Feb 2021 12:50:05 +0800 Subject: [PATCH 43/92] Add possibly incomplete Javadoc, Detailed message pending --- src/main/java/duke/Parser.java | 8 ++++++++ src/main/java/duke/TaskList.java | 19 +++++++++++++++++++ src/main/java/duke/task/Event.java | 7 +++++++ src/main/java/duke/task/Task.java | 16 ++++++++++++++++ 4 files changed, 50 insertions(+) diff --git a/src/main/java/duke/Parser.java b/src/main/java/duke/Parser.java index 24bdbcfbee..47d1d3407f 100644 --- a/src/main/java/duke/Parser.java +++ b/src/main/java/duke/Parser.java @@ -8,6 +8,14 @@ import java.util.List; public class Parser { + /** + * Parses line of input for commands to the application + * + * @param line The line to be parsed + * @return Command to the application + * @throws ParseException If the line could not be reasonably interpreted + * @throws InvalidCommandException If there is an unknown instruction at the start + */ public static Command parse(String line) throws ParseException, InvalidCommandException { line = line.trim(); Command c = null; diff --git a/src/main/java/duke/TaskList.java b/src/main/java/duke/TaskList.java index 35d9ff4c5c..376c234ce8 100644 --- a/src/main/java/duke/TaskList.java +++ b/src/main/java/duke/TaskList.java @@ -27,6 +27,15 @@ public List getRawData(){ return this.store; } + /** + * Runs command on TaskList and returns command specific output. + * Side effects are present on some commands + * + * @param c Command to be run + * @return Output meant for Ui Class + * @throws EmptyArgumentException At least one argument is missing + * @throws BadDateArgumentException An argument that is expected to be a date is ill formatted + */ public String run(Command c) throws EmptyArgumentException, BadDateArgumentException { String[] args = c.run(); String results; @@ -52,9 +61,19 @@ public String run(Command c) throws EmptyArgumentException, BadDateArgumentExcep } return results; } + + /** + * Mark the changes in the TaskList as saved to disk. + */ public void markSaved(){ edited = false; } + + /** + * Check whether TaskList has been edited from when it has been last saved to disk + * + * @return Whether the TaskList has changed + */ public boolean isEdited(){ return this.edited; } diff --git a/src/main/java/duke/task/Event.java b/src/main/java/duke/task/Event.java index e9779973de..afab56204d 100644 --- a/src/main/java/duke/task/Event.java +++ b/src/main/java/duke/task/Event.java @@ -5,6 +5,13 @@ public class Event extends Task{ private String eventPeriod; + /** + * C + * + * @param description Description of event + * @param eventPeriod When the event takes place + * @throws EmptyArgumentException + */ public Event(String description, String eventPeriod) throws EmptyArgumentException { super(description); eventPeriod = eventPeriod.trim(); diff --git a/src/main/java/duke/task/Task.java b/src/main/java/duke/task/Task.java index 3efcf76678..378c1bc12f 100644 --- a/src/main/java/duke/task/Task.java +++ b/src/main/java/duke/task/Task.java @@ -15,10 +15,17 @@ public Task(String description) throws EmptyArgumentException { this.isDone = false; } + /** + * Marks the task as done + */ public void setDone(){ this.isDone = true; } + /** + * Gets the symbol for the status of the task. + * @return Symbol representing the task status + */ public String getStatusIcon() { return (isDone ? "*" : " "); //Don't use unicode, cause it can't test properly } @@ -29,6 +36,10 @@ public String toString() { description; } + /** + * Converts the Task into a format suitable for file system storage + * @return A savable string. + */ public abstract String toFileString(); @Override @@ -36,6 +47,11 @@ public int hashCode(){ return this.toString().hashCode(); } + /** + * Converts raw Task data common to all Tasks into + * a format suitable for file system storage. + * @return A common partial savable string. + */ String toBaseFileString(){ return (isDone ? "1" : "0") + "," + description.length() + "," + description; } From a33d08c37e40e8aaba6a81f77aeda9ba10a52d37 Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Fri, 5 Feb 2021 14:28:33 +0800 Subject: [PATCH 44/92] Finish adding javadoc to every public method except main --- src/main/java/duke/Storage.java | 6 ++++++ src/main/java/duke/TaskList.java | 12 ++++++++++++ src/main/java/duke/command/AddCommand.java | 4 ++++ src/main/java/duke/command/DeleteCommand.java | 4 ++++ src/main/java/duke/command/DoneCommand.java | 5 +++++ src/main/java/duke/command/IndexedCommand.java | 6 ++++++ .../java/duke/exception/InvalidCommandException.java | 5 +++++ src/main/java/duke/task/Deadline.java | 9 +++++++++ src/main/java/duke/task/Event.java | 2 +- src/main/java/duke/task/Task.java | 6 ++++++ src/main/java/duke/task/ToDos.java | 6 ++++++ 11 files changed, 64 insertions(+), 1 deletion(-) diff --git a/src/main/java/duke/Storage.java b/src/main/java/duke/Storage.java index a2c7c9f7d0..f5278a252e 100644 --- a/src/main/java/duke/Storage.java +++ b/src/main/java/duke/Storage.java @@ -87,6 +87,12 @@ public static TaskList LoadTaskList() throws IOException { return new TaskList(store); } + /** + * Saves TaskList to disk. + * + * @param data TaskList to save to disk + * @throws IOException Unable to create subfolder + */ public static void saveTaskList(TaskList data) throws IOException { List store = data.getRawData(); StringBuilder saveText = new StringBuilder(); diff --git a/src/main/java/duke/TaskList.java b/src/main/java/duke/TaskList.java index 376c234ce8..50763a7e11 100644 --- a/src/main/java/duke/TaskList.java +++ b/src/main/java/duke/TaskList.java @@ -23,6 +23,12 @@ public TaskList(List store) { this.store = store; } + /** + * Get Raw data for extraction of File ready data from Task directly + * TODO: Push the preparation of data to TaskList + * + * @return Underlying data structure + */ public List getRawData(){ return this.store; } @@ -105,6 +111,12 @@ private String delete(int deleteIndex){ store.remove(deleteIndex); return returnValue; } + + /** + * Gets a user friendly list of all the task in TaskList + * + * @return User friendly state of TaskList + */ public String getList(){ StringBuilder builder = new StringBuilder(); for (int i = 0 ; i < store.size(); i++) { diff --git a/src/main/java/duke/command/AddCommand.java b/src/main/java/duke/command/AddCommand.java index 69f4a3822e..51d6a49e2a 100644 --- a/src/main/java/duke/command/AddCommand.java +++ b/src/main/java/duke/command/AddCommand.java @@ -6,6 +6,10 @@ public class AddCommand extends Command{ String[] args; + /** + * Create new Add command + * @param args Parameters describing what to add + */ public AddCommand(String[] args){ this.args = args; } diff --git a/src/main/java/duke/command/DeleteCommand.java b/src/main/java/duke/command/DeleteCommand.java index 8074733fda..df202f8cc5 100644 --- a/src/main/java/duke/command/DeleteCommand.java +++ b/src/main/java/duke/command/DeleteCommand.java @@ -3,6 +3,10 @@ import duke.TaskList.Action; public class DeleteCommand extends IndexedCommand{ + /** + * Create command to delete Task from TaskList + * @param position One index position in TaskList of Task to delete + */ public DeleteCommand(int position) { super(position); } diff --git a/src/main/java/duke/command/DoneCommand.java b/src/main/java/duke/command/DoneCommand.java index 6b2ac87ac7..2fb74624be 100644 --- a/src/main/java/duke/command/DoneCommand.java +++ b/src/main/java/duke/command/DoneCommand.java @@ -3,6 +3,11 @@ import duke.TaskList.Action; public class DoneCommand extends IndexedCommand{ + /** + * Create command to mark Task in TaskList as done + * + * @param position One index position in TaskList of Task to mark as done + */ public DoneCommand(int position) { super(position); } diff --git a/src/main/java/duke/command/IndexedCommand.java b/src/main/java/duke/command/IndexedCommand.java index cbeb5aa574..2c1402eb1b 100644 --- a/src/main/java/duke/command/IndexedCommand.java +++ b/src/main/java/duke/command/IndexedCommand.java @@ -2,6 +2,12 @@ abstract class IndexedCommand extends Command{ private final int index; + + /** + * Create command to manipulate Task in TaskList based on position index + * + * @param position One index position in TaskList of Task to manipulate + */ public IndexedCommand(int position){ this.index = position - 1; } diff --git a/src/main/java/duke/exception/InvalidCommandException.java b/src/main/java/duke/exception/InvalidCommandException.java index 076845f125..c5c412c0ad 100644 --- a/src/main/java/duke/exception/InvalidCommandException.java +++ b/src/main/java/duke/exception/InvalidCommandException.java @@ -4,6 +4,11 @@ public class InvalidCommandException extends Exception { private String badCommand; + /** + * Create Exception to indicate an invalid command + * + * @param badCommand Invalid command fragment + */ public InvalidCommandException(String badCommand) { this.badCommand = badCommand; } diff --git a/src/main/java/duke/task/Deadline.java b/src/main/java/duke/task/Deadline.java index 320c3714e6..427cd7a002 100644 --- a/src/main/java/duke/task/Deadline.java +++ b/src/main/java/duke/task/Deadline.java @@ -10,6 +10,15 @@ public class Deadline extends Task { protected LocalDate by; + /** + * Creates a Task with a description and a deadline date that it needs + * to be done by. + * + * @param description Description of Deadline + * @param by When the task needs to be completed + * @throws EmptyArgumentException Some argument, either 'description' or 'by' is empty. + * @throws BadDateArgumentException When 'by' is not well formatted + */ public Deadline(String description, String by) throws EmptyArgumentException, BadDateArgumentException { super(description); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd MM yyyy"); diff --git a/src/main/java/duke/task/Event.java b/src/main/java/duke/task/Event.java index afab56204d..9912e56e2d 100644 --- a/src/main/java/duke/task/Event.java +++ b/src/main/java/duke/task/Event.java @@ -6,7 +6,7 @@ public class Event extends Task{ private String eventPeriod; /** - * C + * Creates an Event that has a description and a duration. * * @param description Description of event * @param eventPeriod When the event takes place diff --git a/src/main/java/duke/task/Task.java b/src/main/java/duke/task/Task.java index 378c1bc12f..888961ee6a 100644 --- a/src/main/java/duke/task/Task.java +++ b/src/main/java/duke/task/Task.java @@ -6,6 +6,12 @@ public abstract class Task { private final String description; private boolean isDone; //TODO: Figure out if I can restrict access + /** + * Creates a Task that has a description + * + * @param description Description of Task + * @throws EmptyArgumentException Description is empty or whitespace + */ public Task(String description) throws EmptyArgumentException { description = description.trim(); if (description.isEmpty()){ diff --git a/src/main/java/duke/task/ToDos.java b/src/main/java/duke/task/ToDos.java index 231a4225c5..0d18bc72f3 100644 --- a/src/main/java/duke/task/ToDos.java +++ b/src/main/java/duke/task/ToDos.java @@ -3,6 +3,12 @@ import duke.exception.EmptyArgumentException; public class ToDos extends Task{ + /** + * Creates a To Do object that is essentially a wrapper on task. + * + * @param description Description of To Do + * @throws EmptyArgumentException when Description is empty or whitespace + */ public ToDos(String description) throws EmptyArgumentException { super(description); } From 856473f3841508e20c3b0d984104e89fc7bfb449 Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Fri, 5 Feb 2021 15:29:57 +0800 Subject: [PATCH 45/92] Fix import statements --- src/main/java/duke/Parser.java | 8 ++++++-- src/main/java/duke/command/AddCommand.java | 1 - 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/duke/Parser.java b/src/main/java/duke/Parser.java index 24bdbcfbee..9729e9b41e 100644 --- a/src/main/java/duke/Parser.java +++ b/src/main/java/duke/Parser.java @@ -1,8 +1,12 @@ package duke; -import duke.command.*; -import duke.exception.InvalidCommandException; +import duke.command.AddCommand; +import duke.command.Command; +import duke.command.DoneCommand; +import duke.command.ListCommand; +import duke.command.DeleteCommand; +import duke.exception.InvalidCommandException; import java.text.ParseException; import java.util.Arrays; import java.util.List; diff --git a/src/main/java/duke/command/AddCommand.java b/src/main/java/duke/command/AddCommand.java index 69f4a3822e..d7b350ebe8 100644 --- a/src/main/java/duke/command/AddCommand.java +++ b/src/main/java/duke/command/AddCommand.java @@ -1,6 +1,5 @@ package duke.command; -import duke.TaskList; import duke.TaskList.Action; public class AddCommand extends Command{ From d269a67d4323741f264309780da6a244196a7290 Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Tue, 9 Feb 2021 00:14:57 +0800 Subject: [PATCH 46/92] Fix spacing for code formatting --- src/main/java/duke/Duke.java | 6 +++--- src/main/java/duke/Parser.java | 4 ++-- src/main/java/duke/Storage.java | 14 +++++++------- src/main/java/duke/TaskList.java | 16 ++++++++-------- src/main/java/duke/Ui.java | 14 +++++++------- src/main/java/duke/command/AddCommand.java | 4 ++-- src/main/java/duke/command/DeleteCommand.java | 2 +- src/main/java/duke/command/DoneCommand.java | 2 +- .../duke/exception/BadDateArgumentException.java | 2 +- .../duke/exception/EmptyArgumentException.java | 2 +- src/main/java/duke/task/Deadline.java | 2 +- src/main/java/duke/task/Event.java | 4 ++-- src/main/java/duke/task/Task.java | 5 ++--- 13 files changed, 38 insertions(+), 39 deletions(-) diff --git a/src/main/java/duke/Duke.java b/src/main/java/duke/Duke.java index 1256b3e15b..86a8ed20b9 100644 --- a/src/main/java/duke/Duke.java +++ b/src/main/java/duke/Duke.java @@ -24,12 +24,12 @@ public static void main(String[] args) { } Scanner in = new Scanner(System.in); String line; - do{ + do { ui.prompt(); line = in.nextLine(); try { Command c = Parser.parse(line); - if (c==null){ //Bye command + if (c==null) { //Bye command break; } String data = store.run(c); @@ -52,7 +52,7 @@ public static void main(String[] args) { } } } - }while(true); + } while (true); ui.goodByeMessage(); in.close(); } diff --git a/src/main/java/duke/Parser.java b/src/main/java/duke/Parser.java index 9729e9b41e..aaff328d11 100644 --- a/src/main/java/duke/Parser.java +++ b/src/main/java/duke/Parser.java @@ -58,7 +58,7 @@ public static Command parse(String line) throws ParseException, InvalidCommandEx } private static String[] splitTokenIntoTwo(String parseTarget,String delimiter) throws ParseException { String[] tokens = parseTarget.split(delimiter,2); - if (tokens.length < 2){ + if (tokens.length < 2) { throw new ParseException("Expected deliminter '"+ delimiter +"'", tokens[0].length()); } return tokens; @@ -67,7 +67,7 @@ private static String[] splitTokenIntoTwo(String parseTarget,String delimiter) t private static String[] splitTokenIntoTwo(String parseTarget,String delimiter, String[] exception) throws ParseException{ List exceptionList = Arrays.asList(exception); String[] tokens = parseTarget.split(delimiter,2); - if (!exceptionList.contains(tokens[0]) && tokens.length < 2){ + if (!exceptionList.contains(tokens[0]) && tokens.length < 2) { throw new ParseException("Expected deliminter '"+ delimiter +"'", tokens[0].length()); } return tokens; diff --git a/src/main/java/duke/Storage.java b/src/main/java/duke/Storage.java index a2c7c9f7d0..7aa79d25f3 100644 --- a/src/main/java/duke/Storage.java +++ b/src/main/java/duke/Storage.java @@ -29,13 +29,13 @@ public static TaskList LoadTaskList() throws IOException { File file = getOrCreateFile(); Scanner s = new Scanner(file); generateLines: //TODO: Whats the code style for this. - while(s.hasNextLine()){ + while (s.hasNextLine()) { Task t; String line = s.nextLine(); String pattern = "([TED]),([01]),(\\d*),(.*)"; Pattern r = Pattern.compile(pattern); Matcher m = r.matcher(line); - if(!m.find()){ + if (!m.find()) { badLines++; break; } @@ -45,7 +45,7 @@ public static TaskList LoadTaskList() throws IOException { String task = m.group(4).substring(0,taskLength); String leftover = m.group(4).substring(taskLength); try { - if (type.equals("E") || type.equals("D") ) { + if (type.equals("E") || type.equals("D")) { line = leftover.substring(1); pattern = "(\\d*),(.*)"; r = Pattern.compile(pattern); @@ -71,14 +71,14 @@ public static TaskList LoadTaskList() throws IOException { } else { t = new ToDos(task); } - }catch(EmptyArgumentException e){ + }catch(EmptyArgumentException e) { badLines++; break; - }catch(BadDateArgumentException e){ + } catch(BadDateArgumentException e) { badLines++; break; } - if (isDone){ + if (isDone) { t.setDone(); } store.add(t); @@ -90,7 +90,7 @@ public static TaskList LoadTaskList() throws IOException { public static void saveTaskList(TaskList data) throws IOException { List store = data.getRawData(); StringBuilder saveText = new StringBuilder(); - for (Task t: store){ + for (Task t: store) { saveText.append(t.toFileString()); saveText.append('\n'); } diff --git a/src/main/java/duke/TaskList.java b/src/main/java/duke/TaskList.java index 35d9ff4c5c..bb20be99be 100644 --- a/src/main/java/duke/TaskList.java +++ b/src/main/java/duke/TaskList.java @@ -11,7 +11,7 @@ import java.util.List; public class TaskList { - public enum Action{ + public enum Action { ADD, LIST, DONE, @@ -30,7 +30,7 @@ public List getRawData(){ public String run(Command c) throws EmptyArgumentException, BadDateArgumentException { String[] args = c.run(); String results; - switch(c.getType()){ + switch (c.getType()) { case ADD: results = addTask(args); edited = true; @@ -60,7 +60,7 @@ public boolean isEdited(){ } private String addTask(String[] tokens) throws EmptyArgumentException, BadDateArgumentException { Task t; - switch(tokens[0]){ + switch (tokens[0]) { case "D": t = new Deadline(tokens[1], tokens[2]); break; @@ -76,26 +76,26 @@ private String addTask(String[] tokens) throws EmptyArgumentException, BadDateAr store.add(t); return formatOrderedPrint(-1); } - private String setDone(int doneIndex){ + private String setDone(int doneIndex) { Task t = store.get(doneIndex); t.setDone(); return formatOrderedPrint(doneIndex); } - private String delete(int deleteIndex){ + private String delete(int deleteIndex) { String returnValue = formatOrderedPrint(deleteIndex); store.remove(deleteIndex); return returnValue; } - public String getList(){ + public String getList() { StringBuilder builder = new StringBuilder(); - for (int i = 0 ; i < store.size(); i++) { + for (int i = 0; i < store.size(); i++) { builder.append(formatOrderedPrint(i)); builder.append('\n'); } return builder.toString(); } - private String formatOrderedPrint(int i){ + private String formatOrderedPrint(int i) { final int size = store.size(); while (i < 0){ i += size; diff --git a/src/main/java/duke/Ui.java b/src/main/java/duke/Ui.java index 2705a90c46..2ac029f233 100644 --- a/src/main/java/duke/Ui.java +++ b/src/main/java/duke/Ui.java @@ -16,7 +16,7 @@ public class Ui { + "|____/ \\__,_|_|\\_\\___|\n"; private String separator = "------------------\n"; - public void startUpMessage(){ + public void startUpMessage() { System.out.println("Hello from\n" + logo); System.out.println("No unicode allowed"); } @@ -26,21 +26,21 @@ public void goodByeMessage(){ public void prompt(){ System.out.print(separator + "Listening to your input: "); } - public void loadStart(){ + public void loadStart() { System.out.println("Loading From File..."); } - public void loadSuccess(){ + public void loadSuccess() { System.out.println("Loaded"); } - public void loadFail(){ + public void loadFail() { System.out.println("Failed to Load file. Aborting."); } - public void dumpState(TaskList store){ + public void dumpState(TaskList store) { System.out.println("Unable to save list. Dumping ..."); System.out.print(store.getList()); System.out.println("Continuing Normal operation"); } - public void commandMessage(Command command, String data){ + public void commandMessage(Command command, String data) { switch(command.getType()){ case LIST: System.out.print(data); @@ -60,7 +60,7 @@ public void commandMessage(Command command, String data){ } } //TODO: Figure out if this overloading is acceptable from a coding style perspective. - public void handleException(ParseException e){ + public void handleException(ParseException e) { System.out.println("Command has invalid parsing."); System.out.println(e.getMessage()); } diff --git a/src/main/java/duke/command/AddCommand.java b/src/main/java/duke/command/AddCommand.java index d7b350ebe8..025799e05f 100644 --- a/src/main/java/duke/command/AddCommand.java +++ b/src/main/java/duke/command/AddCommand.java @@ -2,10 +2,10 @@ import duke.TaskList.Action; -public class AddCommand extends Command{ +public class AddCommand extends Command { String[] args; - public AddCommand(String[] args){ + public AddCommand(String[] args) { this.args = args; } diff --git a/src/main/java/duke/command/DeleteCommand.java b/src/main/java/duke/command/DeleteCommand.java index 8074733fda..819467d03d 100644 --- a/src/main/java/duke/command/DeleteCommand.java +++ b/src/main/java/duke/command/DeleteCommand.java @@ -2,7 +2,7 @@ import duke.TaskList.Action; -public class DeleteCommand extends IndexedCommand{ +public class DeleteCommand extends IndexedCommand { public DeleteCommand(int position) { super(position); } diff --git a/src/main/java/duke/command/DoneCommand.java b/src/main/java/duke/command/DoneCommand.java index 6b2ac87ac7..f1d54e99fd 100644 --- a/src/main/java/duke/command/DoneCommand.java +++ b/src/main/java/duke/command/DoneCommand.java @@ -2,7 +2,7 @@ import duke.TaskList.Action; -public class DoneCommand extends IndexedCommand{ +public class DoneCommand extends IndexedCommand { public DoneCommand(int position) { super(position); } diff --git a/src/main/java/duke/exception/BadDateArgumentException.java b/src/main/java/duke/exception/BadDateArgumentException.java index d3c3607429..fcf98cfc8d 100644 --- a/src/main/java/duke/exception/BadDateArgumentException.java +++ b/src/main/java/duke/exception/BadDateArgumentException.java @@ -1,6 +1,6 @@ package duke.exception; -public class BadDateArgumentException extends Exception{ +public class BadDateArgumentException extends Exception { /** * diff --git a/src/main/java/duke/exception/EmptyArgumentException.java b/src/main/java/duke/exception/EmptyArgumentException.java index c9d8c55814..2c07781de4 100644 --- a/src/main/java/duke/exception/EmptyArgumentException.java +++ b/src/main/java/duke/exception/EmptyArgumentException.java @@ -1,6 +1,6 @@ package duke.exception; -public class EmptyArgumentException extends Exception{ +public class EmptyArgumentException extends Exception { /** * diff --git a/src/main/java/duke/task/Deadline.java b/src/main/java/duke/task/Deadline.java index 320c3714e6..1d9cd4d982 100644 --- a/src/main/java/duke/task/Deadline.java +++ b/src/main/java/duke/task/Deadline.java @@ -16,7 +16,7 @@ public Deadline(String description, String by) throws EmptyArgumentException, Ba try { LocalDate date = LocalDate.parse(by, formatter); this.by = date; - }catch(DateTimeParseException e){ + } catch(DateTimeParseException e) { throw new BadDateArgumentException(); } } diff --git a/src/main/java/duke/task/Event.java b/src/main/java/duke/task/Event.java index e9779973de..f583f52fda 100644 --- a/src/main/java/duke/task/Event.java +++ b/src/main/java/duke/task/Event.java @@ -2,13 +2,13 @@ import duke.exception.EmptyArgumentException; -public class Event extends Task{ +public class Event extends Task { private String eventPeriod; public Event(String description, String eventPeriod) throws EmptyArgumentException { super(description); eventPeriod = eventPeriod.trim(); - if (eventPeriod.isEmpty()){ + if (eventPeriod.isEmpty()) { throw new EmptyArgumentException(); } this.eventPeriod = eventPeriod; diff --git a/src/main/java/duke/task/Task.java b/src/main/java/duke/task/Task.java index 3efcf76678..e88cbd0870 100644 --- a/src/main/java/duke/task/Task.java +++ b/src/main/java/duke/task/Task.java @@ -8,7 +8,7 @@ public abstract class Task { public Task(String description) throws EmptyArgumentException { description = description.trim(); - if (description.isEmpty()){ + if (description.isEmpty()) { throw new EmptyArgumentException(); } this.description = description; @@ -25,8 +25,7 @@ public String getStatusIcon() { @Override public String toString() { - return "["+ this.getStatusIcon()+"]: " + - description; + return "["+ this.getStatusIcon()+"]: " + description; } public abstract String toFileString(); From 42cc0d0cc1969dfe043768dab89f998c42f0ceeb Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Tue, 9 Feb 2021 00:17:49 +0800 Subject: [PATCH 47/92] Fixed Array Formatting --- src/main/java/duke/Parser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/duke/Parser.java b/src/main/java/duke/Parser.java index aaff328d11..9d7d5819d0 100644 --- a/src/main/java/duke/Parser.java +++ b/src/main/java/duke/Parser.java @@ -15,7 +15,7 @@ public class Parser { public static Command parse(String line) throws ParseException, InvalidCommandException { line = line.trim(); Command c = null; - String singleTokens[] = {"bye", "list", "exit", "ls"}; + String[] singleTokens = {"bye", "list", "exit", "ls"}; String[] tokens = splitTokenIntoTwo(line, " ", singleTokens); switch (tokens[0].toLowerCase()) { case "exit": From 89afdd55044b386730b7131e35b23ceff7f60a22 Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Wed, 10 Feb 2021 01:04:45 +0800 Subject: [PATCH 48/92] Add JavaDoc for commandMessage --- src/main/java/duke/Ui.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/duke/Ui.java b/src/main/java/duke/Ui.java index 2705a90c46..4335d3c4d1 100644 --- a/src/main/java/duke/Ui.java +++ b/src/main/java/duke/Ui.java @@ -40,6 +40,13 @@ public void dumpState(TaskList store){ System.out.print(store.getList()); System.out.println("Continuing Normal operation"); } + + /** + * Generate and print message based on command and results from that command + * + * @param command The command that has been issued + * @param data The results of that command, in a pre-processed format + */ public void commandMessage(Command command, String data){ switch(command.getType()){ case LIST: From 621e63fd19955941024833d4af77bbdbb7ef5e8f Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Thu, 11 Feb 2021 23:04:30 +0800 Subject: [PATCH 49/92] Add missing import that somehow slipped past me --- src/main/java/duke/Parser.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/duke/Parser.java b/src/main/java/duke/Parser.java index bc05f9ae1d..176cd9c4f2 100644 --- a/src/main/java/duke/Parser.java +++ b/src/main/java/duke/Parser.java @@ -5,6 +5,7 @@ import duke.command.DoneCommand; import duke.command.ListCommand; import duke.command.DeleteCommand; +import duke.command.SearchCommand; import duke.exception.InvalidCommandException; import java.text.ParseException; From e7457a92df1bfdea0747e6d754325d4885d6c7f6 Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Fri, 12 Feb 2021 17:33:36 +0800 Subject: [PATCH 50/92] Add Checkstyle according to guide --- config/checkstyle/checkstyle.xml | 403 +++++++++++++++++++++++++++++++ 1 file changed, 403 insertions(+) create mode 100644 config/checkstyle/checkstyle.xml diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml new file mode 100644 index 0000000000..4c001417ae --- /dev/null +++ b/config/checkstyle/checkstyle.xml @@ -0,0 +1,403 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 10af3b6be642acff47893ad7ab4855ef30d75a69 Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Fri, 12 Feb 2021 17:47:02 +0800 Subject: [PATCH 51/92] Edit checkstyle to enforce SCREAMING_SNAKE_CASE for private constants --- config/checkstyle/checkstyle.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index 4c001417ae..7c8adb24c1 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -102,11 +102,11 @@ - + - + + value="Variable ''{0}'' should be in ALL_CAPS (if it is a constant)."/> From bb690a74788977f26c2b05e50ea0682eee4aded5 Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Fri, 12 Feb 2021 18:44:04 +0800 Subject: [PATCH 52/92] Add supressions.xml to allow gradle to work --- config/checkstyle/suppressions.xml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 config/checkstyle/suppressions.xml diff --git a/config/checkstyle/suppressions.xml b/config/checkstyle/suppressions.xml new file mode 100644 index 0000000000..39efb6e4ac --- /dev/null +++ b/config/checkstyle/suppressions.xml @@ -0,0 +1,10 @@ + + + + + + + + From 5998f675561687d82363b5e1618966153ede618f Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Fri, 12 Feb 2021 18:54:52 +0800 Subject: [PATCH 53/92] Modify main code to satisfy automated checkStyle validation only --- src/main/java/duke/Duke.java | 19 ++-- src/main/java/duke/Parser.java | 24 ++--- src/main/java/duke/Storage.java | 35 ++++--- src/main/java/duke/TaskList.java | 14 +-- src/main/java/duke/Ui.java | 91 +++++++++++++++---- src/main/java/duke/command/AddCommand.java | 2 +- .../java/duke/command/IndexedCommand.java | 4 +- src/main/java/duke/command/SearchCommand.java | 4 +- .../exception/EmptyArgumentException.java | 1 - .../exception/InvalidCommandException.java | 9 +- src/main/java/duke/task/Deadline.java | 13 ++- src/main/java/duke/task/Event.java | 4 +- src/main/java/duke/task/Task.java | 24 +++-- src/main/java/duke/task/ToDos.java | 2 +- 14 files changed, 149 insertions(+), 97 deletions(-) diff --git a/src/main/java/duke/Duke.java b/src/main/java/duke/Duke.java index 7350c77570..9a7cb78563 100644 --- a/src/main/java/duke/Duke.java +++ b/src/main/java/duke/Duke.java @@ -1,22 +1,29 @@ package duke; +import java.io.IOException; +import java.text.ParseException; +import java.util.Scanner; + import duke.command.Command; import duke.exception.BadDateArgumentException; import duke.exception.EmptyArgumentException; import duke.exception.InvalidCommandException; -import java.io.IOException; -import java.text.ParseException; -import java.util.Scanner; public class Duke { + + /** + * Main application code + * + * @param args Unused arguments + */ public static void main(String[] args) { Ui ui = new Ui(); ui.startUpMessage(); TaskList store; try { ui.loadStart(); - store = Storage.LoadTaskList(); + store = Storage.loadTaskList(); ui.loadSuccess(); } catch (IOException e) { ui.loadFail(); @@ -29,11 +36,11 @@ public static void main(String[] args) { line = in.nextLine(); try { Command c = Parser.parse(line); - if (c==null) { //Bye command + if (c == null) { //Bye command break; } String data = store.run(c); - ui.commandMessage(c,data); + ui.commandMessage(c, data); } catch (ParseException e) { ui.handleException(e); } catch (InvalidCommandException e) { diff --git a/src/main/java/duke/Parser.java b/src/main/java/duke/Parser.java index 176cd9c4f2..b3badfaa29 100644 --- a/src/main/java/duke/Parser.java +++ b/src/main/java/duke/Parser.java @@ -1,16 +1,17 @@ package duke; +import java.text.ParseException; +import java.util.Arrays; +import java.util.List; + import duke.command.AddCommand; import duke.command.Command; +import duke.command.DeleteCommand; import duke.command.DoneCommand; import duke.command.ListCommand; -import duke.command.DeleteCommand; import duke.command.SearchCommand; - import duke.exception.InvalidCommandException; -import java.text.ParseException; -import java.util.Arrays; -import java.util.List; + public class Parser { /** @@ -70,19 +71,20 @@ public static Command parse(String line) throws ParseException, InvalidCommandEx } return c; } - private static String[] splitTokenIntoTwo(String parseTarget,String delimiter) throws ParseException { - String[] tokens = parseTarget.split(delimiter,2); + private static String[] splitTokenIntoTwo(String parseTarget, String delimiter) throws ParseException { + String[] tokens = parseTarget.split(delimiter, 2); if (tokens.length < 2) { - throw new ParseException("Expected deliminter '"+ delimiter +"'", tokens[0].length()); + throw new ParseException("Expected deliminter '" + delimiter + "'", tokens[0].length()); } return tokens; } - private static String[] splitTokenIntoTwo(String parseTarget,String delimiter, String[] exception) throws ParseException{ + private static String[] splitTokenIntoTwo(String parseTarget, String delimiter, String[] exception) + throws ParseException { List exceptionList = Arrays.asList(exception); - String[] tokens = parseTarget.split(delimiter,2); + String[] tokens = parseTarget.split(delimiter, 2); if (!exceptionList.contains(tokens[0]) && tokens.length < 2) { - throw new ParseException("Expected deliminter '"+ delimiter +"'", tokens[0].length()); + throw new ParseException("Expected deliminter '" + delimiter + "'", tokens[0].length()); } return tokens; } diff --git a/src/main/java/duke/Storage.java b/src/main/java/duke/Storage.java index 547056108a..fad1b97e25 100644 --- a/src/main/java/duke/Storage.java +++ b/src/main/java/duke/Storage.java @@ -1,12 +1,5 @@ package duke; -import duke.exception.BadDateArgumentException; -import duke.exception.EmptyArgumentException; -import duke.task.Deadline; -import duke.task.Event; -import duke.task.Task; -import duke.task.ToDos; - import java.io.File; import java.io.FileWriter; import java.io.IOException; @@ -18,13 +11,24 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import duke.exception.BadDateArgumentException; +import duke.exception.EmptyArgumentException; +import duke.task.Deadline; +import duke.task.Event; +import duke.task.Task; +import duke.task.ToDos; + public class Storage { public static final String FILE_DIR = "data"; public static final String FILE_NAME = "duke.txt"; - static int badLines = 0;//Last call bad lines - public static TaskList LoadTaskList() throws IOException { - badLines = 0; + /** + * Loads data from a fixed constant, location relative to the program locatoin + * + * @return TaskList that corresponds to the loaded data + * @throws IOException Uncontrollable IO Error + */ + public static TaskList loadTaskList() throws IOException { List store = new ArrayList<>(); File file = getOrCreateFile(); Scanner s = new Scanner(file); @@ -36,13 +40,12 @@ public static TaskList LoadTaskList() throws IOException { Pattern r = Pattern.compile(pattern); Matcher m = r.matcher(line); if (!m.find()) { - badLines++; break; } String type = m.group(1); boolean isDone = m.group(2).equals("1"); int taskLength = Integer.parseInt(m.group(3)); - String task = m.group(4).substring(0,taskLength); + String task = m.group(4).substring(0, taskLength); String leftover = m.group(4).substring(taskLength); try { if (type.equals("E") || type.equals("D")) { @@ -51,7 +54,6 @@ public static TaskList LoadTaskList() throws IOException { r = Pattern.compile(pattern); m = r.matcher(line); if (!m.find()) { - badLines++; break; } int timeLength = Integer.parseInt(m.group(1)); @@ -65,17 +67,12 @@ public static TaskList LoadTaskList() throws IOException { t = new Deadline(task, timeData); break; default: - badLines++; break generateLines; } } else { t = new ToDos(task); } - }catch(EmptyArgumentException e) { - badLines++; - break; - } catch(BadDateArgumentException e) { - badLines++; + } catch (EmptyArgumentException | BadDateArgumentException e) { break; } if (isDone) { diff --git a/src/main/java/duke/TaskList.java b/src/main/java/duke/TaskList.java index 3e341205e7..aff0958eb1 100644 --- a/src/main/java/duke/TaskList.java +++ b/src/main/java/duke/TaskList.java @@ -1,5 +1,7 @@ package duke; +import java.util.List; + import duke.command.Command; import duke.exception.BadDateArgumentException; import duke.exception.EmptyArgumentException; @@ -8,8 +10,6 @@ import duke.task.Task; import duke.task.ToDos; -import java.util.List; - public class TaskList { public enum Action { ADD, @@ -19,7 +19,7 @@ public enum Action { SEARCH, } private boolean edited = false; - private List store; + private final List store; public TaskList(List store) { this.store = store; } @@ -30,7 +30,7 @@ public TaskList(List store) { * * @return Underlying data structure */ - public List getRawData(){ + public List getRawData() { return this.store; } @@ -142,12 +142,12 @@ private String getFilteredList(String searchTerm) { } private String formatOrderedPrint(int i) { final int size = store.size(); - while (i < 0){ + while (i < 0) { i += size; } - while (i >= size){ + while (i >= size) { i -= size; } - return "Entry " + (i+1) + "|" + store.get(i).toString(); + return "Entry " + (i + 1) + "|" + store.get(i).toString(); } } diff --git a/src/main/java/duke/Ui.java b/src/main/java/duke/Ui.java index 916aff637f..21d7763c96 100644 --- a/src/main/java/duke/Ui.java +++ b/src/main/java/duke/Ui.java @@ -1,40 +1,70 @@ package duke; +import java.text.ParseException; + import duke.command.Command; import duke.exception.BadDateArgumentException; import duke.exception.EmptyArgumentException; import duke.exception.InvalidCommandException; -import java.text.ParseException; - public class Ui { - private String logo = + private static final String LOGO = " ____ _ \n" //TODO: Figure out if this is allowed by style + "| _ \\ _ _| | _____ \n" + "| | | | | | | |/ / _ \\\n" + "| |_| | |_| | < __/\n" + "|____/ \\__,_|_|\\_\\___|\n"; - private String separator = "------------------\n"; + private static final String SEPARATOR = "------------------\n"; + /** + * Prints a startUpMessage for when the program starts. + */ public void startUpMessage() { - System.out.println("Hello from\n" + logo); + System.out.println("Hello from\n" + LOGO); System.out.println("No unicode allowed"); } - public void goodByeMessage(){ - System.out.println(separator + "Goodbye from\n" + logo); + + /** + * Prints a goodByeMessage for when the program ends. + */ + public void goodByeMessage() { + System.out.println(SEPARATOR + "Goodbye from\n" + LOGO); } - public void prompt(){ - System.out.print(separator + "Listening to your input: "); + + /** + * Prints a prompt to indicate that we are expecting input. + */ + public void prompt() { + System.out.print(SEPARATOR + "Listening to your input: "); } + + /** + * Indicate to the user that we are loading a file. + */ public void loadStart() { System.out.println("Loading From File..."); } + + /** + * Indicate to the user that we successfully loaded a file. + */ public void loadSuccess() { System.out.println("Loaded"); } + + /** + * Indicates to the user that the file could not be loaded and that we cannot continue. + */ public void loadFail() { System.out.println("Failed to Load file. Aborting."); } + + /** + * Dumps the state of the task list visually in a manner suitable for the user + * to manually copy and save. + * + * @param store TaskList that needs to be dumped + */ public void dumpState(TaskList store) { System.out.println("Unable to save list. Dumping ..."); System.out.print(store.getList()); @@ -48,43 +78,66 @@ public void dumpState(TaskList store) { * @param data The results of that command, in a pre-processed format */ public void commandMessage(Command command, String data) { - switch(command.getType()){ + switch (command.getType()) { case LIST: System.out.print(data); break; case DONE: - System.out.println("The following task is now marked as done:\n" + - data); + System.out.println("The following task is now marked as done:\n" + + data); break; case ADD: - System.out.println("The following task has been added:\n" + - data); + System.out.println("The following task has been added:\n" + + data); break; case DELETE: System.out.println("The following Task has been deleted:"); System.out.println(data); break; case SEARCH: - if (data.length() > 0){ + if (data.length() > 0) { System.out.println("Matching Task(s):"); System.out.println(data); - }else{ + } else { System.out.println("No Matching Task has been found"); } + break; + default: + System.out.println("ERROR: Unhandled Case!"); } } - //TODO: Figure out if this overloading is acceptable from a coding style perspective. + + /** + * Generates an UI alert for some particular error. + * + * @param e Exception that requires an error message + */ public void handleException(ParseException e) { System.out.println("Command has invalid parsing."); System.out.println(e.getMessage()); } - public void handleException(InvalidCommandException e){ + /** + * Generates an UI alert for some particular error. + * + * @param e Exception that requires an error message + */ + public void handleException(InvalidCommandException e) { System.out.println(e.getMessage()); } - public void handleException(EmptyArgumentException e){ + /** + * Generates an UI alert for some particular error. + * + * @param e Exception that requires an error message + */ + public void handleException(EmptyArgumentException e) { System.out.println("Cannot have empty argument"); System.out.println(e.getMessage()); } + /** + * Generates an UI alert for some particular error. + * + * @param e Exception that requires an error message + */ //TODO: Figure out how to do javadoc for overloaded method. public void handleException(BadDateArgumentException e) { System.out.println("Date must be of format 'dd MM yyyy'; Eg: 27 08 2044"); System.out.println(e.getMessage()); diff --git a/src/main/java/duke/command/AddCommand.java b/src/main/java/duke/command/AddCommand.java index 94c8c1ffbd..b4f9f2cbad 100644 --- a/src/main/java/duke/command/AddCommand.java +++ b/src/main/java/duke/command/AddCommand.java @@ -3,7 +3,7 @@ import duke.TaskList.Action; public class AddCommand extends Command { - String[] args; + private final String[] args; /** * Create new Add command diff --git a/src/main/java/duke/command/IndexedCommand.java b/src/main/java/duke/command/IndexedCommand.java index 2c1402eb1b..016d159c2e 100644 --- a/src/main/java/duke/command/IndexedCommand.java +++ b/src/main/java/duke/command/IndexedCommand.java @@ -1,6 +1,6 @@ package duke.command; -abstract class IndexedCommand extends Command{ +abstract class IndexedCommand extends Command { private final int index; /** @@ -8,7 +8,7 @@ abstract class IndexedCommand extends Command{ * * @param position One index position in TaskList of Task to manipulate */ - public IndexedCommand(int position){ + public IndexedCommand(int position) { this.index = position - 1; } diff --git a/src/main/java/duke/command/SearchCommand.java b/src/main/java/duke/command/SearchCommand.java index adef63393d..3a12e5ec4b 100644 --- a/src/main/java/duke/command/SearchCommand.java +++ b/src/main/java/duke/command/SearchCommand.java @@ -2,7 +2,7 @@ import duke.TaskList; -public class SearchCommand extends Command{ +public class SearchCommand extends Command { private String searchTerm; /** @@ -10,7 +10,7 @@ public class SearchCommand extends Command{ * * @param searchTerm Case and whitespace sensitive search input */ - public SearchCommand(String searchTerm){ + public SearchCommand(String searchTerm) { this.searchTerm = searchTerm; } diff --git a/src/main/java/duke/exception/EmptyArgumentException.java b/src/main/java/duke/exception/EmptyArgumentException.java index 2c07781de4..bc25acf1d5 100644 --- a/src/main/java/duke/exception/EmptyArgumentException.java +++ b/src/main/java/duke/exception/EmptyArgumentException.java @@ -6,5 +6,4 @@ public class EmptyArgumentException extends Exception { * */ private static final long serialVersionUID = 1L; - } diff --git a/src/main/java/duke/exception/InvalidCommandException.java b/src/main/java/duke/exception/InvalidCommandException.java index e3d5484d5a..53da1c7b11 100644 --- a/src/main/java/duke/exception/InvalidCommandException.java +++ b/src/main/java/duke/exception/InvalidCommandException.java @@ -1,7 +1,7 @@ package duke.exception; public class InvalidCommandException extends Exception { - + private static final long serialVersionUID = 1L; private String badCommand; /** @@ -11,12 +11,9 @@ public class InvalidCommandException extends Exception { */ public InvalidCommandException(String badCommand) { this.badCommand = badCommand; - } - - private static final long serialVersionUID = 1L; - + } @Override public String getMessage() { return "Command '" + badCommand + "' is not recognized."; } -} \ No newline at end of file +} diff --git a/src/main/java/duke/task/Deadline.java b/src/main/java/duke/task/Deadline.java index 464b813c06..b5ecff3913 100644 --- a/src/main/java/duke/task/Deadline.java +++ b/src/main/java/duke/task/Deadline.java @@ -1,12 +1,12 @@ package duke.task; -import duke.exception.EmptyArgumentException; -import duke.exception.BadDateArgumentException; - import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; +import duke.exception.BadDateArgumentException; +import duke.exception.EmptyArgumentException; + public class Deadline extends Task { protected LocalDate by; @@ -23,9 +23,8 @@ public Deadline(String description, String by) throws EmptyArgumentException, Ba super(description); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd MM yyyy"); try { - LocalDate date = LocalDate.parse(by, formatter); - this.by = date; - } catch(DateTimeParseException e) { + this.by = LocalDate.parse(by, formatter); + } catch (DateTimeParseException e) { throw new BadDateArgumentException(); } } @@ -42,4 +41,4 @@ public String toFileString() { String date = by.format(formatter); return "D," + super.toBaseFileString() + "," + date.length() + "," + date; } -} \ No newline at end of file +} diff --git a/src/main/java/duke/task/Event.java b/src/main/java/duke/task/Event.java index ca074cc178..02db2a16e9 100644 --- a/src/main/java/duke/task/Event.java +++ b/src/main/java/duke/task/Event.java @@ -3,14 +3,14 @@ import duke.exception.EmptyArgumentException; public class Event extends Task { - private String eventPeriod; + private final String eventPeriod; /** * Creates an Event that has a description and a duration. * * @param description Description of event * @param eventPeriod When the event takes place - * @throws EmptyArgumentException + * @throws EmptyArgumentException When an emtpy description or eventPeriod is passed */ public Event(String description, String eventPeriod) throws EmptyArgumentException { super(description); diff --git a/src/main/java/duke/task/Task.java b/src/main/java/duke/task/Task.java index 610897a165..cb10abfb02 100644 --- a/src/main/java/duke/task/Task.java +++ b/src/main/java/duke/task/Task.java @@ -2,8 +2,6 @@ import duke.exception.EmptyArgumentException; -import java.util.Locale; - public abstract class Task { private final String description; private boolean isDone; //TODO: Figure out if I can restrict access @@ -26,7 +24,7 @@ public Task(String description) throws EmptyArgumentException { /** * Marks the task as done */ - public void setDone(){ + public void setDone() { this.isDone = true; } @@ -40,7 +38,7 @@ public String getStatusIcon() { @Override public String toString() { - return "["+ this.getStatusIcon()+"]: " + description; + return "[" + this.getStatusIcon() + "]: " + description; } /** @@ -50,7 +48,7 @@ public String toString() { public abstract String toFileString(); @Override - public int hashCode(){ + public int hashCode() { return this.toString().hashCode(); } @@ -59,7 +57,7 @@ public int hashCode(){ * a format suitable for file system storage. * @return A common partial savable string. */ - String toBaseFileString(){ + String toBaseFileString() { return (isDone ? "1" : "0") + "," + description.length() + "," + description; } @@ -70,23 +68,23 @@ String toBaseFileString(){ * @param search Case and whitespace sensitive search substring * @return */ - public boolean containsSearch(String search){ + public boolean containsSearch(String search) { String targetString = description; boolean isCaseSensitive = search.toLowerCase().contains(search); - if (isCaseSensitive){ + if (isCaseSensitive) { targetString = targetString.toLowerCase(); } - if (search.contains(" ")){//Literal multi word matching + if (search.contains(" ")) { //Literal multi word matching return targetString.contains(search); - } else {//Smart per word start matching + } else { //Smart per word start matching String[] words = targetString.split(" "); - for(String word: words){ + for (String word: words) { String subWord = word.substring(0, search.length()); - if (subWord.equals(search)){ + if (subWord.equals(search)) { return true; } } return false; } } -} \ No newline at end of file +} diff --git a/src/main/java/duke/task/ToDos.java b/src/main/java/duke/task/ToDos.java index 0d18bc72f3..8538e21f12 100644 --- a/src/main/java/duke/task/ToDos.java +++ b/src/main/java/duke/task/ToDos.java @@ -2,7 +2,7 @@ import duke.exception.EmptyArgumentException; -public class ToDos extends Task{ +public class ToDos extends Task { /** * Creates a To Do object that is essentially a wrapper on task. * From 725faeab5d07e481d7c2dd31c00d433c4f358c80 Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Fri, 12 Feb 2021 23:49:06 +0800 Subject: [PATCH 54/92] Address concerns in reviews for my first PR --- src/main/java/duke/Duke.java | 28 +++++++++---------- src/main/java/duke/Parser.java | 4 +-- src/main/java/duke/TaskList.java | 18 ++++++------ src/main/java/duke/Ui.java | 18 ++++++------ src/main/java/duke/command/AddCommand.java | 2 +- src/main/java/duke/command/Command.java | 2 +- .../java/duke/command/IndexedCommand.java | 2 +- src/main/java/duke/command/ListCommand.java | 2 +- src/main/java/duke/command/SearchCommand.java | 2 +- src/main/java/duke/task/Deadline.java | 8 +++--- src/test/java/duke/ParserTest.java | 6 ++-- 11 files changed, 46 insertions(+), 46 deletions(-) diff --git a/src/main/java/duke/Duke.java b/src/main/java/duke/Duke.java index 9a7cb78563..8025f0b6c1 100644 --- a/src/main/java/duke/Duke.java +++ b/src/main/java/duke/Duke.java @@ -19,28 +19,28 @@ public class Duke { */ public static void main(String[] args) { Ui ui = new Ui(); - ui.startUpMessage(); - TaskList store; + ui.printStartUp(); + TaskList taskList; try { - ui.loadStart(); - store = Storage.loadTaskList(); - ui.loadSuccess(); + ui.printLoadStart(); + taskList = Storage.loadTaskList(); + ui.printLoadSuccess(); } catch (IOException e) { - ui.loadFail(); + ui.printLoadFail(); return; } Scanner in = new Scanner(System.in); String line; do { - ui.prompt(); + ui.printPrompt(); line = in.nextLine(); try { Command c = Parser.parse(line); if (c == null) { //Bye command break; } - String data = store.run(c); - ui.commandMessage(c, data); + String data = taskList.run(c); + ui.printCommandMessage(c, data); } catch (ParseException e) { ui.handleException(e); } catch (InvalidCommandException e) { @@ -50,17 +50,17 @@ public static void main(String[] args) { } catch (BadDateArgumentException e) { ui.handleException(e); } finally { - if (store.isEdited()) { + if (taskList.isEdited()) { try { - Storage.saveTaskList(store); - store.markSaved(); + Storage.saveTaskList(taskList); + taskList.markSaved(); } catch (IOException e) { - ui.dumpState(store); + ui.dumpState(taskList); } } } } while (true); - ui.goodByeMessage(); + ui.printShutDown(); in.close(); } } diff --git a/src/main/java/duke/Parser.java b/src/main/java/duke/Parser.java index b3badfaa29..376ac441e6 100644 --- a/src/main/java/duke/Parser.java +++ b/src/main/java/duke/Parser.java @@ -81,9 +81,9 @@ private static String[] splitTokenIntoTwo(String parseTarget, String delimiter) private static String[] splitTokenIntoTwo(String parseTarget, String delimiter, String[] exception) throws ParseException { - List exceptionList = Arrays.asList(exception); + List exceptionsList = Arrays.asList(exception); String[] tokens = parseTarget.split(delimiter, 2); - if (!exceptionList.contains(tokens[0]) && tokens.length < 2) { + if (!exceptionsList.contains(tokens[0]) && tokens.length < 2) { throw new ParseException("Expected deliminter '" + delimiter + "'", tokens[0].length()); } return tokens; diff --git a/src/main/java/duke/TaskList.java b/src/main/java/duke/TaskList.java index aff0958eb1..bf77289ba6 100644 --- a/src/main/java/duke/TaskList.java +++ b/src/main/java/duke/TaskList.java @@ -44,32 +44,32 @@ public List getRawData() { * @throws BadDateArgumentException An argument that is expected to be a date is ill formatted */ public String run(Command c) throws EmptyArgumentException, BadDateArgumentException { - String[] args = c.run(); - String results; + String[] args = c.getCommandParameters(); + String result; switch (c.getType()) { case ADD: - results = addTask(args); + result = addTask(args); edited = true; break; case DONE: - results = setDone(Integer.parseInt(args[0])); + result = setDone(Integer.parseInt(args[0])); edited = true; break; case DELETE: - results = delete(Integer.parseInt(args[0])); + result = delete(Integer.parseInt(args[0])); edited = true; break; case LIST: - results = getList(); + result = getList(); break; case SEARCH: - results = getFilteredList(args[0]); + result = getFilteredList(args[0]); break; default: - results = ""; + result = ""; break; } - return results; + return result; } /** diff --git a/src/main/java/duke/Ui.java b/src/main/java/duke/Ui.java index 21d7763c96..0ffc7a7e40 100644 --- a/src/main/java/duke/Ui.java +++ b/src/main/java/duke/Ui.java @@ -17,45 +17,45 @@ public class Ui { private static final String SEPARATOR = "------------------\n"; /** - * Prints a startUpMessage for when the program starts. + * Prints a start up message for when the program starts. */ - public void startUpMessage() { + public void printStartUp() { System.out.println("Hello from\n" + LOGO); System.out.println("No unicode allowed"); } /** - * Prints a goodByeMessage for when the program ends. + * Prints a shutdown message for when the program ends. */ - public void goodByeMessage() { + public void printShutDown() { System.out.println(SEPARATOR + "Goodbye from\n" + LOGO); } /** * Prints a prompt to indicate that we are expecting input. */ - public void prompt() { + public void printPrompt() { System.out.print(SEPARATOR + "Listening to your input: "); } /** * Indicate to the user that we are loading a file. */ - public void loadStart() { + public void printLoadStart() { System.out.println("Loading From File..."); } /** * Indicate to the user that we successfully loaded a file. */ - public void loadSuccess() { + public void printLoadSuccess() { System.out.println("Loaded"); } /** * Indicates to the user that the file could not be loaded and that we cannot continue. */ - public void loadFail() { + public void printLoadFail() { System.out.println("Failed to Load file. Aborting."); } @@ -77,7 +77,7 @@ public void dumpState(TaskList store) { * @param command The command that has been issued * @param data The results of that command, in a pre-processed format */ - public void commandMessage(Command command, String data) { + public void printCommandMessage(Command command, String data) { switch (command.getType()) { case LIST: System.out.print(data); diff --git a/src/main/java/duke/command/AddCommand.java b/src/main/java/duke/command/AddCommand.java index b4f9f2cbad..805ecdff76 100644 --- a/src/main/java/duke/command/AddCommand.java +++ b/src/main/java/duke/command/AddCommand.java @@ -14,7 +14,7 @@ public AddCommand(String[] args) { } @Override - public String[] run() { + public String[] getCommandParameters() { return args; } diff --git a/src/main/java/duke/command/Command.java b/src/main/java/duke/command/Command.java index 3ac304d79a..342e69ceac 100644 --- a/src/main/java/duke/command/Command.java +++ b/src/main/java/duke/command/Command.java @@ -3,6 +3,6 @@ import duke.TaskList; public abstract class Command { - public abstract String[] run(); + public abstract String[] getCommandParameters(); public abstract TaskList.Action getType(); } diff --git a/src/main/java/duke/command/IndexedCommand.java b/src/main/java/duke/command/IndexedCommand.java index 016d159c2e..ee0eb0cac1 100644 --- a/src/main/java/duke/command/IndexedCommand.java +++ b/src/main/java/duke/command/IndexedCommand.java @@ -13,7 +13,7 @@ public IndexedCommand(int position) { } @Override - public String[] run() { + public String[] getCommandParameters() { return new String[]{String.valueOf(index)}; } } diff --git a/src/main/java/duke/command/ListCommand.java b/src/main/java/duke/command/ListCommand.java index 420c7f640b..d20412b013 100644 --- a/src/main/java/duke/command/ListCommand.java +++ b/src/main/java/duke/command/ListCommand.java @@ -5,7 +5,7 @@ public class ListCommand extends Command { @Override - public String[] run() { + public String[] getCommandParameters() { return new String[0]; } diff --git a/src/main/java/duke/command/SearchCommand.java b/src/main/java/duke/command/SearchCommand.java index 3a12e5ec4b..51099f6f83 100644 --- a/src/main/java/duke/command/SearchCommand.java +++ b/src/main/java/duke/command/SearchCommand.java @@ -15,7 +15,7 @@ public SearchCommand(String searchTerm) { } @Override - public String[] run() { + public String[] getCommandParameters() { String[] searchTerm = {this.searchTerm}; return searchTerm; } diff --git a/src/main/java/duke/task/Deadline.java b/src/main/java/duke/task/Deadline.java index b5ecff3913..efc8d9ff0d 100644 --- a/src/main/java/duke/task/Deadline.java +++ b/src/main/java/duke/task/Deadline.java @@ -8,7 +8,7 @@ import duke.exception.EmptyArgumentException; public class Deadline extends Task { - protected LocalDate by; + protected LocalDate deadline; /** * Creates a Task with a description and a deadline date that it needs @@ -23,7 +23,7 @@ public Deadline(String description, String by) throws EmptyArgumentException, Ba super(description); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd MM yyyy"); try { - this.by = LocalDate.parse(by, formatter); + this.deadline = LocalDate.parse(by, formatter); } catch (DateTimeParseException e) { throw new BadDateArgumentException(); } @@ -32,13 +32,13 @@ public Deadline(String description, String by) throws EmptyArgumentException, Ba @Override public String toString() { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMMM dd, yyyy"); - return "[D]" + super.toString() + " (Deadline: " + by.format(formatter) + ")"; + return "[D]" + super.toString() + " (Deadline: " + deadline.format(formatter) + ")"; } @Override public String toFileString() { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd MM yyyy"); - String date = by.format(formatter); + String date = deadline.format(formatter); return "D," + super.toBaseFileString() + "," + date.length() + "," + date; } } diff --git a/src/test/java/duke/ParserTest.java b/src/test/java/duke/ParserTest.java index 0a8b9ae726..7f0bfc680b 100644 --- a/src/test/java/duke/ParserTest.java +++ b/src/test/java/duke/ParserTest.java @@ -32,9 +32,9 @@ public void todoTest(){ try { Command c = Parser.parse("TODO blow up the moon"); Assertions.assertTrue(c instanceof AddCommand); - Assertions.assertEquals(2, c.run().length); - Assertions.assertEquals("T", c.run()[0]); - Assertions.assertEquals("blow up the moon", c.run()[1]); + Assertions.assertEquals(2, c.getCommandParameters().length); + Assertions.assertEquals("T", c.getCommandParameters()[0]); + Assertions.assertEquals("blow up the moon", c.getCommandParameters()[1]); } catch (Exception e) { fail("Should not throw Exception"); } From 68d8318d25331c0c064fcaa5096ea798e1e89df6 Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Sat, 13 Feb 2021 00:08:38 +0800 Subject: [PATCH 55/92] Fix naming and bug when searching long word --- src/main/java/duke/task/Task.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/duke/task/Task.java b/src/main/java/duke/task/Task.java index cb10abfb02..bde905fc67 100644 --- a/src/main/java/duke/task/Task.java +++ b/src/main/java/duke/task/Task.java @@ -70,8 +70,8 @@ String toBaseFileString() { */ public boolean containsSearch(String search) { String targetString = description; - boolean isCaseSensitive = search.toLowerCase().contains(search); - if (isCaseSensitive) { + boolean isCaseInsensitive = !search.toLowerCase().contains(search); + if (isCaseInsensitive) { targetString = targetString.toLowerCase(); } if (search.contains(" ")) { //Literal multi word matching @@ -79,6 +79,9 @@ public boolean containsSearch(String search) { } else { //Smart per word start matching String[] words = targetString.split(" "); for (String word: words) { + if (word.length() < search.length()) { + continue; + } String subWord = word.substring(0, search.length()); if (subWord.equals(search)) { return true; From e17d7d6b8da7c0278c0bde3d5da602834e7a2fcb Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Sat, 13 Feb 2021 00:11:53 +0800 Subject: [PATCH 56/92] Set up gradle for JavaFX --- build.gradle | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/build.gradle b/build.gradle index 20c0521cc7..6c4d1111f9 100644 --- a/build.gradle +++ b/build.gradle @@ -12,6 +12,20 @@ repositories { dependencies { testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.5.0' testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.5.0' + String javaFxVersion = '11' + + implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'win' + implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'mac' + implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'linux' + implementation group: 'org.openjfx', name: 'javafx-controls', version: javaFxVersion, classifier: 'win' + implementation group: 'org.openjfx', name: 'javafx-controls', version: javaFxVersion, classifier: 'mac' + implementation group: 'org.openjfx', name: 'javafx-controls', version: javaFxVersion, classifier: 'linux' + implementation group: 'org.openjfx', name: 'javafx-fxml', version: javaFxVersion, classifier: 'win' + implementation group: 'org.openjfx', name: 'javafx-fxml', version: javaFxVersion, classifier: 'mac' + implementation group: 'org.openjfx', name: 'javafx-fxml', version: javaFxVersion, classifier: 'linux' + implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'win' + implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'mac' + implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'linux' } test { From 05f73fcada1f854c6a1501874d1158b49303f133 Mon Sep 17 00:00:00 2001 From: nighoggDatatype Date: Sat, 13 Feb 2021 14:50:34 +0800 Subject: [PATCH 57/92] Add skeleton for JavaFx --- src/main/java/duke/Launcher.java | 12 +++++++ src/main/java/duke/Main.java | 28 ++++++++++++++++ src/main/java/duke/ui/MainWindow.java | 44 +++++++++++++++++++++++++ src/main/resources/view/MainWindow.fxml | 19 +++++++++++ 4 files changed, 103 insertions(+) create mode 100644 src/main/java/duke/Launcher.java create mode 100644 src/main/java/duke/Main.java create mode 100644 src/main/java/duke/ui/MainWindow.java create mode 100644 src/main/resources/view/MainWindow.fxml diff --git a/src/main/java/duke/Launcher.java b/src/main/java/duke/Launcher.java new file mode 100644 index 0000000000..e4ef6b4628 --- /dev/null +++ b/src/main/java/duke/Launcher.java @@ -0,0 +1,12 @@ +package duke; + +import javafx.application.Application; + +/** + * A launcher class to workaround classpath issues. + */ +public class Launcher { + public static void main(String[] args) { + Application.launch(Main.class, args); + } +} diff --git a/src/main/java/duke/Main.java b/src/main/java/duke/Main.java new file mode 100644 index 0000000000..acce71d318 --- /dev/null +++ b/src/main/java/duke/Main.java @@ -0,0 +1,28 @@ +package duke; + +import java.io.IOException; + +import duke.ui.MainWindow; +import javafx.application.Application; +import javafx.fxml.FXMLLoader; +import javafx.scene.Scene; +import javafx.scene.layout.AnchorPane; +import javafx.stage.Stage; + +public class Main extends Application { + + @Override + public void start(Stage stage) { + Duke d = new Duke(); + try { + FXMLLoader fxmlLoader = new FXMLLoader(Main.class.getResource("/view/MainWindow.fxml")); + AnchorPane ap = fxmlLoader.load(); + Scene scene = new Scene(ap); + stage.setScene(scene); + fxmlLoader.getController().setDuke(d); + stage.show(); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/duke/ui/MainWindow.java b/src/main/java/duke/ui/MainWindow.java new file mode 100644 index 0000000000..ad99a99a4b --- /dev/null +++ b/src/main/java/duke/ui/MainWindow.java @@ -0,0 +1,44 @@ +package duke.ui; + +import duke.Duke; +import javafx.fxml.FXML; +import javafx.scene.control.Button; +import javafx.scene.control.ScrollPane; +import javafx.scene.control.TextField; +import javafx.scene.layout.AnchorPane; +import javafx.scene.layout.VBox; +/** + * Controller for MainWindow. Provides the layout for the other controls. + */ +public class MainWindow extends AnchorPane { + @FXML + private ScrollPane scrollPane; + @FXML + private VBox dialogContainer; + @FXML + private TextField userInput; + @FXML + private Button sendButton; + + private Duke duke; + + @FXML + public void initialize() { + scrollPane.vvalueProperty().bind(dialogContainer.heightProperty()); + } + + public void setDuke(Duke d) { + duke = d; + } + + /** + * Creates two dialog boxes, one echoing user input and the other containing Duke's reply and then appends them to + * the dialog container. Clears the user input after processing. + */ + @FXML + private void handleUserInput() { + String input = userInput.getText(); + System.out.println(input); + userInput.clear(); + } +} diff --git a/src/main/resources/view/MainWindow.fxml b/src/main/resources/view/MainWindow.fxml new file mode 100644 index 0000000000..c888558e1b --- /dev/null +++ b/src/main/resources/view/MainWindow.fxml @@ -0,0 +1,19 @@ + + + + + + + + + + + +