Skip to content

Commit

Permalink
Merge pull request #91 from BunnyHoppp/branch-SortCommand
Browse files Browse the repository at this point in the history
Branch sort command
  • Loading branch information
gohqingkhang authored Oct 24, 2024
2 parents b53b486 + 40dc0d2 commit fc1c202
Show file tree
Hide file tree
Showing 47 changed files with 1,049 additions and 25 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ dependencies {
}

shadowJar {
archiveFileName = 'addressbook.jar'
archiveFileName = 'studentmanagerpro.jar'
}

defaultTasks 'clean', 'test'
Expand Down
21 changes: 21 additions & 0 deletions docs/UserGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ Format: `filter [n/NAME] [p/PHONE_NUMBER] [e/EMAIL] [a/ADDRESS] [c/CLASS] [s/SEX

* The search is case-insensitive. e.g `hans` will match `Hans`
* The order of the keywords does not matter. e.g. `Hans Bo` will match `Bo Hans`
* Only the name is searched.
* Only full words will be matched e.g. `Han` will not match `Hans`
* Persons matching at least one keyword will be returned (i.e. `OR` search).
e.g. `Hans Bo` will return `Hans Gruber`, `Bo Yang`
Expand Down Expand Up @@ -267,6 +268,25 @@ Examples:
* `addSubmissionStatus 1 sm/Assignment 1 ss/T`
* `addSubmissionStatus 1 sm/Tutorial 2 ss/NIL`

### Sorting the list : `sort`

Sorts the list of students based on the students attributes.

Format: `sort [ATTRIBUTE]`

<box type="tip" seamless>

**Tip:** Students attributes include: name, phone, email, address, sex, register number, student class, emergency contact name, emergency contact number.
</box>

* Sorts the list based on the ATTRIBUTE
* Unsort the list when the attribute is `none`

Examples:
* `sort name` to sort the list based on student's names
* `sort register number` to sort the list based on student's register numbers
* `sort none` to unsort the list

### Clearing all entries : `clear`

Clears all entries from the address book.
Expand Down Expand Up @@ -332,3 +352,4 @@ _Details coming soon ..._
| **Add Attendance** | `addAttendance INDEX aa/[DATE] ar/[REASON]`<br> e.g., `addAttendance 1 aa/[24-09-2024] ar/[Sick]` |
| **AddSubmission** | `addSubmission sm/SUBMISSION_NAME` <br> e.g., `addSubmission sm/Assignment 1` |
| **AddSubmissionStatus** | `addSubmissionStatus INDEX sm/SUBMISSION_NAME ss/SUBMISSION_STATUS` <br> e.g., `addSubmissionStatus 1 sm/Assignment 1 ss/T` |
| **Sort** | `sort [ATTRIBUTE]` <br> e.g., `sort student class`
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public class FilterCommand extends Command {
+ "[" + PREFIX_ECNAME + "EMERGENCY CONTACT NAME] "
+ "[" + PREFIX_ECNUMBER + "EMERGENCY CONTACT NUMBER] "
+ "[" + PREFIX_TAG + "TAG]...\n"
+ "Example: " + COMMAND_WORD + PREFIX_NAME + "Bob "
+ "Example: " + COMMAND_WORD + " " + PREFIX_NAME + "Bob "
+ PREFIX_PHONE + "90123445";

private final PersonPredicate predicate;
Expand Down
116 changes: 116 additions & 0 deletions src/main/java/seedu/address/logic/commands/SortCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package seedu.address.logic.commands;

import static java.util.Objects.isNull;
import static java.util.Objects.requireNonNull;

import java.util.Comparator;
import java.util.logging.Level;
import java.util.logging.Logger;

import seedu.address.commons.core.LogsCenter;
import seedu.address.logic.parser.ParserUtil.SortAttribute;
import seedu.address.model.Model;
import seedu.address.model.person.Person;
import seedu.address.model.person.comparator.AddressCompare;
import seedu.address.model.person.comparator.EcNameCompare;
import seedu.address.model.person.comparator.EcNumberCompare;
import seedu.address.model.person.comparator.EmailCompare;
import seedu.address.model.person.comparator.NameCompare;
import seedu.address.model.person.comparator.PhoneCompare;
import seedu.address.model.person.comparator.RegisterNumberCompare;
import seedu.address.model.person.comparator.SexCompare;
import seedu.address.model.person.comparator.StudentClassCompare;

/**
* Sorts the list of contacts based on the attribute
*/
public class SortCommand extends Command {

public static final String COMMAND_WORD = "sort";

public static final String MESSAGE_USAGE = COMMAND_WORD + ": Sorts the list based on the attribute\n"
+ "Attributes: name, phone, email, address, register number, sex, \n"
+ "student class, emergency contact name, emergency contact number";

public static final String MESSAGE_SORTED_SUCCESS = "Sorted the list based on %1$s";
public static final String MESSAGE_UNSORTED_SUCCESS = "Your list is now unsorted and back to the original!";
private static final Logger logger = LogsCenter.getLogger(SortCommand.class);
private final SortAttribute sortAttribute;
private Comparator<Person> comparator;


/**
* @param sortAttribute attribute to sort the persons in the list
*/
public SortCommand(SortAttribute sortAttribute) {
requireNonNull(sortAttribute);
this.sortAttribute = sortAttribute;
}

@Override
public CommandResult execute(Model model) {
requireNonNull(model);
this.comparator = this.getComparator();
model.sortFilteredPersonList(this.comparator);
logger.log(Level.INFO, "SortCommand has been executed");
return new CommandResult(this.generateSuccessMessage());
}


public String generateSuccessMessage() {
return isNull(comparator) ? MESSAGE_UNSORTED_SUCCESS : String.format(MESSAGE_SORTED_SUCCESS, sortAttribute);
}
/**
* Retrieves the comparator needed to sort the list.
* Returns null to unsort.
*/
public Comparator<Person> getComparator() {
assert sortAttribute != null;
switch (sortAttribute) {

case NAME:
return new NameCompare();

case PHONE:
return new PhoneCompare();

case EMAIL:
return new EmailCompare();

case ADDRESS:
return new AddressCompare();

case REGISTERNUMBER:
return new RegisterNumberCompare();

case SEX:
return new SexCompare();

case STUDENTCLASS:
return new StudentClassCompare();

case EMERGENCYCONTACTNAME:
return new EcNameCompare();

case EMERGENCYCONTACTNUMBER:
return new EcNumberCompare();

default:
return null;
}
}

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

if (!(other instanceof SortCommand)) {
return false;
}

SortCommand s = (SortCommand) other;
return sortAttribute.equals(s.sortAttribute);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import seedu.address.logic.commands.FilterCommand;
import seedu.address.logic.commands.HelpCommand;
import seedu.address.logic.commands.ListCommand;
import seedu.address.logic.commands.SortCommand;
import seedu.address.logic.parser.exceptions.ParseException;

/**
Expand Down Expand Up @@ -105,6 +106,9 @@ public Command parseCommand(String userInput) throws ParseException {
case AddExamScoreCommand.COMMAND_WORD:
return new AddExamScoreCommandParser().parse(arguments);

case SortCommand.COMMAND_WORD:
return new SortCommandParser().parse(arguments);

default:
logger.finer("This user input caused a ParseException: " + userInput);
throw new ParseException(MESSAGE_UNKNOWN_COMMAND);
Expand Down
47 changes: 47 additions & 0 deletions src/main/java/seedu/address/logic/parser/ParserUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -296,4 +296,51 @@ public static AbsentReason parseAbsentReason(String absentReason) throws ParseEx
return new AbsentReason(trimmedAbsentReason);
}


/**
* Parse {@code String attribute} into a {@code SortAttribute}.
* All whitespaces will be trimmed
*
* @throws ParseException if the given {@code SortAttribute} is invalid.
*/
public static SortAttribute parseSortAttribute(String attribute) throws ParseException {
requireNonNull(attribute);
String trimmedAttribute = attribute.replaceAll("\\s+", "");
String upperCaseAttribute = trimmedAttribute.toUpperCase();
SortAttribute sortAttribute;
try {
sortAttribute = SortAttribute.valueOf(upperCaseAttribute);
} catch (IllegalArgumentException e) {
throw new ParseException(SortAttribute.MESSAGE_CONSTRAINTS);
}
return sortAttribute;
}

/**
* Enum to encapsulate all the possible attributes to sort the list by.
*/
public enum SortAttribute {
NAME("name"),
PHONE("phone"),
EMAIL("email"),
ADDRESS("address"),
REGISTERNUMBER("register number"),
SEX("sex"),
STUDENTCLASS("student class"),
EMERGENCYCONTACTNAME("emergency contact name"),
EMERGENCYCONTACTNUMBER("emergency contact number"),
NONE("none");

public static final String MESSAGE_CONSTRAINTS = "Sorting Attribute is invalid";

private final String attribute;
SortAttribute(String attribute) {
this.attribute = attribute;
}

@Override
public String toString() {
return this.attribute;
}
}
}
40 changes: 40 additions & 0 deletions src/main/java/seedu/address/logic/parser/SortCommandParser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package seedu.address.logic.parser;

import static java.util.Objects.requireNonNull;
import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;

import java.util.logging.Level;
import java.util.logging.Logger;

import seedu.address.commons.core.LogsCenter;
import seedu.address.commons.exceptions.IllegalValueException;
import seedu.address.logic.commands.SortCommand;
import seedu.address.logic.parser.ParserUtil.SortAttribute;
import seedu.address.logic.parser.exceptions.ParseException;

/**
* Parses input arguments and creates a new SortCommand object
*/
public class SortCommandParser implements Parser<SortCommand> {

private static final Logger logger = LogsCenter.getLogger(SortCommandParser.class);

/**
* Parses the given {@code String} of arguments in the context of the SortCommand
* and returns a SortCommand object for execution.
* @throws ParseException if the user input does not conform the expected format.
*/
public SortCommand parse(String args) throws ParseException {
requireNonNull(args);
SortAttribute sortAttribute;
try {
sortAttribute = ParserUtil.parseSortAttribute(args);
} catch (IllegalValueException ive) {
throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT,
SortCommand.MESSAGE_USAGE), ive);
}
assert sortAttribute != null;
logger.log(Level.INFO, "parsed sort command without exception");
return new SortCommand(sortAttribute);
}
}
7 changes: 7 additions & 0 deletions src/main/java/seedu/address/model/Model.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package seedu.address.model;

import java.nio.file.Path;
import java.util.Comparator;
import java.util.function.Predicate;

import javafx.collections.ObservableList;
Expand Down Expand Up @@ -84,4 +85,10 @@ public interface Model {
* @throws NullPointerException if {@code predicate} is null.
*/
void updateFilteredPersonList(Predicate<Person> predicate);

/**
* Sorts the filteredPersonList using the comparator.
* @param comparator to sort the list.
*/
void sortFilteredPersonList(Comparator<Person> comparator);
}
13 changes: 12 additions & 1 deletion src/main/java/seedu/address/model/ModelManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;

import java.nio.file.Path;
import java.util.Comparator;
import java.util.function.Predicate;
import java.util.logging.Logger;

import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.collections.transformation.SortedList;
import seedu.address.commons.core.GuiSettings;
import seedu.address.commons.core.LogsCenter;
import seedu.address.model.person.Person;
Expand All @@ -22,6 +24,7 @@ public class ModelManager implements Model {
private final AddressBook addressBook;
private final UserPrefs userPrefs;
private final FilteredList<Person> filteredPersons;
private final SortedList<Person> sortedAndFilteredPersons;

/**
* Initializes a ModelManager with the given addressBook and userPrefs.
Expand All @@ -34,6 +37,7 @@ public ModelManager(ReadOnlyAddressBook addressBook, ReadOnlyUserPrefs userPrefs
this.addressBook = new AddressBook(addressBook);
this.userPrefs = new UserPrefs(userPrefs);
filteredPersons = new FilteredList<>(this.addressBook.getPersonList());
sortedAndFilteredPersons = new SortedList<>(filteredPersons);
}

public ModelManager() {
Expand Down Expand Up @@ -119,13 +123,20 @@ public void setPerson(Person target, Person editedPerson) {
*/
@Override
public ObservableList<Person> getFilteredPersonList() {
return filteredPersons;
return sortedAndFilteredPersons;
}

@Override
public void updateFilteredPersonList(Predicate<Person> predicate) {
requireNonNull(predicate);
filteredPersons.setPredicate(predicate);
logger.fine("Person list is filtered");
}

@Override
public void sortFilteredPersonList(Comparator<Person> comparator) {
sortedAndFilteredPersons.setComparator(comparator);
logger.fine("Person list is sorted");
}

@Override
Expand Down
7 changes: 6 additions & 1 deletion src/main/java/seedu/address/model/person/Address.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
* Represents a Person's address in the address book.
* Guarantees: immutable; is valid as declared in {@link #isValidAddress(String)}
*/
public class Address {
public class Address implements Comparable<Address> {

public static final String MESSAGE_GUI = "Address: %1$s";
public static final String MESSAGE_CONSTRAINTS = "Addresses can take any values, and it should not be blank";
Expand Down Expand Up @@ -63,4 +63,9 @@ public int hashCode() {
return value.hashCode();
}

@Override
public int compareTo(Address a) {
return this.toString().compareTo(a.toString());
}

}
6 changes: 5 additions & 1 deletion src/main/java/seedu/address/model/person/EcName.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
* Represents a person's emergency contact name in the address book
* The name can be empty or contain only alphanumeric characters and spaces.
*/
public class EcName {
public class EcName implements Comparable<EcName> {

public static final String MESSAGE_GUI = "Emergency Contact Name: %1$s";
public static final String MESSAGE_CONSTRAINTS =
Expand Down Expand Up @@ -65,4 +65,8 @@ public int hashCode() {
return value.hashCode();
}

@Override
public int compareTo(EcName e) {
return this.toString().compareTo(e.toString());
}
}
Loading

0 comments on commit fc1c202

Please sign in to comment.