Merge branch 'feature/ui' into develop
This commit is contained in:
+20
@@ -41,6 +41,13 @@
|
|||||||
<artifactId>junit-jupiter-params</artifactId>
|
<artifactId>junit-jupiter-params</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.googlecode.lanterna</groupId>
|
||||||
|
<artifactId>lanterna</artifactId>
|
||||||
|
<version>3.1.5</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
@@ -91,5 +98,18 @@
|
|||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</pluginManagement>
|
</pluginManagement>
|
||||||
|
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
<artifactId>exec-maven-plugin</artifactId>
|
||||||
|
<version>3.6.3</version>
|
||||||
|
|
||||||
|
<configuration>
|
||||||
|
<mainClass>ru.project.App</mainClass>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
|
||||||
</build>
|
</build>
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -1,10 +1,45 @@
|
|||||||
package ru.project;
|
package ru.project;
|
||||||
|
|
||||||
/**
|
import com.googlecode.lanterna.gui2.MultiWindowTextGUI;
|
||||||
* Hello world!
|
import com.googlecode.lanterna.screen.Screen;
|
||||||
*/
|
import com.googlecode.lanterna.terminal.DefaultTerminalFactory;
|
||||||
public class App {
|
import ru.project.model.AppState;
|
||||||
public static void main(String[] args) {
|
import ru.project.ui.main.MainMenu;
|
||||||
System.out.println("Hello World!");
|
|
||||||
|
public final class App {
|
||||||
|
|
||||||
|
private App() {}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
Screen screen = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
DefaultTerminalFactory terminalFactory = new DefaultTerminalFactory();
|
||||||
|
|
||||||
|
screen = terminalFactory.createScreen();
|
||||||
|
screen.startScreen();
|
||||||
|
|
||||||
|
MultiWindowTextGUI gui = new MultiWindowTextGUI(screen);
|
||||||
|
|
||||||
|
AppState state = new AppState();
|
||||||
|
|
||||||
|
MainMenu mainMenu = new MainMenu(gui, state);
|
||||||
|
|
||||||
|
mainMenu.showModal();
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println("Произошла ошибка при выполнении программы:");
|
||||||
|
e.printStackTrace();
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
if (screen != null) {
|
||||||
|
try {
|
||||||
|
screen.stopScreen();
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println("Не удалось корректно завершить работу терминала:");
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,120 @@
|
|||||||
|
package ru.project.collection;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public class MyLinkedList<T> implements MyList<T> {
|
||||||
|
private Node<T> head;
|
||||||
|
private int size;
|
||||||
|
|
||||||
|
public void add(T value) {
|
||||||
|
if (head == null) {
|
||||||
|
this.head = new Node<>(value);
|
||||||
|
} else {
|
||||||
|
Node<T> temp = head;
|
||||||
|
while (temp.getNext() != null) {
|
||||||
|
temp = temp.getNext();
|
||||||
|
}
|
||||||
|
temp.setNext(new Node<>(value));
|
||||||
|
}
|
||||||
|
size++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T get(int index) {
|
||||||
|
int currentIndex = 0;
|
||||||
|
Node<T> temp = head;
|
||||||
|
while (temp != null) {
|
||||||
|
if (currentIndex == index) {
|
||||||
|
return temp.getValue();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
temp = temp.getNext();
|
||||||
|
currentIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove(int index) {
|
||||||
|
if (index < 0 || index >= size) {
|
||||||
|
throw new IndexOutOfBoundsException();
|
||||||
|
}
|
||||||
|
if (index == 0) {
|
||||||
|
head = head.getNext();
|
||||||
|
size--;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int currentIndex = 0;
|
||||||
|
Node<T> temp = head;
|
||||||
|
while (temp != null) {
|
||||||
|
if (currentIndex == index - 1) {
|
||||||
|
temp.setNext(temp.getNext().getNext());
|
||||||
|
size--;
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
temp = temp.getNext();
|
||||||
|
currentIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public T set(int index, T value) {
|
||||||
|
if (index < 0 || index >= size) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
|
||||||
|
Node<T> temp = head;
|
||||||
|
for (int i = 0; i < index; i++) {
|
||||||
|
temp = temp.getNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
T oldValue = temp.getValue();
|
||||||
|
temp.setValue(value);
|
||||||
|
return oldValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int size() {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return size == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
Object[] res = new Object[size];
|
||||||
|
int index = 0;
|
||||||
|
Node<T> temp = head;
|
||||||
|
while (temp != null) {
|
||||||
|
res[index] = temp.getValue();
|
||||||
|
index++;
|
||||||
|
temp = temp.getNext();
|
||||||
|
}
|
||||||
|
return Arrays.toString(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Node<T> {
|
||||||
|
private T value;
|
||||||
|
private Node<T> next;
|
||||||
|
|
||||||
|
public Node(T value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(T value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNext(Node<T> next) {
|
||||||
|
this.next = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Node<T> getNext() {
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package ru.project.collection;
|
||||||
|
|
||||||
|
public interface MyList<T> {
|
||||||
|
|
||||||
|
void add(T element);
|
||||||
|
|
||||||
|
T get(int index);
|
||||||
|
|
||||||
|
T set(int index, T element);
|
||||||
|
|
||||||
|
void remove(int index);
|
||||||
|
|
||||||
|
int size();
|
||||||
|
|
||||||
|
boolean isEmpty();
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package ru.project.model;
|
||||||
|
|
||||||
|
import ru.project.collection.MyLinkedList;
|
||||||
|
import ru.project.collection.MyList;
|
||||||
|
import ru.project.student.Student;
|
||||||
|
|
||||||
|
public class AppState {
|
||||||
|
|
||||||
|
private MyList<Student> mainCollection;
|
||||||
|
private MyList<Student> customDataCollection;
|
||||||
|
private String currentFilePath;
|
||||||
|
|
||||||
|
public AppState() {
|
||||||
|
this.mainCollection = new MyLinkedList<>();
|
||||||
|
this.customDataCollection = new MyLinkedList<>();
|
||||||
|
this.currentFilePath = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MyList<Student> getMainCollection() {
|
||||||
|
return mainCollection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMainCollection(MyList<Student> currentCollection) {
|
||||||
|
this.mainCollection = currentCollection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MyList<Student> getCustomDataCollection() {
|
||||||
|
return customDataCollection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCustomDataCollection(MyList<Student> customDataCollection) {
|
||||||
|
|
||||||
|
this.customDataCollection = customDataCollection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCurrentFilePath() {
|
||||||
|
return currentFilePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCurrentFilePath(String currentFilePath) {
|
||||||
|
this.currentFilePath = currentFilePath;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package ru.project.sorting;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
import ru.project.collection.MyList;
|
||||||
|
|
||||||
|
public class BubbleSortStrategy<T> implements SortStrategy<T> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sort(MyList<T> list, Comparator<T> comparator) {
|
||||||
|
if (list == null || list.size() <= 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int n = list.size();
|
||||||
|
for (int i = 0; i < n - 1; i++) {
|
||||||
|
for (int j = 0; j < n - i - 1; j++) {
|
||||||
|
if (comparator.compare(list.get(j), list.get(j + 1)) > 0) {
|
||||||
|
T temp = list.get(j);
|
||||||
|
list.set(j, list.get(j + 1));
|
||||||
|
list.set(j + 1, temp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
package ru.project.sorting;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.ToIntFunction;
|
||||||
|
import ru.project.collection.MyList;
|
||||||
|
|
||||||
|
public class EvenOnlyMergeSortStrategy<T> implements SortStrategy<T> {
|
||||||
|
|
||||||
|
private final ToIntFunction<T> valueExtractor;
|
||||||
|
|
||||||
|
public EvenOnlyMergeSortStrategy(ToIntFunction<T> valueExtractor) {
|
||||||
|
this.valueExtractor = valueExtractor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sort(MyList<T> list, Comparator<T> comparator) {
|
||||||
|
if (list == null || list.size() <= 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Integer> evenIndices = new ArrayList<>();
|
||||||
|
List<T> evenElements = new ArrayList<>();
|
||||||
|
|
||||||
|
for (int i = 0; i < list.size(); i++) {
|
||||||
|
T element = list.get(i);
|
||||||
|
int value = valueExtractor.applyAsInt(element);
|
||||||
|
if (value % 2 == 0) {
|
||||||
|
evenIndices.add(i);
|
||||||
|
evenElements.add(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (evenElements.size() <= 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<T> sortedEven = mergeSort(evenElements, comparator);
|
||||||
|
|
||||||
|
for (int j = 0; j < evenIndices.size(); j++) {
|
||||||
|
list.set(evenIndices.get(j), sortedEven.get(j));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<T> mergeSort(List<T> list, Comparator<T> comparator) {
|
||||||
|
if (list.size() <= 1) {
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mid = list.size() / 2;
|
||||||
|
List<T> left = mergeSort(list.subList(0, mid), comparator);
|
||||||
|
List<T> right = mergeSort(list.subList(mid, list.size()), comparator);
|
||||||
|
|
||||||
|
return merge(left, right, comparator);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<T> merge(List<T> left, List<T> right, Comparator<T> comparator) {
|
||||||
|
List<T> result = new ArrayList<>();
|
||||||
|
int i = 0, j = 0;
|
||||||
|
|
||||||
|
while (i < left.size() && j < right.size()) {
|
||||||
|
if (comparator.compare(left.get(i), right.get(j)) <= 0) {
|
||||||
|
result.add(left.get(i));
|
||||||
|
i++;
|
||||||
|
} else {
|
||||||
|
result.add(right.get(j));
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (i < left.size()) {
|
||||||
|
result.add(left.get(i));
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (j < right.size()) {
|
||||||
|
result.add(right.get(j));
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
package ru.project.sorting;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.function.ToIntFunction;
|
||||||
|
import ru.project.collection.MyLinkedList;
|
||||||
|
import ru.project.collection.MyList;
|
||||||
|
|
||||||
|
public class EvenOnlySortStrategy<T> implements SortStrategy<T> {
|
||||||
|
|
||||||
|
private SortStrategy<T> sortStrategy;
|
||||||
|
private ToIntFunction<T> valueExtractor;
|
||||||
|
|
||||||
|
public EvenOnlySortStrategy() {}
|
||||||
|
|
||||||
|
public EvenOnlySortStrategy(SortStrategy<T> sortStrategy) {
|
||||||
|
setSortStrategy(sortStrategy);
|
||||||
|
}
|
||||||
|
|
||||||
|
public EvenOnlySortStrategy(SortStrategy<T> sortStrategy, ToIntFunction<T> valueExtractor) {
|
||||||
|
setSortStrategy(sortStrategy);
|
||||||
|
setValueExtractor(valueExtractor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSortStrategy(SortStrategy<T> sortStrategy) {
|
||||||
|
if (sortStrategy == null) {
|
||||||
|
throw new IllegalArgumentException("Sort strategy must not be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.sortStrategy = sortStrategy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValueExtractor(ToIntFunction<T> valueExtractor) {
|
||||||
|
if (valueExtractor == null) {
|
||||||
|
throw new IllegalArgumentException("Value extractor must not be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.valueExtractor = valueExtractor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sort(MyList<T> list, Comparator<T> comparator) {
|
||||||
|
if (sortStrategy == null) {
|
||||||
|
throw new IllegalStateException("Sort strategy is not set");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (valueExtractor == null) {
|
||||||
|
throw new IllegalStateException("Value extractor is not set");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (list == null || list.size() <= 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int evenCount = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < list.size(); i++) {
|
||||||
|
T element = list.get(i);
|
||||||
|
|
||||||
|
if (valueExtractor.applyAsInt(element) % 2 == 0) {
|
||||||
|
evenCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (evenCount <= 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MyList<T> evenElements = new MyLinkedList<>();
|
||||||
|
int[] evenIndexes = new int[evenCount];
|
||||||
|
|
||||||
|
int evenIndex = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < list.size(); i++) {
|
||||||
|
T element = list.get(i);
|
||||||
|
|
||||||
|
if (valueExtractor.applyAsInt(element) % 2 == 0) {
|
||||||
|
evenElements.add(element);
|
||||||
|
evenIndexes[evenIndex] = i;
|
||||||
|
evenIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sortStrategy.sort(evenElements, comparator);
|
||||||
|
|
||||||
|
for (int i = 0; i < evenIndexes.length; i++) {
|
||||||
|
list.set(evenIndexes[i], evenElements.get(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
package ru.project.sorting;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
import ru.project.collection.MyList;
|
||||||
|
|
||||||
|
public class MergeSortStrategy<T> implements SortStrategy<T> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sort(MyList<T> list, Comparator<T> comparator) {
|
||||||
|
if (list == null || list.size() <= 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mergeSort(list, 0, list.size() - 1, comparator);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void mergeSort(MyList<T> list, int left, int right, Comparator<T> comparator) {
|
||||||
|
if (left >= right) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int mid = (left + right) / 2;
|
||||||
|
mergeSort(list, left, mid, comparator);
|
||||||
|
mergeSort(list, mid + 1, right, comparator);
|
||||||
|
merge(list, left, mid, right, comparator);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void merge(MyList<T> list, int left, int mid, int right, Comparator<T> comparator) {
|
||||||
|
int leftSize = mid - left + 1;
|
||||||
|
int rightSize = right - mid;
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
T[] leftArray = (T[]) new Object[leftSize];
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
T[] rightArray = (T[]) new Object[rightSize];
|
||||||
|
|
||||||
|
for (int i = 0; i < leftSize; i++) {
|
||||||
|
leftArray[i] = list.get(left + i);
|
||||||
|
}
|
||||||
|
for (int j = 0; j < rightSize; j++) {
|
||||||
|
rightArray[j] = list.get(mid + 1 + j);
|
||||||
|
}
|
||||||
|
|
||||||
|
int i = 0, j = 0, k = left;
|
||||||
|
|
||||||
|
while (i < leftSize && j < rightSize) {
|
||||||
|
if (comparator.compare(leftArray[i], rightArray[j]) <= 0) {
|
||||||
|
list.set(k, leftArray[i]);
|
||||||
|
i++;
|
||||||
|
} else {
|
||||||
|
list.set(k, rightArray[j]);
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
k++;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (i < leftSize) {
|
||||||
|
list.set(k, leftArray[i]);
|
||||||
|
i++;
|
||||||
|
k++;
|
||||||
|
}
|
||||||
|
while (j < rightSize) {
|
||||||
|
list.set(k, rightArray[j]);
|
||||||
|
j++;
|
||||||
|
k++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package ru.project.sorting;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
import ru.project.collection.MyList;
|
||||||
|
|
||||||
|
public interface SortStrategy<T> {
|
||||||
|
void sort(MyList<T> list, Comparator<T> comparator);
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package ru.project.sorting;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
import ru.project.student.Student;
|
||||||
|
|
||||||
|
public class StudentAverageGradeComparator implements Comparator<Student> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compare(Student s1, Student s2) {
|
||||||
|
return Double.compare(s1.getAverageGrade(), s2.getAverageGrade());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package ru.project.sorting;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
import ru.project.student.Student;
|
||||||
|
|
||||||
|
public class StudentGroupComparator implements Comparator<Student> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compare(Student s1, Student s2) {
|
||||||
|
return s1.getGroupNumber().compareTo(s2.getGroupNumber());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package ru.project.sorting;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
import ru.project.student.Student;
|
||||||
|
|
||||||
|
public class StudentRecordBookComparator implements Comparator<Student> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compare(Student s1, Student s2) {
|
||||||
|
return Integer.compare(s1.getRecordBookNumber(), s2.getRecordBookNumber());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
package ru.project.student;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class Student {
|
||||||
|
|
||||||
|
public static final double MIN_AVERAGE_GRADE = 0.0;
|
||||||
|
public static final double MAX_AVERAGE_GRADE = 5.0;
|
||||||
|
public static final int MIN_RECORD_BOOK_NUMBER = 1;
|
||||||
|
public static final String GROUP_NUMBER_PATTERN = "^[A-Z][0-9]{2}$";
|
||||||
|
|
||||||
|
private final String groupNumber;
|
||||||
|
private final double averageGrade;
|
||||||
|
private final int recordBookNumber;
|
||||||
|
|
||||||
|
public Student(String groupNumber, double averageGrade, int recordBookNumber) {
|
||||||
|
if (groupNumber == null || !groupNumber.matches(GROUP_NUMBER_PATTERN)) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Group number must match pattern: " + GROUP_NUMBER_PATTERN);
|
||||||
|
}
|
||||||
|
if (averageGrade < MIN_AVERAGE_GRADE || averageGrade > MAX_AVERAGE_GRADE) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Average grade must be between " + MIN_AVERAGE_GRADE + " and " + MAX_AVERAGE_GRADE);
|
||||||
|
}
|
||||||
|
if (recordBookNumber <= 0) {
|
||||||
|
throw new IllegalArgumentException("Record book number must be positive");
|
||||||
|
}
|
||||||
|
if (recordBookNumber < MIN_RECORD_BOOK_NUMBER) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Record book number must be at least " + MIN_RECORD_BOOK_NUMBER);
|
||||||
|
}
|
||||||
|
this.groupNumber = groupNumber;
|
||||||
|
this.averageGrade = averageGrade;
|
||||||
|
this.recordBookNumber = recordBookNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getGroupNumber() {
|
||||||
|
return groupNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getAverageGrade() {
|
||||||
|
return averageGrade;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRecordBookNumber() {
|
||||||
|
return recordBookNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Student withGroupNumber(String groupNumber) {
|
||||||
|
return new Student(groupNumber, this.averageGrade, this.recordBookNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Student withAverageGrade(double averageGrade) {
|
||||||
|
return new Student(this.groupNumber, averageGrade, this.recordBookNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Student withRecordBookNumber(int recordBookNumber) {
|
||||||
|
return new Student(this.groupNumber, this.averageGrade, recordBookNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double getMinAverageGrade() {
|
||||||
|
return MIN_AVERAGE_GRADE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double getMaxAverageGrade() {
|
||||||
|
return MAX_AVERAGE_GRADE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getMinRecordBookNumber() {
|
||||||
|
return MIN_RECORD_BOOK_NUMBER;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getGroupNumberPattern() {
|
||||||
|
return GROUP_NUMBER_PATTERN;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return "Student{"
|
||||||
|
+ "groupNumber='"
|
||||||
|
+ groupNumber
|
||||||
|
+ '\''
|
||||||
|
+ ", averageGrade="
|
||||||
|
+ averageGrade
|
||||||
|
+ ", recordBookNumber="
|
||||||
|
+ recordBookNumber
|
||||||
|
+ '}';
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(groupNumber, averageGrade, recordBookNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (obj == null || getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.hashCode() != obj.hashCode()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Student student = (Student) obj;
|
||||||
|
return Double.compare(averageGrade, student.averageGrade) == 0
|
||||||
|
&& recordBookNumber == student.recordBookNumber
|
||||||
|
&& Objects.equals(groupNumber, student.groupNumber);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package ru.project.student;
|
||||||
|
|
||||||
|
public class StudentBuilder {
|
||||||
|
private String groupNumber;
|
||||||
|
private double averageGrade;
|
||||||
|
private int recordBookNumber;
|
||||||
|
|
||||||
|
public StudentBuilder setGroupNumber(String groupNumber) {
|
||||||
|
this.groupNumber = groupNumber;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StudentBuilder setAverageGrade(double averageGrade) {
|
||||||
|
this.averageGrade = averageGrade;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StudentBuilder setRecordBookNumber(int recordBookNumber) {
|
||||||
|
this.recordBookNumber = recordBookNumber;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Student build() {
|
||||||
|
return new Student(groupNumber, averageGrade, recordBookNumber);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package ru.project.ui.base;
|
||||||
|
|
||||||
|
import com.googlecode.lanterna.gui2.BasicWindow;
|
||||||
|
import com.googlecode.lanterna.gui2.WindowBasedTextGUI;
|
||||||
|
|
||||||
|
public abstract class BaseModalWindow extends BasicWindow {
|
||||||
|
|
||||||
|
protected final WindowBasedTextGUI gui;
|
||||||
|
|
||||||
|
protected BaseModalWindow(String title, WindowBasedTextGUI gui) {
|
||||||
|
super(title);
|
||||||
|
|
||||||
|
this.gui = gui;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void showModal() {
|
||||||
|
gui.addWindowAndWait(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
package ru.project.ui.common;
|
||||||
|
|
||||||
|
import com.googlecode.lanterna.TerminalSize;
|
||||||
|
import com.googlecode.lanterna.gui2.Button;
|
||||||
|
import com.googlecode.lanterna.gui2.Direction;
|
||||||
|
import com.googlecode.lanterna.gui2.EmptySpace;
|
||||||
|
import com.googlecode.lanterna.gui2.LinearLayout;
|
||||||
|
import com.googlecode.lanterna.gui2.Panel;
|
||||||
|
import com.googlecode.lanterna.gui2.TextBox;
|
||||||
|
import com.googlecode.lanterna.gui2.WindowBasedTextGUI;
|
||||||
|
import com.googlecode.lanterna.input.KeyStroke;
|
||||||
|
import com.googlecode.lanterna.input.KeyType;
|
||||||
|
import ru.project.collection.MyList;
|
||||||
|
import ru.project.student.Student;
|
||||||
|
import ru.project.ui.base.BaseModalWindow;
|
||||||
|
|
||||||
|
public class CollectionDisplayWindow extends BaseModalWindow {
|
||||||
|
|
||||||
|
private final MyList<Student> collection;
|
||||||
|
|
||||||
|
private TextBox collectionTextBox;
|
||||||
|
private Button exitButton;
|
||||||
|
|
||||||
|
public CollectionDisplayWindow(WindowBasedTextGUI gui, MyList<Student> collection) {
|
||||||
|
|
||||||
|
super("Просмотр коллекции", gui);
|
||||||
|
|
||||||
|
this.collection = collection;
|
||||||
|
|
||||||
|
Panel panel = createPanel();
|
||||||
|
|
||||||
|
setComponent(panel);
|
||||||
|
|
||||||
|
exitButton.takeFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handleInput(KeyStroke key) {
|
||||||
|
if (key.getKeyType() == KeyType.Escape && collectionTextBox.isFocused()) {
|
||||||
|
|
||||||
|
exitButton.takeFocus();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.handleInput(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Panel createPanel() {
|
||||||
|
Panel panel = new Panel();
|
||||||
|
|
||||||
|
panel.setLayoutManager(new LinearLayout(Direction.VERTICAL));
|
||||||
|
|
||||||
|
addCollectionDisplay(panel);
|
||||||
|
addExitButton(panel);
|
||||||
|
|
||||||
|
return panel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addCollectionDisplay(Panel panel) {
|
||||||
|
collectionTextBox = createCollectionScrollBox();
|
||||||
|
|
||||||
|
panel.addComponent(collectionTextBox);
|
||||||
|
}
|
||||||
|
|
||||||
|
private TextBox createCollectionScrollBox() {
|
||||||
|
TextBox textBox = new TextBox(new TerminalSize(80, 20), TextBox.Style.MULTI_LINE);
|
||||||
|
|
||||||
|
textBox.setReadOnly(true);
|
||||||
|
|
||||||
|
if (collection == null || collection.isEmpty()) {
|
||||||
|
textBox.setText("Коллекция пуста.");
|
||||||
|
} else {
|
||||||
|
textBox.setText(buildCollectionText());
|
||||||
|
}
|
||||||
|
|
||||||
|
return textBox;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addExitButton(Panel panel) {
|
||||||
|
panel.addComponent(new EmptySpace(new TerminalSize(0, 1)));
|
||||||
|
|
||||||
|
exitButton = new Button("Выйти", this::close);
|
||||||
|
|
||||||
|
panel.addComponent(exitButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String buildCollectionText() {
|
||||||
|
StringBuilder text = new StringBuilder();
|
||||||
|
|
||||||
|
for (int i = 0; i < collection.size(); i++) {
|
||||||
|
Student student = collection.get(i);
|
||||||
|
|
||||||
|
text.append("[")
|
||||||
|
.append(i)
|
||||||
|
.append("] ")
|
||||||
|
.append(student == null ? "null" : student)
|
||||||
|
.append("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return text.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package ru.project.ui.common;
|
||||||
|
|
||||||
|
import com.googlecode.lanterna.gui2.Button;
|
||||||
|
import com.googlecode.lanterna.gui2.Label;
|
||||||
|
import com.googlecode.lanterna.gui2.LinearLayout;
|
||||||
|
import com.googlecode.lanterna.gui2.Panel;
|
||||||
|
import com.googlecode.lanterna.gui2.TextBox;
|
||||||
|
import com.googlecode.lanterna.gui2.WindowBasedTextGUI;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
import ru.project.ui.base.BaseModalWindow;
|
||||||
|
|
||||||
|
public class InputValueWindow extends BaseModalWindow {
|
||||||
|
|
||||||
|
private final TextBox textBox;
|
||||||
|
private final Predicate<String> onSave;
|
||||||
|
|
||||||
|
public InputValueWindow(
|
||||||
|
WindowBasedTextGUI gui,
|
||||||
|
String title,
|
||||||
|
String prompt,
|
||||||
|
String initialValue,
|
||||||
|
Predicate<String> onSave) {
|
||||||
|
|
||||||
|
super(title, gui);
|
||||||
|
|
||||||
|
this.onSave = onSave;
|
||||||
|
|
||||||
|
Panel panel = new Panel();
|
||||||
|
panel.setLayoutManager(new LinearLayout());
|
||||||
|
|
||||||
|
panel.addComponent(new Label(prompt));
|
||||||
|
|
||||||
|
textBox = new TextBox(initialValue == null ? "" : initialValue);
|
||||||
|
|
||||||
|
panel.addComponent(textBox);
|
||||||
|
|
||||||
|
panel.addComponent(new Button("Сохранить", this::save));
|
||||||
|
|
||||||
|
panel.addComponent(new Button("Отмена", this::close));
|
||||||
|
|
||||||
|
setComponent(panel);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void save() {
|
||||||
|
String value = textBox.getText().trim();
|
||||||
|
|
||||||
|
if (value.isEmpty()) {
|
||||||
|
MessageWindow.showModal(gui, "Значение не может быть пустым.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (onSave.test(value)) {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package ru.project.ui.common;
|
||||||
|
|
||||||
|
import com.googlecode.lanterna.gui2.Button;
|
||||||
|
import com.googlecode.lanterna.gui2.Label;
|
||||||
|
import com.googlecode.lanterna.gui2.LinearLayout;
|
||||||
|
import com.googlecode.lanterna.gui2.Panel;
|
||||||
|
import com.googlecode.lanterna.gui2.WindowBasedTextGUI;
|
||||||
|
import ru.project.ui.base.BaseModalWindow;
|
||||||
|
|
||||||
|
public class MessageWindow extends BaseModalWindow {
|
||||||
|
|
||||||
|
public MessageWindow(WindowBasedTextGUI gui, String message) {
|
||||||
|
super("Информация", gui);
|
||||||
|
|
||||||
|
Panel panel = new Panel();
|
||||||
|
panel.setLayoutManager(new LinearLayout());
|
||||||
|
|
||||||
|
panel.addComponent(new Label(message));
|
||||||
|
|
||||||
|
panel.addComponent(new Button("OK", this::close));
|
||||||
|
|
||||||
|
setComponent(panel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void showModal(WindowBasedTextGUI gui, String message) {
|
||||||
|
new MessageWindow(gui, message).showModal();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,169 @@
|
|||||||
|
package ru.project.ui.creation;
|
||||||
|
|
||||||
|
import com.googlecode.lanterna.gui2.Button;
|
||||||
|
import com.googlecode.lanterna.gui2.Label;
|
||||||
|
import com.googlecode.lanterna.gui2.LinearLayout;
|
||||||
|
import com.googlecode.lanterna.gui2.Panel;
|
||||||
|
import com.googlecode.lanterna.gui2.WindowBasedTextGUI;
|
||||||
|
import ru.project.collection.MyLinkedList;
|
||||||
|
import ru.project.collection.MyList;
|
||||||
|
import ru.project.model.AppState;
|
||||||
|
import ru.project.student.Student;
|
||||||
|
import ru.project.ui.base.BaseModalWindow;
|
||||||
|
import ru.project.ui.common.InputValueWindow;
|
||||||
|
import ru.project.ui.common.MessageWindow;
|
||||||
|
|
||||||
|
public class CreateCollectionMenu extends BaseModalWindow {
|
||||||
|
|
||||||
|
private int collectionSize;
|
||||||
|
private FillMethod selectedFillMethod;
|
||||||
|
|
||||||
|
private final Label sizeLabel;
|
||||||
|
private final Label fillMethodLabel;
|
||||||
|
|
||||||
|
private final CustomDataSettingsWindow customDataSettingsWindow;
|
||||||
|
|
||||||
|
public CreateCollectionMenu(WindowBasedTextGUI gui, AppState state) {
|
||||||
|
super("Создание новой коллекции", gui);
|
||||||
|
|
||||||
|
collectionSize = 0;
|
||||||
|
selectedFillMethod = FillMethod.CUSTOM;
|
||||||
|
|
||||||
|
customDataSettingsWindow = new CustomDataSettingsWindow(gui, state, () -> collectionSize);
|
||||||
|
|
||||||
|
Panel panel = new Panel();
|
||||||
|
panel.setLayoutManager(new LinearLayout());
|
||||||
|
|
||||||
|
sizeLabel = new Label("Размер: не задан");
|
||||||
|
|
||||||
|
fillMethodLabel = new Label("Способ заполнения: " + getFillMethodName(selectedFillMethod));
|
||||||
|
|
||||||
|
panel.addComponent(sizeLabel);
|
||||||
|
panel.addComponent(fillMethodLabel);
|
||||||
|
|
||||||
|
panel.addComponent(new Button("Задать размер", this::showCollectionSizeInputValueWindow));
|
||||||
|
|
||||||
|
panel.addComponent(new Button("Выбрать способ заполнения", this::selectFillMethod));
|
||||||
|
|
||||||
|
panel.addComponent(
|
||||||
|
new Button("Настроить текущий способ заполнения", this::setupCurrentFillMethod));
|
||||||
|
|
||||||
|
panel.addComponent(new Button("Создать новую коллекцию", () -> updateMainCollection(state)));
|
||||||
|
|
||||||
|
panel.addComponent(new Button("Выйти", this::close));
|
||||||
|
|
||||||
|
setComponent(panel);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showCollectionSizeInputValueWindow() {
|
||||||
|
InputValueWindow window =
|
||||||
|
new InputValueWindow(
|
||||||
|
gui,
|
||||||
|
"Размер коллекции",
|
||||||
|
"Введите размер коллекции:",
|
||||||
|
collectionSize > 0 ? String.valueOf(collectionSize) : null,
|
||||||
|
this::handleSizeEntered);
|
||||||
|
|
||||||
|
window.showModal();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean handleSizeEntered(String value) {
|
||||||
|
try {
|
||||||
|
int enteredSize = Integer.parseInt(value);
|
||||||
|
if (enteredSize <= 0) {
|
||||||
|
MessageWindow.showModal(gui, "Размер должен быть больше 0.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
collectionSize = enteredSize;
|
||||||
|
sizeLabel.setText("Размер: " + collectionSize);
|
||||||
|
return true;
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
MessageWindow.showModal(gui, "Введите целое число.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupCurrentFillMethod() {
|
||||||
|
switch (selectedFillMethod) {
|
||||||
|
case CUSTOM -> {
|
||||||
|
customDataSettingsWindow.showModal();
|
||||||
|
}
|
||||||
|
|
||||||
|
case FILE ->
|
||||||
|
// TODO
|
||||||
|
MessageWindow.showModal(gui, "Не реализовано.");
|
||||||
|
|
||||||
|
case RANDOM ->
|
||||||
|
MessageWindow.showModal(
|
||||||
|
gui, "Для случайных данных дополнительные настройки не требуются.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void selectFillMethod() {
|
||||||
|
BaseModalWindow menu =
|
||||||
|
new FillMethodSelectionWindow(
|
||||||
|
gui,
|
||||||
|
fillMethod -> {
|
||||||
|
selectedFillMethod = fillMethod;
|
||||||
|
fillMethodLabel.setText(
|
||||||
|
"Способ заполнения: " + getFillMethodName(selectedFillMethod));
|
||||||
|
});
|
||||||
|
|
||||||
|
menu.showModal();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateMainCollection(AppState state) {
|
||||||
|
if (collectionSize <= 0) {
|
||||||
|
MessageWindow.showModal(gui, "Сначала задайте размер коллекции.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (selectedFillMethod) {
|
||||||
|
case CUSTOM:
|
||||||
|
createCollectionFromCustomData(state);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RANDOM:
|
||||||
|
createCollectionFromRandomData(state);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FILE:
|
||||||
|
createCollectionFromFileData(state);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createCollectionFromCustomData(AppState state) {
|
||||||
|
MyList<Student> customDataCollection = state.getCustomDataCollection();
|
||||||
|
|
||||||
|
MyList<Student> mainCollection = new MyLinkedList<>();
|
||||||
|
|
||||||
|
for (int i = 0; i < customDataCollection.size(); i++) {
|
||||||
|
mainCollection.add(customDataCollection.get(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
state.setMainCollection(mainCollection);
|
||||||
|
|
||||||
|
MessageWindow.showModal(gui, "Коллекция успешно создана.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createCollectionFromRandomData(AppState state) {
|
||||||
|
// TODO
|
||||||
|
MessageWindow.showModal(gui, "Не реализовано.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createCollectionFromFileData(AppState state) {
|
||||||
|
// TODO
|
||||||
|
MessageWindow.showModal(gui, "Не реализовано.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getFillMethodName(FillMethod fillMethod) {
|
||||||
|
return switch (fillMethod) {
|
||||||
|
case CUSTOM -> "Пользовательские данные";
|
||||||
|
|
||||||
|
case RANDOM -> "Случайные данные";
|
||||||
|
|
||||||
|
case FILE -> "Данные из файла";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,289 @@
|
|||||||
|
package ru.project.ui.creation;
|
||||||
|
|
||||||
|
import com.googlecode.lanterna.gui2.Button;
|
||||||
|
import com.googlecode.lanterna.gui2.Label;
|
||||||
|
import com.googlecode.lanterna.gui2.LinearLayout;
|
||||||
|
import com.googlecode.lanterna.gui2.Panel;
|
||||||
|
import com.googlecode.lanterna.gui2.WindowBasedTextGUI;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
import ru.project.collection.MyLinkedList;
|
||||||
|
import ru.project.collection.MyList;
|
||||||
|
import ru.project.model.AppState;
|
||||||
|
import ru.project.student.Student;
|
||||||
|
import ru.project.student.StudentBuilder;
|
||||||
|
import ru.project.ui.base.BaseModalWindow;
|
||||||
|
import ru.project.ui.common.CollectionDisplayWindow;
|
||||||
|
import ru.project.ui.common.InputValueWindow;
|
||||||
|
import ru.project.ui.common.MessageWindow;
|
||||||
|
|
||||||
|
public class CustomDataSettingsWindow extends BaseModalWindow {
|
||||||
|
|
||||||
|
private final AppState state;
|
||||||
|
private final Supplier<Integer> requestedCollectionSize;
|
||||||
|
private final StudentBuilder studentBuilder;
|
||||||
|
|
||||||
|
private String groupNumber;
|
||||||
|
private Double averageGrade;
|
||||||
|
private Integer recordBookNumber;
|
||||||
|
private Integer selectedObjectIndex;
|
||||||
|
|
||||||
|
private final Label groupNumberLabel;
|
||||||
|
private final Label averageGradeLabel;
|
||||||
|
private final Label recordBookNumberLabel;
|
||||||
|
private final Label indexLabel;
|
||||||
|
|
||||||
|
private MyList<Student> preparedCustomDataCollection;
|
||||||
|
|
||||||
|
public CustomDataSettingsWindow(
|
||||||
|
WindowBasedTextGUI gui, AppState state, Supplier<Integer> collectionSize) {
|
||||||
|
|
||||||
|
super("Настройка пользовательских данных", gui);
|
||||||
|
|
||||||
|
this.state = state;
|
||||||
|
this.requestedCollectionSize = collectionSize;
|
||||||
|
|
||||||
|
this.studentBuilder = new StudentBuilder();
|
||||||
|
|
||||||
|
Panel panel = new Panel();
|
||||||
|
panel.setLayoutManager(new LinearLayout());
|
||||||
|
|
||||||
|
groupNumberLabel = new Label("Номер группы: не задан");
|
||||||
|
|
||||||
|
averageGradeLabel = new Label("Средний балл: не задан");
|
||||||
|
|
||||||
|
recordBookNumberLabel = new Label("Номер зачётной книжки: не задан");
|
||||||
|
|
||||||
|
indexLabel = new Label("Индекс объекта: не задан");
|
||||||
|
|
||||||
|
panel.addComponent(groupNumberLabel);
|
||||||
|
panel.addComponent(averageGradeLabel);
|
||||||
|
panel.addComponent(recordBookNumberLabel);
|
||||||
|
panel.addComponent(indexLabel);
|
||||||
|
|
||||||
|
panel.addComponent(new Button("Задать номер группы", this::setGroupNumber));
|
||||||
|
|
||||||
|
panel.addComponent(new Button("Задать средний балл", this::setAverageGrade));
|
||||||
|
|
||||||
|
panel.addComponent(new Button("Задать номер зачётной книжки", this::setRecordBookNumber));
|
||||||
|
|
||||||
|
panel.addComponent(new Button("Задать индекс объекта", this::setObjectIndex));
|
||||||
|
|
||||||
|
panel.addComponent(new Button("Задать данные объекта", this::editObject));
|
||||||
|
|
||||||
|
panel.addComponent(new Button("Предпросмотр", this::preview));
|
||||||
|
|
||||||
|
panel.addComponent(new Button("Применить", this::apply));
|
||||||
|
|
||||||
|
panel.addComponent(new Button("Назад", this::close));
|
||||||
|
|
||||||
|
setComponent(panel);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void showModal() {
|
||||||
|
prepareCustomDataCollection();
|
||||||
|
super.showModal();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void prepareCustomDataCollection() {
|
||||||
|
preparedCustomDataCollection = new MyLinkedList<>();
|
||||||
|
|
||||||
|
int targetCollectionSize = requestedCollectionSize.get();
|
||||||
|
int currentCustomDataCollectionSize = state.getCustomDataCollection().size();
|
||||||
|
|
||||||
|
int elementsToCopy = Math.min(currentCustomDataCollectionSize, targetCollectionSize);
|
||||||
|
|
||||||
|
for (int i = 0; i < elementsToCopy; i++) {
|
||||||
|
preparedCustomDataCollection.add(state.getCustomDataCollection().get(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = elementsToCopy; i < targetCollectionSize; i++) {
|
||||||
|
preparedCustomDataCollection.add(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setGroupNumber() {
|
||||||
|
InputValueWindow window =
|
||||||
|
new InputValueWindow(
|
||||||
|
gui,
|
||||||
|
"Номер группы",
|
||||||
|
"Введите номер группы (например, A12):",
|
||||||
|
groupNumber,
|
||||||
|
value -> {
|
||||||
|
if (!value.matches(Student.getGroupNumberPattern())) {
|
||||||
|
MessageWindow.showModal(gui, "Номер группы должен соответствовать формату A12.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
groupNumber = value;
|
||||||
|
studentBuilder.setGroupNumber(value);
|
||||||
|
|
||||||
|
groupNumberLabel.setText("Номер группы: " + groupNumber);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
window.showModal();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setAverageGrade() {
|
||||||
|
InputValueWindow window =
|
||||||
|
new InputValueWindow(
|
||||||
|
gui,
|
||||||
|
"Средний балл",
|
||||||
|
"Введите средний балл от 0.0 до 5.0:",
|
||||||
|
averageGrade == null ? null : String.valueOf(averageGrade),
|
||||||
|
value -> {
|
||||||
|
try {
|
||||||
|
double parsedValue = Double.parseDouble(value);
|
||||||
|
|
||||||
|
if (parsedValue < Student.getMinAverageGrade()
|
||||||
|
|| parsedValue > Student.getMaxAverageGrade()) {
|
||||||
|
|
||||||
|
MessageWindow.showModal(gui, "Средний балл должен быть от 0.0 до 5.0.");
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
averageGrade = parsedValue;
|
||||||
|
|
||||||
|
studentBuilder.setAverageGrade(parsedValue);
|
||||||
|
|
||||||
|
averageGradeLabel.setText("Средний балл: " + averageGrade);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
MessageWindow.showModal(gui, "Введите корректное число.");
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
window.showModal();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setRecordBookNumber() {
|
||||||
|
InputValueWindow window =
|
||||||
|
new InputValueWindow(
|
||||||
|
gui,
|
||||||
|
"Номер зачётной книжки",
|
||||||
|
"Введите номер зачётной книжки:",
|
||||||
|
recordBookNumber == null ? null : String.valueOf(recordBookNumber),
|
||||||
|
value -> {
|
||||||
|
try {
|
||||||
|
int parsedValue = Integer.parseInt(value);
|
||||||
|
|
||||||
|
if (parsedValue < Student.getMinRecordBookNumber()) {
|
||||||
|
|
||||||
|
MessageWindow.showModal(gui, "Номер зачётной книжки должен быть положительным.");
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
recordBookNumber = parsedValue;
|
||||||
|
|
||||||
|
studentBuilder.setRecordBookNumber(parsedValue);
|
||||||
|
|
||||||
|
recordBookNumberLabel.setText("Номер зачётной книжки: " + recordBookNumber);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
MessageWindow.showModal(gui, "Введите целое число.");
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
window.showModal();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setObjectIndex() {
|
||||||
|
InputValueWindow window =
|
||||||
|
new InputValueWindow(
|
||||||
|
gui,
|
||||||
|
"Индекс объекта",
|
||||||
|
"Введите индекс объекта:",
|
||||||
|
selectedObjectIndex == null ? null : String.valueOf(selectedObjectIndex),
|
||||||
|
value -> {
|
||||||
|
try {
|
||||||
|
int index = Integer.parseInt(value);
|
||||||
|
|
||||||
|
if (index < 0) {
|
||||||
|
MessageWindow.showModal(gui, "Индекс объекта не может быть отрицательным.");
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int size = requestedCollectionSize.get();
|
||||||
|
|
||||||
|
if (index >= size) {
|
||||||
|
MessageWindow.showModal(gui, "Индекс должен быть меньше размера коллекции.");
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedObjectIndex = index;
|
||||||
|
|
||||||
|
indexLabel.setText("Индекс объекта: " + selectedObjectIndex);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
MessageWindow.showModal(gui, "Введите целое число.");
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
window.showModal();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void editObject() {
|
||||||
|
if (!hasStudentData()) {
|
||||||
|
MessageWindow.showModal(gui, "Сначала задайте все поля студента.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedObjectIndex == null) {
|
||||||
|
MessageWindow.showModal(gui, "Сначала задайте индекс объекта.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedObjectIndex >= preparedCustomDataCollection.size()) {
|
||||||
|
MessageWindow.showModal(gui, "Индекс объекта выходит за границы подготовленной коллекции.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Student student = studentBuilder.build();
|
||||||
|
|
||||||
|
preparedCustomDataCollection.set(selectedObjectIndex, student);
|
||||||
|
|
||||||
|
MessageWindow.showModal(gui, "Данные объекта успешно заданы.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void apply() {
|
||||||
|
state.setCustomDataCollection(preparedCustomDataCollection);
|
||||||
|
prepareCustomDataCollection();
|
||||||
|
|
||||||
|
MessageWindow.showModal(gui, "Пользовательские данные успешно применены.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void preview() {
|
||||||
|
if (preparedCustomDataCollection == null || preparedCustomDataCollection.isEmpty()) {
|
||||||
|
|
||||||
|
MessageWindow.showModal(gui, "Подготовленная коллекция пуста.");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CollectionDisplayWindow window = new CollectionDisplayWindow(gui, preparedCustomDataCollection);
|
||||||
|
|
||||||
|
window.showModal();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasStudentData() {
|
||||||
|
return groupNumber != null && averageGrade != null && recordBookNumber != null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package ru.project.ui.creation;
|
||||||
|
|
||||||
|
public enum FillMethod {
|
||||||
|
CUSTOM,
|
||||||
|
RANDOM,
|
||||||
|
FILE
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package ru.project.ui.creation;
|
||||||
|
|
||||||
|
import com.googlecode.lanterna.gui2.ActionListBox;
|
||||||
|
import com.googlecode.lanterna.gui2.WindowBasedTextGUI;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import ru.project.ui.base.BaseModalWindow;
|
||||||
|
|
||||||
|
public class FillMethodSelectionWindow extends BaseModalWindow {
|
||||||
|
|
||||||
|
private final Consumer<FillMethod> onFillMethodSelected;
|
||||||
|
|
||||||
|
public FillMethodSelectionWindow(
|
||||||
|
WindowBasedTextGUI gui, Consumer<FillMethod> onFillMethodSelected) {
|
||||||
|
|
||||||
|
super("Выбор способа заполнения", gui);
|
||||||
|
|
||||||
|
this.onFillMethodSelected = onFillMethodSelected;
|
||||||
|
|
||||||
|
ActionListBox menu = new ActionListBox();
|
||||||
|
|
||||||
|
menu.addItem("Пользовательские данные", () -> selectFillMethod(FillMethod.CUSTOM));
|
||||||
|
|
||||||
|
menu.addItem("Случайные данные", () -> selectFillMethod(FillMethod.RANDOM));
|
||||||
|
|
||||||
|
menu.addItem("Данные из файла", () -> selectFillMethod(FillMethod.FILE));
|
||||||
|
|
||||||
|
menu.addItem("Выйти", this::close);
|
||||||
|
|
||||||
|
setComponent(menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void selectFillMethod(FillMethod fillMethod) {
|
||||||
|
onFillMethodSelected.accept(fillMethod);
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
package ru.project.ui.main;
|
||||||
|
|
||||||
|
import com.googlecode.lanterna.gui2.ActionListBox;
|
||||||
|
import com.googlecode.lanterna.gui2.WindowBasedTextGUI;
|
||||||
|
import ru.project.collection.MyList;
|
||||||
|
import ru.project.model.AppState;
|
||||||
|
import ru.project.student.Student;
|
||||||
|
import ru.project.ui.base.BaseModalWindow;
|
||||||
|
import ru.project.ui.common.CollectionDisplayWindow;
|
||||||
|
import ru.project.ui.common.MessageWindow;
|
||||||
|
import ru.project.ui.creation.CreateCollectionMenu;
|
||||||
|
import ru.project.ui.sorting.SortCollectionMenu;
|
||||||
|
|
||||||
|
public class MainMenu extends BaseModalWindow {
|
||||||
|
|
||||||
|
private final ActionListBox menu;
|
||||||
|
|
||||||
|
private final BaseModalWindow createCollectionMenu;
|
||||||
|
private final BaseModalWindow sortCollectionMenu;
|
||||||
|
|
||||||
|
public MainMenu(WindowBasedTextGUI gui, AppState state) {
|
||||||
|
super("Главное меню", gui);
|
||||||
|
|
||||||
|
this.createCollectionMenu = new CreateCollectionMenu(gui, state);
|
||||||
|
this.sortCollectionMenu = new SortCollectionMenu(gui, state);
|
||||||
|
|
||||||
|
menu = new ActionListBox();
|
||||||
|
|
||||||
|
menu.addItem("Показать текущую коллекцию", () -> showMainCollection(state));
|
||||||
|
|
||||||
|
menu.addItem("Меню создания новой коллекции", this::showCreateCollectionMenu);
|
||||||
|
|
||||||
|
menu.addItem("Меню сохранения текущей коллекции в файл", this::saveCollection);
|
||||||
|
|
||||||
|
menu.addItem("Меню сортировки текущей коллекции", this::sortCollection);
|
||||||
|
|
||||||
|
menu.addItem("Меню поиска элемента в текущей коллекции", this::searchCollection);
|
||||||
|
|
||||||
|
menu.addItem("Меню подсчёта количества вхождений элемента", this::countOccurrences);
|
||||||
|
|
||||||
|
menu.addItem("Завершить выполнение программы", this::exit);
|
||||||
|
|
||||||
|
setComponent(menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showMainCollection(AppState state) {
|
||||||
|
MyList<Student> mainCollection = state.getMainCollection();
|
||||||
|
|
||||||
|
BaseModalWindow window = new CollectionDisplayWindow(gui, mainCollection);
|
||||||
|
|
||||||
|
window.showModal();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showCreateCollectionMenu() {
|
||||||
|
createCollectionMenu.showModal();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveCollection() {
|
||||||
|
// TODO
|
||||||
|
MessageWindow.showModal(gui, "Не реализовано.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sortCollection() {
|
||||||
|
sortCollectionMenu.showModal();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void searchCollection() {
|
||||||
|
// TODO
|
||||||
|
MessageWindow.showModal(gui, "Не реализовано.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void countOccurrences() {
|
||||||
|
// TODO
|
||||||
|
MessageWindow.showModal(gui, "Не реализовано.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void exit() {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package ru.project.ui.sorting;
|
||||||
|
|
||||||
|
import com.googlecode.lanterna.gui2.ActionListBox;
|
||||||
|
import com.googlecode.lanterna.gui2.Button;
|
||||||
|
import com.googlecode.lanterna.gui2.LinearLayout;
|
||||||
|
import com.googlecode.lanterna.gui2.Panel;
|
||||||
|
import com.googlecode.lanterna.gui2.WindowBasedTextGUI;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import ru.project.ui.base.BaseModalWindow;
|
||||||
|
|
||||||
|
public class NormalSortSettingsWindow extends BaseModalWindow {
|
||||||
|
|
||||||
|
private final Consumer<SortField> onSortFieldSelected;
|
||||||
|
|
||||||
|
public NormalSortSettingsWindow(WindowBasedTextGUI gui, Consumer<SortField> onSortFieldSelected) {
|
||||||
|
|
||||||
|
super("Обычная сортировка", gui);
|
||||||
|
|
||||||
|
this.onSortFieldSelected = onSortFieldSelected;
|
||||||
|
|
||||||
|
Panel panel = new Panel();
|
||||||
|
panel.setLayoutManager(new LinearLayout());
|
||||||
|
|
||||||
|
ActionListBox menu = new ActionListBox();
|
||||||
|
|
||||||
|
menu.addItem("Сортировать по номеру группы", () -> selectSortField(SortField.GROUP_NUMBER));
|
||||||
|
|
||||||
|
menu.addItem("Сортировать по среднему баллу", () -> selectSortField(SortField.AVERAGE_GRADE));
|
||||||
|
|
||||||
|
menu.addItem(
|
||||||
|
"Сортировать по номеру зачётной книжки",
|
||||||
|
() -> selectSortField(SortField.RECORD_BOOK_NUMBER));
|
||||||
|
|
||||||
|
panel.addComponent(menu);
|
||||||
|
|
||||||
|
panel.addComponent(new Button("Выйти", this::close));
|
||||||
|
|
||||||
|
setComponent(panel);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void selectSortField(SortField sortField) {
|
||||||
|
onSortFieldSelected.accept(sortField);
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package ru.project.ui.sorting;
|
||||||
|
|
||||||
|
import com.googlecode.lanterna.gui2.Button;
|
||||||
|
import com.googlecode.lanterna.gui2.Label;
|
||||||
|
import com.googlecode.lanterna.gui2.LinearLayout;
|
||||||
|
import com.googlecode.lanterna.gui2.Panel;
|
||||||
|
import com.googlecode.lanterna.gui2.WindowBasedTextGUI;
|
||||||
|
import ru.project.ui.base.BaseModalWindow;
|
||||||
|
|
||||||
|
public class ParitySortSettingsWindow extends BaseModalWindow {
|
||||||
|
|
||||||
|
public ParitySortSettingsWindow(WindowBasedTextGUI gui) {
|
||||||
|
super("Настройка сортировки по чётности", gui);
|
||||||
|
|
||||||
|
Panel panel = new Panel();
|
||||||
|
panel.setLayoutManager(new LinearLayout());
|
||||||
|
|
||||||
|
panel.addComponent(new Label("Сортировка выполняется по номеру зачётной книжки."));
|
||||||
|
|
||||||
|
panel.addComponent(new Button("Назад", this::close));
|
||||||
|
|
||||||
|
setComponent(panel);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
package ru.project.ui.sorting;
|
||||||
|
|
||||||
|
import com.googlecode.lanterna.gui2.Button;
|
||||||
|
import com.googlecode.lanterna.gui2.Label;
|
||||||
|
import com.googlecode.lanterna.gui2.LinearLayout;
|
||||||
|
import com.googlecode.lanterna.gui2.Panel;
|
||||||
|
import com.googlecode.lanterna.gui2.WindowBasedTextGUI;
|
||||||
|
import ru.project.model.AppState;
|
||||||
|
import ru.project.ui.base.BaseModalWindow;
|
||||||
|
import ru.project.ui.common.MessageWindow;
|
||||||
|
|
||||||
|
public class SortCollectionMenu extends BaseModalWindow {
|
||||||
|
|
||||||
|
private final AppState state;
|
||||||
|
|
||||||
|
private final Label sortMethodLabel;
|
||||||
|
private final Label sortFieldLabel;
|
||||||
|
|
||||||
|
private final SortMethodSelectionWindow sortMethodSelectionWindow;
|
||||||
|
private final NormalSortSettingsWindow normalSortSettingsWindow;
|
||||||
|
private final ParitySortSettingsWindow paritySortSettingsWindow;
|
||||||
|
|
||||||
|
private SortMethod selectedSortMethod;
|
||||||
|
private SortField selectedSortField;
|
||||||
|
|
||||||
|
public SortCollectionMenu(WindowBasedTextGUI gui, AppState state) {
|
||||||
|
|
||||||
|
super("Меню сортировки текущей коллекции", gui);
|
||||||
|
|
||||||
|
this.state = state;
|
||||||
|
this.selectedSortMethod = SortMethod.NORMAL;
|
||||||
|
this.selectedSortField = SortField.GROUP_NUMBER;
|
||||||
|
|
||||||
|
Panel panel = new Panel();
|
||||||
|
panel.setLayoutManager(new LinearLayout());
|
||||||
|
|
||||||
|
this.sortMethodLabel = new Label("Способ сортировки: " + getSortMethodName(selectedSortMethod));
|
||||||
|
|
||||||
|
this.sortFieldLabel = new Label("Сортировать по: " + getSortFieldName(selectedSortField));
|
||||||
|
|
||||||
|
this.sortMethodSelectionWindow =
|
||||||
|
new SortMethodSelectionWindow(
|
||||||
|
gui,
|
||||||
|
sortMethod -> {
|
||||||
|
selectedSortMethod = sortMethod;
|
||||||
|
|
||||||
|
sortMethodLabel.setText(
|
||||||
|
"Способ сортировки: " + getSortMethodName(selectedSortMethod));
|
||||||
|
});
|
||||||
|
|
||||||
|
this.normalSortSettingsWindow =
|
||||||
|
new NormalSortSettingsWindow(
|
||||||
|
gui,
|
||||||
|
sortField -> {
|
||||||
|
selectedSortField = sortField;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.paritySortSettingsWindow = new ParitySortSettingsWindow(gui);
|
||||||
|
|
||||||
|
panel.addComponent(sortMethodLabel);
|
||||||
|
panel.addComponent(sortFieldLabel);
|
||||||
|
|
||||||
|
panel.addComponent(new Button("Выбрать способ сортировки", this::selectSortMethod));
|
||||||
|
|
||||||
|
panel.addComponent(
|
||||||
|
new Button("Настроить текущий способ сортировки", this::setupCurrentSortMethod));
|
||||||
|
|
||||||
|
panel.addComponent(new Button("Сортировать текущую коллекцию", this::sortCurrentCollection));
|
||||||
|
|
||||||
|
panel.addComponent(new Button("Выйти", this::close));
|
||||||
|
|
||||||
|
setComponent(panel);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupCurrentSortMethod() {
|
||||||
|
switch (selectedSortMethod) {
|
||||||
|
case NORMAL -> normalSortSettingsWindow.showModal();
|
||||||
|
|
||||||
|
case PARITY -> paritySortSettingsWindow.showModal();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void selectSortMethod() {
|
||||||
|
sortMethodSelectionWindow.showModal();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sortCurrentCollection() {
|
||||||
|
if (state.getMainCollection() == null || state.getMainCollection().isEmpty()) {
|
||||||
|
|
||||||
|
MessageWindow.showModal(gui, "Текущая коллекция пуста.");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (selectedSortMethod) {
|
||||||
|
case NORMAL -> sortNormally();
|
||||||
|
|
||||||
|
case PARITY -> sortByParity();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sortNormally() {
|
||||||
|
// TODO
|
||||||
|
MessageWindow.showModal(gui, "Обычная сортировка не реализована.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sortByParity() {
|
||||||
|
// TODO
|
||||||
|
MessageWindow.showModal(gui, "Сортировка по чётности не реализована.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getSortMethodName(SortMethod sortMethod) {
|
||||||
|
return switch (sortMethod) {
|
||||||
|
case NORMAL -> "Обычная сортировка";
|
||||||
|
case PARITY -> "Сортировка по чётности";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getSortFieldName(SortField sortField) {
|
||||||
|
return switch (sortField) {
|
||||||
|
case GROUP_NUMBER -> "номеру группы";
|
||||||
|
case AVERAGE_GRADE -> "среднему баллу";
|
||||||
|
case RECORD_BOOK_NUMBER -> "номеру зачётной книжки";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package ru.project.ui.sorting;
|
||||||
|
|
||||||
|
public enum SortField {
|
||||||
|
GROUP_NUMBER,
|
||||||
|
AVERAGE_GRADE,
|
||||||
|
RECORD_BOOK_NUMBER
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package ru.project.ui.sorting;
|
||||||
|
|
||||||
|
public enum SortMethod {
|
||||||
|
NORMAL,
|
||||||
|
PARITY
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package ru.project.ui.sorting;
|
||||||
|
|
||||||
|
import com.googlecode.lanterna.gui2.ActionListBox;
|
||||||
|
import com.googlecode.lanterna.gui2.WindowBasedTextGUI;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import ru.project.ui.base.BaseModalWindow;
|
||||||
|
|
||||||
|
public class SortMethodSelectionWindow extends BaseModalWindow {
|
||||||
|
|
||||||
|
private final Consumer<SortMethod> onSortMethodSelected;
|
||||||
|
|
||||||
|
public SortMethodSelectionWindow(
|
||||||
|
WindowBasedTextGUI gui, Consumer<SortMethod> onSortMethodSelected) {
|
||||||
|
|
||||||
|
super("Выбрать способ сортировки", gui);
|
||||||
|
|
||||||
|
this.onSortMethodSelected = onSortMethodSelected;
|
||||||
|
|
||||||
|
ActionListBox menu = new ActionListBox();
|
||||||
|
|
||||||
|
menu.addItem("Обычная сортировка", () -> selectSortMethod(SortMethod.NORMAL));
|
||||||
|
|
||||||
|
menu.addItem("Сортировка по чётности", () -> selectSortMethod(SortMethod.PARITY));
|
||||||
|
|
||||||
|
menu.addItem("Выйти", this::close);
|
||||||
|
|
||||||
|
setComponent(menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void selectSortMethod(SortMethod sortMethod) {
|
||||||
|
onSortMethodSelected.accept(sortMethod);
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,16 +4,12 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
|||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
/**
|
/** Unit test for simple App. */
|
||||||
* Unit test for simple App.
|
|
||||||
*/
|
|
||||||
public class AppTest {
|
public class AppTest {
|
||||||
|
|
||||||
/**
|
/** Rigorous Test :-) */
|
||||||
* Rigorous Test :-)
|
@Test
|
||||||
*/
|
public void shouldAnswerWithTrue() {
|
||||||
@Test
|
assertTrue(true);
|
||||||
public void shouldAnswerWithTrue() {
|
}
|
||||||
assertTrue(true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,286 @@
|
|||||||
|
package ru.project.sorting;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import ru.project.collection.MyLinkedList;
|
||||||
|
import ru.project.collection.MyList;
|
||||||
|
import ru.project.student.Student;
|
||||||
|
|
||||||
|
class EvenOnlySortStrategyTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldHandleEmptyList() {
|
||||||
|
MyList<Integer> list = new MyLinkedList<>();
|
||||||
|
|
||||||
|
EvenOnlySortStrategy<Integer> strategy =
|
||||||
|
new EvenOnlySortStrategy<>(new MergeSortStrategy<>(), value -> value);
|
||||||
|
|
||||||
|
strategy.sort(list, Integer::compare);
|
||||||
|
|
||||||
|
assertEquals(0, list.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldKeepSingleEvenElementUnchanged() {
|
||||||
|
MyList<Integer> list = new MyLinkedList<>();
|
||||||
|
list.add(4);
|
||||||
|
|
||||||
|
EvenOnlySortStrategy<Integer> strategy =
|
||||||
|
new EvenOnlySortStrategy<>(new MergeSortStrategy<>(), value -> value);
|
||||||
|
|
||||||
|
strategy.sort(list, Integer::compare);
|
||||||
|
|
||||||
|
assertEquals(4, list.get(0));
|
||||||
|
assertEquals(1, list.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldKeepSingleOddElementUnchanged() {
|
||||||
|
MyList<Integer> list = new MyLinkedList<>();
|
||||||
|
list.add(7);
|
||||||
|
|
||||||
|
EvenOnlySortStrategy<Integer> strategy =
|
||||||
|
new EvenOnlySortStrategy<>(new MergeSortStrategy<>(), value -> value);
|
||||||
|
|
||||||
|
strategy.sort(list, Integer::compare);
|
||||||
|
|
||||||
|
assertEquals(7, list.get(0));
|
||||||
|
assertEquals(1, list.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldHandleDuplicateEvenValues() {
|
||||||
|
MyList<Integer> list = new MyLinkedList<>();
|
||||||
|
|
||||||
|
list.add(8);
|
||||||
|
list.add(4);
|
||||||
|
list.add(8);
|
||||||
|
list.add(2);
|
||||||
|
list.add(4);
|
||||||
|
|
||||||
|
EvenOnlySortStrategy<Integer> strategy =
|
||||||
|
new EvenOnlySortStrategy<>(new MergeSortStrategy<>(), value -> value);
|
||||||
|
|
||||||
|
strategy.sort(list, Integer::compare);
|
||||||
|
|
||||||
|
assertEquals(2, list.get(0));
|
||||||
|
assertEquals(4, list.get(1));
|
||||||
|
assertEquals(4, list.get(2));
|
||||||
|
assertEquals(8, list.get(3));
|
||||||
|
assertEquals(8, list.get(4));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldKeepOddStudentObjectsAtSameIndexes() {
|
||||||
|
Student oddFirst = new Student("A01", 4.0, 7);
|
||||||
|
Student evenFirst = new Student("A02", 4.0, 8);
|
||||||
|
Student oddSecond = new Student("A03", 4.0, 3);
|
||||||
|
Student evenSecond = new Student("A04", 4.0, 2);
|
||||||
|
Student oddThird = new Student("A05", 4.0, 5);
|
||||||
|
Student evenThird = new Student("A06", 4.0, 4);
|
||||||
|
|
||||||
|
MyList<Student> students = new MyLinkedList<>();
|
||||||
|
|
||||||
|
students.add(oddFirst);
|
||||||
|
students.add(evenFirst);
|
||||||
|
students.add(oddSecond);
|
||||||
|
students.add(evenSecond);
|
||||||
|
students.add(oddThird);
|
||||||
|
students.add(evenThird);
|
||||||
|
|
||||||
|
EvenOnlySortStrategy<Student> strategy =
|
||||||
|
new EvenOnlySortStrategy<>(new MergeSortStrategy<>(), Student::getRecordBookNumber);
|
||||||
|
|
||||||
|
strategy.sort(students, new StudentRecordBookComparator());
|
||||||
|
|
||||||
|
assertSame(oddFirst, students.get(0));
|
||||||
|
assertSame(oddSecond, students.get(2));
|
||||||
|
assertSame(oddThird, students.get(4));
|
||||||
|
|
||||||
|
assertEquals(2, students.get(1).getRecordBookNumber());
|
||||||
|
assertEquals(4, students.get(3).getRecordBookNumber());
|
||||||
|
assertEquals(8, students.get(5).getRecordBookNumber());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldSortWhenStrategyPassedThroughConstructor() {
|
||||||
|
MyList<Integer> list = new MyLinkedList<>();
|
||||||
|
|
||||||
|
list.add(8);
|
||||||
|
list.add(2);
|
||||||
|
list.add(4);
|
||||||
|
|
||||||
|
EvenOnlySortStrategy<Integer> strategy = new EvenOnlySortStrategy<>(new MergeSortStrategy<>());
|
||||||
|
|
||||||
|
strategy.setValueExtractor(value -> value);
|
||||||
|
|
||||||
|
strategy.sort(list, Integer::compare);
|
||||||
|
|
||||||
|
assertEquals(2, list.get(0));
|
||||||
|
assertEquals(4, list.get(1));
|
||||||
|
assertEquals(8, list.get(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldSortOnlyEvenElements() {
|
||||||
|
MyList<Student> students = new MyLinkedList<>();
|
||||||
|
|
||||||
|
students.add(new Student("A01", 4.0, 7));
|
||||||
|
students.add(new Student("A02", 4.0, 8));
|
||||||
|
students.add(new Student("A03", 4.0, 3));
|
||||||
|
students.add(new Student("A04", 4.0, 2));
|
||||||
|
students.add(new Student("A05", 4.0, 5));
|
||||||
|
students.add(new Student("A06", 4.0, 4));
|
||||||
|
|
||||||
|
EvenOnlySortStrategy<Student> strategy =
|
||||||
|
new EvenOnlySortStrategy<>(new MergeSortStrategy<>(), Student::getRecordBookNumber);
|
||||||
|
|
||||||
|
strategy.sort(students, new StudentRecordBookComparator());
|
||||||
|
|
||||||
|
assertEquals(7, students.get(0).getRecordBookNumber());
|
||||||
|
assertEquals(2, students.get(1).getRecordBookNumber());
|
||||||
|
assertEquals(3, students.get(2).getRecordBookNumber());
|
||||||
|
assertEquals(4, students.get(3).getRecordBookNumber());
|
||||||
|
assertEquals(5, students.get(4).getRecordBookNumber());
|
||||||
|
assertEquals(8, students.get(5).getRecordBookNumber());
|
||||||
|
|
||||||
|
assertEquals(6, students.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldSortAllEvenElements() {
|
||||||
|
MyList<Integer> list = new MyLinkedList<>();
|
||||||
|
|
||||||
|
list.add(8);
|
||||||
|
list.add(2);
|
||||||
|
list.add(6);
|
||||||
|
list.add(4);
|
||||||
|
|
||||||
|
EvenOnlySortStrategy<Integer> strategy =
|
||||||
|
new EvenOnlySortStrategy<>(new MergeSortStrategy<>(), value -> value);
|
||||||
|
|
||||||
|
strategy.sort(list, Integer::compare);
|
||||||
|
|
||||||
|
assertEquals(2, list.get(0));
|
||||||
|
assertEquals(4, list.get(1));
|
||||||
|
assertEquals(6, list.get(2));
|
||||||
|
assertEquals(8, list.get(3));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldKeepOddElementsUnchanged() {
|
||||||
|
MyList<Integer> list = new MyLinkedList<>();
|
||||||
|
|
||||||
|
list.add(7);
|
||||||
|
list.add(3);
|
||||||
|
list.add(5);
|
||||||
|
list.add(1);
|
||||||
|
|
||||||
|
EvenOnlySortStrategy<Integer> strategy =
|
||||||
|
new EvenOnlySortStrategy<>(new MergeSortStrategy<>(), value -> value);
|
||||||
|
|
||||||
|
strategy.sort(list, Integer::compare);
|
||||||
|
|
||||||
|
assertEquals(7, list.get(0));
|
||||||
|
assertEquals(3, list.get(1));
|
||||||
|
assertEquals(5, list.get(2));
|
||||||
|
assertEquals(1, list.get(3));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldThrowWhenSortStrategyIsNotSet() {
|
||||||
|
EvenOnlySortStrategy<Integer> strategy = new EvenOnlySortStrategy<>();
|
||||||
|
|
||||||
|
strategy.setValueExtractor(value -> value);
|
||||||
|
|
||||||
|
MyList<Integer> list = new MyLinkedList<>();
|
||||||
|
list.add(2);
|
||||||
|
list.add(4);
|
||||||
|
|
||||||
|
assertThrows(IllegalStateException.class, () -> strategy.sort(list, Integer::compare));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldRejectNullSortStrategy() {
|
||||||
|
EvenOnlySortStrategy<Integer> strategy = new EvenOnlySortStrategy<>();
|
||||||
|
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> strategy.setSortStrategy(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldDelegateSortingToProvidedStrategy() {
|
||||||
|
MyList<Integer> list = new MyLinkedList<>();
|
||||||
|
|
||||||
|
list.add(7);
|
||||||
|
list.add(8);
|
||||||
|
list.add(3);
|
||||||
|
list.add(2);
|
||||||
|
|
||||||
|
RecordingSortStrategy recordingStrategy = new RecordingSortStrategy();
|
||||||
|
|
||||||
|
EvenOnlySortStrategy<Integer> strategy =
|
||||||
|
new EvenOnlySortStrategy<>(recordingStrategy, value -> value);
|
||||||
|
|
||||||
|
strategy.sort(list, Integer::compare);
|
||||||
|
|
||||||
|
assertTrue(recordingStrategy.wasCalled);
|
||||||
|
assertEquals(2, recordingStrategy.receivedSize);
|
||||||
|
assertEquals(8, recordingStrategy.firstReceivedElement);
|
||||||
|
assertEquals(2, recordingStrategy.secondReceivedElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldUseNewStrategyAfterReplacement() {
|
||||||
|
RecordingSortStrategy firstStrategy = new RecordingSortStrategy();
|
||||||
|
|
||||||
|
RecordingSortStrategy secondStrategy = new RecordingSortStrategy();
|
||||||
|
|
||||||
|
EvenOnlySortStrategy<Integer> strategy =
|
||||||
|
new EvenOnlySortStrategy<>(firstStrategy, value -> value);
|
||||||
|
|
||||||
|
MyList<Integer> firstList = new MyLinkedList<>();
|
||||||
|
firstList.add(4);
|
||||||
|
firstList.add(2);
|
||||||
|
|
||||||
|
strategy.sort(firstList, Integer::compare);
|
||||||
|
|
||||||
|
assertTrue(firstStrategy.wasCalled);
|
||||||
|
|
||||||
|
strategy.setSortStrategy(secondStrategy);
|
||||||
|
|
||||||
|
MyList<Integer> secondList = new MyLinkedList<>();
|
||||||
|
secondList.add(8);
|
||||||
|
secondList.add(6);
|
||||||
|
|
||||||
|
strategy.sort(secondList, Integer::compare);
|
||||||
|
|
||||||
|
assertTrue(secondStrategy.wasCalled);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class RecordingSortStrategy implements SortStrategy<Integer> {
|
||||||
|
|
||||||
|
private boolean wasCalled;
|
||||||
|
private int receivedSize;
|
||||||
|
private Integer firstReceivedElement;
|
||||||
|
private Integer secondReceivedElement;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sort(MyList<Integer> list, Comparator<Integer> comparator) {
|
||||||
|
wasCalled = true;
|
||||||
|
receivedSize = list.size();
|
||||||
|
|
||||||
|
if (list.size() > 0) {
|
||||||
|
firstReceivedElement = list.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (list.size() > 1) {
|
||||||
|
secondReceivedElement = list.get(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,162 @@
|
|||||||
|
package ru.project.sorting;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import ru.project.collection.MyLinkedList;
|
||||||
|
import ru.project.collection.MyList;
|
||||||
|
import ru.project.student.Student;
|
||||||
|
|
||||||
|
class SortStrategyTest {
|
||||||
|
|
||||||
|
private MyList<Student> students;
|
||||||
|
private final Comparator<Student> groupComparator = new StudentGroupComparator();
|
||||||
|
private final Comparator<Student> gradeComparator = new StudentAverageGradeComparator();
|
||||||
|
private final Comparator<Student> recordComparator = new StudentRecordBookComparator();
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setUp() {
|
||||||
|
students = new MyLinkedList<>();
|
||||||
|
students.add(new Student("A12", 4.5, 12345));
|
||||||
|
students.add(new Student("B32", 3.8, 12346));
|
||||||
|
students.add(new Student("Z00", 4.9, 12347));
|
||||||
|
students.add(new Student("A12", 4.2, 12348));
|
||||||
|
students.add(new Student("B32", 5.0, 12349));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testMergeSortByGroupNumber() {
|
||||||
|
SortStrategy<Student> strategy = new MergeSortStrategy<>();
|
||||||
|
strategy.sort(students, groupComparator);
|
||||||
|
assertOrder(students, "A12", "A12", "B32", "B32", "Z00");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testMergeSortByAverageGrade() {
|
||||||
|
SortStrategy<Student> strategy = new MergeSortStrategy<>();
|
||||||
|
strategy.sort(students, gradeComparator);
|
||||||
|
assertOrder(students, 3.8, 4.2, 4.5, 4.9, 5.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testMergeSortByRecordBookNumber() {
|
||||||
|
SortStrategy<Student> strategy = new MergeSortStrategy<>();
|
||||||
|
strategy.sort(students, recordComparator);
|
||||||
|
assertOrder(students, 12345, 12346, 12347, 12348, 12349);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testBubbleSortByGroupNumber() {
|
||||||
|
SortStrategy<Student> strategy = new BubbleSortStrategy<>();
|
||||||
|
strategy.sort(students, groupComparator);
|
||||||
|
assertOrder(students, "A12", "A12", "B32", "B32", "Z00");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testBubbleSortByAverageGrade() {
|
||||||
|
SortStrategy<Student> strategy = new BubbleSortStrategy<>();
|
||||||
|
strategy.sort(students, gradeComparator);
|
||||||
|
assertOrder(students, 3.8, 4.2, 4.5, 4.9, 5.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testBubbleSortByRecordBookNumber() {
|
||||||
|
SortStrategy<Student> strategy = new BubbleSortStrategy<>();
|
||||||
|
strategy.sort(students, recordComparator);
|
||||||
|
assertOrder(students, 12345, 12346, 12347, 12348, 12349);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testEvenOnlySortByRecordBookNumber() {
|
||||||
|
MyList<Student> list = new MyLinkedList<>();
|
||||||
|
list.add(new Student("A01", 4.5, 7));
|
||||||
|
list.add(new Student("A02", 4.5, 8));
|
||||||
|
list.add(new Student("A03", 4.5, 3));
|
||||||
|
list.add(new Student("A04", 4.5, 2));
|
||||||
|
list.add(new Student("A05", 4.5, 5));
|
||||||
|
list.add(new Student("A06", 4.5, 4));
|
||||||
|
|
||||||
|
EvenOnlyMergeSortStrategy<Student> strategy =
|
||||||
|
new EvenOnlyMergeSortStrategy<>(Student::getRecordBookNumber);
|
||||||
|
strategy.sort(list, Comparator.comparingInt(Student::getRecordBookNumber));
|
||||||
|
|
||||||
|
int[] expected = {7, 2, 3, 4, 5, 8};
|
||||||
|
for (int i = 0; i < list.size(); i++) {
|
||||||
|
assertEquals(expected[i], list.get(i).getRecordBookNumber());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testEvenOnlyWithNoEvenElements() {
|
||||||
|
MyList<Student> list = new MyLinkedList<>();
|
||||||
|
list.add(new Student("A01", 4.5, 1));
|
||||||
|
list.add(new Student("A02", 4.5, 3));
|
||||||
|
list.add(new Student("A03", 4.5, 5));
|
||||||
|
|
||||||
|
EvenOnlyMergeSortStrategy<Student> strategy =
|
||||||
|
new EvenOnlyMergeSortStrategy<>(Student::getRecordBookNumber);
|
||||||
|
strategy.sort(list, Comparator.comparingInt(Student::getRecordBookNumber));
|
||||||
|
|
||||||
|
int[] expected = {1, 3, 5};
|
||||||
|
for (int i = 0; i < list.size(); i++) {
|
||||||
|
assertEquals(expected[i], list.get(i).getRecordBookNumber());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testEvenOnlyWithAllEvenElements() {
|
||||||
|
MyList<Student> list = new MyLinkedList<>();
|
||||||
|
list.add(new Student("A01", 4.5, 4));
|
||||||
|
list.add(new Student("A02", 4.5, 2));
|
||||||
|
list.add(new Student("A03", 4.5, 6));
|
||||||
|
|
||||||
|
EvenOnlyMergeSortStrategy<Student> strategy =
|
||||||
|
new EvenOnlyMergeSortStrategy<>(Student::getRecordBookNumber);
|
||||||
|
strategy.sort(list, Comparator.comparingInt(Student::getRecordBookNumber));
|
||||||
|
|
||||||
|
int[] expected = {2, 4, 6};
|
||||||
|
for (int i = 0; i < list.size(); i++) {
|
||||||
|
assertEquals(expected[i], list.get(i).getRecordBookNumber());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSortEmptyList() {
|
||||||
|
MyList<Student> empty = new MyLinkedList<>();
|
||||||
|
SortStrategy<Student> strategy = new MergeSortStrategy<>();
|
||||||
|
strategy.sort(empty, groupComparator);
|
||||||
|
assertEquals(0, empty.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSortSingleElement() {
|
||||||
|
MyList<Student> single = new MyLinkedList<>();
|
||||||
|
single.add(new Student("A12", 4.5, 12345));
|
||||||
|
SortStrategy<Student> strategy = new MergeSortStrategy<>();
|
||||||
|
strategy.sort(single, groupComparator);
|
||||||
|
assertEquals(1, single.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertOrder(MyList<Student> list, String... groups) {
|
||||||
|
assertEquals(groups.length, list.size());
|
||||||
|
for (int i = 0; i < groups.length; i++) {
|
||||||
|
assertEquals(groups[i], list.get(i).getGroupNumber());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertOrder(MyList<Student> list, double... grades) {
|
||||||
|
assertEquals(grades.length, list.size());
|
||||||
|
for (int i = 0; i < grades.length; i++) {
|
||||||
|
assertEquals(grades[i], list.get(i).getAverageGrade(), 0.001);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertOrder(MyList<Student> list, int... records) {
|
||||||
|
assertEquals(records.length, list.size());
|
||||||
|
for (int i = 0; i < records.length; i++) {
|
||||||
|
assertEquals(records[i], list.get(i).getRecordBookNumber());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,141 @@
|
|||||||
|
package ru.project.student;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotSame;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
class StudentTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testValidStudentCreation() {
|
||||||
|
Student student = new Student("A12", 4.5, 12345);
|
||||||
|
assertEquals("A12", student.getGroupNumber());
|
||||||
|
assertEquals(4.5, student.getAverageGrade());
|
||||||
|
assertEquals(12345, student.getRecordBookNumber());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testValidGroupNumbers() {
|
||||||
|
assertDoesNotThrow(() -> new Student("A12", 4.5, 1));
|
||||||
|
assertDoesNotThrow(() -> new Student("B32", 4.5, 1));
|
||||||
|
assertDoesNotThrow(() -> new Student("Z00", 4.5, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testInvalidGroupNumbers() {
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> new Student("a12", 4.5, 1));
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> new Student("A1", 4.5, 1));
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> new Student("A123", 4.5, 1));
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> new Student("AA1", 4.5, 1));
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> new Student("а1А", 4.5, 1));
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> new Student("аа!!а123", 4.5, 1));
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> new Student("23фи!12", 4.5, 1));
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> new Student("№№###*()", 4.5, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testValidAverageGrades() {
|
||||||
|
assertDoesNotThrow(() -> new Student("A12", 0.0, 1));
|
||||||
|
assertDoesNotThrow(() -> new Student("A12", 5.0, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testInvalidAverageGrades() {
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> new Student("A12", -1.0, 1));
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> new Student("A12", 6.0, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testValidRecordBookNumbers() {
|
||||||
|
assertDoesNotThrow(() -> new Student("A12", 4.5, 1));
|
||||||
|
assertDoesNotThrow(() -> new Student("A12", 4.5, 12345));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testInvalidRecordBookNumbers() {
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> new Student("A12", 4.5, 0));
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> new Student("A12", 4.5, -1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testWithGroupNumber() {
|
||||||
|
Student original = new Student("A12", 4.5, 12345);
|
||||||
|
Student updated = original.withGroupNumber("B32");
|
||||||
|
|
||||||
|
assertNotSame(original, updated);
|
||||||
|
assertEquals("B32", updated.getGroupNumber());
|
||||||
|
assertEquals(4.5, updated.getAverageGrade());
|
||||||
|
assertEquals(12345, updated.getRecordBookNumber());
|
||||||
|
|
||||||
|
assertEquals("A12", original.getGroupNumber());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testWithAverageGrade() {
|
||||||
|
Student original = new Student("A12", 4.5, 12345);
|
||||||
|
Student updated = original.withAverageGrade(4.8);
|
||||||
|
|
||||||
|
assertNotSame(original, updated);
|
||||||
|
assertEquals(4.8, updated.getAverageGrade());
|
||||||
|
assertEquals("A12", updated.getGroupNumber());
|
||||||
|
assertEquals(12345, updated.getRecordBookNumber());
|
||||||
|
|
||||||
|
assertEquals(4.5, original.getAverageGrade());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testWithRecordBookNumber() {
|
||||||
|
Student original = new Student("A12", 4.5, 12345);
|
||||||
|
Student updated = original.withRecordBookNumber(99999);
|
||||||
|
|
||||||
|
assertNotSame(original, updated);
|
||||||
|
assertEquals(99999, updated.getRecordBookNumber());
|
||||||
|
assertEquals("A12", updated.getGroupNumber());
|
||||||
|
assertEquals(4.5, updated.getAverageGrade());
|
||||||
|
|
||||||
|
assertEquals(12345, original.getRecordBookNumber());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testWithInvalidGroupNumber() {
|
||||||
|
Student original = new Student("A12", 4.5, 12345);
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> original.withGroupNumber("a12"));
|
||||||
|
assertEquals("A12", original.getGroupNumber()); // не изменился
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testWithInvalidAverageGrade() {
|
||||||
|
Student original = new Student("A12", 4.5, 12345);
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> original.withAverageGrade(6.0));
|
||||||
|
assertEquals(4.5, original.getAverageGrade());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testWithInvalidRecordBookNumber() {
|
||||||
|
Student original = new Student("A12", 4.5, 12345);
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> original.withRecordBookNumber(0));
|
||||||
|
assertEquals(12345, original.getRecordBookNumber());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testEqualsAndHashCode() {
|
||||||
|
Student s1 = new Student("A12", 4.5, 12345);
|
||||||
|
Student s2 = new Student("A12", 4.5, 12345);
|
||||||
|
Student s3 = new Student("B32", 4.5, 12345);
|
||||||
|
Student s4 = new Student("A12", 4.8, 12345);
|
||||||
|
Student s5 = new Student("A12", 4.5, 99999);
|
||||||
|
|
||||||
|
assertEquals(s1, s2);
|
||||||
|
assertEquals(s1.hashCode(), s2.hashCode());
|
||||||
|
|
||||||
|
assertNotEquals(s1, s3);
|
||||||
|
assertNotEquals(s1, s4);
|
||||||
|
assertNotEquals(s1, s5);
|
||||||
|
assertNotEquals(s1, null);
|
||||||
|
assertNotEquals(s1, "some string");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
Главное меню
|
||||||
|
{
|
||||||
|
Показать текущую коллекцию
|
||||||
|
|
||||||
|
Меню создания новой коллекции
|
||||||
|
{
|
||||||
|
Вернуться
|
||||||
|
|
||||||
|
Задать размер
|
||||||
|
|
||||||
|
Настроить способ заполнения
|
||||||
|
{
|
||||||
|
Пользовательские данные
|
||||||
|
{
|
||||||
|
Задать поле 'Название A'
|
||||||
|
Задать поле 'Название B'
|
||||||
|
Задать поле 'Название C'
|
||||||
|
Задать индекс изменяемого объекта
|
||||||
|
Изменить данные объекта
|
||||||
|
Предпросмотр
|
||||||
|
}
|
||||||
|
|
||||||
|
Случайные данные
|
||||||
|
{
|
||||||
|
Настройка диапазона генерации
|
||||||
|
{
|
||||||
|
Поле 'Название A'
|
||||||
|
{
|
||||||
|
Задать минимальное значение
|
||||||
|
Задать максимальное значение
|
||||||
|
}
|
||||||
|
|
||||||
|
Поле 'Название B'
|
||||||
|
{
|
||||||
|
Задать минимальное значение
|
||||||
|
Задать максимальное значение
|
||||||
|
}
|
||||||
|
|
||||||
|
Поле 'Название C'
|
||||||
|
{
|
||||||
|
Задать минимальное значение
|
||||||
|
Задать максимальное значение
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Данные из файла
|
||||||
|
{
|
||||||
|
Задать путь до файла
|
||||||
|
{
|
||||||
|
Абсолютный
|
||||||
|
Относительный
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Выбрать способ заполнения
|
||||||
|
{
|
||||||
|
Пользовательские данные *
|
||||||
|
Случайные данные
|
||||||
|
Данные из файла
|
||||||
|
}
|
||||||
|
|
||||||
|
Создать новую коллекцию
|
||||||
|
}
|
||||||
|
|
||||||
|
Меню сохранения текущей коллекции в файл
|
||||||
|
{
|
||||||
|
Вывести текущий абсолютный путь до файла
|
||||||
|
|
||||||
|
Задать путь до файла
|
||||||
|
{
|
||||||
|
Абсолютный
|
||||||
|
Относительный
|
||||||
|
}
|
||||||
|
|
||||||
|
Дописать коллекцию в текущий файл
|
||||||
|
}
|
||||||
|
|
||||||
|
Меню сортировки текущей коллекции
|
||||||
|
{
|
||||||
|
Вернуться
|
||||||
|
|
||||||
|
Настроить способ сортировки
|
||||||
|
{
|
||||||
|
Обычная сортировка
|
||||||
|
{
|
||||||
|
Сортировать по полю 'Название A'
|
||||||
|
Сортировать по полю 'Название B'
|
||||||
|
Сортировать по полю 'Название C'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Настроить способ сортировки
|
||||||
|
{
|
||||||
|
Сортировка по чётности
|
||||||
|
{
|
||||||
|
Выбрать числовое поле 'Название A'
|
||||||
|
Выбрать числовое поле 'Название B'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Выбрать способ сортировки
|
||||||
|
{
|
||||||
|
Обычная сортировка *
|
||||||
|
Сортировка по чётности
|
||||||
|
}
|
||||||
|
|
||||||
|
Сортировать текущую коллекцию
|
||||||
|
}
|
||||||
|
|
||||||
|
Меню поиска элемента в текущей коллекции
|
||||||
|
{
|
||||||
|
Вернуться
|
||||||
|
Задать значение поля 'Название A'
|
||||||
|
Задать значение поля 'Название B'
|
||||||
|
Задать значение поля 'Название C'
|
||||||
|
Найти первое вхождение в текущей коллекции
|
||||||
|
}
|
||||||
|
|
||||||
|
Меню подсчёта количества вхождений элемента
|
||||||
|
{
|
||||||
|
Задать значение поля 'Название A'
|
||||||
|
Задать значение поля 'Название B'
|
||||||
|
Задать значение поля 'Название C'
|
||||||
|
Выполнить многопоточный подсчёт
|
||||||
|
}
|
||||||
|
|
||||||
|
Завершить выполнение программы
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user