Merge branch 'feature/ui' into develop
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
package ru.project;
|
||||
|
||||
import com.googlecode.lanterna.gui2.MultiWindowTextGUI;
|
||||
import com.googlecode.lanterna.screen.Screen;
|
||||
import com.googlecode.lanterna.terminal.DefaultTerminalFactory;
|
||||
import ru.project.model.AppState;
|
||||
import ru.project.ui.MainMenu;
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,13 +7,9 @@ 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() {
|
||||
@@ -23,21 +19,4 @@ public class AppState {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,156 +1,172 @@
|
||||
package ru.project.random;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
import java.util.Random;
|
||||
import java.util.regex.Pattern;
|
||||
import ru.project.collection.MyLinkedList;
|
||||
import ru.project.collection.MyList;
|
||||
import ru.project.student.Student;
|
||||
import java.util.Random;
|
||||
import java.util.regex.Pattern;
|
||||
import ru.project.student.StudentBuilder;
|
||||
|
||||
public class RandomStudentGenerator
|
||||
{
|
||||
private static final Random RANDOM = new Random();
|
||||
private String minGroupNumber;
|
||||
private String maxGroupNumber;
|
||||
private Double minAverageGrade;
|
||||
private Double maxAverageGrade;
|
||||
private Integer minRecordBookNumber;
|
||||
private Integer maxRecordBookNumber;
|
||||
private static final double DEFAULT_MIN_GRADE = 0.0;
|
||||
private static final double DEFAULT_MAX_GRADE = 5.0;
|
||||
private static final int DEFAULT_MIN_RECORD_BOOK = 1;
|
||||
private static final String GROUP_PATTERN_REGEX = "^[A-Z][0-9]{2}$";
|
||||
private static final Pattern GROUP_PATTERN = Pattern.compile(GROUP_PATTERN_REGEX);
|
||||
public RandomStudentGenerator setMinGroupNumber(String minGroupNumber) {
|
||||
if (minGroupNumber != null && !GROUP_PATTERN.matcher(minGroupNumber).matches()) {
|
||||
throw new IllegalArgumentException("minGroupNumber does not match Student group pattern: " + GROUP_PATTERN_REGEX);
|
||||
}
|
||||
this.minGroupNumber = minGroupNumber;
|
||||
return this;
|
||||
}
|
||||
public RandomStudentGenerator setMaxGroupNumber(String maxGroupNumber) {
|
||||
if (maxGroupNumber != null && !GROUP_PATTERN.matcher(maxGroupNumber).matches()) {
|
||||
throw new IllegalArgumentException("maxGroupNumber does not match Student group pattern: " + GROUP_PATTERN_REGEX);
|
||||
}
|
||||
this.maxGroupNumber = maxGroupNumber;
|
||||
return this;
|
||||
}
|
||||
public class RandomStudentGenerator {
|
||||
private static final Random RANDOM = new Random();
|
||||
private String minGroupNumber;
|
||||
private String maxGroupNumber;
|
||||
private Double minAverageGrade;
|
||||
private Double maxAverageGrade;
|
||||
private Integer minRecordBookNumber;
|
||||
private Integer maxRecordBookNumber;
|
||||
private static final double DEFAULT_MIN_GRADE = 0.0;
|
||||
private static final double DEFAULT_MAX_GRADE = 5.0;
|
||||
private static final int DEFAULT_MIN_RECORD_BOOK = 1;
|
||||
private static final String GROUP_PATTERN_REGEX = "^[A-Z][0-9]{2}$";
|
||||
private static final Pattern GROUP_PATTERN = Pattern.compile(GROUP_PATTERN_REGEX);
|
||||
|
||||
public RandomStudentGenerator setMinAverageGrade(double minAverageGrade) {
|
||||
if (minAverageGrade < DEFAULT_MIN_GRADE || minAverageGrade > DEFAULT_MAX_GRADE) {
|
||||
throw new IllegalArgumentException(
|
||||
"minAverageGrade out of Student allowed range [" + DEFAULT_MIN_GRADE + ", " + DEFAULT_MAX_GRADE + "]"
|
||||
);
|
||||
}
|
||||
this.minAverageGrade = minAverageGrade;
|
||||
return this;
|
||||
public RandomStudentGenerator setMinGroupNumber(String minGroupNumber) {
|
||||
if (minGroupNumber != null && !GROUP_PATTERN.matcher(minGroupNumber).matches()) {
|
||||
throw new IllegalArgumentException(
|
||||
"minGroupNumber does not match Student group pattern: " + GROUP_PATTERN_REGEX);
|
||||
}
|
||||
this.minGroupNumber = minGroupNumber;
|
||||
return this;
|
||||
}
|
||||
|
||||
public RandomStudentGenerator setMaxAverageGrade(double maxAverageGrade) {
|
||||
if (maxAverageGrade < DEFAULT_MIN_GRADE || maxAverageGrade > DEFAULT_MAX_GRADE) {
|
||||
throw new IllegalArgumentException(
|
||||
"maxAverageGrade out of Student allowed range [" + DEFAULT_MIN_GRADE + ", " + DEFAULT_MAX_GRADE + "]"
|
||||
);
|
||||
}
|
||||
this.maxAverageGrade = maxAverageGrade;
|
||||
return this;
|
||||
public RandomStudentGenerator setMaxGroupNumber(String maxGroupNumber) {
|
||||
if (maxGroupNumber != null && !GROUP_PATTERN.matcher(maxGroupNumber).matches()) {
|
||||
throw new IllegalArgumentException(
|
||||
"maxGroupNumber does not match Student group pattern: " + GROUP_PATTERN_REGEX);
|
||||
}
|
||||
this.maxGroupNumber = maxGroupNumber;
|
||||
return this;
|
||||
}
|
||||
|
||||
public RandomStudentGenerator setMinRecordBookNumber(int minRecordBookNumber) {
|
||||
if (minRecordBookNumber < DEFAULT_MIN_RECORD_BOOK) {
|
||||
throw new IllegalArgumentException(
|
||||
"minRecordBookNumber must be >= " + DEFAULT_MIN_RECORD_BOOK
|
||||
);
|
||||
}
|
||||
this.minRecordBookNumber = minRecordBookNumber;
|
||||
return this;
|
||||
public RandomStudentGenerator setMinAverageGrade(double minAverageGrade) {
|
||||
if (minAverageGrade < DEFAULT_MIN_GRADE || minAverageGrade > DEFAULT_MAX_GRADE) {
|
||||
throw new IllegalArgumentException(
|
||||
"minAverageGrade out of Student allowed range ["
|
||||
+ DEFAULT_MIN_GRADE
|
||||
+ ", "
|
||||
+ DEFAULT_MAX_GRADE
|
||||
+ "]");
|
||||
}
|
||||
this.minAverageGrade = minAverageGrade;
|
||||
return this;
|
||||
}
|
||||
|
||||
public RandomStudentGenerator setMaxRecordBookNumber(int maxRecordBookNumber) {
|
||||
if (maxRecordBookNumber < DEFAULT_MIN_RECORD_BOOK) {
|
||||
throw new IllegalArgumentException(
|
||||
"maxRecordBookNumber must be >= " + DEFAULT_MIN_RECORD_BOOK
|
||||
);
|
||||
}
|
||||
this.maxRecordBookNumber = maxRecordBookNumber;
|
||||
return this;
|
||||
public RandomStudentGenerator setMaxAverageGrade(double maxAverageGrade) {
|
||||
if (maxAverageGrade < DEFAULT_MIN_GRADE || maxAverageGrade > DEFAULT_MAX_GRADE) {
|
||||
throw new IllegalArgumentException(
|
||||
"maxAverageGrade out of Student allowed range ["
|
||||
+ DEFAULT_MIN_GRADE
|
||||
+ ", "
|
||||
+ DEFAULT_MAX_GRADE
|
||||
+ "]");
|
||||
}
|
||||
public MyList<Student> generate(int size) {
|
||||
if (size < 0) {
|
||||
throw new IllegalArgumentException("size must be non-negative");
|
||||
}
|
||||
validateRanges();
|
||||
MyList<Student> result = new MyLinkedList<>();
|
||||
for (int i = 0; i < size; i++) {
|
||||
String group = generateGroupNumber();
|
||||
double grade = generateAverageGrade();
|
||||
int recordBook = generateRecordBookNumber();
|
||||
this.maxAverageGrade = maxAverageGrade;
|
||||
return this;
|
||||
}
|
||||
|
||||
Student student = new StudentBuilder()
|
||||
.setGroupNumber(group)
|
||||
.setAverageGrade(grade)
|
||||
.setRecordBookNumber(recordBook)
|
||||
.build();
|
||||
public RandomStudentGenerator setMinRecordBookNumber(int minRecordBookNumber) {
|
||||
if (minRecordBookNumber < DEFAULT_MIN_RECORD_BOOK) {
|
||||
throw new IllegalArgumentException(
|
||||
"minRecordBookNumber must be >= " + DEFAULT_MIN_RECORD_BOOK);
|
||||
}
|
||||
this.minRecordBookNumber = minRecordBookNumber;
|
||||
return this;
|
||||
}
|
||||
|
||||
result.add(student);
|
||||
}
|
||||
return result;
|
||||
public RandomStudentGenerator setMaxRecordBookNumber(int maxRecordBookNumber) {
|
||||
if (maxRecordBookNumber < DEFAULT_MIN_RECORD_BOOK) {
|
||||
throw new IllegalArgumentException(
|
||||
"maxRecordBookNumber must be >= " + DEFAULT_MIN_RECORD_BOOK);
|
||||
}
|
||||
private void validateRanges() {
|
||||
this.maxRecordBookNumber = maxRecordBookNumber;
|
||||
return this;
|
||||
}
|
||||
|
||||
double effectiveMinGrade = (minAverageGrade != null) ? minAverageGrade : DEFAULT_MIN_GRADE;
|
||||
double effectiveMaxGrade = (maxAverageGrade != null) ? maxAverageGrade : DEFAULT_MAX_GRADE;
|
||||
if (effectiveMinGrade > effectiveMaxGrade) {
|
||||
throw new IllegalArgumentException("minAverageGrade cannot be greater than maxAverageGrade");
|
||||
}
|
||||
int effectiveMinRecord = (minRecordBookNumber != null) ? minRecordBookNumber : DEFAULT_MIN_RECORD_BOOK;
|
||||
int effectiveMaxRecord = (maxRecordBookNumber != null) ? maxRecordBookNumber : Integer.MAX_VALUE;
|
||||
if (effectiveMaxRecord == Integer.MAX_VALUE) {
|
||||
effectiveMaxRecord = effectiveMinRecord + 999_999;
|
||||
}
|
||||
if (effectiveMinRecord > effectiveMaxRecord) {
|
||||
throw new IllegalArgumentException("minRecordBookNumber cannot be greater than maxRecordBookNumber");
|
||||
}
|
||||
if (minGroupNumber != null && maxGroupNumber != null) {
|
||||
if (minGroupNumber.compareTo(maxGroupNumber) > 0) {
|
||||
throw new IllegalArgumentException("minGroupNumber cannot be greater than maxGroupNumber");
|
||||
}
|
||||
}
|
||||
}
|
||||
private String generateGroupNumber() {
|
||||
String min = (minGroupNumber != null) ? minGroupNumber : "A00";
|
||||
String max = (maxGroupNumber != null) ? maxGroupNumber : "Z99";
|
||||
char minLetter = min.charAt(0);
|
||||
char maxLetter = max.charAt(0);
|
||||
int minDigit = Integer.parseInt(min.substring(1));
|
||||
int maxDigit = Integer.parseInt(max.substring(1));
|
||||
char letter = (char) (minLetter + RANDOM.nextInt((maxLetter - minLetter) + 1));
|
||||
int digit;
|
||||
if (letter == minLetter && letter == maxLetter) {
|
||||
digit = minDigit + RANDOM.nextInt((maxDigit - minDigit) + 1);
|
||||
} else if (letter == minLetter) {
|
||||
digit = minDigit + RANDOM.nextInt(100 - minDigit);
|
||||
} else if (letter == maxLetter) {
|
||||
digit = RANDOM.nextInt(maxDigit + 1);
|
||||
} else {
|
||||
digit = RANDOM.nextInt(100);
|
||||
}
|
||||
return letter + String.format("%02d", digit);
|
||||
public MyList<Student> generate(int size) {
|
||||
if (size < 0) {
|
||||
throw new IllegalArgumentException("size must be non-negative");
|
||||
}
|
||||
validateRanges();
|
||||
MyList<Student> result = new MyLinkedList<>();
|
||||
for (int i = 0; i < size; i++) {
|
||||
String group = generateGroupNumber();
|
||||
double grade = generateAverageGrade();
|
||||
int recordBook = generateRecordBookNumber();
|
||||
|
||||
private double generateAverageGrade() {
|
||||
double min = (minAverageGrade != null) ? minAverageGrade : DEFAULT_MIN_GRADE;
|
||||
double max = (maxAverageGrade != null) ? maxAverageGrade : DEFAULT_MAX_GRADE;
|
||||
Student student =
|
||||
new StudentBuilder()
|
||||
.setGroupNumber(group)
|
||||
.setAverageGrade(grade)
|
||||
.setRecordBookNumber(recordBook)
|
||||
.build();
|
||||
|
||||
double range = max - min;
|
||||
return min + (range * RANDOM.nextDouble());
|
||||
result.add(student);
|
||||
}
|
||||
private int generateRecordBookNumber() {
|
||||
int min = (minRecordBookNumber != null) ? minRecordBookNumber : DEFAULT_MIN_RECORD_BOOK;
|
||||
int max = (maxRecordBookNumber != null) ? maxRecordBookNumber : min + 999_999; // разумный максимум
|
||||
if (max < min) {
|
||||
max = min;
|
||||
}
|
||||
return min + RANDOM.nextInt((max - min) + 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
private void validateRanges() {
|
||||
|
||||
double effectiveMinGrade = (minAverageGrade != null) ? minAverageGrade : DEFAULT_MIN_GRADE;
|
||||
double effectiveMaxGrade = (maxAverageGrade != null) ? maxAverageGrade : DEFAULT_MAX_GRADE;
|
||||
if (effectiveMinGrade > effectiveMaxGrade) {
|
||||
throw new IllegalArgumentException("minAverageGrade cannot be greater than maxAverageGrade");
|
||||
}
|
||||
int effectiveMinRecord =
|
||||
(minRecordBookNumber != null) ? minRecordBookNumber : DEFAULT_MIN_RECORD_BOOK;
|
||||
int effectiveMaxRecord =
|
||||
(maxRecordBookNumber != null) ? maxRecordBookNumber : Integer.MAX_VALUE;
|
||||
if (effectiveMaxRecord == Integer.MAX_VALUE) {
|
||||
effectiveMaxRecord = effectiveMinRecord + 999_999;
|
||||
}
|
||||
if (effectiveMinRecord > effectiveMaxRecord) {
|
||||
throw new IllegalArgumentException(
|
||||
"minRecordBookNumber cannot be greater than maxRecordBookNumber");
|
||||
}
|
||||
if (minGroupNumber != null && maxGroupNumber != null) {
|
||||
if (minGroupNumber.compareTo(maxGroupNumber) > 0) {
|
||||
throw new IllegalArgumentException("minGroupNumber cannot be greater than maxGroupNumber");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String generateGroupNumber() {
|
||||
String min = (minGroupNumber != null) ? minGroupNumber : "A00";
|
||||
String max = (maxGroupNumber != null) ? maxGroupNumber : "Z99";
|
||||
char minLetter = min.charAt(0);
|
||||
char maxLetter = max.charAt(0);
|
||||
int minDigit = Integer.parseInt(min.substring(1));
|
||||
int maxDigit = Integer.parseInt(max.substring(1));
|
||||
char letter = (char) (minLetter + RANDOM.nextInt((maxLetter - minLetter) + 1));
|
||||
int digit;
|
||||
if (letter == minLetter && letter == maxLetter) {
|
||||
digit = minDigit + RANDOM.nextInt((maxDigit - minDigit) + 1);
|
||||
} else if (letter == minLetter) {
|
||||
digit = minDigit + RANDOM.nextInt(100 - minDigit);
|
||||
} else if (letter == maxLetter) {
|
||||
digit = RANDOM.nextInt(maxDigit + 1);
|
||||
} else {
|
||||
digit = RANDOM.nextInt(100);
|
||||
}
|
||||
return letter + String.format("%02d", digit);
|
||||
}
|
||||
|
||||
private double generateAverageGrade() {
|
||||
double min = (minAverageGrade != null) ? minAverageGrade : DEFAULT_MIN_GRADE;
|
||||
double max = (maxAverageGrade != null) ? maxAverageGrade : DEFAULT_MAX_GRADE;
|
||||
|
||||
double range = max - min;
|
||||
return min + (range * RANDOM.nextDouble());
|
||||
}
|
||||
|
||||
private int generateRecordBookNumber() {
|
||||
int min = (minRecordBookNumber != null) ? minRecordBookNumber : DEFAULT_MIN_RECORD_BOOK;
|
||||
int max =
|
||||
(maxRecordBookNumber != null) ? maxRecordBookNumber : min + 999_999; // разумный максимум
|
||||
if (max < min) {
|
||||
max = min;
|
||||
}
|
||||
return min + RANDOM.nextInt((max - min) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package ru.project.search;
|
||||
|
||||
import ru.project.collection.MyList;
|
||||
import ru.project.collection.MyLinkedList;
|
||||
import ru.project.collection.MyList;
|
||||
import ru.project.student.Student;
|
||||
|
||||
public class StudentSearchService {
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
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,38 @@
|
||||
package ru.project.ui;
|
||||
|
||||
import com.googlecode.lanterna.gui2.ActionListBox;
|
||||
import com.googlecode.lanterna.gui2.WindowBasedTextGUI;
|
||||
import ru.project.model.AppState;
|
||||
import ru.project.ui.base.BaseModalWindow;
|
||||
import ru.project.ui.collection.CurrentCollectionMenu;
|
||||
import ru.project.ui.creation.CreateCollectionMenu;
|
||||
|
||||
public class MainMenu extends BaseModalWindow {
|
||||
|
||||
private final ActionListBox menu;
|
||||
|
||||
private final BaseModalWindow currentCollectionMenu;
|
||||
private final BaseModalWindow createCollectionMenu;
|
||||
|
||||
public MainMenu(WindowBasedTextGUI gui, AppState state) {
|
||||
super("Главное меню", gui);
|
||||
|
||||
this.currentCollectionMenu = new CurrentCollectionMenu(gui, state);
|
||||
|
||||
this.createCollectionMenu = new CreateCollectionMenu(gui, state);
|
||||
|
||||
menu = new ActionListBox();
|
||||
|
||||
menu.addItem("Меню текущей коллекции", currentCollectionMenu::showModal);
|
||||
|
||||
menu.addItem("Меню создания новой коллекции", createCollectionMenu::showModal);
|
||||
|
||||
menu.addItem("Завершить выполнение программы", this::exit);
|
||||
|
||||
setComponent(menu);
|
||||
}
|
||||
|
||||
private void exit() {
|
||||
close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package ru.project.ui.collection;
|
||||
|
||||
import com.googlecode.lanterna.gui2.ActionListBox;
|
||||
import com.googlecode.lanterna.gui2.WindowBasedTextGUI;
|
||||
import ru.project.model.AppState;
|
||||
import ru.project.ui.base.BaseModalWindow;
|
||||
import ru.project.ui.collection.counting.CountOccurrencesMenu;
|
||||
import ru.project.ui.collection.search.SearchCollectionMenu;
|
||||
import ru.project.ui.collection.sorting.SortCollectionMenu;
|
||||
import ru.project.ui.common.CollectionDisplayWindow;
|
||||
import ru.project.ui.common.CollectionFileSaveWindow;
|
||||
|
||||
public class CurrentCollectionMenu extends BaseModalWindow {
|
||||
|
||||
private final AppState state;
|
||||
|
||||
private final SortCollectionMenu sortCollectionMenu;
|
||||
private final SearchCollectionMenu searchCollectionMenu;
|
||||
private final CountOccurrencesMenu countOccurrencesMenu;
|
||||
|
||||
public CurrentCollectionMenu(WindowBasedTextGUI gui, AppState state) {
|
||||
|
||||
super("Меню текущей коллекции", gui);
|
||||
|
||||
this.state = state;
|
||||
|
||||
this.sortCollectionMenu = new SortCollectionMenu(gui, state);
|
||||
|
||||
this.searchCollectionMenu = new SearchCollectionMenu(gui, state);
|
||||
|
||||
this.countOccurrencesMenu = new CountOccurrencesMenu(gui, state);
|
||||
|
||||
ActionListBox menu = new ActionListBox();
|
||||
menu.addItem("Показать коллекцию...", this::showCurrentCollection);
|
||||
|
||||
menu.addItem("Сохранить коллекцию в файл...", this::saveCurrentCollection);
|
||||
|
||||
menu.addItem("Меню сортировки коллекции", sortCollectionMenu::showModal);
|
||||
|
||||
menu.addItem("Меню поиска элемента в коллекции", searchCollectionMenu::showModal);
|
||||
|
||||
menu.addItem("Меню подсчёта количества вхождений элемента", countOccurrencesMenu::showModal);
|
||||
|
||||
menu.addItem("Выйти", this::close);
|
||||
|
||||
setComponent(menu);
|
||||
}
|
||||
|
||||
private void showCurrentCollection() {
|
||||
CollectionDisplayWindow window = new CollectionDisplayWindow(gui, state.getMainCollection());
|
||||
|
||||
window.showModal();
|
||||
}
|
||||
|
||||
private void saveCurrentCollection() {
|
||||
CollectionFileSaveWindow window = new CollectionFileSaveWindow(gui, state.getMainCollection());
|
||||
|
||||
window.showModal();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package ru.project.ui.collection.counting;
|
||||
|
||||
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.MyList;
|
||||
import ru.project.finder.StudentOccurrenceIndexFinder;
|
||||
import ru.project.model.AppState;
|
||||
import ru.project.student.Student;
|
||||
import ru.project.ui.base.BaseModalWindow;
|
||||
import ru.project.ui.common.MessageWindow;
|
||||
|
||||
public class CountOccurrencesMenu extends BaseModalWindow {
|
||||
|
||||
private final AppState state;
|
||||
|
||||
private final OccurrenceStudentSettingsWindow occurrenceStudentSettingsWindow;
|
||||
|
||||
private Student selectedStudent;
|
||||
private int occurrences;
|
||||
|
||||
private final Label studentLabel;
|
||||
private final Label occurrencesLabel;
|
||||
|
||||
public CountOccurrencesMenu(WindowBasedTextGUI gui, AppState state) {
|
||||
|
||||
super("Меню подсчёта количества вхождений элемента", gui);
|
||||
|
||||
this.state = state;
|
||||
this.selectedStudent = null;
|
||||
this.occurrences = 0;
|
||||
|
||||
this.studentLabel = new Label("Элемент для поиска: не задан");
|
||||
|
||||
this.occurrencesLabel = new Label("Количество вхождений: не подсчитано");
|
||||
|
||||
this.occurrenceStudentSettingsWindow =
|
||||
new OccurrenceStudentSettingsWindow(
|
||||
gui,
|
||||
student -> {
|
||||
selectedStudent = student;
|
||||
|
||||
studentLabel.setText("Элемент для поиска: задан");
|
||||
});
|
||||
|
||||
Panel panel = new Panel();
|
||||
panel.setLayoutManager(new LinearLayout());
|
||||
|
||||
panel.addComponent(studentLabel);
|
||||
panel.addComponent(occurrencesLabel);
|
||||
|
||||
panel.addComponent(new Button("Настроить элемент для поиска...", this::setupStudent));
|
||||
|
||||
panel.addComponent(new Button("Выполнить подсчёт", this::countOccurrences));
|
||||
|
||||
panel.addComponent(new Button("Выйти", this::close));
|
||||
|
||||
setComponent(panel);
|
||||
}
|
||||
|
||||
private void setupStudent() {
|
||||
occurrenceStudentSettingsWindow.showModal();
|
||||
}
|
||||
|
||||
private void countOccurrences() {
|
||||
MyList<Student> collection = state.getMainCollection();
|
||||
|
||||
if (collection == null || collection.isEmpty()) {
|
||||
MessageWindow.showModal(gui, "Текущая коллекция пуста.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedStudent == null) {
|
||||
MessageWindow.showModal(gui, "Сначала настройте элемент для поиска.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
StudentOccurrenceIndexFinder finder = new StudentOccurrenceIndexFinder();
|
||||
|
||||
int[] occurrenceIndices = finder.findOccurrences(collection, selectedStudent);
|
||||
|
||||
occurrences = occurrenceIndices.length;
|
||||
|
||||
StringBuilder result = new StringBuilder();
|
||||
|
||||
result.append("Количество вхождений: ").append(occurrences);
|
||||
|
||||
result.append("\nИндексы: ");
|
||||
|
||||
if (occurrenceIndices.length == 0) {
|
||||
result.append("нет");
|
||||
} else {
|
||||
for (int i = 0; i < occurrenceIndices.length; i++) {
|
||||
|
||||
if (i > 0) {
|
||||
result.append(", ");
|
||||
}
|
||||
|
||||
result.append(occurrenceIndices[i]);
|
||||
}
|
||||
}
|
||||
|
||||
occurrencesLabel.setText(result.toString());
|
||||
}
|
||||
}
|
||||
+172
@@ -0,0 +1,172 @@
|
||||
package ru.project.ui.collection.counting;
|
||||
|
||||
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.Consumer;
|
||||
import ru.project.student.Student;
|
||||
import ru.project.student.StudentBuilder;
|
||||
import ru.project.ui.base.BaseModalWindow;
|
||||
import ru.project.ui.common.InputValueWindow;
|
||||
import ru.project.ui.common.MessageWindow;
|
||||
|
||||
public class OccurrenceStudentSettingsWindow extends BaseModalWindow {
|
||||
|
||||
private final StudentBuilder studentBuilder;
|
||||
private final Consumer<Student> onApply;
|
||||
|
||||
private String groupNumber;
|
||||
private Double averageGrade;
|
||||
private Integer recordBookNumber;
|
||||
|
||||
private final Label groupNumberLabel;
|
||||
private final Label averageGradeLabel;
|
||||
private final Label recordBookNumberLabel;
|
||||
|
||||
public OccurrenceStudentSettingsWindow(WindowBasedTextGUI gui, Consumer<Student> onApply) {
|
||||
|
||||
super("Настройка элемента для поиска", gui);
|
||||
|
||||
this.studentBuilder = new StudentBuilder();
|
||||
this.onApply = onApply;
|
||||
|
||||
Panel panel = new Panel();
|
||||
panel.setLayoutManager(new LinearLayout());
|
||||
|
||||
groupNumberLabel = new Label("Номер группы: не задан");
|
||||
|
||||
averageGradeLabel = new Label("Средний балл: не задан");
|
||||
|
||||
recordBookNumberLabel = new Label("Номер зачётной книжки: не задан");
|
||||
|
||||
panel.addComponent(groupNumberLabel);
|
||||
panel.addComponent(averageGradeLabel);
|
||||
panel.addComponent(recordBookNumberLabel);
|
||||
|
||||
panel.addComponent(new Button("Задать номер группы...", this::setGroupNumber));
|
||||
|
||||
panel.addComponent(new Button("Задать средний балл...", this::setAverageGrade));
|
||||
|
||||
panel.addComponent(new Button("Задать номер зачётной книжки...", this::setRecordBookNumber));
|
||||
|
||||
panel.addComponent(new Button("Применить", this::apply));
|
||||
|
||||
panel.addComponent(new Button("Выйти", this::close));
|
||||
|
||||
setComponent(panel);
|
||||
}
|
||||
|
||||
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 apply() {
|
||||
if (groupNumber == null || averageGrade == null || recordBookNumber == null) {
|
||||
|
||||
MessageWindow.showModal(gui, "Необходимо задать все поля элемента.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Student student = studentBuilder.build();
|
||||
|
||||
onApply.accept(student);
|
||||
|
||||
MessageWindow.showModal(gui, "Элемент для поиска успешно настроен.");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package ru.project.ui.collection.search;
|
||||
|
||||
public enum FilterRelation {
|
||||
AND,
|
||||
OR
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
package ru.project.ui.collection.search;
|
||||
|
||||
import com.googlecode.lanterna.gui2.ActionListBox;
|
||||
import com.googlecode.lanterna.gui2.WindowBasedTextGUI;
|
||||
import ru.project.collection.MyLinkedList;
|
||||
import ru.project.collection.MyList;
|
||||
import ru.project.model.AppState;
|
||||
import ru.project.search.AverageGradeRangeCriteria;
|
||||
import ru.project.search.CompositeStudentSearchCriteria;
|
||||
import ru.project.search.GroupNumberRangeCriteria;
|
||||
import ru.project.search.RecordBookNumberRangeCriteria;
|
||||
import ru.project.search.SearchOperation;
|
||||
import ru.project.search.StudentSearchCriteria;
|
||||
import ru.project.search.StudentSearchService;
|
||||
import ru.project.student.Student;
|
||||
import ru.project.ui.base.BaseModalWindow;
|
||||
import ru.project.ui.common.CollectionDisplayWindow;
|
||||
import ru.project.ui.common.CollectionFileSaveWindow;
|
||||
import ru.project.ui.common.MessageWindow;
|
||||
|
||||
public class SearchCollectionMenu extends BaseModalWindow {
|
||||
|
||||
private final AppState state;
|
||||
|
||||
private final SearchSettingsWindow searchSettingsWindow;
|
||||
|
||||
private SearchSettings searchSettings;
|
||||
private MyList<Student> searchResultCollection;
|
||||
|
||||
public SearchCollectionMenu(WindowBasedTextGUI gui, AppState state) {
|
||||
|
||||
super("Меню поиска элемента в коллекции", gui);
|
||||
|
||||
this.state = state;
|
||||
this.searchSettings = new SearchSettings();
|
||||
this.searchResultCollection = new MyLinkedList<>();
|
||||
|
||||
this.searchSettingsWindow =
|
||||
new SearchSettingsWindow(gui, settings -> this.searchSettings = settings);
|
||||
|
||||
ActionListBox menu = new ActionListBox();
|
||||
|
||||
menu.addItem("Выполнить поиск", this::updateSearchResult);
|
||||
|
||||
menu.addItem("Показать результат поиска", this::showSearchResult);
|
||||
|
||||
menu.addItem("Сохранить результат поиска в файл", this::saveSearchResult);
|
||||
|
||||
menu.addItem("Настроить процесс поиска...", searchSettingsWindow::showModal);
|
||||
|
||||
menu.addItem("Выйти", this::close);
|
||||
|
||||
setComponent(menu);
|
||||
}
|
||||
|
||||
private void updateSearchResult() {
|
||||
MyList<Student> collection = state.getMainCollection();
|
||||
|
||||
if (collection == null || collection.isEmpty()) {
|
||||
MessageWindow.showModal(gui, "Коллекция для поиска пуста.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!hasEnabledFilters()) {
|
||||
MessageWindow.showModal(gui, "Не выбран ни один фильтр.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!hasValidFilterRanges()) {
|
||||
return;
|
||||
}
|
||||
|
||||
StudentSearchCriteria criteria = createSearchCriteria();
|
||||
|
||||
StudentSearchService searchService = new StudentSearchService(criteria);
|
||||
|
||||
searchResultCollection = searchService.find(collection);
|
||||
|
||||
MessageWindow.showModal(gui, "Результат поиска обновлён.");
|
||||
}
|
||||
|
||||
private StudentSearchCriteria createSearchCriteria() {
|
||||
SearchOperation operation =
|
||||
searchSettings.getRelation() == FilterRelation.AND
|
||||
? SearchOperation.INTERSECTION
|
||||
: SearchOperation.UNION;
|
||||
|
||||
CompositeStudentSearchCriteria compositeCriteria =
|
||||
new CompositeStudentSearchCriteria(operation);
|
||||
|
||||
if (searchSettings.isGroupNumberFilterEnabled()) {
|
||||
compositeCriteria.add(
|
||||
new GroupNumberRangeCriteria(
|
||||
searchSettings.getMinGroupNumber(), searchSettings.getMaxGroupNumber()));
|
||||
}
|
||||
|
||||
if (searchSettings.isAverageGradeFilterEnabled()) {
|
||||
compositeCriteria.add(
|
||||
new AverageGradeRangeCriteria(
|
||||
searchSettings.getMinAverageGrade(), searchSettings.getMaxAverageGrade()));
|
||||
}
|
||||
|
||||
if (searchSettings.isRecordBookNumberFilterEnabled()) {
|
||||
compositeCriteria.add(
|
||||
new RecordBookNumberRangeCriteria(
|
||||
searchSettings.getMinRecordBookNumber(), searchSettings.getMaxRecordBookNumber()));
|
||||
}
|
||||
|
||||
return compositeCriteria;
|
||||
}
|
||||
|
||||
private boolean hasEnabledFilters() {
|
||||
return searchSettings.isGroupNumberFilterEnabled()
|
||||
|| searchSettings.isAverageGradeFilterEnabled()
|
||||
|| searchSettings.isRecordBookNumberFilterEnabled();
|
||||
}
|
||||
|
||||
private boolean hasValidFilterRanges() {
|
||||
StringBuilder errors = new StringBuilder();
|
||||
|
||||
if (!hasValidGroupNumberRange()) {
|
||||
errors.append("Для фильтра по номеру группы задайте минимальное и максимальное значения.\n");
|
||||
}
|
||||
|
||||
if (!hasValidAverageGradeRange()) {
|
||||
errors.append("Для фильтра по среднему баллу задайте минимальное и максимальное значения.\n");
|
||||
}
|
||||
|
||||
if (!hasValidRecordBookNumberRange()) {
|
||||
errors.append(
|
||||
"Для фильтра по номеру зачётной книжки задайте минимальное и максимальное значения.\n");
|
||||
}
|
||||
|
||||
if (errors.length() > 0) {
|
||||
MessageWindow.showModal(gui, errors.toString());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean hasValidGroupNumberRange() {
|
||||
if (!searchSettings.isGroupNumberFilterEnabled()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return searchSettings.getMinGroupNumber() != null && searchSettings.getMaxGroupNumber() != null;
|
||||
}
|
||||
|
||||
private boolean hasValidAverageGradeRange() {
|
||||
if (!searchSettings.isAverageGradeFilterEnabled()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return searchSettings.getMinAverageGrade() != null
|
||||
&& searchSettings.getMaxAverageGrade() != null;
|
||||
}
|
||||
|
||||
private boolean hasValidRecordBookNumberRange() {
|
||||
if (!searchSettings.isRecordBookNumberFilterEnabled()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return searchSettings.getMinRecordBookNumber() != null
|
||||
&& searchSettings.getMaxRecordBookNumber() != null;
|
||||
}
|
||||
|
||||
private void showSearchResult() {
|
||||
if (searchResultCollection == null || searchResultCollection.isEmpty()) {
|
||||
|
||||
MessageWindow.showModal(gui, "Результат поиска пуст.");
|
||||
return;
|
||||
}
|
||||
|
||||
CollectionDisplayWindow window = new CollectionDisplayWindow(gui, searchResultCollection);
|
||||
|
||||
window.showModal();
|
||||
}
|
||||
|
||||
private void saveSearchResult() {
|
||||
if (searchResultCollection == null || searchResultCollection.isEmpty()) {
|
||||
|
||||
MessageWindow.showModal(gui, "Результат поиска пуст.");
|
||||
return;
|
||||
}
|
||||
|
||||
CollectionFileSaveWindow window = new CollectionFileSaveWindow(gui, searchResultCollection);
|
||||
|
||||
window.showModal();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
package ru.project.ui.collection.search;
|
||||
|
||||
public class SearchSettings {
|
||||
|
||||
private FilterRelation relation;
|
||||
|
||||
private boolean groupNumberFilterEnabled;
|
||||
private boolean averageGradeFilterEnabled;
|
||||
private boolean recordBookNumberFilterEnabled;
|
||||
|
||||
private String minGroupNumber;
|
||||
private String maxGroupNumber;
|
||||
|
||||
private Double minAverageGrade;
|
||||
private Double maxAverageGrade;
|
||||
|
||||
private Integer minRecordBookNumber;
|
||||
private Integer maxRecordBookNumber;
|
||||
|
||||
public SearchSettings() {
|
||||
this.relation = FilterRelation.AND;
|
||||
|
||||
this.groupNumberFilterEnabled = false;
|
||||
this.averageGradeFilterEnabled = false;
|
||||
this.recordBookNumberFilterEnabled = false;
|
||||
|
||||
this.minGroupNumber = null;
|
||||
this.maxGroupNumber = null;
|
||||
|
||||
this.minAverageGrade = null;
|
||||
this.maxAverageGrade = null;
|
||||
|
||||
this.minRecordBookNumber = null;
|
||||
this.maxRecordBookNumber = null;
|
||||
}
|
||||
|
||||
public FilterRelation getRelation() {
|
||||
return relation;
|
||||
}
|
||||
|
||||
public void setRelation(FilterRelation relation) {
|
||||
this.relation = relation;
|
||||
}
|
||||
|
||||
public boolean isGroupNumberFilterEnabled() {
|
||||
return groupNumberFilterEnabled;
|
||||
}
|
||||
|
||||
public void setGroupNumberFilterEnabled(boolean enabled) {
|
||||
this.groupNumberFilterEnabled = enabled;
|
||||
}
|
||||
|
||||
public boolean isAverageGradeFilterEnabled() {
|
||||
return averageGradeFilterEnabled;
|
||||
}
|
||||
|
||||
public void setAverageGradeFilterEnabled(boolean enabled) {
|
||||
this.averageGradeFilterEnabled = enabled;
|
||||
}
|
||||
|
||||
public boolean isRecordBookNumberFilterEnabled() {
|
||||
return recordBookNumberFilterEnabled;
|
||||
}
|
||||
|
||||
public void setRecordBookNumberFilterEnabled(boolean enabled) {
|
||||
this.recordBookNumberFilterEnabled = enabled;
|
||||
}
|
||||
|
||||
public String getMinGroupNumber() {
|
||||
return minGroupNumber;
|
||||
}
|
||||
|
||||
public void setMinGroupNumber(String minGroupNumber) {
|
||||
this.minGroupNumber = minGroupNumber;
|
||||
}
|
||||
|
||||
public String getMaxGroupNumber() {
|
||||
return maxGroupNumber;
|
||||
}
|
||||
|
||||
public void setMaxGroupNumber(String maxGroupNumber) {
|
||||
this.maxGroupNumber = maxGroupNumber;
|
||||
}
|
||||
|
||||
public Double getMinAverageGrade() {
|
||||
return minAverageGrade;
|
||||
}
|
||||
|
||||
public void setMinAverageGrade(Double minAverageGrade) {
|
||||
this.minAverageGrade = minAverageGrade;
|
||||
}
|
||||
|
||||
public Double getMaxAverageGrade() {
|
||||
return maxAverageGrade;
|
||||
}
|
||||
|
||||
public void setMaxAverageGrade(Double maxAverageGrade) {
|
||||
this.maxAverageGrade = maxAverageGrade;
|
||||
}
|
||||
|
||||
public Integer getMinRecordBookNumber() {
|
||||
return minRecordBookNumber;
|
||||
}
|
||||
|
||||
public void setMinRecordBookNumber(Integer minRecordBookNumber) {
|
||||
this.minRecordBookNumber = minRecordBookNumber;
|
||||
}
|
||||
|
||||
public Integer getMaxRecordBookNumber() {
|
||||
return maxRecordBookNumber;
|
||||
}
|
||||
|
||||
public void setMaxRecordBookNumber(Integer maxRecordBookNumber) {
|
||||
this.maxRecordBookNumber = maxRecordBookNumber;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,355 @@
|
||||
package ru.project.ui.collection.search;
|
||||
|
||||
import com.googlecode.lanterna.gui2.Button;
|
||||
import com.googlecode.lanterna.gui2.CheckBox;
|
||||
import com.googlecode.lanterna.gui2.Label;
|
||||
import com.googlecode.lanterna.gui2.LinearLayout;
|
||||
import com.googlecode.lanterna.gui2.Panel;
|
||||
import com.googlecode.lanterna.gui2.RadioBoxList;
|
||||
import com.googlecode.lanterna.gui2.WindowBasedTextGUI;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
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 SearchSettingsWindow extends BaseModalWindow {
|
||||
|
||||
private final SearchSettings settings;
|
||||
private final Consumer<SearchSettings> onApply;
|
||||
|
||||
private final CheckBox groupNumberFilterCheckBox;
|
||||
private final CheckBox averageGradeFilterCheckBox;
|
||||
private final CheckBox recordBookNumberFilterCheckBox;
|
||||
|
||||
private final Label minGroupNumberLabel;
|
||||
private final Label maxGroupNumberLabel;
|
||||
|
||||
private final Label minAverageGradeLabel;
|
||||
private final Label maxAverageGradeLabel;
|
||||
|
||||
private final Label minRecordBookNumberLabel;
|
||||
private final Label maxRecordBookNumberLabel;
|
||||
|
||||
private final RadioBoxList<String> relationList;
|
||||
|
||||
public SearchSettingsWindow(WindowBasedTextGUI gui, Consumer<SearchSettings> onApply) {
|
||||
|
||||
super("Настройка процесса поиска", gui);
|
||||
|
||||
this.settings = new SearchSettings();
|
||||
this.onApply = onApply;
|
||||
|
||||
Panel panel = new Panel();
|
||||
panel.setLayoutManager(new LinearLayout());
|
||||
|
||||
panel.addComponent(new Label("Отношение фильтров:"));
|
||||
|
||||
relationList = new RadioBoxList<>();
|
||||
relationList.addItem("И");
|
||||
relationList.addItem("ИЛИ");
|
||||
relationList.setCheckedItemIndex(0);
|
||||
|
||||
panel.addComponent(relationList);
|
||||
|
||||
groupNumberFilterCheckBox = new CheckBox("Фильтр по номеру группы");
|
||||
|
||||
averageGradeFilterCheckBox = new CheckBox("Фильтр по среднему баллу");
|
||||
|
||||
recordBookNumberFilterCheckBox = new CheckBox("Фильтр по номеру зачётной книжки");
|
||||
|
||||
panel.addComponent(groupNumberFilterCheckBox);
|
||||
|
||||
minGroupNumberLabel =
|
||||
new Label("Минимум номера группы: " + getValueOrDefault(settings.getMinGroupNumber()));
|
||||
|
||||
maxGroupNumberLabel =
|
||||
new Label("Максимум номера группы: " + getValueOrDefault(settings.getMaxGroupNumber()));
|
||||
|
||||
panel.addComponent(minGroupNumberLabel);
|
||||
panel.addComponent(maxGroupNumberLabel);
|
||||
|
||||
panel.addComponent(new Button("Задать минимум номера группы...", this::setMinGroupNumber));
|
||||
|
||||
panel.addComponent(new Button("Задать максимум номера группы...", this::setMaxGroupNumber));
|
||||
|
||||
panel.addComponent(averageGradeFilterCheckBox);
|
||||
|
||||
minAverageGradeLabel =
|
||||
new Label("Минимум среднего балла: " + getValueOrDefault(settings.getMinAverageGrade()));
|
||||
|
||||
maxAverageGradeLabel =
|
||||
new Label("Максимум среднего балла: " + getValueOrDefault(settings.getMaxAverageGrade()));
|
||||
|
||||
panel.addComponent(minAverageGradeLabel);
|
||||
panel.addComponent(maxAverageGradeLabel);
|
||||
|
||||
panel.addComponent(new Button("Задать минимум среднего балла...", this::setMinAverageGrade));
|
||||
|
||||
panel.addComponent(new Button("Задать максимум среднего балла...", this::setMaxAverageGrade));
|
||||
|
||||
panel.addComponent(recordBookNumberFilterCheckBox);
|
||||
|
||||
minRecordBookNumberLabel =
|
||||
new Label(
|
||||
"Минимум номера зачётной книжки: "
|
||||
+ getValueOrDefault(settings.getMinRecordBookNumber()));
|
||||
|
||||
maxRecordBookNumberLabel =
|
||||
new Label(
|
||||
"Максимум номера зачётной книжки: "
|
||||
+ getValueOrDefault(settings.getMaxRecordBookNumber()));
|
||||
|
||||
panel.addComponent(minRecordBookNumberLabel);
|
||||
panel.addComponent(maxRecordBookNumberLabel);
|
||||
|
||||
panel.addComponent(
|
||||
new Button("Задать минимум номера зачётной книжки...", this::setMinRecordBookNumber));
|
||||
|
||||
panel.addComponent(
|
||||
new Button("Задать максимум номера зачётной книжки...", this::setMaxRecordBookNumber));
|
||||
|
||||
panel.addComponent(new Button("Применить", this::apply));
|
||||
|
||||
panel.addComponent(new Button("Выйти", this::close));
|
||||
|
||||
setComponent(panel);
|
||||
}
|
||||
|
||||
private void setMinGroupNumber() {
|
||||
showGroupNumberInput(
|
||||
"Минимальный номер группы",
|
||||
settings.getMinGroupNumber(),
|
||||
value -> {
|
||||
if (!value.matches(Student.getGroupNumberPattern())) {
|
||||
|
||||
MessageWindow.showModal(gui, "Номер группы должен соответствовать формату A12.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (settings.getMaxGroupNumber() != null
|
||||
&& value.compareTo(settings.getMaxGroupNumber()) > 0) {
|
||||
|
||||
MessageWindow.showModal(
|
||||
gui, "Минимальный номер группы не может быть больше максимального.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
settings.setMinGroupNumber(value);
|
||||
|
||||
minGroupNumberLabel.setText("Минимум номера группы: " + value);
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void setMaxGroupNumber() {
|
||||
showGroupNumberInput(
|
||||
"Максимальный номер группы",
|
||||
settings.getMaxGroupNumber(),
|
||||
value -> {
|
||||
if (!value.matches(Student.getGroupNumberPattern())) {
|
||||
|
||||
MessageWindow.showModal(gui, "Номер группы должен соответствовать формату A12.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (settings.getMinGroupNumber() != null
|
||||
&& value.compareTo(settings.getMinGroupNumber()) < 0) {
|
||||
|
||||
MessageWindow.showModal(
|
||||
gui, "Максимальный номер группы не может быть меньше минимального.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
settings.setMaxGroupNumber(value);
|
||||
|
||||
maxGroupNumberLabel.setText("Максимум номера группы: " + value);
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void showGroupNumberInput(String title, String initialValue, Predicate<String> onSave) {
|
||||
|
||||
InputValueWindow window =
|
||||
new InputValueWindow(
|
||||
gui, title, "Введите номер группы (например, A12):", initialValue, onSave);
|
||||
|
||||
window.showModal();
|
||||
}
|
||||
|
||||
private void setMinAverageGrade() {
|
||||
showAverageGradeInput(
|
||||
"Минимальный средний балл",
|
||||
settings.getMinAverageGrade(),
|
||||
value -> {
|
||||
if (settings.getMaxAverageGrade() != null && value > settings.getMaxAverageGrade()) {
|
||||
|
||||
MessageWindow.showModal(
|
||||
gui, "Минимальный средний балл не может быть больше максимального.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
settings.setMinAverageGrade(value);
|
||||
|
||||
minAverageGradeLabel.setText("Минимум среднего балла: " + value);
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void setMaxAverageGrade() {
|
||||
showAverageGradeInput(
|
||||
"Максимальный средний балл",
|
||||
settings.getMaxAverageGrade(),
|
||||
value -> {
|
||||
if (settings.getMinAverageGrade() != null && value < settings.getMinAverageGrade()) {
|
||||
|
||||
MessageWindow.showModal(
|
||||
gui, "Максимальный средний балл не может быть меньше минимального.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
settings.setMaxAverageGrade(value);
|
||||
|
||||
maxAverageGradeLabel.setText("Максимум среднего балла: " + value);
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void showAverageGradeInput(String title, Double initialValue, Predicate<Double> onSave) {
|
||||
|
||||
InputValueWindow window =
|
||||
new InputValueWindow(
|
||||
gui,
|
||||
title,
|
||||
"Введите значение от 0.0 до 5.0:",
|
||||
initialValue == null ? null : String.valueOf(initialValue),
|
||||
value -> {
|
||||
try {
|
||||
double parsedValue = Double.parseDouble(value);
|
||||
|
||||
if (parsedValue < Student.getMinAverageGrade()
|
||||
|| parsedValue > Student.getMaxAverageGrade()) {
|
||||
|
||||
MessageWindow.showModal(gui, "Средний балл должен быть от 0.0 до 5.0.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return onSave.test(parsedValue);
|
||||
|
||||
} catch (NumberFormatException e) {
|
||||
MessageWindow.showModal(gui, "Введите корректное число.");
|
||||
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
window.showModal();
|
||||
}
|
||||
|
||||
private void setMinRecordBookNumber() {
|
||||
showRecordBookNumberInput(
|
||||
"Минимальный номер зачётной книжки",
|
||||
settings.getMinRecordBookNumber(),
|
||||
value -> {
|
||||
if (settings.getMaxRecordBookNumber() != null
|
||||
&& value > settings.getMaxRecordBookNumber()) {
|
||||
|
||||
MessageWindow.showModal(
|
||||
gui, "Минимальный номер зачётной книжки не может быть больше максимального.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
settings.setMinRecordBookNumber(value);
|
||||
|
||||
minRecordBookNumberLabel.setText("Минимум номера зачётной книжки: " + value);
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void setMaxRecordBookNumber() {
|
||||
showRecordBookNumberInput(
|
||||
"Максимальный номер зачётной книжки",
|
||||
settings.getMaxRecordBookNumber(),
|
||||
value -> {
|
||||
if (settings.getMinRecordBookNumber() != null
|
||||
&& value < settings.getMinRecordBookNumber()) {
|
||||
|
||||
MessageWindow.showModal(
|
||||
gui, "Максимальный номер зачётной книжки не может быть меньше минимального.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
settings.setMaxRecordBookNumber(value);
|
||||
|
||||
maxRecordBookNumberLabel.setText("Максимум номера зачётной книжки: " + value);
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void showRecordBookNumberInput(
|
||||
String title, Integer initialValue, Predicate<Integer> onSave) {
|
||||
|
||||
InputValueWindow window =
|
||||
new InputValueWindow(
|
||||
gui,
|
||||
title,
|
||||
"Введите номер зачётной книжки:",
|
||||
initialValue == null ? null : String.valueOf(initialValue),
|
||||
value -> {
|
||||
try {
|
||||
int parsedValue = Integer.parseInt(value);
|
||||
|
||||
if (parsedValue < Student.getMinRecordBookNumber()) {
|
||||
|
||||
MessageWindow.showModal(gui, "Номер зачётной книжки должен быть положительным.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return onSave.test(parsedValue);
|
||||
|
||||
} catch (NumberFormatException e) {
|
||||
MessageWindow.showModal(gui, "Введите целое число.");
|
||||
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
window.showModal();
|
||||
}
|
||||
|
||||
private void apply() {
|
||||
settings.setGroupNumberFilterEnabled(groupNumberFilterCheckBox.isChecked());
|
||||
|
||||
settings.setAverageGradeFilterEnabled(averageGradeFilterCheckBox.isChecked());
|
||||
|
||||
settings.setRecordBookNumberFilterEnabled(recordBookNumberFilterCheckBox.isChecked());
|
||||
|
||||
settings.setRelation(
|
||||
relationList.getCheckedItemIndex() == 0 ? FilterRelation.AND : FilterRelation.OR);
|
||||
|
||||
onApply.accept(settings);
|
||||
|
||||
MessageWindow.showModal(gui, "Настройки процесса поиска успешно применены.");
|
||||
}
|
||||
|
||||
private String getValueOrDefault(Object value) {
|
||||
return value == null ? "не задан" : String.valueOf(value);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package ru.project.ui.sorting;
|
||||
package ru.project.ui.collection.sorting;
|
||||
|
||||
import com.googlecode.lanterna.gui2.ActionListBox;
|
||||
import com.googlecode.lanterna.gui2.Button;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package ru.project.ui.sorting;
|
||||
package ru.project.ui.collection.sorting;
|
||||
|
||||
import com.googlecode.lanterna.gui2.Button;
|
||||
import com.googlecode.lanterna.gui2.Label;
|
||||
@@ -0,0 +1,6 @@
|
||||
package ru.project.ui.collection.sorting;
|
||||
|
||||
public enum SortAlgorithm {
|
||||
BUBBLE,
|
||||
MERGE
|
||||
}
|
||||
+102
-13
@@ -1,11 +1,20 @@
|
||||
package ru.project.ui.sorting;
|
||||
package ru.project.ui.collection.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 java.util.Comparator;
|
||||
import ru.project.model.AppState;
|
||||
import ru.project.sorting.BubbleSortStrategy;
|
||||
import ru.project.sorting.EvenOnlySortStrategy;
|
||||
import ru.project.sorting.MergeSortStrategy;
|
||||
import ru.project.sorting.SortStrategy;
|
||||
import ru.project.sorting.StudentAverageGradeComparator;
|
||||
import ru.project.sorting.StudentGroupComparator;
|
||||
import ru.project.sorting.StudentRecordBookComparator;
|
||||
import ru.project.student.Student;
|
||||
import ru.project.ui.base.BaseModalWindow;
|
||||
import ru.project.ui.common.MessageWindow;
|
||||
|
||||
@@ -13,30 +22,39 @@ public class SortCollectionMenu extends BaseModalWindow {
|
||||
|
||||
private final AppState state;
|
||||
|
||||
private final Label sortMethodLabel;
|
||||
private final Label sortAlgorithmLabel;
|
||||
private final Label sortFieldLabel;
|
||||
private final Label sortMethodLabel;
|
||||
|
||||
private final SortMethodSelectionWindow sortMethodSelectionWindow;
|
||||
private final NormalSortSettingsWindow normalSortSettingsWindow;
|
||||
private final ParitySortSettingsWindow paritySortSettingsWindow;
|
||||
private final SortMethodSelectionWindow sortMethodSelectionWindow;
|
||||
private final SortStrategySelectionWindow sortStrategySelectionWindow;
|
||||
|
||||
private SortMethod selectedSortMethod;
|
||||
private SortAlgorithm selectedSortAlgorithm;
|
||||
private SortField selectedSortField;
|
||||
private SortMethod selectedSortMethod;
|
||||
|
||||
public SortCollectionMenu(WindowBasedTextGUI gui, AppState state) {
|
||||
|
||||
super("Меню сортировки текущей коллекции", gui);
|
||||
|
||||
this.state = state;
|
||||
this.selectedSortMethod = SortMethod.NORMAL;
|
||||
|
||||
this.selectedSortAlgorithm = SortAlgorithm.BUBBLE;
|
||||
this.selectedSortField = SortField.GROUP_NUMBER;
|
||||
this.selectedSortMethod = SortMethod.NORMAL;
|
||||
|
||||
Panel panel = new Panel();
|
||||
panel.setLayoutManager(new LinearLayout());
|
||||
|
||||
this.sortMethodLabel = new Label("Способ сортировки: " + getSortMethodName(selectedSortMethod));
|
||||
|
||||
this.sortFieldLabel = new Label("Сортировать по: " + getSortFieldName(selectedSortField));
|
||||
this.sortAlgorithmLabel =
|
||||
new Label("Алгоритм сортировки: " + getSortAlgorithmName(selectedSortAlgorithm));
|
||||
|
||||
this.sortFieldLabel =
|
||||
new Label("Сортировать по: " + getSortFieldName(selectedSortMethod, selectedSortField));
|
||||
|
||||
this.sortMethodSelectionWindow =
|
||||
new SortMethodSelectionWindow(
|
||||
@@ -46,6 +64,19 @@ public class SortCollectionMenu extends BaseModalWindow {
|
||||
|
||||
sortMethodLabel.setText(
|
||||
"Способ сортировки: " + getSortMethodName(selectedSortMethod));
|
||||
|
||||
sortFieldLabel.setText(
|
||||
"Сортировать по: " + getSortFieldName(selectedSortMethod, selectedSortField));
|
||||
});
|
||||
|
||||
this.sortStrategySelectionWindow =
|
||||
new SortStrategySelectionWindow(
|
||||
gui,
|
||||
sortAlgorithm -> {
|
||||
selectedSortAlgorithm = sortAlgorithm;
|
||||
|
||||
sortAlgorithmLabel.setText(
|
||||
"Алгоритм сортировки: " + getSortAlgorithmName(selectedSortAlgorithm));
|
||||
});
|
||||
|
||||
this.normalSortSettingsWindow =
|
||||
@@ -53,17 +84,23 @@ public class SortCollectionMenu extends BaseModalWindow {
|
||||
gui,
|
||||
sortField -> {
|
||||
selectedSortField = sortField;
|
||||
|
||||
sortFieldLabel.setText(
|
||||
"Сортировать по: " + getSortFieldName(selectedSortMethod, selectedSortField));
|
||||
});
|
||||
|
||||
this.paritySortSettingsWindow = new ParitySortSettingsWindow(gui);
|
||||
|
||||
panel.addComponent(sortMethodLabel);
|
||||
panel.addComponent(sortFieldLabel);
|
||||
panel.addComponent(sortAlgorithmLabel);
|
||||
|
||||
panel.addComponent(new Button("Выбрать способ сортировки", this::selectSortMethod));
|
||||
panel.addComponent(new Button("Выбрать способ сортировки...", this::selectSortMethod));
|
||||
|
||||
panel.addComponent(new Button("Выбрать алгоритм сортировки...", this::selectSortAlgorithm));
|
||||
|
||||
panel.addComponent(
|
||||
new Button("Настроить текущий способ сортировки", this::setupCurrentSortMethod));
|
||||
new Button("Настроить текущий способ сортировки...", this::setupCurrentSortMethod));
|
||||
|
||||
panel.addComponent(new Button("Сортировать текущую коллекцию", this::sortCurrentCollection));
|
||||
|
||||
@@ -84,6 +121,10 @@ public class SortCollectionMenu extends BaseModalWindow {
|
||||
sortMethodSelectionWindow.showModal();
|
||||
}
|
||||
|
||||
private void selectSortAlgorithm() {
|
||||
sortStrategySelectionWindow.showModal();
|
||||
}
|
||||
|
||||
private void sortCurrentCollection() {
|
||||
if (state.getMainCollection() == null || state.getMainCollection().isEmpty()) {
|
||||
|
||||
@@ -100,26 +141,74 @@ public class SortCollectionMenu extends BaseModalWindow {
|
||||
}
|
||||
|
||||
private void sortNormally() {
|
||||
// TODO
|
||||
MessageWindow.showModal(gui, "Обычная сортировка не реализована.");
|
||||
SortStrategy<Student> sortStrategy = getSortStrategy();
|
||||
|
||||
Comparator<Student> comparator = getSortComparator();
|
||||
|
||||
sortStrategy.sort(state.getMainCollection(), comparator);
|
||||
|
||||
MessageWindow.showModal(gui, "Обычная сортировка успешно выполнена.");
|
||||
}
|
||||
|
||||
private void sortByParity() {
|
||||
// TODO
|
||||
MessageWindow.showModal(gui, "Сортировка по чётности не реализована.");
|
||||
SortStrategy<Student> sortStrategy =
|
||||
new EvenOnlySortStrategy<>(getSortStrategy(), Student::getRecordBookNumber);
|
||||
|
||||
Comparator<Student> comparator = new StudentRecordBookComparator();
|
||||
|
||||
sortStrategy.sort(state.getMainCollection(), comparator);
|
||||
|
||||
MessageWindow.showModal(gui, "Сортировка по чётности успешно выполнена.");
|
||||
}
|
||||
|
||||
private SortStrategy<Student> getSortStrategy() {
|
||||
return switch (selectedSortAlgorithm) {
|
||||
case BUBBLE -> new BubbleSortStrategy<>();
|
||||
|
||||
case MERGE -> new MergeSortStrategy<>();
|
||||
};
|
||||
}
|
||||
|
||||
private Comparator<Student> getSortComparator() {
|
||||
return switch (selectedSortField) {
|
||||
case GROUP_NUMBER -> new StudentGroupComparator();
|
||||
|
||||
case AVERAGE_GRADE -> new StudentAverageGradeComparator();
|
||||
|
||||
case RECORD_BOOK_NUMBER -> new StudentRecordBookComparator();
|
||||
};
|
||||
}
|
||||
|
||||
private String getSortMethodName(SortMethod sortMethod) {
|
||||
return switch (sortMethod) {
|
||||
case NORMAL -> "Обычная сортировка";
|
||||
|
||||
case PARITY -> "Сортировка по чётности";
|
||||
};
|
||||
}
|
||||
|
||||
private String getSortFieldName(SortField sortField) {
|
||||
private String getSortAlgorithmName(SortAlgorithm sortAlgorithm) {
|
||||
return switch (sortAlgorithm) {
|
||||
case BUBBLE -> "Сортировка пузырьком";
|
||||
|
||||
case MERGE -> "Сортировка слиянием";
|
||||
};
|
||||
}
|
||||
|
||||
private String getSortFieldName(SortMethod sortMethod, SortField sortField) {
|
||||
return switch (sortMethod) {
|
||||
case NORMAL -> getNormalSortFieldName(sortField);
|
||||
|
||||
case PARITY -> "номеру зачётной книжки";
|
||||
};
|
||||
}
|
||||
|
||||
private String getNormalSortFieldName(SortField sortField) {
|
||||
return switch (sortField) {
|
||||
case GROUP_NUMBER -> "номеру группы";
|
||||
|
||||
case AVERAGE_GRADE -> "среднему баллу";
|
||||
|
||||
case RECORD_BOOK_NUMBER -> "номеру зачётной книжки";
|
||||
};
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package ru.project.ui.sorting;
|
||||
package ru.project.ui.collection.sorting;
|
||||
|
||||
public enum SortField {
|
||||
GROUP_NUMBER,
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package ru.project.ui.sorting;
|
||||
package ru.project.ui.collection.sorting;
|
||||
|
||||
public enum SortMethod {
|
||||
NORMAL,
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package ru.project.ui.sorting;
|
||||
package ru.project.ui.collection.sorting;
|
||||
|
||||
import com.googlecode.lanterna.gui2.ActionListBox;
|
||||
import com.googlecode.lanterna.gui2.WindowBasedTextGUI;
|
||||
@@ -0,0 +1,34 @@
|
||||
package ru.project.ui.collection.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 SortStrategySelectionWindow extends BaseModalWindow {
|
||||
|
||||
private final Consumer<SortAlgorithm> onSortAlgorithmSelected;
|
||||
|
||||
public SortStrategySelectionWindow(
|
||||
WindowBasedTextGUI gui, Consumer<SortAlgorithm> onSortAlgorithmSelected) {
|
||||
|
||||
super("Выбор алгоритма сортировки", gui);
|
||||
|
||||
this.onSortAlgorithmSelected = onSortAlgorithmSelected;
|
||||
|
||||
ActionListBox menu = new ActionListBox();
|
||||
|
||||
menu.addItem("Сортировка пузырьком", () -> selectSortAlgorithm(SortAlgorithm.BUBBLE));
|
||||
|
||||
menu.addItem("Сортировка слиянием", () -> selectSortAlgorithm(SortAlgorithm.MERGE));
|
||||
|
||||
menu.addItem("Выйти", this::close);
|
||||
|
||||
setComponent(menu);
|
||||
}
|
||||
|
||||
private void selectSortAlgorithm(SortAlgorithm sortAlgorithm) {
|
||||
onSortAlgorithmSelected.accept(sortAlgorithm);
|
||||
close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package ru.project.ui.common;
|
||||
|
||||
import com.googlecode.lanterna.gui2.WindowBasedTextGUI;
|
||||
import com.googlecode.lanterna.gui2.dialogs.FileDialogBuilder;
|
||||
import com.googlecode.lanterna.gui2.dialogs.MessageDialog;
|
||||
import com.googlecode.lanterna.gui2.dialogs.MessageDialogButton;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import ru.project.collection.MyList;
|
||||
import ru.project.io.StudentCsvWriter;
|
||||
import ru.project.student.Student;
|
||||
|
||||
public class CollectionFileSaveWindow {
|
||||
|
||||
private final WindowBasedTextGUI gui;
|
||||
private final MyList<Student> collection;
|
||||
|
||||
public CollectionFileSaveWindow(WindowBasedTextGUI gui, MyList<Student> collection) {
|
||||
|
||||
this.gui = gui;
|
||||
this.collection = collection;
|
||||
}
|
||||
|
||||
public void showModal() {
|
||||
File selectedFile = selectFile();
|
||||
|
||||
if (selectedFile == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedFile.exists()) {
|
||||
saveToFile(selectedFile);
|
||||
return;
|
||||
}
|
||||
|
||||
MessageDialogButton result =
|
||||
MessageDialog.showMessageDialog(
|
||||
gui,
|
||||
"Создание файла",
|
||||
"Файл не существует. Создать новый файл?",
|
||||
MessageDialogButton.Yes,
|
||||
MessageDialogButton.No);
|
||||
|
||||
if (result == MessageDialogButton.Yes) {
|
||||
createAndSaveToFile(selectedFile);
|
||||
}
|
||||
}
|
||||
|
||||
private File selectFile() {
|
||||
return new FileDialogBuilder()
|
||||
.setTitle("Сохранение коллекции")
|
||||
.setDescription("Выберите файл:")
|
||||
.setActionLabel("Сохранить")
|
||||
.build()
|
||||
.showDialog(gui);
|
||||
}
|
||||
|
||||
private void createAndSaveToFile(File file) {
|
||||
try {
|
||||
if (!file.createNewFile()) {
|
||||
MessageWindow.showModal(gui, "Не удалось создать файл.");
|
||||
return;
|
||||
}
|
||||
|
||||
saveToFile(file);
|
||||
|
||||
} catch (IOException e) {
|
||||
MessageWindow.showModal(gui, "Не удалось создать файл.");
|
||||
}
|
||||
}
|
||||
|
||||
private void saveToFile(File file) {
|
||||
try {
|
||||
StudentCsvWriter writer = new StudentCsvWriter(file.getAbsolutePath());
|
||||
|
||||
for (int i = 0; i < collection.size(); i++) {
|
||||
writer.write(collection.get(i));
|
||||
}
|
||||
|
||||
MessageWindow.showModal(gui, "Коллекция успешно сохранена.");
|
||||
|
||||
} catch (IOException e) {
|
||||
MessageWindow.showModal(gui, "Не удалось сохранить коллекцию.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package ru.project.ui.common;
|
||||
|
||||
import com.googlecode.lanterna.gui2.WindowBasedTextGUI;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class CollectionSizeInputWindow {
|
||||
|
||||
private final WindowBasedTextGUI gui;
|
||||
private final Integer currentSize;
|
||||
private final Consumer<Integer> onSizeEntered;
|
||||
|
||||
public CollectionSizeInputWindow(
|
||||
WindowBasedTextGUI gui, Integer currentSize, Consumer<Integer> onSizeEntered) {
|
||||
|
||||
this.gui = gui;
|
||||
this.currentSize = currentSize;
|
||||
this.onSizeEntered = onSizeEntered;
|
||||
}
|
||||
|
||||
public void showModal() {
|
||||
InputValueWindow window =
|
||||
new InputValueWindow(
|
||||
gui,
|
||||
"Размер коллекции",
|
||||
"Введите размер коллекции:",
|
||||
currentSize != null && currentSize > 0 ? String.valueOf(currentSize) : null,
|
||||
this::handleSizeEntered);
|
||||
|
||||
window.showModal();
|
||||
}
|
||||
|
||||
private boolean handleSizeEntered(String value) {
|
||||
try {
|
||||
int size = Integer.parseInt(value);
|
||||
|
||||
if (size <= 0) {
|
||||
MessageWindow.showModal(gui, "Размер должен быть больше 0.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
onSizeEntered.accept(size);
|
||||
return true;
|
||||
|
||||
} catch (NumberFormatException e) {
|
||||
MessageWindow.showModal(gui, "Введите целое число.");
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,97 +5,82 @@ 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;
|
||||
import ru.project.ui.creation.file.FileDataSettingsWindow;
|
||||
import ru.project.ui.creation.file.FileFillSettings;
|
||||
import ru.project.ui.creation.file.FileFillStrategy;
|
||||
import ru.project.ui.creation.manual.ManualDataSettingsWindow;
|
||||
import ru.project.ui.creation.manual.ManualFillSettings;
|
||||
import ru.project.ui.creation.manual.ManualFillStrategy;
|
||||
import ru.project.ui.creation.random.RandomDataSettingsWindow;
|
||||
import ru.project.ui.creation.random.RandomFillSettings;
|
||||
import ru.project.ui.creation.random.RandomFillStrategy;
|
||||
|
||||
public class CreateCollectionMenu extends BaseModalWindow {
|
||||
|
||||
private int collectionSize;
|
||||
private FillMethod selectedFillMethod;
|
||||
private final AppState state;
|
||||
|
||||
private FillMethod selectedFillMethod;
|
||||
private FillStrategy fillStrategy;
|
||||
|
||||
private final Label sizeLabel;
|
||||
private final Label fillMethodLabel;
|
||||
|
||||
private final CustomDataSettingsWindow customDataSettingsWindow;
|
||||
private final ManualDataSettingsWindow manualDataSettingsWindow;
|
||||
private final FileDataSettingsWindow fileDataSettingsWindow;
|
||||
private final RandomDataSettingsWindow randomDataSettingsWindow;
|
||||
|
||||
public CreateCollectionMenu(WindowBasedTextGUI gui, AppState state) {
|
||||
|
||||
super("Создание новой коллекции", gui);
|
||||
|
||||
collectionSize = 0;
|
||||
selectedFillMethod = FillMethod.CUSTOM;
|
||||
this.state = state;
|
||||
this.selectedFillMethod = FillMethod.CUSTOM;
|
||||
this.fillStrategy = null;
|
||||
|
||||
customDataSettingsWindow = new CustomDataSettingsWindow(gui, state, () -> collectionSize);
|
||||
this.manualDataSettingsWindow = new ManualDataSettingsWindow(gui, this::setManualFillStrategy);
|
||||
this.fileDataSettingsWindow = new FileDataSettingsWindow(gui, this::setFileFillStrategy);
|
||||
this.randomDataSettingsWindow = new RandomDataSettingsWindow(gui, this::setRandomFillStrategy);
|
||||
|
||||
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::selectFillMethod));
|
||||
|
||||
panel.addComponent(
|
||||
new Button("Настроить текущий способ заполнения", this::setupCurrentFillMethod));
|
||||
new Button("Настроить текущий способ заполнения...", this::setupCurrentFillMethod));
|
||||
|
||||
panel.addComponent(new Button("Создать новую коллекцию", () -> updateMainCollection(state)));
|
||||
panel.addComponent(new Button("Создать новую коллекцию", this::updateMainCollection));
|
||||
|
||||
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 void setManualFillStrategy(ManualFillSettings settings) {
|
||||
fillStrategy = new ManualFillStrategy(settings);
|
||||
}
|
||||
|
||||
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 setFileFillStrategy(FileFillSettings settings) {
|
||||
fillStrategy = new FileFillStrategy(settings);
|
||||
}
|
||||
|
||||
private void setRandomFillStrategy(RandomFillSettings settings) {
|
||||
fillStrategy = new RandomFillStrategy(settings);
|
||||
}
|
||||
|
||||
private void setupCurrentFillMethod() {
|
||||
switch (selectedFillMethod) {
|
||||
case CUSTOM -> {
|
||||
customDataSettingsWindow.showModal();
|
||||
}
|
||||
case CUSTOM -> manualDataSettingsWindow.showModal();
|
||||
|
||||
case FILE ->
|
||||
// TODO
|
||||
MessageWindow.showModal(gui, "Не реализовано.");
|
||||
case FILE -> fileDataSettingsWindow.showModal();
|
||||
|
||||
case RANDOM ->
|
||||
MessageWindow.showModal(
|
||||
gui, "Для случайных данных дополнительные настройки не требуются.");
|
||||
case RANDOM -> randomDataSettingsWindow.showModal();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,6 +90,7 @@ public class CreateCollectionMenu extends BaseModalWindow {
|
||||
gui,
|
||||
fillMethod -> {
|
||||
selectedFillMethod = fillMethod;
|
||||
|
||||
fillMethodLabel.setText(
|
||||
"Способ заполнения: " + getFillMethodName(selectedFillMethod));
|
||||
});
|
||||
@@ -112,57 +98,22 @@ public class CreateCollectionMenu extends BaseModalWindow {
|
||||
menu.showModal();
|
||||
}
|
||||
|
||||
private void updateMainCollection(AppState state) {
|
||||
if (collectionSize <= 0) {
|
||||
MessageWindow.showModal(gui, "Сначала задайте размер коллекции.");
|
||||
private void updateMainCollection() {
|
||||
if (fillStrategy == null) {
|
||||
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);
|
||||
state.setMainCollection(fillStrategy.create());
|
||||
|
||||
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,9 @@
|
||||
package ru.project.ui.creation;
|
||||
|
||||
import ru.project.collection.MyList;
|
||||
import ru.project.student.Student;
|
||||
|
||||
public interface FillStrategy {
|
||||
|
||||
MyList<Student> create();
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package ru.project.ui.creation.file;
|
||||
|
||||
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 com.googlecode.lanterna.gui2.dialogs.FileDialog;
|
||||
import com.googlecode.lanterna.gui2.dialogs.FileDialogBuilder;
|
||||
import java.io.File;
|
||||
import java.util.function.Consumer;
|
||||
import ru.project.ui.base.BaseModalWindow;
|
||||
|
||||
public class FileDataSettingsWindow extends BaseModalWindow {
|
||||
|
||||
// private final StudentBuilder studentBuilder;
|
||||
|
||||
private final FileFillSettings settings;
|
||||
private final Consumer<FileFillSettings> onApply;
|
||||
|
||||
private final Label filePathLabel;
|
||||
|
||||
public FileDataSettingsWindow(WindowBasedTextGUI gui, Consumer<FileFillSettings> onApply) {
|
||||
|
||||
super("Данные из файла", gui);
|
||||
|
||||
this.onApply = onApply;
|
||||
|
||||
this.settings = new FileFillSettings();
|
||||
// this.studentBuilder = new StudentBuilder();
|
||||
|
||||
Panel panel = new Panel();
|
||||
panel.setLayoutManager(new LinearLayout());
|
||||
|
||||
filePathLabel = new Label("Абсолютный путь: " + getFilePathLabel());
|
||||
|
||||
panel.addComponent(filePathLabel);
|
||||
|
||||
panel.addComponent(new Button("Выбрать файл", this::selectFile));
|
||||
|
||||
panel.addComponent(new Button("Применить", this::apply));
|
||||
|
||||
panel.addComponent(new Button("Выйти", this::close));
|
||||
|
||||
setComponent(panel);
|
||||
}
|
||||
|
||||
private void selectFile() {
|
||||
FileDialog fileDialog =
|
||||
new FileDialogBuilder()
|
||||
.setTitle("Выбор файла")
|
||||
.setDescription("Выберите файл:")
|
||||
.setActionLabel("Открыть")
|
||||
.build();
|
||||
|
||||
File selectedFile = fileDialog.showDialog(gui);
|
||||
|
||||
if (selectedFile == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
settings.setAbsoluteFilePath(selectedFile.getAbsolutePath());
|
||||
|
||||
filePathLabel.setText("Абсолютный путь: " + settings.getAbsoluteFilePath());
|
||||
}
|
||||
|
||||
private void apply() {
|
||||
onApply.accept(settings);
|
||||
|
||||
close();
|
||||
}
|
||||
|
||||
private String getFilePathLabel() {
|
||||
String filePath = settings.getAbsoluteFilePath();
|
||||
|
||||
return filePath == null || filePath.isBlank() ? "не задан" : filePath;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package ru.project.ui.creation.file;
|
||||
|
||||
public class FileFillSettings {
|
||||
|
||||
private String absoluteFilePath;
|
||||
|
||||
public FileFillSettings() {
|
||||
this.absoluteFilePath = null;
|
||||
}
|
||||
|
||||
public String getAbsoluteFilePath() {
|
||||
return absoluteFilePath;
|
||||
}
|
||||
|
||||
public void setAbsoluteFilePath(String absoluteFilePath) {
|
||||
this.absoluteFilePath = absoluteFilePath;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package ru.project.ui.creation.file;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import ru.project.collection.MyLinkedList;
|
||||
import ru.project.collection.MyList;
|
||||
import ru.project.io.StudentCsvReader;
|
||||
import ru.project.student.Student;
|
||||
import ru.project.ui.creation.FillStrategy;
|
||||
|
||||
public class FileFillStrategy implements FillStrategy {
|
||||
|
||||
private final FileFillSettings settings;
|
||||
|
||||
public FileFillStrategy(FileFillSettings settings) {
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MyList<Student> create() {
|
||||
MyList<Student> collection = new MyLinkedList<>();
|
||||
|
||||
Path path = Path.of(settings.getAbsoluteFilePath());
|
||||
|
||||
try (StudentCsvReader reader = new StudentCsvReader(path)) {
|
||||
|
||||
while (reader.hasNext()) {
|
||||
collection.add(reader.next());
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Не удалось прочитать коллекцию из файла.", e);
|
||||
}
|
||||
|
||||
return collection;
|
||||
}
|
||||
}
|
||||
+93
-44
@@ -1,32 +1,32 @@
|
||||
package ru.project.ui.creation;
|
||||
package ru.project.ui.creation.manual;
|
||||
|
||||
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 java.util.function.Consumer;
|
||||
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.CollectionSizeInputWindow;
|
||||
import ru.project.ui.common.InputValueWindow;
|
||||
import ru.project.ui.common.MessageWindow;
|
||||
|
||||
public class CustomDataSettingsWindow extends BaseModalWindow {
|
||||
public class ManualDataSettingsWindow 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 Integer lastRequestedCollectionSize;
|
||||
private String lastRequestedGroupNumber;
|
||||
private Double lastRequestedAverageGrade;
|
||||
private Integer lastRequestedRecordBookNumber;
|
||||
private Integer lastRequestedSelectedObjectIndex;
|
||||
|
||||
private final Label sizeLabel;
|
||||
private final Label groupNumberLabel;
|
||||
private final Label averageGradeLabel;
|
||||
private final Label recordBookNumberLabel;
|
||||
@@ -34,19 +34,23 @@ public class CustomDataSettingsWindow extends BaseModalWindow {
|
||||
|
||||
private MyList<Student> preparedCustomDataCollection;
|
||||
|
||||
public CustomDataSettingsWindow(
|
||||
WindowBasedTextGUI gui, AppState state, Supplier<Integer> collectionSize) {
|
||||
private final ManualFillSettings settings;
|
||||
private final Consumer<ManualFillSettings> onApply;
|
||||
|
||||
public ManualDataSettingsWindow(WindowBasedTextGUI gui, Consumer<ManualFillSettings> onApply) {
|
||||
|
||||
super("Настройка пользовательских данных", gui);
|
||||
|
||||
this.state = state;
|
||||
this.requestedCollectionSize = collectionSize;
|
||||
this.onApply = onApply;
|
||||
|
||||
this.settings = new ManualFillSettings();
|
||||
this.studentBuilder = new StudentBuilder();
|
||||
|
||||
Panel panel = new Panel();
|
||||
panel.setLayoutManager(new LinearLayout());
|
||||
|
||||
sizeLabel = new Label("Размер: не задан");
|
||||
|
||||
groupNumberLabel = new Label("Номер группы: не задан");
|
||||
|
||||
averageGradeLabel = new Label("Средний балл: не задан");
|
||||
@@ -55,11 +59,14 @@ public class CustomDataSettingsWindow extends BaseModalWindow {
|
||||
|
||||
indexLabel = new Label("Индекс объекта: не задан");
|
||||
|
||||
panel.addComponent(sizeLabel);
|
||||
panel.addComponent(groupNumberLabel);
|
||||
panel.addComponent(averageGradeLabel);
|
||||
panel.addComponent(recordBookNumberLabel);
|
||||
panel.addComponent(indexLabel);
|
||||
|
||||
panel.addComponent(new Button("Задать размер", this::showCollectionSizeInputWindow));
|
||||
|
||||
panel.addComponent(new Button("Задать номер группы", this::setGroupNumber));
|
||||
|
||||
panel.addComponent(new Button("Задать средний балл", this::setAverageGrade));
|
||||
@@ -79,25 +86,65 @@ public class CustomDataSettingsWindow extends BaseModalWindow {
|
||||
setComponent(panel);
|
||||
}
|
||||
|
||||
private void showCollectionSizeInputWindow() {
|
||||
CollectionSizeInputWindow window =
|
||||
new CollectionSizeInputWindow(
|
||||
gui, preparedCustomDataCollection.size(), this::handleCollectionSizeEntered);
|
||||
|
||||
window.showModal();
|
||||
}
|
||||
|
||||
private void handleCollectionSizeEntered(int size) {
|
||||
MyList<Student> resizedCollection = new MyLinkedList<>();
|
||||
|
||||
int currentCollectionSize = preparedCustomDataCollection.size();
|
||||
|
||||
int elementsToCopy = Math.min(currentCollectionSize, size);
|
||||
|
||||
for (int i = 0; i < elementsToCopy; i++) {
|
||||
resizedCollection.add(preparedCustomDataCollection.get(i));
|
||||
}
|
||||
|
||||
for (int i = elementsToCopy; i < size; i++) {
|
||||
resizedCollection.add(null);
|
||||
}
|
||||
|
||||
preparedCustomDataCollection = resizedCollection;
|
||||
lastRequestedCollectionSize = size;
|
||||
|
||||
if (lastRequestedSelectedObjectIndex != null
|
||||
&& lastRequestedSelectedObjectIndex >= lastRequestedCollectionSize) {
|
||||
lastRequestedSelectedObjectIndex = null;
|
||||
indexLabel.setText("Индекс объекта: не задан");
|
||||
}
|
||||
|
||||
sizeLabel.setText("Размер: " + lastRequestedCollectionSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showModal() {
|
||||
prepareCustomDataCollection();
|
||||
|
||||
super.showModal();
|
||||
}
|
||||
|
||||
private void prepareCustomDataCollection() {
|
||||
MyList<Student> currentCustomDataCollection = settings.getCollection();
|
||||
|
||||
preparedCustomDataCollection = new MyLinkedList<>();
|
||||
|
||||
int targetCollectionSize = requestedCollectionSize.get();
|
||||
int currentCustomDataCollectionSize = state.getCustomDataCollection().size();
|
||||
int currentCollectionSize = currentCustomDataCollection.size();
|
||||
|
||||
int elementsToCopy = Math.min(currentCustomDataCollectionSize, targetCollectionSize);
|
||||
int targetSize =
|
||||
lastRequestedCollectionSize == null ? currentCollectionSize : lastRequestedCollectionSize;
|
||||
|
||||
int elementsToCopy = Math.min(currentCollectionSize, targetSize);
|
||||
|
||||
for (int i = 0; i < elementsToCopy; i++) {
|
||||
preparedCustomDataCollection.add(state.getCustomDataCollection().get(i));
|
||||
preparedCustomDataCollection.add(currentCustomDataCollection.get(i));
|
||||
}
|
||||
|
||||
for (int i = elementsToCopy; i < targetCollectionSize; i++) {
|
||||
for (int i = elementsToCopy; i < targetSize; i++) {
|
||||
preparedCustomDataCollection.add(null);
|
||||
}
|
||||
}
|
||||
@@ -108,17 +155,17 @@ public class CustomDataSettingsWindow extends BaseModalWindow {
|
||||
gui,
|
||||
"Номер группы",
|
||||
"Введите номер группы (например, A12):",
|
||||
groupNumber,
|
||||
lastRequestedGroupNumber,
|
||||
value -> {
|
||||
if (!value.matches(Student.getGroupNumberPattern())) {
|
||||
MessageWindow.showModal(gui, "Номер группы должен соответствовать формату A12.");
|
||||
return false;
|
||||
}
|
||||
|
||||
groupNumber = value;
|
||||
lastRequestedGroupNumber = value;
|
||||
studentBuilder.setGroupNumber(value);
|
||||
|
||||
groupNumberLabel.setText("Номер группы: " + groupNumber);
|
||||
groupNumberLabel.setText("Номер группы: " + lastRequestedGroupNumber);
|
||||
|
||||
return true;
|
||||
});
|
||||
@@ -132,7 +179,7 @@ public class CustomDataSettingsWindow extends BaseModalWindow {
|
||||
gui,
|
||||
"Средний балл",
|
||||
"Введите средний балл от 0.0 до 5.0:",
|
||||
averageGrade == null ? null : String.valueOf(averageGrade),
|
||||
lastRequestedAverageGrade == null ? null : String.valueOf(lastRequestedAverageGrade),
|
||||
value -> {
|
||||
try {
|
||||
double parsedValue = Double.parseDouble(value);
|
||||
@@ -145,11 +192,11 @@ public class CustomDataSettingsWindow extends BaseModalWindow {
|
||||
return false;
|
||||
}
|
||||
|
||||
averageGrade = parsedValue;
|
||||
lastRequestedAverageGrade = parsedValue;
|
||||
|
||||
studentBuilder.setAverageGrade(parsedValue);
|
||||
|
||||
averageGradeLabel.setText("Средний балл: " + averageGrade);
|
||||
averageGradeLabel.setText("Средний балл: " + lastRequestedAverageGrade);
|
||||
|
||||
return true;
|
||||
|
||||
@@ -169,7 +216,9 @@ public class CustomDataSettingsWindow extends BaseModalWindow {
|
||||
gui,
|
||||
"Номер зачётной книжки",
|
||||
"Введите номер зачётной книжки:",
|
||||
recordBookNumber == null ? null : String.valueOf(recordBookNumber),
|
||||
lastRequestedRecordBookNumber == null
|
||||
? null
|
||||
: String.valueOf(lastRequestedRecordBookNumber),
|
||||
value -> {
|
||||
try {
|
||||
int parsedValue = Integer.parseInt(value);
|
||||
@@ -181,11 +230,12 @@ public class CustomDataSettingsWindow extends BaseModalWindow {
|
||||
return false;
|
||||
}
|
||||
|
||||
recordBookNumber = parsedValue;
|
||||
lastRequestedRecordBookNumber = parsedValue;
|
||||
|
||||
studentBuilder.setRecordBookNumber(parsedValue);
|
||||
|
||||
recordBookNumberLabel.setText("Номер зачётной книжки: " + recordBookNumber);
|
||||
recordBookNumberLabel.setText(
|
||||
"Номер зачётной книжки: " + lastRequestedRecordBookNumber);
|
||||
|
||||
return true;
|
||||
|
||||
@@ -205,34 +255,31 @@ public class CustomDataSettingsWindow extends BaseModalWindow {
|
||||
gui,
|
||||
"Индекс объекта",
|
||||
"Введите индекс объекта:",
|
||||
selectedObjectIndex == null ? null : String.valueOf(selectedObjectIndex),
|
||||
lastRequestedSelectedObjectIndex == null
|
||||
? null
|
||||
: String.valueOf(lastRequestedSelectedObjectIndex),
|
||||
value -> {
|
||||
try {
|
||||
int index = Integer.parseInt(value);
|
||||
|
||||
if (index < 0) {
|
||||
MessageWindow.showModal(gui, "Индекс объекта не может быть отрицательным.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int size = requestedCollectionSize.get();
|
||||
|
||||
if (index >= size) {
|
||||
if (index >= preparedCustomDataCollection.size()) {
|
||||
MessageWindow.showModal(gui, "Индекс должен быть меньше размера коллекции.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
selectedObjectIndex = index;
|
||||
lastRequestedSelectedObjectIndex = index;
|
||||
|
||||
indexLabel.setText("Индекс объекта: " + selectedObjectIndex);
|
||||
indexLabel.setText("Индекс объекта: " + lastRequestedSelectedObjectIndex);
|
||||
|
||||
return true;
|
||||
|
||||
} catch (NumberFormatException e) {
|
||||
MessageWindow.showModal(gui, "Введите целое число.");
|
||||
|
||||
return false;
|
||||
}
|
||||
});
|
||||
@@ -246,28 +293,28 @@ public class CustomDataSettingsWindow extends BaseModalWindow {
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedObjectIndex == null) {
|
||||
if (lastRequestedSelectedObjectIndex == null) {
|
||||
MessageWindow.showModal(gui, "Сначала задайте индекс объекта.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedObjectIndex >= preparedCustomDataCollection.size()) {
|
||||
if (lastRequestedSelectedObjectIndex >= preparedCustomDataCollection.size()) {
|
||||
MessageWindow.showModal(gui, "Индекс объекта выходит за границы подготовленной коллекции.");
|
||||
return;
|
||||
}
|
||||
|
||||
Student student = studentBuilder.build();
|
||||
|
||||
preparedCustomDataCollection.set(selectedObjectIndex, student);
|
||||
preparedCustomDataCollection.set(lastRequestedSelectedObjectIndex, student);
|
||||
|
||||
MessageWindow.showModal(gui, "Данные объекта успешно заданы.");
|
||||
}
|
||||
|
||||
private void apply() {
|
||||
state.setCustomDataCollection(preparedCustomDataCollection);
|
||||
prepareCustomDataCollection();
|
||||
settings.setCollection(preparedCustomDataCollection);
|
||||
onApply.accept(settings);
|
||||
|
||||
MessageWindow.showModal(gui, "Пользовательские данные успешно применены.");
|
||||
MessageWindow.showModal(gui, "Настройки создания коллекции вручную успешно применены.");
|
||||
}
|
||||
|
||||
private void preview() {
|
||||
@@ -284,6 +331,8 @@ public class CustomDataSettingsWindow extends BaseModalWindow {
|
||||
}
|
||||
|
||||
private boolean hasStudentData() {
|
||||
return groupNumber != null && averageGrade != null && recordBookNumber != null;
|
||||
return lastRequestedGroupNumber != null
|
||||
&& lastRequestedAverageGrade != null
|
||||
&& lastRequestedRecordBookNumber != null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package ru.project.ui.creation.manual;
|
||||
|
||||
import ru.project.collection.MyLinkedList;
|
||||
import ru.project.collection.MyList;
|
||||
import ru.project.student.Student;
|
||||
|
||||
public class ManualFillSettings {
|
||||
|
||||
private MyList<Student> manualDataCollection;
|
||||
|
||||
public ManualFillSettings() {
|
||||
this.manualDataCollection = new MyLinkedList<>();
|
||||
}
|
||||
|
||||
public MyList<Student> getCollection() {
|
||||
return manualDataCollection;
|
||||
}
|
||||
|
||||
public void setCollection(MyList<Student> collection) {
|
||||
this.manualDataCollection = collection;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package ru.project.ui.creation.manual;
|
||||
|
||||
import ru.project.collection.MyLinkedList;
|
||||
import ru.project.collection.MyList;
|
||||
import ru.project.student.Student;
|
||||
import ru.project.ui.creation.FillStrategy;
|
||||
|
||||
public class ManualFillStrategy implements FillStrategy {
|
||||
|
||||
private final ManualFillSettings settings;
|
||||
|
||||
public ManualFillStrategy(ManualFillSettings settings) {
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MyList<Student> create() {
|
||||
MyList<Student> mainCollection = new MyLinkedList<>();
|
||||
|
||||
MyList<Student> manualDataCollection = settings.getCollection();
|
||||
|
||||
for (int i = 0; i < manualDataCollection.size(); i++) {
|
||||
mainCollection.add(manualDataCollection.get(i));
|
||||
}
|
||||
|
||||
return mainCollection;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,361 @@
|
||||
package ru.project.ui.creation.random;
|
||||
|
||||
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.Consumer;
|
||||
import ru.project.ui.base.BaseModalWindow;
|
||||
import ru.project.ui.common.InputValueWindow;
|
||||
import ru.project.ui.common.MessageWindow;
|
||||
|
||||
public class RandomDataSettingsWindow extends BaseModalWindow {
|
||||
|
||||
private final RandomFillSettings settings;
|
||||
private final Consumer<RandomFillSettings> onApply;
|
||||
|
||||
private final Label collectionSizeLabel;
|
||||
private final Label minGroupNumberLabel;
|
||||
private final Label maxGroupNumberLabel;
|
||||
private final Label minAverageGradeLabel;
|
||||
private final Label maxAverageGradeLabel;
|
||||
private final Label minRecordBookNumberLabel;
|
||||
private final Label maxRecordBookNumberLabel;
|
||||
|
||||
public RandomDataSettingsWindow(WindowBasedTextGUI gui, Consumer<RandomFillSettings> onApply) {
|
||||
|
||||
super("Настройка случайного заполнения", gui);
|
||||
|
||||
this.settings = new RandomFillSettings();
|
||||
this.onApply = onApply;
|
||||
|
||||
Panel panel = new Panel();
|
||||
panel.setLayoutManager(new LinearLayout());
|
||||
|
||||
collectionSizeLabel =
|
||||
new Label("Размер коллекции: " + getValueOrDefault(settings.getCollectionSize()));
|
||||
|
||||
panel.addComponent(collectionSizeLabel);
|
||||
minGroupNumberLabel =
|
||||
new Label("Минимальный номер группы: " + getValueOrDefault(settings.getMinGroupNumber()));
|
||||
|
||||
maxGroupNumberLabel =
|
||||
new Label("Максимальный номер группы: " + getValueOrDefault(settings.getMaxGroupNumber()));
|
||||
|
||||
minAverageGradeLabel =
|
||||
new Label("Минимальный средний балл: " + getValueOrDefault(settings.getMinAverageGrade()));
|
||||
|
||||
maxAverageGradeLabel =
|
||||
new Label("Максимальный средний балл: " + getValueOrDefault(settings.getMaxAverageGrade()));
|
||||
|
||||
minRecordBookNumberLabel =
|
||||
new Label(
|
||||
"Минимальный номер зачётной книжки: "
|
||||
+ getValueOrDefault(settings.getMinRecordBookNumber()));
|
||||
|
||||
maxRecordBookNumberLabel =
|
||||
new Label(
|
||||
"Максимальный номер зачётной книжки: "
|
||||
+ getValueOrDefault(settings.getMaxRecordBookNumber()));
|
||||
|
||||
panel.addComponent(minGroupNumberLabel);
|
||||
panel.addComponent(maxGroupNumberLabel);
|
||||
panel.addComponent(minAverageGradeLabel);
|
||||
panel.addComponent(maxAverageGradeLabel);
|
||||
panel.addComponent(minRecordBookNumberLabel);
|
||||
panel.addComponent(maxRecordBookNumberLabel);
|
||||
|
||||
panel.addComponent(new Button("Задать размер коллекции...", this::setCollectionSize));
|
||||
|
||||
panel.addComponent(new Button("Задать минимальный номер группы", this::setMinGroupNumber));
|
||||
|
||||
panel.addComponent(new Button("Задать максимальный номер группы", this::setMaxGroupNumber));
|
||||
|
||||
panel.addComponent(new Button("Задать минимальный средний балл", this::setMinAverageGrade));
|
||||
|
||||
panel.addComponent(new Button("Задать максимальный средний балл", this::setMaxAverageGrade));
|
||||
|
||||
panel.addComponent(
|
||||
new Button("Задать минимальный номер зачётной книжки", this::setMinRecordBookNumber));
|
||||
|
||||
panel.addComponent(
|
||||
new Button("Задать максимальный номер зачётной книжки", this::setMaxRecordBookNumber));
|
||||
|
||||
panel.addComponent(new Button("Применить", this::apply));
|
||||
|
||||
panel.addComponent(new Button("Назад", this::close));
|
||||
|
||||
setComponent(panel);
|
||||
}
|
||||
|
||||
private void setCollectionSize() {
|
||||
InputValueWindow window =
|
||||
new InputValueWindow(
|
||||
gui,
|
||||
"Размер коллекции",
|
||||
"Введите размер коллекции:",
|
||||
settings.getCollectionSize() == null
|
||||
? null
|
||||
: String.valueOf(settings.getCollectionSize()),
|
||||
value -> {
|
||||
try {
|
||||
int collectionSize = Integer.parseInt(value);
|
||||
|
||||
if (collectionSize <= 0) {
|
||||
MessageWindow.showModal(gui, "Размер коллекции должен быть больше 0.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
settings.setCollectionSize(collectionSize);
|
||||
|
||||
collectionSizeLabel.setText("Размер коллекции: " + collectionSize);
|
||||
|
||||
return true;
|
||||
|
||||
} catch (NumberFormatException e) {
|
||||
MessageWindow.showModal(gui, "Введите целое число.");
|
||||
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
window.showModal();
|
||||
}
|
||||
|
||||
private void setMinGroupNumber() {
|
||||
showGroupNumberInput(
|
||||
"Минимальный номер группы",
|
||||
settings.getMinGroupNumber(),
|
||||
value -> {
|
||||
if (!value.matches("[A-Z]\\d{2}")) {
|
||||
|
||||
MessageWindow.showModal(gui, "Номер группы должен соответствовать формату A12.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (settings.getMaxGroupNumber() != null
|
||||
&& value.compareTo(settings.getMaxGroupNumber()) > 0) {
|
||||
|
||||
MessageWindow.showModal(
|
||||
gui, "Минимальный номер группы не может быть больше максимального.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
settings.setMinGroupNumber(value);
|
||||
|
||||
minGroupNumberLabel.setText("Минимальный номер группы: " + value);
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void setMaxGroupNumber() {
|
||||
showGroupNumberInput(
|
||||
"Максимальный номер группы",
|
||||
settings.getMaxGroupNumber(),
|
||||
value -> {
|
||||
if (!value.matches("[A-Z]\\d{2}")) {
|
||||
|
||||
MessageWindow.showModal(gui, "Номер группы должен соответствовать формату A12.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (settings.getMinGroupNumber() != null
|
||||
&& value.compareTo(settings.getMinGroupNumber()) < 0) {
|
||||
|
||||
MessageWindow.showModal(
|
||||
gui, "Максимальный номер группы не может быть меньше минимального.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
settings.setMaxGroupNumber(value);
|
||||
|
||||
maxGroupNumberLabel.setText("Максимальный номер группы: " + value);
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void showGroupNumberInput(
|
||||
String title, String initialValue, java.util.function.Predicate<String> onSave) {
|
||||
|
||||
InputValueWindow window =
|
||||
new InputValueWindow(
|
||||
gui, title, "Введите номер группы (например, A12):", initialValue, onSave);
|
||||
|
||||
window.showModal();
|
||||
}
|
||||
|
||||
private void setMinAverageGrade() {
|
||||
showAverageGradeInput(
|
||||
"Минимальный средний балл",
|
||||
settings.getMinAverageGrade(),
|
||||
value -> {
|
||||
if (settings.getMaxAverageGrade() != null && value > settings.getMaxAverageGrade()) {
|
||||
|
||||
MessageWindow.showModal(
|
||||
gui, "Минимальный средний балл не может быть больше максимального.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
settings.setMinAverageGrade(value);
|
||||
|
||||
minAverageGradeLabel.setText("Минимальный средний балл: " + value);
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void setMaxAverageGrade() {
|
||||
showAverageGradeInput(
|
||||
"Максимальный средний балл",
|
||||
settings.getMaxAverageGrade(),
|
||||
value -> {
|
||||
if (settings.getMinAverageGrade() != null && value < settings.getMinAverageGrade()) {
|
||||
|
||||
MessageWindow.showModal(
|
||||
gui, "Максимальный средний балл не может быть меньше минимального.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
settings.setMaxAverageGrade(value);
|
||||
|
||||
maxAverageGradeLabel.setText("Максимальный средний балл: " + value);
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void showAverageGradeInput(
|
||||
String title, Double initialValue, java.util.function.Predicate<Double> onSave) {
|
||||
|
||||
InputValueWindow window =
|
||||
new InputValueWindow(
|
||||
gui,
|
||||
title,
|
||||
"Введите значение от " + "0.0 до 5.0:",
|
||||
initialValue == null ? null : String.valueOf(initialValue),
|
||||
value -> {
|
||||
try {
|
||||
double parsedValue = Double.parseDouble(value);
|
||||
|
||||
if (parsedValue < ru.project.student.Student.getMinAverageGrade()
|
||||
|| parsedValue > ru.project.student.Student.getMaxAverageGrade()) {
|
||||
|
||||
MessageWindow.showModal(gui, "Средний балл должен быть от 0.0 до 5.0.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return onSave.test(parsedValue);
|
||||
|
||||
} catch (NumberFormatException e) {
|
||||
MessageWindow.showModal(gui, "Введите корректное число.");
|
||||
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
window.showModal();
|
||||
}
|
||||
|
||||
private void setMinRecordBookNumber() {
|
||||
showRecordBookNumberInput(
|
||||
"Минимальный номер зачётной книжки",
|
||||
settings.getMinRecordBookNumber(),
|
||||
value -> {
|
||||
if (settings.getMaxRecordBookNumber() != null
|
||||
&& value > settings.getMaxRecordBookNumber()) {
|
||||
|
||||
MessageWindow.showModal(
|
||||
gui, "Минимальный номер зачётной книжки не может быть больше максимального.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
settings.setMinRecordBookNumber(value);
|
||||
|
||||
minRecordBookNumberLabel.setText("Минимальный номер зачётной книжки: " + value);
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void setMaxRecordBookNumber() {
|
||||
showRecordBookNumberInput(
|
||||
"Максимальный номер зачётной книжки",
|
||||
settings.getMaxRecordBookNumber(),
|
||||
value -> {
|
||||
if (settings.getMinRecordBookNumber() != null
|
||||
&& value < settings.getMinRecordBookNumber()) {
|
||||
|
||||
MessageWindow.showModal(
|
||||
gui, "Максимальный номер зачётной книжки не может быть меньше минимального.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
settings.setMaxRecordBookNumber(value);
|
||||
|
||||
maxRecordBookNumberLabel.setText("Максимальный номер зачётной книжки: " + value);
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void showRecordBookNumberInput(
|
||||
String title, Integer initialValue, java.util.function.Predicate<Integer> onSave) {
|
||||
|
||||
InputValueWindow window =
|
||||
new InputValueWindow(
|
||||
gui,
|
||||
title,
|
||||
"Введите номер зачётной книжки:",
|
||||
initialValue == null ? null : String.valueOf(initialValue),
|
||||
value -> {
|
||||
try {
|
||||
int parsedValue = Integer.parseInt(value);
|
||||
|
||||
if (parsedValue < ru.project.student.Student.getMinRecordBookNumber()) {
|
||||
|
||||
MessageWindow.showModal(gui, "Номер зачётной книжки должен быть положительным.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return onSave.test(parsedValue);
|
||||
|
||||
} catch (NumberFormatException e) {
|
||||
MessageWindow.showModal(gui, "Введите целое число.");
|
||||
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
window.showModal();
|
||||
}
|
||||
|
||||
private void apply() {
|
||||
if (settings.getCollectionSize() == null) {
|
||||
MessageWindow.showModal(gui, "Сначала задайте размер коллекции.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
onApply.accept(settings);
|
||||
|
||||
MessageWindow.showModal(gui, "Настройки создания коллекции случайно успешно применены.");
|
||||
}
|
||||
|
||||
private String getValueOrDefault(Object value) {
|
||||
return value == null ? "не задан" : String.valueOf(value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package ru.project.ui.creation.random;
|
||||
|
||||
public class RandomFillSettings {
|
||||
|
||||
private Integer collectionSize;
|
||||
|
||||
private String minGroupNumber;
|
||||
private String maxGroupNumber;
|
||||
|
||||
private Double minAverageGrade;
|
||||
private Double maxAverageGrade;
|
||||
|
||||
private Integer minRecordBookNumber;
|
||||
private Integer maxRecordBookNumber;
|
||||
|
||||
public RandomFillSettings() {
|
||||
this.collectionSize = null;
|
||||
|
||||
this.minGroupNumber = null;
|
||||
this.maxGroupNumber = null;
|
||||
|
||||
this.minAverageGrade = null;
|
||||
this.maxAverageGrade = null;
|
||||
|
||||
this.minRecordBookNumber = null;
|
||||
this.maxRecordBookNumber = null;
|
||||
}
|
||||
|
||||
public Integer getCollectionSize() {
|
||||
return collectionSize;
|
||||
}
|
||||
|
||||
public void setCollectionSize(Integer collectionSize) {
|
||||
this.collectionSize = collectionSize;
|
||||
}
|
||||
|
||||
public String getMinGroupNumber() {
|
||||
return minGroupNumber;
|
||||
}
|
||||
|
||||
public void setMinGroupNumber(String minGroupNumber) {
|
||||
this.minGroupNumber = minGroupNumber;
|
||||
}
|
||||
|
||||
public String getMaxGroupNumber() {
|
||||
return maxGroupNumber;
|
||||
}
|
||||
|
||||
public void setMaxGroupNumber(String maxGroupNumber) {
|
||||
this.maxGroupNumber = maxGroupNumber;
|
||||
}
|
||||
|
||||
public Double getMinAverageGrade() {
|
||||
return minAverageGrade;
|
||||
}
|
||||
|
||||
public void setMinAverageGrade(Double minAverageGrade) {
|
||||
this.minAverageGrade = minAverageGrade;
|
||||
}
|
||||
|
||||
public Double getMaxAverageGrade() {
|
||||
return maxAverageGrade;
|
||||
}
|
||||
|
||||
public void setMaxAverageGrade(Double maxAverageGrade) {
|
||||
this.maxAverageGrade = maxAverageGrade;
|
||||
}
|
||||
|
||||
public Integer getMinRecordBookNumber() {
|
||||
return minRecordBookNumber;
|
||||
}
|
||||
|
||||
public void setMinRecordBookNumber(Integer minRecordBookNumber) {
|
||||
this.minRecordBookNumber = minRecordBookNumber;
|
||||
}
|
||||
|
||||
public Integer getMaxRecordBookNumber() {
|
||||
return maxRecordBookNumber;
|
||||
}
|
||||
|
||||
public void setMaxRecordBookNumber(Integer maxRecordBookNumber) {
|
||||
this.maxRecordBookNumber = maxRecordBookNumber;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package ru.project.ui.creation.random;
|
||||
|
||||
import ru.project.collection.MyList;
|
||||
import ru.project.random.RandomStudentGenerator;
|
||||
import ru.project.student.Student;
|
||||
import ru.project.ui.creation.FillStrategy;
|
||||
|
||||
public class RandomFillStrategy implements FillStrategy {
|
||||
|
||||
private final RandomFillSettings settings;
|
||||
|
||||
public RandomFillStrategy(RandomFillSettings settings) {
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MyList<Student> create() {
|
||||
RandomStudentGenerator generator = new RandomStudentGenerator();
|
||||
|
||||
if (settings.getMinGroupNumber() != null) {
|
||||
generator.setMinGroupNumber(settings.getMinGroupNumber());
|
||||
}
|
||||
|
||||
if (settings.getMaxGroupNumber() != null) {
|
||||
generator.setMaxGroupNumber(settings.getMaxGroupNumber());
|
||||
}
|
||||
|
||||
if (settings.getMinAverageGrade() != null) {
|
||||
generator.setMinAverageGrade(settings.getMinAverageGrade());
|
||||
}
|
||||
|
||||
if (settings.getMaxAverageGrade() != null) {
|
||||
generator.setMaxAverageGrade(settings.getMaxAverageGrade());
|
||||
}
|
||||
|
||||
if (settings.getMinRecordBookNumber() != null) {
|
||||
generator.setMinRecordBookNumber(settings.getMinRecordBookNumber());
|
||||
}
|
||||
|
||||
if (settings.getMaxRecordBookNumber() != null) {
|
||||
generator.setMaxRecordBookNumber(settings.getMaxRecordBookNumber());
|
||||
}
|
||||
|
||||
return generator.generate(settings.getCollectionSize());
|
||||
}
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -1,157 +1,163 @@
|
||||
package ru.project.random;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
import ru.project.collection.MyLinkedList;
|
||||
import ru.project.collection.MyList;
|
||||
import ru.project.student.Student;
|
||||
import java.util.regex.Pattern;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
public class RandomStudentGeneratorTest
|
||||
{
|
||||
private static final Pattern GROUP_PATTERN = Pattern.compile("^[A-Z][0-9]{2}$");
|
||||
private static final double MIN_GRADE = 0.0;
|
||||
private static final double MAX_GRADE = 5.0;
|
||||
@Test
|
||||
void shouldTestgenerate_withoutConstraints_returnsCorrectSizeAndValidStudents() {
|
||||
int size = 100;
|
||||
RandomStudentGenerator generator = new RandomStudentGenerator();
|
||||
MyList<Student> students = generator.generate(size);
|
||||
assertEquals(size, students.size(), "Размер списка должен совпадать с запрошенным");
|
||||
for (int i = 0; i < students.size(); i++) {
|
||||
Student s = students.get(i);
|
||||
assertTrue(GROUP_PATTERN.matcher(s.getGroupNumber()).matches(),
|
||||
"groupNumber должен соответствовать шаблону A00–Z99");
|
||||
assertTrue(s.getAverageGrade() >= MIN_GRADE && s.getAverageGrade() <= MAX_GRADE,
|
||||
"averageGrade должен быть в диапазоне [0.0, 5.0]");
|
||||
assertTrue(s.getRecordBookNumber() >= 1,
|
||||
"recordBookNumber должен быть >= 1");
|
||||
}
|
||||
}
|
||||
@Test
|
||||
void shouldTestgenerate_withGroupRange_respectsLexicographicalBounds() {
|
||||
RandomStudentGenerator generator = new RandomStudentGenerator()
|
||||
.setMinGroupNumber("A00")
|
||||
.setMaxGroupNumber("B99");
|
||||
MyList<Student> students = generator.generate(200);
|
||||
assertEquals(200, students.size());
|
||||
for (int i = 0; i < students.size(); i++) {
|
||||
Student s = students.get(i);
|
||||
String g = s.getGroupNumber();
|
||||
assertTrue(g.compareTo("A00") >= 0, "Группа не должна быть меньше A00");
|
||||
assertTrue(g.compareTo("B99") <= 0, "Группа не должна быть больше B99");
|
||||
assertTrue(GROUP_PATTERN.matcher(g).matches(), "Группа должна соответствовать шаблону");
|
||||
}
|
||||
}
|
||||
@Test
|
||||
void shouldTestgenerate_withGradeRange_respectsBounds() {
|
||||
double minGrade = 3.0;
|
||||
double maxGrade = 4.0;
|
||||
|
||||
RandomStudentGenerator generator = new RandomStudentGenerator()
|
||||
.setMinAverageGrade(minGrade)
|
||||
.setMaxAverageGrade(maxGrade);
|
||||
MyList<Student> students = generator.generate(100);
|
||||
public class RandomStudentGeneratorTest {
|
||||
private static final Pattern GROUP_PATTERN = Pattern.compile("^[A-Z][0-9]{2}$");
|
||||
private static final double MIN_GRADE = 0.0;
|
||||
private static final double MAX_GRADE = 5.0;
|
||||
|
||||
for (int i = 0; i < students.size(); i++) {
|
||||
Student s = students.get(i);
|
||||
double g = s.getAverageGrade();
|
||||
assertTrue(g >= minGrade && g <= maxGrade,
|
||||
"averageGrade должен быть в заданном диапазоне");
|
||||
}
|
||||
@Test
|
||||
void shouldTestgenerate_withoutConstraints_returnsCorrectSizeAndValidStudents() {
|
||||
int size = 100;
|
||||
RandomStudentGenerator generator = new RandomStudentGenerator();
|
||||
MyList<Student> students = generator.generate(size);
|
||||
assertEquals(size, students.size(), "Размер списка должен совпадать с запрошенным");
|
||||
for (int i = 0; i < students.size(); i++) {
|
||||
Student s = students.get(i);
|
||||
assertTrue(
|
||||
GROUP_PATTERN.matcher(s.getGroupNumber()).matches(),
|
||||
"groupNumber должен соответствовать шаблону A00–Z99");
|
||||
assertTrue(
|
||||
s.getAverageGrade() >= MIN_GRADE && s.getAverageGrade() <= MAX_GRADE,
|
||||
"averageGrade должен быть в диапазоне [0.0, 5.0]");
|
||||
assertTrue(s.getRecordBookNumber() >= 1, "recordBookNumber должен быть >= 1");
|
||||
}
|
||||
@Test
|
||||
void shouldTestgenerate_withRecordBookRange_respectsBounds() {
|
||||
int minRec = 10_000;
|
||||
int maxRec = 20_000;
|
||||
}
|
||||
|
||||
RandomStudentGenerator generator = new RandomStudentGenerator()
|
||||
.setMinRecordBookNumber(minRec)
|
||||
.setMaxRecordBookNumber(maxRec);
|
||||
MyList<Student> students = generator.generate(100);
|
||||
@Test
|
||||
void shouldTestgenerate_withGroupRange_respectsLexicographicalBounds() {
|
||||
RandomStudentGenerator generator =
|
||||
new RandomStudentGenerator().setMinGroupNumber("A00").setMaxGroupNumber("B99");
|
||||
MyList<Student> students = generator.generate(200);
|
||||
assertEquals(200, students.size());
|
||||
for (int i = 0; i < students.size(); i++) {
|
||||
Student s = students.get(i);
|
||||
String g = s.getGroupNumber();
|
||||
assertTrue(g.compareTo("A00") >= 0, "Группа не должна быть меньше A00");
|
||||
assertTrue(g.compareTo("B99") <= 0, "Группа не должна быть больше B99");
|
||||
assertTrue(GROUP_PATTERN.matcher(g).matches(), "Группа должна соответствовать шаблону");
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < students.size(); i++) {
|
||||
Student s = students.get(i);
|
||||
int r = s.getRecordBookNumber();
|
||||
assertTrue(r >= minRec && r <= maxRec,
|
||||
"recordBookNumber должен быть в заданном диапазоне");
|
||||
}
|
||||
}
|
||||
@Test
|
||||
void shouldTestgenerate_withGradeRange_respectsBounds() {
|
||||
double minGrade = 3.0;
|
||||
double maxGrade = 4.0;
|
||||
|
||||
@Test
|
||||
void shouldTestgenerate_negativeSize_throwsException() {
|
||||
RandomStudentGenerator generator = new RandomStudentGenerator();
|
||||
assertThrows(IllegalArgumentException.class, () -> generator.generate(-1));
|
||||
RandomStudentGenerator generator =
|
||||
new RandomStudentGenerator().setMinAverageGrade(minGrade).setMaxAverageGrade(maxGrade);
|
||||
MyList<Student> students = generator.generate(100);
|
||||
|
||||
for (int i = 0; i < students.size(); i++) {
|
||||
Student s = students.get(i);
|
||||
double g = s.getAverageGrade();
|
||||
assertTrue(g >= minGrade && g <= maxGrade, "averageGrade должен быть в заданном диапазоне");
|
||||
}
|
||||
@Test
|
||||
void shouldTestsetMinGroupNumber_invalidPattern_throwsException() {
|
||||
RandomStudentGenerator generator = new RandomStudentGenerator();
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> generator.setMinGroupNumber("invalid"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldTestgenerate_withRecordBookRange_respectsBounds() {
|
||||
int minRec = 10_000;
|
||||
int maxRec = 20_000;
|
||||
|
||||
RandomStudentGenerator generator =
|
||||
new RandomStudentGenerator().setMinRecordBookNumber(minRec).setMaxRecordBookNumber(maxRec);
|
||||
MyList<Student> students = generator.generate(100);
|
||||
|
||||
for (int i = 0; i < students.size(); i++) {
|
||||
Student s = students.get(i);
|
||||
int r = s.getRecordBookNumber();
|
||||
assertTrue(r >= minRec && r <= maxRec, "recordBookNumber должен быть в заданном диапазоне");
|
||||
}
|
||||
@Test
|
||||
void shouldTestsetMaxGroupNumber_invalidPattern_throwsException() {
|
||||
RandomStudentGenerator generator = new RandomStudentGenerator();
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> generator.setMaxGroupNumber("ZZ")); // не 2 цифры
|
||||
}
|
||||
@Test
|
||||
void shouldTestsetMinMaxGroupNumber_minGreaterThanMax_throwsException() {
|
||||
RandomStudentGenerator generator = new RandomStudentGenerator();
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> generator.setMinGroupNumber("C00").setMaxGroupNumber("A99").generate(1));
|
||||
}
|
||||
@Test
|
||||
void shouldTestsetMinAverageGrade_outOfRange_throwsException() {
|
||||
RandomStudentGenerator generator = new RandomStudentGenerator();
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> generator.setMinAverageGrade(-0.1));
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> generator.setMinAverageGrade(5.1));
|
||||
}
|
||||
@Test
|
||||
void shouldTestsetMaxAverageGrade_outOfRange_throwsException() {
|
||||
RandomStudentGenerator generator = new RandomStudentGenerator();
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> generator.setMaxAverageGrade(-0.1));
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> generator.setMaxAverageGrade(5.1));
|
||||
}
|
||||
@Test
|
||||
void shouldTestsetMinMaxAverageGrade_minGreaterThanMax_throwsException() {
|
||||
RandomStudentGenerator generator = new RandomStudentGenerator();
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> generator.setMinAverageGrade(4.0).setMaxAverageGrade(3.0).generate(1));
|
||||
}
|
||||
@Test
|
||||
void shouldTestsetMinRecordBookNumber_lessThanAllowed_throwsException() {
|
||||
RandomStudentGenerator generator = new RandomStudentGenerator();
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> generator.setMinRecordBookNumber(0));
|
||||
}
|
||||
@Test
|
||||
void shouldTestsetMinMaxRecordBookNumber_minGreaterThanMax_throwsException() {
|
||||
RandomStudentGenerator generator = new RandomStudentGenerator();
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> generator.setMinRecordBookNumber(20_000).setMaxRecordBookNumber(10_000).generate(1));
|
||||
}
|
||||
@Test
|
||||
void shouldTestchainedBuilderStyle_worksAsExpected() {
|
||||
RandomStudentGenerator generator = new RandomStudentGenerator()
|
||||
.setMinGroupNumber("A00")
|
||||
.setMaxGroupNumber("Z99")
|
||||
.setMinAverageGrade(2.0)
|
||||
.setMaxAverageGrade(4.0)
|
||||
.setMinRecordBookNumber(1_000)
|
||||
.setMaxRecordBookNumber(9_999);
|
||||
MyList<Student> students = generator.generate(50);
|
||||
assertEquals(50, students.size());
|
||||
for (int i = 0; i < students.size(); i++) {
|
||||
Student s = students.get(i);
|
||||
assertTrue(s.getGroupNumber().compareTo("A00") >= 0
|
||||
&& s.getGroupNumber().compareTo("Z99") <= 0);
|
||||
assertTrue(s.getAverageGrade() >= 2.0 && s.getAverageGrade() <= 4.0);
|
||||
assertTrue(s.getRecordBookNumber() >= 1_000 && s.getRecordBookNumber() <= 9_999);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldTestgenerate_negativeSize_throwsException() {
|
||||
RandomStudentGenerator generator = new RandomStudentGenerator();
|
||||
assertThrows(IllegalArgumentException.class, () -> generator.generate(-1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldTestsetMinGroupNumber_invalidPattern_throwsException() {
|
||||
RandomStudentGenerator generator = new RandomStudentGenerator();
|
||||
assertThrows(IllegalArgumentException.class, () -> generator.setMinGroupNumber("invalid"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldTestsetMaxGroupNumber_invalidPattern_throwsException() {
|
||||
RandomStudentGenerator generator = new RandomStudentGenerator();
|
||||
assertThrows(
|
||||
IllegalArgumentException.class, () -> generator.setMaxGroupNumber("ZZ")); // не 2 цифры
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldTestsetMinMaxGroupNumber_minGreaterThanMax_throwsException() {
|
||||
RandomStudentGenerator generator = new RandomStudentGenerator();
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> generator.setMinGroupNumber("C00").setMaxGroupNumber("A99").generate(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldTestsetMinAverageGrade_outOfRange_throwsException() {
|
||||
RandomStudentGenerator generator = new RandomStudentGenerator();
|
||||
assertThrows(IllegalArgumentException.class, () -> generator.setMinAverageGrade(-0.1));
|
||||
assertThrows(IllegalArgumentException.class, () -> generator.setMinAverageGrade(5.1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldTestsetMaxAverageGrade_outOfRange_throwsException() {
|
||||
RandomStudentGenerator generator = new RandomStudentGenerator();
|
||||
assertThrows(IllegalArgumentException.class, () -> generator.setMaxAverageGrade(-0.1));
|
||||
assertThrows(IllegalArgumentException.class, () -> generator.setMaxAverageGrade(5.1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldTestsetMinMaxAverageGrade_minGreaterThanMax_throwsException() {
|
||||
RandomStudentGenerator generator = new RandomStudentGenerator();
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> generator.setMinAverageGrade(4.0).setMaxAverageGrade(3.0).generate(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldTestsetMinRecordBookNumber_lessThanAllowed_throwsException() {
|
||||
RandomStudentGenerator generator = new RandomStudentGenerator();
|
||||
assertThrows(IllegalArgumentException.class, () -> generator.setMinRecordBookNumber(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldTestsetMinMaxRecordBookNumber_minGreaterThanMax_throwsException() {
|
||||
RandomStudentGenerator generator = new RandomStudentGenerator();
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> generator.setMinRecordBookNumber(20_000).setMaxRecordBookNumber(10_000).generate(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldTestchainedBuilderStyle_worksAsExpected() {
|
||||
RandomStudentGenerator generator =
|
||||
new RandomStudentGenerator()
|
||||
.setMinGroupNumber("A00")
|
||||
.setMaxGroupNumber("Z99")
|
||||
.setMinAverageGrade(2.0)
|
||||
.setMaxAverageGrade(4.0)
|
||||
.setMinRecordBookNumber(1_000)
|
||||
.setMaxRecordBookNumber(9_999);
|
||||
MyList<Student> students = generator.generate(50);
|
||||
assertEquals(50, students.size());
|
||||
for (int i = 0; i < students.size(); i++) {
|
||||
Student s = students.get(i);
|
||||
assertTrue(
|
||||
s.getGroupNumber().compareTo("A00") >= 0 && s.getGroupNumber().compareTo("Z99") <= 0);
|
||||
assertTrue(s.getAverageGrade() >= 2.0 && s.getAverageGrade() <= 4.0);
|
||||
assertTrue(s.getRecordBookNumber() >= 1_000 && s.getRecordBookNumber() <= 9_999);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@ package ru.project.search;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import ru.project.collection.MyList;
|
||||
import ru.project.collection.MyLinkedList;
|
||||
import ru.project.collection.MyList;
|
||||
import ru.project.student.Student;
|
||||
|
||||
class StudentSearchTest {
|
||||
@@ -79,7 +79,7 @@ class StudentSearchTest {
|
||||
@Test
|
||||
void testAverageGradeRangeDoesNotMatchAbove() {
|
||||
StudentSearchCriteria criteria = new AverageGradeRangeCriteria(4.0, 5.0);
|
||||
Student student = new Student("A12", 5.1, 123);
|
||||
Student student = new Student("A12", 2.0, 123);
|
||||
assertFalse(criteria.matches(student));
|
||||
}
|
||||
|
||||
@@ -199,8 +199,10 @@ class StudentSearchTest {
|
||||
|
||||
Student student = new Student("B20", 4.5, 150);
|
||||
assertTrue(outer.matches(student));
|
||||
|
||||
student = new Student("B20", 3.5, 150);
|
||||
assertFalse(outer.matches(student));
|
||||
assertTrue(outer.matches(student));
|
||||
|
||||
student = new Student("D00", 4.5, 150);
|
||||
assertFalse(outer.matches(student));
|
||||
}
|
||||
|
||||
@@ -78,8 +78,9 @@ class SortStrategyTest {
|
||||
list.add(new Student("A05", 4.5, 5));
|
||||
list.add(new Student("A06", 4.5, 4));
|
||||
|
||||
EvenOnlyMergeSortStrategy<Student> strategy =
|
||||
new EvenOnlyMergeSortStrategy<>(Student::getRecordBookNumber);
|
||||
EvenOnlySortStrategy<Student> strategy =
|
||||
new EvenOnlySortStrategy<>(new MergeSortStrategy<Student>(), Student::getRecordBookNumber);
|
||||
|
||||
strategy.sort(list, Comparator.comparingInt(Student::getRecordBookNumber));
|
||||
|
||||
int[] expected = {7, 2, 3, 4, 5, 8};
|
||||
@@ -95,8 +96,8 @@ class SortStrategyTest {
|
||||
list.add(new Student("A02", 4.5, 3));
|
||||
list.add(new Student("A03", 4.5, 5));
|
||||
|
||||
EvenOnlyMergeSortStrategy<Student> strategy =
|
||||
new EvenOnlyMergeSortStrategy<>(Student::getRecordBookNumber);
|
||||
EvenOnlySortStrategy<Student> strategy =
|
||||
new EvenOnlySortStrategy<>(new MergeSortStrategy<Student>(), Student::getRecordBookNumber);
|
||||
strategy.sort(list, Comparator.comparingInt(Student::getRecordBookNumber));
|
||||
|
||||
int[] expected = {1, 3, 5};
|
||||
@@ -112,8 +113,8 @@ class SortStrategyTest {
|
||||
list.add(new Student("A02", 4.5, 2));
|
||||
list.add(new Student("A03", 4.5, 6));
|
||||
|
||||
EvenOnlyMergeSortStrategy<Student> strategy =
|
||||
new EvenOnlyMergeSortStrategy<>(Student::getRecordBookNumber);
|
||||
EvenOnlySortStrategy<Student> strategy =
|
||||
new EvenOnlySortStrategy<>(new MergeSortStrategy<Student>(), Student::getRecordBookNumber);
|
||||
strategy.sort(list, Comparator.comparingInt(Student::getRecordBookNumber));
|
||||
|
||||
int[] expected = {2, 4, 6};
|
||||
|
||||
Reference in New Issue
Block a user