diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..98b99a551e28559528e090cbfc676dcff9bd7def --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ +# Eclipse +.classpath +.project +.settings/ + +# Intellij +.idea/ +*.iml +*.iws + +# Mac +.DS_Store + +# Maven +log/ +target/ diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..8cd3d951f155791faf1c07ced3647ff7de4866ba --- /dev/null +++ b/pom.xml @@ -0,0 +1,90 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + 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</groupId> + <artifactId>efrei-lab-fx</artifactId> + <version>0.0.1-SNAPSHOT</version> + + <name>efrei-lab-fx</name> + + <packaging>jar</packaging> + + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <maven.compiler.release>21</maven.compiler.release> + <JavaFX.version>23</JavaFX.version> + <JUnit.version>5.11.0</JUnit.version> + <log4j.version>2.23.1</log4j.version> + <lombok.version>1.18.34</lombok.version> + </properties> + <dependencyManagement> + <dependencies> + <dependency> + <groupId>org.junit</groupId> + <artifactId>junit-bom</artifactId> + <version>${JUnit.version}</version> + <type>pom</type> + <scope>import</scope> + </dependency> + </dependencies> + </dependencyManagement> + + <dependencies> + <dependency> + <groupId>org.openjfx</groupId> + <artifactId>javafx-controls</artifactId> + <version>${JavaFX.version}</version> + </dependency> + <dependency> + <groupId>org.openjfx</groupId> + <artifactId>javafx-fxml</artifactId> + <version>${JavaFX.version}</version> + </dependency> + <dependency> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-jupiter</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.logging.log4j</groupId> + <artifactId>log4j-core</artifactId> + <version>${log4j.version}</version> + </dependency> + <dependency> + <groupId>org.apache.logging.log4j</groupId> + <artifactId>log4j-api</artifactId> + <version>${log4j.version}</version> + </dependency> + <dependency> + <groupId>org.projectlombok</groupId> + <artifactId>lombok</artifactId> + <version>${lombok.version}</version> + <scope>provided</scope> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.13.0</version> + <configuration> + <annotationProcessorPaths> + <path> + <groupId>org.projectlombok</groupId> + <artifactId>lombok</artifactId> + <version>${lombok.version}</version> + </path> + </annotationProcessorPaths> + </configuration> + </plugin> + <plugin> + <artifactId>maven-surefire-plugin</artifactId> + <version>3.5.0</version> + </plugin> + </plugins> + </build> + +</project> diff --git a/src/main/java/cz/vsb/fei/efrei/labfx/AlreadyDeadException.java b/src/main/java/cz/vsb/fei/efrei/labfx/AlreadyDeadException.java new file mode 100644 index 0000000000000000000000000000000000000000..7c4a80c8301bae57e0102929fd7dd9da1539d332 --- /dev/null +++ b/src/main/java/cz/vsb/fei/efrei/labfx/AlreadyDeadException.java @@ -0,0 +1,22 @@ +package cz.vsb.fei.efrei.labfx; + +public class AlreadyDeadException extends Exception { + + private static final long serialVersionUID = -7052667091386255519L; + + private Fighter fighter; + + public AlreadyDeadException(Fighter fighter) { + this.fighter = fighter; + } + + public Fighter getFighter() { + return fighter; + } + + + + + + +} diff --git a/src/main/java/cz/vsb/fei/efrei/labfx/App.java b/src/main/java/cz/vsb/fei/efrei/labfx/App.java new file mode 100644 index 0000000000000000000000000000000000000000..9e4c9007dea94aa14723dee6617a418c96672d82 --- /dev/null +++ b/src/main/java/cz/vsb/fei/efrei/labfx/App.java @@ -0,0 +1,52 @@ +package cz.vsb.fei.efrei.labfx; + +import javafx.application.Application; +import javafx.fxml.FXMLLoader; +import javafx.scene.Scene; +import javafx.scene.layout.BorderPane; +import javafx.stage.Stage; +import javafx.stage.WindowEvent; +import lombok.extern.log4j.Log4j2; + +/** + * Class <b>App</b> - extends class Application and it is an entry point of the program + * @author Java I + */ +@Log4j2 +public class App extends Application { + + public static void main(String[] args) { + log.info("Launching JavaFX application."); + launch(args); + } + + private AppController controller; + + @Override + public void start(Stage primaryStage) { + try { + //Construct a main window with a canvas. + + FXMLLoader loader = new FXMLLoader(this.getClass().getResource("AppWindow.fxml")); + + BorderPane root = loader.load(); + + Scene scene = new Scene(root); + + + primaryStage.setScene(scene); + primaryStage.setTitle("Monster catalog"); + primaryStage.show(); + controller = loader.getController(); + + //Exit program when main window is closed + primaryStage.setOnCloseRequest(this::exitProgram); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void exitProgram(WindowEvent evt) { + System.exit(0); + } +} \ No newline at end of file diff --git a/src/main/java/cz/vsb/fei/efrei/labfx/AppController.java b/src/main/java/cz/vsb/fei/efrei/labfx/AppController.java new file mode 100644 index 0000000000000000000000000000000000000000..272d7c212801d3ab7174f3473e28d9a0780654a6 --- /dev/null +++ b/src/main/java/cz/vsb/fei/efrei/labfx/AppController.java @@ -0,0 +1,80 @@ +package cz.vsb.fei.efrei.labfx; + +import java.util.Optional; + +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.control.Alert; +import javafx.scene.control.Alert.AlertType; +import javafx.scene.control.Button; +import javafx.scene.control.ButtonBar.ButtonData; +import javafx.scene.control.ButtonType; +import javafx.scene.control.MenuItem; +import javafx.scene.control.TableColumn; +import javafx.scene.control.TableView; +import javafx.scene.control.cell.PropertyValueFactory; + +public class AppController { + + @FXML + private Button buttonDelete; + + @FXML + private Button buttonGenerate; + + @FXML + private TableColumn<Monster, String> leaderColumn; + + @FXML + private TableColumn<Monster, Integer> livesColumn; + + @FXML + private TableView<Monster> monsterTable; + + @FXML + private TableColumn<Monster, String> nameColumn; + + @FXML + private TableColumn<Monster, Integer> strengthColumn; + + @FXML + void buttonDeletePressed(ActionEvent event) { + Alert alertDialog = new Alert(AlertType.CONFIRMATION, "Are you sure??"); + Optional<ButtonType> result = alertDialog.showAndWait(); + if (result.isPresent() && result.get().getButtonData() == ButtonData.OK_DONE) { + monsterTable.getItems().removeAll(monsterTable.getSelectionModel().getSelectedItems()); + } + } + + @FXML + void buttonGeneratePressed(ActionEvent event) { + monsterTable.getItems().add(new Monster(Utils.generateMonsterName())); + } + + @FXML + private void menuPressed(ActionEvent event) { + if (event.getSource() instanceof MenuItem menuItem) { + + } + } + + @FXML + void initialize() { + assert buttonDelete != null : "fx:id=\"buttonDelete\" was not injected: check your FXML file 'AppWindow.fxml'."; + assert buttonGenerate != null + : "fx:id=\"buttonGenerate\" was not injected: check your FXML file 'AppWindow.fxml'."; + assert leaderColumn != null : "fx:id=\"leaderColumn\" was not injected: check your FXML file 'AppWindow.fxml'."; + assert livesColumn != null : "fx:id=\"livesColumn\" was not injected: check your FXML file 'AppWindow.fxml'."; + assert monsterTable != null : "fx:id=\"monsterTable\" was not injected: check your FXML file 'AppWindow.fxml'."; + assert nameColumn != null : "fx:id=\"nameColumn\" was not injected: check your FXML file 'AppWindow.fxml'."; + assert strengthColumn != null + : "fx:id=\"strengthColumn\" was not injected: check your FXML file 'AppWindow.fxml'."; + + nameColumn.setCellValueFactory(new PropertyValueFactory<>("name")); + strengthColumn.setCellValueFactory(new PropertyValueFactory<>("strenght")); + livesColumn.setCellValueFactory(new PropertyValueFactory<>("lives")); + leaderColumn.setCellValueFactory(new PropertyValueFactory<>("leader")); + + } + +} diff --git a/src/main/java/cz/vsb/fei/efrei/labfx/Fighter.java b/src/main/java/cz/vsb/fei/efrei/labfx/Fighter.java new file mode 100644 index 0000000000000000000000000000000000000000..458721501fa261a9033ce310cee40cfdefaf508d --- /dev/null +++ b/src/main/java/cz/vsb/fei/efrei/labfx/Fighter.java @@ -0,0 +1,17 @@ +package cz.vsb.fei.efrei.labfx; + +public interface Fighter extends Comparable<Fighter> { + + int getLives(); + + public default boolean isAlive() { + return getLives() > 0; + } + + public void attackedBy(Fighter fighter) throws AlreadyDeadException; + + public String getName(); + + public int getStrenght(); + +} diff --git a/src/main/java/cz/vsb/fei/efrei/labfx/Monster.java b/src/main/java/cz/vsb/fei/efrei/labfx/Monster.java new file mode 100644 index 0000000000000000000000000000000000000000..7439780750d448e55e049698af230804c35fdd5e --- /dev/null +++ b/src/main/java/cz/vsb/fei/efrei/labfx/Monster.java @@ -0,0 +1,67 @@ +package cz.vsb.fei.efrei.labfx; + +import java.util.Random; + +public class Monster implements Fighter { + + private static final Random RANDOM = new Random(); + + private String name; + private final int strenght; + private int lives; + private boolean leader = true; + + public Monster(String name, int strenght) { + if (name == null || name.length() < 2) { + throw new IllegalArgumentException("Too short name"); + } + if (strenght < 10) { + throw new IllegalArgumentException("Monster is too weak!!"); + } + this.name = name; + this.strenght = strenght; + this.lives = 100; + } + + public Monster(String name) { + this(name, RANDOM.nextInt(90) + 10); + } + + @Override + public void attackedBy(Fighter fighter) { +// System.out.println(fighter.getName() + " attack " + getName() + "!"); + lives -= fighter.getStrenght(); + } + + @Override + public String getName() { + return name; + } + + @Override + public int getStrenght() { + return strenght; + } + + @Override + public int getLives() { + return lives; + } + + @Override + public String toString() { + return String.format("Monster %20s (%4d) - has %4d lives.", name, strenght, lives); + } + + @Override + public int compareTo(Fighter o) { + return this.getName().compareTo(o.getName()); + } + + public boolean isLeader() { + return leader; + } + + + +} diff --git a/src/main/java/cz/vsb/fei/efrei/labfx/Utils.java b/src/main/java/cz/vsb/fei/efrei/labfx/Utils.java new file mode 100644 index 0000000000000000000000000000000000000000..d79525c38f9479cdfd6cf0c692813e60ed359512 --- /dev/null +++ b/src/main/java/cz/vsb/fei/efrei/labfx/Utils.java @@ -0,0 +1,30 @@ +package cz.vsb.fei.efrei.labfx; + +import java.util.Arrays; +import java.util.List; +import java.util.Random; + +public class Utils { + + public static final Random RANDOM = new Random(); + private static List<String> heroNames = Arrays.asList("Captain Freedom", "Iron Blade", "Shadow Hunter", + "ÄŚSilver Hawk", "Ĺ˝Mighty Thunder", "ÄšLunar Knight", "Phoenix Blaze", "Stormbreaker", "Star Guardian", + "ŇSolar Sentinel", "Dark Raven", "Blaze Falcon", "Crystal Viper", "Lightning Strike", "Firestorm", + "Eagle Eye", "Nightshade", "Frostbite", "Wind Whisperer", "Shadow Blaze"); + + private static List<String> monsterNames = Arrays.asList("Nightmare Reaper", "Shadow Fiend", "Bonecrusher", + "ĂVenomous Hydra", "ÉDoomfang", "Blightbringer", "Void Stalker", "Inferno Drake", "Ghoul King", "Frost Wyrm", + "Terrorclaw", "ĂŤBloodfeast", "Ravenous Maw", "Storm Serpent", "Hellhound", "Dark Overlord", "Necroshade", + "Plaguebeast", "Stone Golem", "Fire Leviathan"); + + public static String generateHeroName() { + return heroNames.get(RANDOM.nextInt(heroNames.size())); + } + public static String generateMonsterName() { + return monsterNames.get(RANDOM.nextInt(monsterNames.size())); + } + + public static <T> T getRandom(List<T> list) { + return list.get(RANDOM.nextInt(list.size())); + } +} diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java new file mode 100644 index 0000000000000000000000000000000000000000..8f3d439a63d238d42384377192e14b3dffcfda42 --- /dev/null +++ b/src/main/java/module-info.java @@ -0,0 +1,8 @@ +module cz.vsb.fei.efrei.labfx { + requires transitive javafx.controls; + requires javafx.fxml; + requires static lombok; + requires org.apache.logging.log4j; + opens cz.vsb.fei.efrei.labfx to javafx.fxml; + exports cz.vsb.fei.efrei.labfx; +} \ No newline at end of file diff --git a/src/main/resources/cz/vsb/fei/efrei/labfx/AppWindow.fxml b/src/main/resources/cz/vsb/fei/efrei/labfx/AppWindow.fxml new file mode 100644 index 0000000000000000000000000000000000000000..7da5781939ed729da6891bde5f0e5d0a2033568e --- /dev/null +++ b/src/main/resources/cz/vsb/fei/efrei/labfx/AppWindow.fxml @@ -0,0 +1,108 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<!-- + Copyright (c) 2015, 2019, Gluon and/or its affiliates. + All rights reserved. Use is subject to license terms. + + This file is available and licensed under the following license: + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + - Neither the name of Oracle Corporation nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--> + +<?import javafx.scene.control.Button?> +<?import javafx.scene.control.Menu?> +<?import javafx.scene.control.MenuBar?> +<?import javafx.scene.control.MenuItem?> +<?import javafx.scene.control.SeparatorMenuItem?> +<?import javafx.scene.control.TableColumn?> +<?import javafx.scene.control.TableView?> +<?import javafx.scene.layout.BorderPane?> +<?import javafx.scene.layout.VBox?> + +<BorderPane minHeight="200.0" minWidth="300.0" xmlns="http://javafx.com/javafx/22" xmlns:fx="http://javafx.com/fxml/1" fx:controller="cz.vsb.fei.efrei.labfx.AppController"> + <top> + <MenuBar BorderPane.alignment="CENTER"> + <menus> + <Menu mnemonicParsing="false" text="File"> + <items> + <MenuItem mnemonicParsing="false" onAction="#menuPressed" text="New" /> + <MenuItem mnemonicParsing="false" onAction="#menuPressed" text="Open…" /> + <Menu mnemonicParsing="false" text="Open Recent" /> + <SeparatorMenuItem mnemonicParsing="false" /> + <MenuItem mnemonicParsing="false" onAction="#menuPressed" text="Close" /> + <MenuItem mnemonicParsing="false" onAction="#menuPressed" text="Save" /> + <MenuItem mnemonicParsing="false" onAction="#menuPressed" text="Save As…" /> + <MenuItem mnemonicParsing="false" onAction="#menuPressed" text="Revert" /> + <SeparatorMenuItem mnemonicParsing="false" onAction="#menuPressed" /> + <MenuItem mnemonicParsing="false" onAction="#menuPressed" text="Preferences…" /> + <SeparatorMenuItem mnemonicParsing="false" /> + <MenuItem mnemonicParsing="false" onAction="#menuPressed" text="Quit" /> + </items> + </Menu> + <Menu mnemonicParsing="false" text="Edit"> + <items> + <MenuItem mnemonicParsing="false" onAction="#menuPressed" text="Undo" /> + <MenuItem mnemonicParsing="false" onAction="#menuPressed" text="Redo" /> + <SeparatorMenuItem mnemonicParsing="false" /> + <MenuItem mnemonicParsing="false" onAction="#menuPressed" text="Cut" /> + <MenuItem mnemonicParsing="false" onAction="#menuPressed" text="Copy" /> + <MenuItem mnemonicParsing="false" onAction="#menuPressed" text="Paste" /> + <MenuItem mnemonicParsing="false" onAction="#menuPressed" text="Delete" /> + <SeparatorMenuItem mnemonicParsing="false" /> + <MenuItem mnemonicParsing="false" onAction="#menuPressed" text="Select All" /> + <MenuItem mnemonicParsing="false" onAction="#menuPressed" text="Unselect All" /> + </items> + </Menu> + <Menu mnemonicParsing="false" text="Help"> + <items> + <MenuItem mnemonicParsing="false" onAction="#menuPressed" text="About MyHelloApp" /> + </items> + </Menu> + </menus> + </MenuBar> + </top> + <right> + <VBox BorderPane.alignment="CENTER"> + <children> + <Button fx:id="buttonGenerate" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#buttonGeneratePressed" text="Generate monster" textFill="#3504bf" /> + <Button fx:id="buttonDelete" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#buttonDeletePressed" text="DeleteMonster" /> + </children> + </VBox> + </right> + <center> + <TableView fx:id="monsterTable" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" BorderPane.alignment="CENTER"> + <columns> + <TableColumn fx:id="nameColumn" maxWidth="1.7976931348623157E308" prefWidth="150.0" text="Name" /> + <TableColumn fx:id="strengthColumn" maxWidth="1.7976931348623157E308" prefWidth="70.0" text="Strength" /> + <TableColumn fx:id="livesColumn" maxWidth="1.7976931348623157E308" prefWidth="50.0" text="Lives" /> + <TableColumn fx:id="leaderColumn" prefWidth="50.0" text="Leader" /> + </columns> + <columnResizePolicy> + <TableView fx:constant="CONSTRAINED_RESIZE_POLICY" /> + </columnResizePolicy> + </TableView> + </center> +</BorderPane> diff --git a/src/main/resources/cz/vsb/fei/efrei/labfx/application.css b/src/main/resources/cz/vsb/fei/efrei/labfx/application.css new file mode 100644 index 0000000000000000000000000000000000000000..83d6f3343843c65d5dfaf3fedb97b6494c19113d --- /dev/null +++ b/src/main/resources/cz/vsb/fei/efrei/labfx/application.css @@ -0,0 +1 @@ +/* JavaFX CSS - Leave this comment until you have at least create one rule which uses -fx-Property */ \ No newline at end of file diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml new file mode 100644 index 0000000000000000000000000000000000000000..acb3514078f6fb73f4f09ffd7a172b47f184e961 --- /dev/null +++ b/src/main/resources/log4j2.xml @@ -0,0 +1,13 @@ +<Configuration> + <Appenders> + <Console name="Console"> + <PatternLayout + pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" /> + </Console> + </Appenders> + <Loggers> + <Root level="info"> + <AppenderRef ref="Console"></AppenderRef> + </Root> + </Loggers> +</Configuration> diff --git a/src/test/java/cz/vsb/fei/efrei/labfx/AppTest.java b/src/test/java/cz/vsb/fei/efrei/labfx/AppTest.java new file mode 100644 index 0000000000000000000000000000000000000000..519d2465e246d6d1f3ba142c1942e519179d3c75 --- /dev/null +++ b/src/test/java/cz/vsb/fei/efrei/labfx/AppTest.java @@ -0,0 +1,19 @@ +package cz.vsb.fei.efrei.labfx; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +/** + * Unit test for simple App. + */ +class AppTest { + + /** + * Rigorous Test :-) + */ + @Test + void shouldAnswerWithTrue() { + assertTrue(true); + } +}