Skip to content
Snippets Groups Projects
Commit 2ccb4fc9 authored by jez04's avatar jez04
Browse files

feat: lab 10 assignment

parent 09245b67
No related merge requests found
......@@ -3,9 +3,9 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cz.vsb.fei.java2</groupId>
<artifactId>java2-lab09-v2</artifactId>
<artifactId>java2-lab10-v2</artifactId>
<version>0.0.1-SNAPHOST</version>
<name>java2-lab09-v2</name>
<name>java2-lab10-v2</name>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
......
JavaJester;274;HARD
DataDetective;296;HARD
AppArchitect;88;MEDIUM
DataDynamo;186;EASY
AppArchitect;88;MEDIUM
CodeConductor;273;MEDIUM
package lab.data;
public enum Level {
EASY, MEDIUM, HARD;
EASY, MEDIUM, HARD;
public static Level from(String s) {
for (Level l : values()) {
if (l.toString().equals(s)) {
return l;
}
}
return null;
}
}
......@@ -10,9 +10,12 @@ import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.ButtonType;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.stage.WindowEvent;
import lab.Config;
import lab.data.Score;
import lab.storage.FileStorage;
import lombok.extern.log4j.Log4j2;
......@@ -27,6 +30,7 @@ import lombok.extern.log4j.Log4j2;
public class App extends Application {
private GameController gameController;
private MainScreenController menuController;
private boolean viewMode;
......@@ -71,6 +75,7 @@ public class App extends Application {
// Construct a main window with a canvas.
FXMLLoader menuLoader = new FXMLLoader(getClass().getResource("/lab/gui/mainScreen.fxml"));
Parent root = menuLoader.load();
menuController = menuLoader.getController();
MainScreenController menuController = menuLoader.getController();
menuController.setApp(this);
Scene scene = new Scene(root);
......@@ -79,6 +84,25 @@ public class App extends Application {
primaryStage.setScene(scene);
}
public Stage createDialogStage(Score score) throws IOException {
Stage dialog = new Stage();
dialog.initStyle(StageStyle.UTILITY);
FXMLLoader editLoader = new FXMLLoader(getClass().getResource("/lab/gui/edit.fxml"));
Parent root = editLoader.load();
EditController editController = editLoader.getController();
editController.setStage(dialog);
editController.setObjectToEdit(score);
editController.setMainScreenController(menuController);
Scene scene = new Scene(root);
URL cssUrl = getClass().getResource("application.css");
scene.getStylesheets().add(cssUrl.toString());
dialog.setScene(scene);
dialog.initModality(Modality.APPLICATION_MODAL);
dialog.initOwner(primaryStage);
return dialog;
}
@Override
public void stop() throws Exception {
if(gameController != null) {
......
package lab.gui;
import java.util.HashMap;
import java.util.Map;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.geometry.HPos;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
import lab.data.Score;
import lombok.Setter;
/**
*
*/
public class EditController {
private static Logger log = LogManager.getLogger(EditController.class);
@FXML
private Button btnOk;
@FXML
private Button btnCancel;
@FXML
private Label txtTitle;
@FXML
private GridPane content;
private Object data;
private App app;
private Map<String, TextField> nameToTextField = new HashMap<>();
@Setter
private Stage stage;
@Setter
private MainScreenController mainScreenController;
@FXML
void btnOkAction(ActionEvent event) {
//TODO: add code to read values from text fields
mainScreenController.updateData((Score)data);
stage.hide();
}
@FXML
void btnCancelAction(ActionEvent event) {
stage.hide();
}
@FXML
void initialize() {
log.info("Screen initialized.");
}
public void setObjectToEdit(Object data) {
this.data = data;
log.info("data set {}", data);
content.getChildren().clear();
//TODO: code to detect properties and add rows to dialog
}
private void addDialogRow(int rowNumber, String name, String descriptionName, String stringValue,
boolean editable) {
Label label = new Label(descriptionName);
TextField textField = new TextField(stringValue);
textField.setEditable(editable);
nameToTextField.put(name, textField);
content.addRow(rowNumber, label, textField);
GridPane.setHalignment(label, HPos.RIGHT);
}
}
......@@ -13,11 +13,13 @@ import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.ToggleButton;
import javafx.scene.control.ToggleGroup;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.MouseButton;
import lab.Config;
import lab.data.Level;
import lab.data.Score;
......@@ -110,6 +112,11 @@ public class MainScreenController {
this.scores.getItems().addAll(scores);
}
public void updateData(Score score) {
Config.getInstance().getScoreStorageInterface().save(score);
updateScoreTable(Config.getInstance().getScoreStorageInterface().getAll());
}
@FXML
void initialize() {
assert difficult != null : "fx:id=\"difficult\" was not injected: check your FXML file 'mainScreen.fxml'.";
......@@ -123,6 +130,20 @@ public class MainScreenController {
difficultColumn.setCellValueFactory(new PropertyValueFactory<>("level"));
btnDelete.setDisable(true);
scores.setRowFactory(tableView -> {
TableRow<Score> row = new TableRow<>();
row.setOnMouseClicked(event -> {
if (event.getClickCount() >= 2 && event.getButton() == MouseButton.PRIMARY && row.getItem() != null) {
try {
MainScreenController.this.app.createDialogStage(row.getItem()).show();
} catch (IOException e) {
e.printStackTrace();
}
}
});
return row;
});
scores.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
scores.getSelectionModel().getSelectedItems()
.addListener((ListChangeListener.Change<? extends Score> change) ->
......
......@@ -10,6 +10,7 @@ import java.util.Comparator;
import java.util.List;
import java.util.stream.Stream;
import lab.data.Level;
import lab.data.Score;
public class FileStorage implements ScoreStorageInterface {
......@@ -21,7 +22,7 @@ public class FileStorage implements ScoreStorageInterface {
if (Files.exists(Paths.get(SCORE_FILE_NAME))) {
try (Stream<String> lines = Files.lines(Paths.get(SCORE_FILE_NAME))) {
List<Score> result = lines.map(line -> line.split(";"))
.map(parts -> new Score(null, parts[0], Integer.parseInt(parts[1]), null)).toList();
.map(parts -> new Score(null, parts[0], Integer.parseInt(parts[1]), Level.from(parts[2]))).toList();
return new ArrayList<>(result);
} catch (IOException e) {
e.printStackTrace();
......@@ -34,7 +35,7 @@ public class FileStorage implements ScoreStorageInterface {
public List<Score> getFirstTen() {
List<Score> all = getAll();
Collections.sort(all, Comparator.comparing(Score::getPoints).reversed());
return all.subList(0, 10);
return all.subList(0, Math.min(all.size(), 10));
}
@Override
......@@ -51,9 +52,9 @@ public class FileStorage implements ScoreStorageInterface {
}
private void storeAll(List<Score> all) {
List<String> lines = all.stream().map(s -> String.format("%s;%d", s.getName(), s.getPoints())).toList();
List<String> lines = all.stream().map(s -> String.format("%s;%d;%s", s.getName(), s.getPoints(), s.getLevel())).toList();
try {
Files.write(Paths.get(SCORE_FILE_NAME), lines, StandardOpenOption.TRUNCATE_EXISTING);
Files.write(Paths.get(SCORE_FILE_NAME), lines, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE);
} catch (IOException e) {
e.printStackTrace();
}
......
......@@ -8,6 +8,7 @@ module cz.vsb.fei.java2.lab03_module {
requires com.h2database;
requires jakarta.persistence;
requires org.hibernate.orm.core;
requires java.desktop;
opens lab.gui to javafx.fxml;
opens lab.data to javafx.base,org.hibernate.orm.core;
......
......@@ -24,6 +24,22 @@ Label {
-fx-background-size: stretch;
}
#content {
-fx-grid-lines-visible: true;
}
#btnOk {
-fx-background-color: RGBA(0.0,255.0,0.0,0.5);
}
#btnCancel {
-fx-background-color: RGBA(150.0,150.0,0.0,0.5);
}
.actionButton:hover {
-fx-text-fill: white;
}
#playButton {
-fx-background-color: RGBA(255.0,0.0,0.0,0.5);
}
......
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.text.Font?>
<BorderPane fx:id="menuPanel" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1" fx:controller="lab.gui.EditController">
<bottom>
<HBox BorderPane.alignment="CENTER">
<children>
<Button fx:id="btnCancel" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#btnCancelAction" styleClass="actionButton" text="Cancle" HBox.hgrow="ALWAYS">
<font>
<Font name="System Bold" size="51.0" />
</font>
</Button>
<Button fx:id="btnOk" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#btnOkAction" styleClass="actionButton" text="Ok" HBox.hgrow="ALWAYS">
<font>
<Font name="System Bold" size="51.0" />
</font>
</Button>
</children>
</HBox>
</bottom>
<center>
<GridPane fx:id="content" BorderPane.alignment="CENTER">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" vgrow="NEVER" />
</rowConstraints>
</GridPane>
</center>
<top>
<Label fx:id="txtTitle" text="Title" BorderPane.alignment="CENTER">
<font>
<Font name="System Bold" size="48.0" />
</font>
</Label>
</top>
</BorderPane>
......@@ -2,176 +2,40 @@ package jez04.structure.test;
import static org.hamcrest.MatcherAssert.assertThat;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Objects;
import java.util.regex.Pattern;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import cz.vsb.fei.kelvin.unittest.ProjectContains;
import cz.vsb.fei.kelvin.unittest.StructureHelper;
import cz.vsb.fei.kelvin.unittest.TextFileContains;
import cz.vsb.fei.kelvin.unittest.XmlFileContains;
import lab.data.Level;
import lab.data.Score;
import lab.storage.JpaConnector;
class ClassStructureTest {
StructureHelper helper = StructureHelper.getInstance(ClassStructureTest.class);
@Test
void jakartaAndHibernateAsDependencyTest() throws URISyntaxException {
assertThat(TextFileContains.getProjectRoot(getClass()), new XmlFileContains("pom.xml",
"/project/dependencies/dependency/artifactId[text() = 'jakarta.persistence-api']"));
assertThat(TextFileContains.getProjectRoot(getClass()), new XmlFileContains("pom.xml",
"/project/dependencies/dependency/artifactId[text() = 'hibernate-core']"));
// @formatter:off
@ParameterizedTest
@CsvSource({
"Score.java,@MyEdit,4",
"EditController.java,Introspector.getBeanInfo,1",
"EditController.java,BeanInfo,1",
"EditController.java,PropertyDescriptor,1",
"EditController.java,getDeclaredField,1",
"EditController.java,getAnnotation,1",
"EditController.java,\\.readOnly\\(\\),1",
"EditController.java,\\.visible\\(\\),1",
"MyEdit.java,@interface,1",
"MyEdit.java,@Retention,1",
"MyEdit.java,RetentionPolicy\\.RUNTIME,1",
"MyEdit.java,readOnly\\(\\),1",
"MyEdit.java,visible\\(\\),1",
"msg(_.*)?\\.properties,points,2",
})
// @formatter:on
void anotaceTest(String file, String annotation, int count) throws URISyntaxException {
assertThat(TextFileContains.getProjectRoot(getClass()), new TextFileContains(file, annotation).count(count).useRegExpForName(true));
}
@Test
void jakartaInModulInfoTest() throws URISyntaxException {
assertThat(TextFileContains.getProjectRoot(getClass()),
new TextFileContains("module-info.java", "jakarta.persistence;"));
assertThat(TextFileContains.getProjectRoot(getClass()),
new TextFileContains("module-info.java", "opens\\s+lab.data;|opens\\s+lab.data\\s+to\\s+javafx.base,org.hibernate.orm.core;"));
}
@Test
void pesistenceXmlTest() throws URISyntaxException {
ProjectContains projectContains = new ProjectContains("persistence.xml");
assertThat(TextFileContains.getProjectRoot(getClass()), projectContains);
assertThat(projectContains.getFoundFiles(), Matchers.not(Matchers.hasSize(0)));
Path persistenceXml = projectContains.getFoundFiles().getFirst();
assertThat(persistenceXml.toAbsolutePath().toString(),
Matchers.endsWith(Paths.get("resources", "META-INF", "persistence.xml").toString()));
}
@Test
void useEnumeratedTest() throws URISyntaxException {
assertThat(TextFileContains.getProjectRoot(getClass()),
new TextFileContains("Score.java", "@Enumerated\\(\\s*EnumType.STRING\\s*\\)"));
}
@TestMethodOrder(OrderAnnotation.class)
@Nested
class JpaConnectorTests {
private Score template = new Score(null, "Tester", 100, Level.EASY);
private JpaConnector connector;
@BeforeEach
void init() {
connector = new JpaConnector();
}
@AfterEach
void cleanUp() {
connector.stop();
}
boolean same(Score s1, Score s2) {
return s1.getLevel() == s2.getLevel() && s1.getPoints() == s2.getPoints()
&& Objects.equals(s1.getName(), s2.getName());
}
@Test
@Order(100)
void jpaScoreInsertTest() {
Score savedScore = connector.save(template);
assertThat(savedScore.getId(), Matchers.notNullValue());
}
@Test
@Order(200)
void jpaScoreReadTest() {
List<Score> savedScores = connector.getAll().stream().filter(s -> same(s, template)).toList();
assertThat(savedScores, Matchers.not(Matchers.hasSize(0)));
}
@Test
@Order(250)
void jpaReadSortedTest() {
for (int i = 0; i < 20; i++) {
connector.save(template.toBuilder().points(i).build());
}
List<Score> result = connector.getFirstTen();
assertThat(result, Matchers.hasSize(10));
for (int i = 0; i < result.size()-1; i++) {
assertThat(result.get(i).getPoints(), Matchers.greaterThanOrEqualTo(result.get(i+1).getPoints()));
}
}
@Test
@Order(300)
void jpaScoreModifyTest() {
List<Score> savedScores = connector.getAll().stream().filter(s -> same(s, template)).toList();
List<Long> savedIds = savedScores.stream().map(Score::getId).toList();
assertThat(savedScores, Matchers.not(Matchers.hasSize(0)));
for (Score score : savedScores) {
score.setLevel(Level.HARD);
connector.save(score);
}
List<Score> modifiedScores = connector.getAll().stream().filter(s -> savedIds.contains(s.getId())).toList();
assertThat(modifiedScores, Matchers.not(Matchers.hasSize(0)));
List<Score> originalDataScores = connector.getAll().stream().filter(s -> same(s, template)).toList();
assertThat(originalDataScores, Matchers.hasSize(0));
}
@Test
@Order(400)
void jpaScoreDeleteTest() {
template.setLevel(Level.HARD);
List<Score> savedScores = connector.getAll().stream().filter(s -> same(s, template)).toList();
List<Long> savedIds = savedScores.stream().map(Score::getId).toList();
assertThat(savedScores, Matchers.not(Matchers.hasSize(0)));
connector.delete(savedScores);
List<Score> modifiedScores = connector.getAll().stream().filter(s -> savedIds.contains(s.getId())).toList();
assertThat(modifiedScores, Matchers.hasSize(0));
List<Score> originalDataScores = connector.getAll().stream().filter(s -> same(s, template)).toList();
assertThat(originalDataScores, Matchers.hasSize(0));
}
@Test
@Order(400)
void jpaMergeTest() {
connector.save(template);
connector.find(template.getId());
Score copy = template.toBuilder().points(500).build();
Score result = connector.save(copy);
assertThat(result, Matchers.not(Matchers.sameInstance(copy)));
}
@Test
@Order(500)
void jpamodifyNoPersistNoMergeTest() throws URISyntaxException, IOException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, SecurityException {
template.setName("aaa");
connector.save(template);
connector.modifyNoPersistOrMerge(template.getId(), score -> score.setName("ok"));
Object em = connector.getEntityManager();
em.getClass().getMethod("clear").invoke(em);
assertThat(connector.find(template.getId()).getName(), Matchers.equalTo("ok"));
TextFileContains textFileContains = new TextFileContains("JpaConnector.java",
"void\\s+modifyNoPersistOrMerge[\\s\\S]*}").multiline(true);
assertThat(TextFileContains.getProjectRoot(ClassStructureTest.class), textFileContains);
Path score = textFileContains.getFoundFiles().getFirst();
String src = Files.readString(score);
String method = Pattern.compile("void\\s+modifyNoPersistOrMerge[\\s\\S]*}").matcher(src).results().findFirst().get().group();
assertThat(method, Matchers.not(Matchers.containsString("persist")));
assertThat(method, Matchers.not(Matchers.containsString("merge")));
}
}
}
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment