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