<groupId>de.diejungsvondertanke.tankstelle</groupId>
<artifactId>tankstelle</artifactId>
<version>1.0-SNAPSHOT</version>
+ <packaging>jar</packaging>
<build>
<plugins>
+ <!-- Adds the mainClass to the jar so it will run outside -->
<plugin>
- <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
- <version>3.3.0</version>
+ <version>3.1.0</version>
<configuration>
<archive>
<manifest>
- <mainClass>de.diejungsvondertanke.tankstelle.Main</mainClass>
+ <mainClass>${mainClass}</mainClass>
+ <!-- <mainClass>de.diejungsvondertanke.tankstelle.Main</mainClass> -->
</manifest>
</archive>
+ <outputDirectory>${project.build.directory}/modules</outputDirectory>
+ </configuration>
+ </plugin>
+
+ <!-- sets up the version of Java you are running -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.8.0</version>
+ <configuration>
+ <release>${java.version}</release>
+ </configuration>
+ <dependencies>
+ <dependency>
+ <groupId>org.ow2.asm</groupId>
+ <artifactId>asm</artifactId>
+ <version>6.2.1</version>
+ </dependency>
+ </dependencies>
+ </plugin>
+
+ <!-- Copies the depend FX files to your program -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>copy-dependencies</id>
+ <phase>prepare-package</phase>
+ <goals>
+ <goal>copy-dependencies</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>${project.build.directory}/modules</outputDirectory>
+ <includeScope>runtime</includeScope>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <!-- Maven Compiler -->
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.11.0</version>
+ <configuration>
+ <source>${java.version}</source>
+ <target>${java.version}</target>
+ </configuration>
+ </plugin>
+
+ <!-- Maven Exec Plugin to run JavaFX app -->
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>exec-maven-plugin</artifactId>
+ <version>3.1.0</version>
+ <configuration>
+ <mainClass>${main.Class}</mainClass>
+ <commandlineArgs>
+ --module-path
+ ${java.home}/lib
+ --add-modules=javafx.controls,javafx.fxml
+ </commandlineArgs>
</configuration>
</plugin>
</plugins>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>25</maven.compiler.source>
<maven.compiler.target>25</maven.compiler.target>
+ <java.version>20</java.version>
+ <javafx.version>23.0.2</javafx.version>
+ <main.Class>de.diejungsvondertanke.tankstelle.ui.JFX</main.Class>
</properties>
+ <dependencies>
+ <!-- JavaFX modules -->
+ <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.openjfx</groupId>
+ <artifactId>javafx-graphics</artifactId>
+ <version>${javafx.version}</version>
+ </dependency>
+
+ <!-- Optional: if you use TableView + properties -->
+ <dependency>
+ <groupId>org.openjfx</groupId>
+ <artifactId>javafx-base</artifactId>
+ <version>${javafx.version}</version>
+ </dependency>
+ </dependencies>
</project>
\ No newline at end of file
* @author Robin Cheney
* @author Nils Göbbert
*/
-abstract class FuelStation {
+public abstract class FuelStation {
/**
* Number of employees of this fuel station
*/
* create an array list to store the fuel stations while the program is running
* add the initial array of fuel stations to the List
*/
- static ArrayList<FuelStation> fuelStations = new ArrayList<FuelStation>(Arrays.asList(initialFuelStations));
+ public static ArrayList<FuelStation> fuelStations = new ArrayList<FuelStation>(Arrays.asList(initialFuelStations));
/**
* Main method
* @param args Program arguments (not in use)
*/
public static void main(String[] args) {
- javax.swing.SwingUtilities.invokeLater(() -> {
- FuelStationUI ui = new FuelStationUI();
- ui.setVisible(true);
- });
+ // javax.swing.SwingUtilities.invokeLater(() -> {
+ // FuelStationUI ui = new FuelStationUI();
+ // ui.setVisible(true);
+ // });
}
/**
--- /dev/null
+package de.diejungsvondertanke.tankstelle.controllers;
+
+public class ControllerRegistry {
+ private static FuelStationUIController main;
+
+ public static void registerMain(FuelStationUIController controller) {
+ main = controller;
+ }
+
+ public static FuelStationUIController getMain() {
+ return main;
+ }
+}
--- /dev/null
+package de.diejungsvondertanke.tankstelle.controllers;
+
+import java.io.IOException;
+import java.util.function.Consumer;
+
+import de.diejungsvondertanke.tankstelle.*;
+import javafx.fxml.FXML;
+import javafx.fxml.FXMLLoader;
+import javafx.scene.Parent;
+import javafx.scene.control.*;
+import javafx.scene.layout.BorderPane;
+import javafx.scene.layout.GridPane;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.Pane;
+
+public class FuelStationUIController {
+
+ // @FXML
+ // public ComboBox<String> comboFuelStations;
+
+ // @FXML
+ // public ComboBox<FuelType> comboFuelTypes;
+
+ // @FXML
+ // private TabPane tabPane;
+
+ // // child controllers
+ // @FXML
+ // private HBox resultTab;
+
+ // @FXML
+ // private HBox priceTab;
+
+ // @FXML
+ // private HBox stockTab;
+
+ // @FXML
+ // private HBox searchTab;
+
+ // @FXML
+ // private HBox newStationTab;
+
+ // @FXML
+ // private HBox overviewTab;
+
+ // @FXML
+ // private TextArea outputArea;
+
+ @FXML
+ public ComboBox<String> comboFuelStations;
+ @FXML
+ public ComboBox<FuelType> comboFuelTypes;
+ @FXML
+ private TabPane tabPane;
+ @FXML
+ private TextArea outputArea;
+
+ // Placeholder containers for the included tabs
+ @FXML
+ private HBox resultTabContainer;
+ @FXML
+ private GridPane priceTabContainer;
+ @FXML
+ private GridPane stockTabContainer;
+ @FXML
+ private HBox searchTabContainer;
+ @FXML
+ private GridPane newStationTabContainer;
+ @FXML
+ private BorderPane overviewTabContainer;
+
+ // Controllers of included tabs
+ private ResultTabController resultTabController;
+ private PriceTabController priceTabController;
+ private StockTabController stockTabController;
+ private SearchTabController searchTabController;
+ private NewStationTabController newStationTabController;
+ private OverviewTabController overviewTabController;
+
+ @FXML
+ public void initialize() {
+ // Load all tabs manually and keep controllers
+ comboFuelTypes.getItems().setAll(FuelType.values());
+ // loadTab("/ui/ResultTab.fxml", resultTabContainer,
+ // (ResultTabController controller) -> resultTabController = controller);
+ // loadTab("/ui/PriceTab.fxml", priceTabContainer,
+ // (PriceTabController controller) -> priceTabController = controller);
+ // loadTab("/ui/StockTab.fxml", stockTabContainer,
+ // (StockTabController controller) -> stockTabController = controller);
+ // loadTab("/ui/SearchTab.fxml", searchTabContainer,
+ // (SearchTabController controller) -> searchTabController = controller);
+ // loadTab("/ui/NewStationTab.fxml", newStationTabContainer,
+ // (NewStationTabController controller) -> newStationTabController =
+ // controller);
+ // loadTab("/ui/OverviewTab.fxml", overviewTabContainer,
+ // (OverviewTabController controller) -> overviewTabController = controller);
+
+ try {
+ loadTab("/ui/ResultTab.fxml", resultTabContainer, (ResultTabController c) -> resultTabController = c);
+ loadTab("/ui/PriceTab.fxml", priceTabContainer, (PriceTabController c) -> priceTabController = c);
+ loadTab("/ui/StockTab.fxml", stockTabContainer, (StockTabController c) -> stockTabController = c);
+ loadTab("/ui/SearchTab.fxml", searchTabContainer, (SearchTabController c) -> searchTabController = c);
+ loadTab("/ui/NewStationTab.fxml", newStationTabContainer,
+ (NewStationTabController c) -> newStationTabController = c);
+ loadTab("/ui/OverviewTab.fxml", overviewTabContainer,
+ (OverviewTabController c) -> overviewTabController = c);
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ }
+
+ // Generic loader helper
+ // private <T> void loadTab(String fxmlPath, Parent placeholder,
+ // java.util.function.Consumer<T> controllerSetter) {
+ // try {
+ // FXMLLoader loader = new FXMLLoader(getClass().getResource(fxmlPath));
+ // Parent content = loader.load();
+ // T controller = loader.getController();
+ // controllerSetter.accept(controller);
+ // placeholder.getChildren().setAll(content);
+ // } catch (IOException e) {
+ // e.printStackTrace();
+ // }
+ // }
+
+ private <T> void loadTab(String fxmlPath, Parent container, Consumer<T> controllerConsumer) throws IOException {
+ FXMLLoader loader = new FXMLLoader(getClass().getResource(fxmlPath));
+ Parent loaded = loader.load();
+ T controller = loader.getController();
+
+ // Add loaded node to the container
+ if (container instanceof Pane pane) {
+ pane.getChildren().setAll(loaded);
+ } else if (container instanceof ScrollPane scroll) {
+ scroll.setContent(loaded);
+ } else if (container instanceof BorderPane border) {
+ border.setCenter(loaded);
+ } else {
+ throw new IllegalArgumentException("Unsupported container type: " + container.getClass());
+ }
+
+ controllerConsumer.accept(controller);
+ }
+
+ public FuelStation getSelectedStation() {
+ int idx = comboFuelStations.getSelectionModel().getSelectedIndex();
+ if (idx < 0 || idx >= Main.fuelStations.size())
+ return null;
+ return Main.fuelStations.get(idx);
+ }
+
+ public void refreshStationNames() {
+ comboFuelStations.getItems().setAll(
+ Main.fuelStations.stream()
+ .map(this::getDisplayName)
+ .toList());
+ }
+
+ public String getDisplayName(FuelStation fs) {
+ int index = Main.fuelStations.indexOf(fs);
+ if (index >= 0) {
+ return "Station " + (index + 1) + " (" + fs.getClass().getSimpleName() + ")";
+ }
+ return fs.getClass().getSimpleName();
+ }
+
+ public void appendOutput(String text) {
+ outputArea.appendText(text + "\n\n");
+ }
+
+ public void showError(String msg) {
+ Alert alert = new Alert(Alert.AlertType.ERROR);
+ alert.setHeaderText("Error");
+ alert.setContentText(msg);
+ alert.showAndWait();
+ }
+}
--- /dev/null
+package de.diejungsvondertanke.tankstelle.controllers;
+
+import de.diejungsvondertanke.tankstelle.Main;
+import de.diejungsvondertanke.tankstelle.ui.JFX;
+import javafx.fxml.FXML;
+import javafx.scene.control.*;
+
+public class NewStationTabController {
+
+ @FXML
+ private RadioButton rbSmall, rbMedium, rbLarge;
+ @FXML
+ private TextField txtAttr;
+
+ private FuelStationUIController parentController;
+
+ // Called by parent after full initialization
+ public void setParentController(FuelStationUIController parent) {
+ this.parentController = parent;
+ }
+
+ @FXML
+ private void add() {
+ try {
+ if (rbSmall.isSelected()) {
+ short vending = Short.parseShort(txtAttr.getText().trim());
+ Main.addNewFuelStation(vending);
+ parentController.appendOutput("Added small station (" + vending + " vending machines).");
+
+ } else if (rbMedium.isSelected()) {
+ float size = Float.parseFloat(txtAttr.getText().replace(",", "."));
+ Main.addNewFuelStation(size);
+ parentController.appendOutput("Added medium station (" + size + " m²).");
+
+ } else if (rbLarge.isSelected()) {
+ String company = txtAttr.getText().trim();
+ Main.addNewFuelStation(company);
+ parentController.appendOutput("Added large station (" + company + ").");
+ }
+
+ parentController.refreshStationNames();
+ txtAttr.clear();
+
+ } catch (Exception e) {
+ parentController.showError(e.getMessage());
+ }
+ }
+}
--- /dev/null
+package de.diejungsvondertanke.tankstelle.controllers;
+
+import de.diejungsvondertanke.tankstelle.*;
+import de.diejungsvondertanke.tankstelle.ui.JFX;
+import javafx.beans.property.SimpleFloatProperty;
+import javafx.beans.property.SimpleIntegerProperty;
+import javafx.beans.property.SimpleStringProperty;
+import javafx.fxml.FXML;
+import javafx.scene.control.TableColumn;
+import javafx.scene.control.TableView;
+
+public class OverviewTabController {
+
+ @FXML
+ private TableView<FuelRow> table;
+
+ @FXML
+ private TableColumn<FuelRow, String> colStation;
+ @FXML
+ private TableColumn<FuelRow, String> colType;
+ @FXML
+ private TableColumn<FuelRow, String> colFuel;
+ @FXML
+ private TableColumn<FuelRow, Float> colAmount;
+ @FXML
+ private TableColumn<FuelRow, Integer> colCapacity;
+ @FXML
+ private TableColumn<FuelRow, Float> colPrice;
+
+ private FuelStationUIController parentController;
+
+ // Called by parent after full initialization
+ public void setParentController(FuelStationUIController parent) {
+ this.parentController = parent;
+ }
+
+ @FXML
+ public void initialize() {
+ colStation.setCellValueFactory(data -> new SimpleStringProperty(data.getValue().station()));
+ colType.setCellValueFactory(data -> new SimpleStringProperty(data.getValue().type()));
+ colFuel.setCellValueFactory(data -> new SimpleStringProperty(data.getValue().fuel()));
+ colAmount.setCellValueFactory(data -> new SimpleFloatProperty(data.getValue().amount()).asObject());
+ colCapacity.setCellValueFactory(data -> new SimpleIntegerProperty(data.getValue().capacity()).asObject());
+ colPrice.setCellValueFactory(data -> new SimpleFloatProperty(data.getValue().price()).asObject());
+
+ refresh();
+ }
+
+ @FXML
+ public void refresh() {
+ table.getItems().clear();
+
+ for (FuelStation station : Main.fuelStations) {
+ for (Fuel f : station.fuels) {
+ table.getItems().add(
+ new FuelRow(
+ parentController.getDisplayName(station),
+ station.getClass().getSimpleName(),
+ f.FUEL_TYPE.toString(),
+ f.getStored_amount(),
+ f.CAPACITY,
+ f.getPrice()));
+ }
+ }
+ }
+
+ public record FuelRow(
+ String station,
+ String type,
+ String fuel,
+ float amount,
+ int capacity,
+ float price) {
+ }
+}
--- /dev/null
+package de.diejungsvondertanke.tankstelle.controllers;
+
+import de.diejungsvondertanke.tankstelle.FuelStation;
+import de.diejungsvondertanke.tankstelle.FuelType;
+import de.diejungsvondertanke.tankstelle.error.NoSuchFuelTypeError;
+import de.diejungsvondertanke.tankstelle.ui.JFX;
+import javafx.fxml.FXML;
+import javafx.scene.control.TextField;
+
+public class PriceTabController {
+
+ @FXML
+ private TextField txtPrice;
+
+ private FuelStationUIController parentController;
+
+ // Called by parent after full initialization
+ public void setParentController(FuelStationUIController parent) {
+ this.parentController = parent;
+ }
+
+ @FXML
+ private void save() {
+ FuelStation station = parentController.getSelectedStation();
+ FuelType type = parentController.comboFuelTypes.getValue();
+
+ if (station == null) {
+ parentController.showError("Select a station.");
+ return;
+ }
+
+ try {
+ float price = Float.parseFloat(txtPrice.getText().replace(",", "."));
+ station.set_price(type, price);
+
+ parentController.appendOutput("Price of %s at %s changed to %.3f €/L"
+ .formatted(type, parentController.getDisplayName(station), price));
+
+ txtPrice.clear();
+
+ } catch (NumberFormatException ex) {
+ parentController.showError("Invalid number.");
+ } catch (NoSuchFuelTypeError ex) {
+ parentController.showError("Fuel type unavailable.");
+ }
+ }
+}
--- /dev/null
+package de.diejungsvondertanke.tankstelle.controllers;
+
+import de.diejungsvondertanke.tankstelle.*;
+import de.diejungsvondertanke.tankstelle.error.NoSuchFuelTypeError;
+import de.diejungsvondertanke.tankstelle.ui.JFX;
+import javafx.fxml.FXML;
+import javafx.scene.control.ListView;
+
+public class ResultTabController {
+
+ @FXML
+ private ListView<String> listFuelStations;
+ private FuelStationUIController parentController;
+
+ public void setParentController(FuelStationUIController parentController) {
+ this.parentController = parentController;
+ }
+
+ public void refreshList() {
+ if (parentController != null && parentController.comboFuelStations != null) {
+ listFuelStations.getItems().setAll(parentController.comboFuelStations.getItems());
+ }
+ }
+
+ // Example action using parent
+ @FXML
+ private void handleTotalPrice() {
+ if (parentController != null) {
+ parentController.appendOutput("Total price calculation here...");
+ }
+ }
+
+ @FXML
+ private void handleHighestPrice() {
+ FuelType type = parentController.comboFuelTypes.getValue();
+ try {
+ FuelStation fs = Main.getHighestPrice(type);
+ parentController.appendOutput("Highest price for %s: %s"
+ .formatted(type, parentController.getDisplayName(fs)));
+ } catch (NoSuchFuelTypeError ex) {
+ parentController.showError("Fuel type unavailable.");
+ }
+ }
+
+ @FXML
+ private void handleHighestTotalValue() {
+ try {
+ FuelStation fs = Main.getHighestAccumulatedValue();
+ parentController.appendOutput("Highest total value: " + parentController.getDisplayName(fs));
+ } catch (NoSuchFuelTypeError ex) {
+ parentController.showError("Calculation error.");
+ }
+ }
+
+ @FXML
+ private void handleStock() {
+ FuelType type = parentController.comboFuelTypes.getValue();
+ try {
+ FuelStation max = Main.getHighestStoredAmount(type);
+ FuelStation min = Main.getLowestStoredAmount(type);
+ parentController.appendOutput("""
+ Stock for %s:
+ - Highest: %s
+ - Lowest: %s
+ """.formatted(type, parentController.getDisplayName(max), parentController.getDisplayName(min)));
+ } catch (NoSuchFuelTypeError e) {
+ parentController.showError("Fuel type unavailable.");
+ }
+ }
+
+ @FXML
+ private void handleTotalStock() {
+ FuelType type = parentController.comboFuelTypes.getValue();
+ var items = listFuelStations.getSelectionModel().getSelectedIndices();
+
+ if (items.isEmpty()) {
+ parentController.showError("Select at least one station.");
+ return;
+ }
+
+ FuelStation[] stations = items.stream()
+ .map(i -> Main.fuelStations.get(i))
+ .toArray(FuelStation[]::new);
+
+ float total = Main.getTotalStockLevelOfFuel(type, stations);
+ parentController.appendOutput("Total for %s: %.2f L".formatted(type, total));
+ }
+}
--- /dev/null
+package de.diejungsvondertanke.tankstelle.controllers;
+
+import de.diejungsvondertanke.tankstelle.*;
+import de.diejungsvondertanke.tankstelle.ui.JFX;
+import de.diejungsvondertanke.tankstelle.error.NoSuchFuelTypeError;
+import javafx.fxml.FXML;
+
+public class SearchTabController {
+
+ private FuelStationUIController parentController;
+
+ // Called by parent after full initialization
+ public void setParentController(FuelStationUIController parent) {
+ this.parentController = parent;
+ }
+
+ @FXML
+ private void search() {
+ FuelType type = parentController.comboFuelTypes.getValue();
+
+ StringBuilder sb = new StringBuilder("Stations with " + type + ":\n");
+
+ for (FuelStation station : Main.fuelStations) {
+ try {
+ station.getStored_amount(type);
+ sb.append(" - ").append(parentController.getDisplayName(station)).append("\n");
+ } catch (NoSuchFuelTypeError ignore) {
+ }
+ }
+
+ parentController.appendOutput(sb.toString());
+ }
+}
--- /dev/null
+package de.diejungsvondertanke.tankstelle.controllers;
+
+import de.diejungsvondertanke.tankstelle.*;
+import de.diejungsvondertanke.tankstelle.ui.JFX;
+import de.diejungsvondertanke.tankstelle.error.NoSuchFuelTypeError;
+import javafx.fxml.FXML;
+import javafx.scene.control.*;
+
+public class StockTabController {
+
+ @FXML
+ private TextField txtAmount;
+ @FXML
+ private RadioButton rbAbsolute;
+ @FXML
+ private RadioButton rbDelta;
+
+ private FuelStationUIController parentController;
+
+ // Called by parent after full initialization
+ public void setParentController(FuelStationUIController parent) {
+ this.parentController = parent;
+ }
+
+ private int getCapacity(FuelStation station, FuelType type) throws NoSuchFuelTypeError {
+ for (Fuel f : station.fuels) {
+ if (f.FUEL_TYPE == type)
+ return f.CAPACITY;
+ }
+ throw new NoSuchFuelTypeError("Fuel type not available");
+ }
+
+ @FXML
+ private void save() {
+ FuelStation station = parentController.getSelectedStation();
+ FuelType type = parentController.comboFuelTypes.getValue();
+
+ if (station == null) {
+ parentController.showError("Select a station.");
+ return;
+ }
+
+ try {
+ float value = Float.parseFloat(txtAmount.getText().replace(",", "."));
+ int capacity = getCapacity(station, type);
+ float current = station.getStored_amount(type);
+
+ if (rbAbsolute.isSelected()) {
+ if (value < 0 || value > capacity) {
+ parentController.showError("Invalid amount.");
+ return;
+ }
+ station.set_stored_amount(value, type);
+ parentController.appendOutput("Stock of %s at %s set to %.2f L"
+ .formatted(type, parentController.getDisplayName(station), value));
+ } else {
+ float updated = current + value;
+ if (updated < 0 || updated > capacity) {
+ parentController.showError("Out of capacity bounds.");
+ return;
+ }
+ station.add_stored_amount(value, type);
+ parentController.appendOutput("Stock of %s at %s changed by %.2f L"
+ .formatted(type, parentController.getDisplayName(station), value));
+ }
+
+ txtAmount.clear();
+
+ } catch (Exception ex) {
+ parentController.showError(ex.getMessage());
+ }
+ }
+}
--- /dev/null
+package de.diejungsvondertanke.tankstelle.ui;
+
+import java.io.IOException;
+
+// import de.diejungsvondertanke.tankstelle.controllers.ControllerRegistry;
+import de.diejungsvondertanke.tankstelle.controllers.FuelStationUIController;
+import javafx.application.Application;
+import javafx.fxml.FXMLLoader;
+import javafx.scene.Parent;
+import javafx.scene.Scene;
+import javafx.stage.Stage;
+
+public class JFX extends Application {
+
+ static Stage stage;
+
+ public static FuelStationUIController controller;
+
+ static Parent parent;
+
+ @Override
+ public void start(Stage s) throws Exception {
+ stage = s;
+ Parent parent = loadFXML("FuelStationUI");
+ Scene scene = new Scene(parent);
+
+ stage.setScene(scene);
+ stage.setTitle("Fuel Station Management System");
+ stage.show();
+ }
+
+ public static void main(String[] args) {
+ launch(args);
+ }
+
+ private static Parent loadFXML(String fxml) throws IOException {
+ FXMLLoader fxmlLoader = new FXMLLoader(JFX.class.getResource("/ui/" + fxml + ".fxml"));
+ parent = fxmlLoader.load();
+ controller = fxmlLoader.getController();
+ return parent;
+ }
+}
--- /dev/null
+module tankstelle {
+ requires javafx.controls;
+ requires javafx.fxml;
+ requires javafx.graphics;
+ requires javafx.base;
+
+ opens de.diejungsvondertanke.tankstelle.ui to javafx.fxml, javafx.graphics;
+ opens de.diejungsvondertanke.tankstelle.controllers to javafx.fxml, javafx.graphics;
+ // exports de.diejungsvondertanke.tankstelle;
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<?import javafx.geometry.Insets?>
+<?import javafx.scene.layout.*?>
+<?import javafx.scene.control.*?>
+
+<BorderPane xmlns:fx="http://javafx.com/fxml"
+ fx:controller="de.diejungsvondertanke.tankstelle.controllers.FuelStationUIController"
+ prefWidth="900" prefHeight="700">
+
+ <!-- TOP — fuel station + fuel type selectors -->
+ <top>
+ <HBox spacing="10" styleClass="top-bar" alignment="CENTER_LEFT">
+ <padding>
+ <Insets top="10" right="10" bottom="10" left="10" />
+ </padding>
+ <Label text="Fuel station:" />
+ <ComboBox fx:id="comboFuelStations" prefWidth="200" />
+ <Label text="Fuel type:" />
+ <ComboBox fx:id="comboFuelTypes" prefWidth="150" />
+ </HBox>
+ </top>
+
+ <!-- CENTER — tabs -->
+ <center>
+ <TabPane fx:id="tabPane">
+ <tabs>
+ <Tab text="Result" closable="false">
+ <HBox fx:id="resultTabContainer" />
+ </Tab>
+ <Tab text="Change price" closable="false">
+ <GridPane fx:id="priceTabContainer" />
+ </Tab>
+ <Tab text="Change stock" closable="false">
+ <GridPane fx:id="stockTabContainer" />
+ </Tab>
+ <Tab text="Search" closable="false">
+ <HBox fx:id="searchTabContainer" />
+ </Tab>
+ <Tab text="New fuel station" closable="false">
+ <GridPane fx:id="newStationTabContainer" />
+ </Tab>
+ <Tab text="Overview" closable="false">
+ <BorderPane fx:id="overviewTabContainer" />
+ </Tab>
+ </tabs>
+ </TabPane>
+ </center>
+
+ <!-- BOTTOM — output area -->
+ <bottom>
+ <VBox>
+ <Label text="Output:" />
+ <TextArea fx:id="outputArea" editable="false" wrapText="true" prefRowCount="5" />
+ </VBox>
+ </bottom>
+</BorderPane>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<?import javafx.geometry.Insets?>
+<?import javafx.scene.control.*?>
+<?import javafx.scene.layout.*?>
+
+<GridPane xmlns:fx="http://javafx.com/fxml"
+ fx:controller="de.diejungsvondertanke.tankstelle.controllers.NewStationTabController"
+ hgap="10" vgap="10">
+ <padding>
+ <Insets top="15" right="15" bottom="15" left="15"/>
+ </padding>
+
+ <Label text="Type:" GridPane.rowIndex="0" GridPane.columnIndex="0" />
+
+ <ToggleGroup fx:id="group" />
+ <RadioButton fx:id="rbSmall" text="Small" selected="true"
+ toggleGroup="$group"
+ GridPane.rowIndex="1" GridPane.columnIndex="0" />
+ <RadioButton fx:id="rbMedium" text="Medium"
+ toggleGroup="$group"
+ GridPane.rowIndex="1" GridPane.columnIndex="1" />
+ <RadioButton fx:id="rbLarge" text="Large"
+ toggleGroup="$group"
+ GridPane.rowIndex="1" GridPane.columnIndex="2" />
+
+ <Label text="Attribute:" GridPane.rowIndex="2" GridPane.columnIndex="0" />
+ <TextField fx:id="txtAttr" GridPane.rowIndex="2" GridPane.columnIndex="1"
+ GridPane.columnSpan="2" />
+
+ <Label text="Hint:" GridPane.rowIndex="3" GridPane.columnIndex="0" />
+ <Label text="Small=vending machines, Medium=m², Large=supermarket-company"
+ wrapText="true"
+ GridPane.rowIndex="3" GridPane.columnIndex="1" GridPane.columnSpan="2" />
+
+ <Button text="Add fuel station" onAction="#add"
+ GridPane.rowIndex="4" GridPane.columnIndex="0" GridPane.columnSpan="3" />
+
+</GridPane>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<?import javafx.geometry.Insets?>
+<?import javafx.scene.control.*?>
+<?import javafx.scene.layout.*?>
+
+<BorderPane xmlns:fx="http://javafx.com/fxml"
+ fx:controller="de.diejungsvondertanke.tankstelle.controllers.OverviewTabController"
+>
+ <padding>
+ <Insets top="15" right="15" bottom="15" left="15"/>
+ </padding>
+
+ <top>
+ <HBox spacing="10">
+ <Label text="Overview of all fuels" />
+ <Button text="Refresh" onAction="#refresh" />
+ </HBox>
+ </top>
+
+ <center>
+ <TableView fx:id="table">
+ <columns>
+ <TableColumn fx:id="colStation" text="Fuel Station" />
+ <TableColumn fx:id="colType" text="Station Type" />
+ <TableColumn fx:id="colFuel" text="Fuel" />
+ <TableColumn fx:id="colAmount" text="Amount (L)" />
+ <TableColumn fx:id="colCapacity" text="Capacity (L)" />
+ <TableColumn fx:id="colPrice" text="Price (€/L)" />
+ </columns>
+ </TableView>
+ </center>
+</BorderPane>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<?import javafx.geometry.Insets?>
+<?import javafx.scene.layout.*?>
+<?import javafx.scene.control.*?>
+
+<GridPane xmlns:fx="http://javafx.com/fxml"
+ fx:controller="de.diejungsvondertanke.tankstelle.controllers.PriceTabController"
+ hgap="10" vgap="10">
+ <padding>
+ <Insets top="15" right="15" bottom="15" left="15"/>
+ </padding>
+
+ <Label text="New price (€/L):" GridPane.rowIndex="0" GridPane.columnIndex="0" />
+ <TextField fx:id="txtPrice" GridPane.rowIndex="0" GridPane.columnIndex="1" />
+
+ <Button text="Change price" onAction="#save"
+ GridPane.rowIndex="1" GridPane.columnIndex="0" GridPane.columnSpan="2" />
+
+</GridPane>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<?import javafx.geometry.Insets?>
+<?import javafx.scene.layout.*?>
+<?import javafx.scene.control.*?>
+
+<HBox xmlns:fx="http://javafx.com/fxml"
+ fx:controller="de.diejungsvondertanke.tankstelle.controllers.ResultTabController"
+ spacing="20">
+ <padding>
+ <Insets top="15" right="15" bottom="15" left="15"/>
+ </padding>
+
+ <VBox spacing="10">
+ <Button text="Total selling value of all fuel types" onAction="#handleTotalPrice" />
+ <Button text="Highest price (chosen fuel type)" onAction="#handleHighestPrice" />
+ <Button text="Highest total value" onAction="#handleHighestTotalValue" />
+ <Button text="Highest / lowest stock" onAction="#handleStock" />
+ <Button text="Total stock (selection)" onAction="#handleTotalStock" />
+ </VBox>
+
+ <VBox spacing="10">
+ <Label text="Fuel station selection (multiple):" />
+ <ListView fx:id="listFuelStations" prefWidth="220" />
+ </VBox>
+
+</HBox>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<?import javafx.geometry.Insets?>
+<?import javafx.scene.control.*?>
+<?import javafx.scene.layout.*?>
+
+<HBox xmlns:fx="http://javafx.com/fxml"
+ fx:controller="de.diejungsvondertanke.tankstelle.controllers.SearchTabController"
+>
+ <padding>
+ <Insets top="15" right="15" bottom="15" left="15"/>
+ </padding>
+
+ <Button text="Show stations with chosen fuel type" onAction="#search" />
+
+</HBox>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<?import javafx.geometry.Insets?>
+<?import javafx.scene.control.*?>
+<?import javafx.scene.layout.*?>
+
+<GridPane xmlns:fx="http://javafx.com/fxml"
+ fx:controller="de.diejungsvondertanke.tankstelle.controllers.StockTabController"
+ hgap="10" vgap="10">
+ <padding>
+ <Insets top="15" right="15" bottom="15" left="15"/>
+ </padding>
+
+ <Label text="Amount (L):" GridPane.rowIndex="0" GridPane.columnIndex="0" />
+ <TextField fx:id="txtAmount" GridPane.rowIndex="0" GridPane.columnIndex="1" />
+
+ <RadioButton fx:id="rbAbsolute" text="Set absolute" selected="true"
+ GridPane.rowIndex="1" GridPane.columnIndex="0" GridPane.columnSpan="2" />
+ <RadioButton fx:id="rbDelta" text="Change (+/-)"
+ GridPane.rowIndex="2" GridPane.columnIndex="0" GridPane.columnSpan="2" />
+
+ <Button text="Change stock" onAction="#save"
+ GridPane.rowIndex="3" GridPane.columnIndex="0" GridPane.columnSpan="2" />
+</GridPane>
\ No newline at end of file