diff --git a/src/main/java/dev/ksan/travelpathoptimizer/Main.java b/src/main/java/dev/ksan/travelpathoptimizer/Main.java new file mode 100644 index 0000000..8099e4e --- /dev/null +++ b/src/main/java/dev/ksan/travelpathoptimizer/Main.java @@ -0,0 +1,4 @@ +package dev.ksan.travelpathoptimizer; + +public class Main { +} diff --git a/src/main/java/dev/ksan/travelpathoptimizer/app/TransportDataGenerator.java b/src/main/java/dev/ksan/travelpathoptimizer/app/TransportDataGenerator.java index e582dfc..3d12f4c 100644 --- a/src/main/java/dev/ksan/travelpathoptimizer/app/TransportDataGenerator.java +++ b/src/main/java/dev/ksan/travelpathoptimizer/app/TransportDataGenerator.java @@ -8,17 +8,26 @@ public class TransportDataGenerator { private static final int SIZE = 10; private int n; private int m; - - private static final int DEPARTURES_PER_STATION = 1; + private static final int DEPARTURES_DEFAULT = 3; + private static int DEPARTURES_PER_STATION = DEPARTURES_DEFAULT; private static final Random random = new Random(); - public static void main(String[] args) { - TransportDataGenerator generator = new TransportDataGenerator(2, 2); + + + public static void generateNewMap(int n, int m) { + DEPARTURES_PER_STATION= DEPARTURES_DEFAULT; + TransportDataGenerator generator = new TransportDataGenerator(n, m); + TransportData data = generator.generateData(); + generator.saveToJson(data, "transport_data.json"); + System.out.println("Podaci su generisani i sacuvani kao transport_data.json"); + } + public static void generateNewMap(int n, int m, int departures) { + TransportDataGenerator generator = new TransportDataGenerator(n, m); + DEPARTURES_PER_STATION = departures; TransportData data = generator.generateData(); generator.saveToJson(data, "transport_data.json"); System.out.println("Podaci su generisani i sacuvani kao transport_data.json"); } - TransportDataGenerator() { this.n = SIZE; this.m = SIZE; diff --git a/src/main/java/dev/ksan/travelpathoptimizer/app/TravelPathOptimizerApplication.java b/src/main/java/dev/ksan/travelpathoptimizer/app/TravelPathOptimizerApplication.java index 5aa86c6..26e3bae 100644 --- a/src/main/java/dev/ksan/travelpathoptimizer/app/TravelPathOptimizerApplication.java +++ b/src/main/java/dev/ksan/travelpathoptimizer/app/TravelPathOptimizerApplication.java @@ -1,23 +1,34 @@ package dev.ksan.travelpathoptimizer.app; +import java.io.IOException; import javafx.application.Application; import javafx.fxml.FXMLLoader; +import javafx.scene.Group; import javafx.scene.Scene; +import javafx.scene.image.Image; +import javafx.scene.paint.Color; import javafx.stage.Stage; -import java.io.IOException; - public class TravelPathOptimizerApplication extends Application { - @Override - public void start(Stage stage) throws IOException { - FXMLLoader fxmlLoader = new FXMLLoader(TravelPathOptimizerApplication.class.getResource("hello-view.fxml")); - Scene scene = new Scene(fxmlLoader.load(), 320, 240); - stage.setTitle("Hello!"); - stage.setScene(scene); - stage.show(); - } + @Override + public void start(Stage stage) throws IOException { + + FXMLLoader fxmlLoader = + new FXMLLoader(TravelPathOptimizerApplication.class.getResource("main.fxml")); + + String css = this.getClass().getResource("application.css").toExternalForm(); + + Scene scene = new Scene(fxmlLoader.load()); + Image image = new Image(getClass().getResourceAsStream("/images/img1.jpg")); + scene.getStylesheets().add(css); + stage.getIcons().add(image); + stage.setTitle("Hello!"); + stage.setScene(scene); + stage.show(); + } + + public static void main(String[] args) { + launch(); + } +} - public static void main(String[] args) { - launch(); - } -} \ No newline at end of file diff --git a/src/main/java/dev/ksan/travelpathoptimizer/controller/MainController.java b/src/main/java/dev/ksan/travelpathoptimizer/controller/MainController.java new file mode 100644 index 0000000..9fb9d23 --- /dev/null +++ b/src/main/java/dev/ksan/travelpathoptimizer/controller/MainController.java @@ -0,0 +1,278 @@ +package dev.ksan.travelpathoptimizer.controller; + +import dev.ksan.travelpathoptimizer.app.TransportDataGenerator; +import dev.ksan.travelpathoptimizer.model.City; +import dev.ksan.travelpathoptimizer.model.Departure; +import dev.ksan.travelpathoptimizer.model.Location; +import dev.ksan.travelpathoptimizer.service.CityManager; +import dev.ksan.travelpathoptimizer.util.JsonParser; +import java.io.File; +import java.util.List; +import javafx.fxml.FXML; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.TextField; +import javafx.scene.layout.ColumnConstraints; +import javafx.scene.layout.GridPane; +import javafx.scene.layout.Priority; +import javafx.scene.layout.RowConstraints; +import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; +import javafx.scene.text.Text; +import javafx.stage.FileChooser; +import javafx.stage.Stage; + +public class MainController { + + @FXML private GridPane map; + @FXML private Label welcomeText; + @FXML private Text selectedFileText; + private City startCity = null; + private City endCity = null; + private boolean selectingStart = false; + private boolean selectingEnd = false; + @FXML private TextField startCityText; + @FXML private TextField endCityText; + @FXML private Button startCityButton; + @FXML private Button endCityButton; + + City[][] cities; + private CityManager cityManager; + private File selectedFile; + @FXML private Button openFileButton; + @FXML private TextField nTextField; + @FXML private TextField mTextField; + @FXML private TextField departureTextField; + @FXML private VBox randomSideBar; + @FXML private VBox mapSideBar; + + @FXML + protected void onHelloButtonClick() { + welcomeText.setText("Welcome to JavaFX Application!"); + } + + @FXML + void showRandomSideBar() { + boolean visible = randomSideBar.isVisible(); + randomSideBar.setVisible(!visible); + randomSideBar.setManaged(!visible); + } + + @FXML + void showMapSideBar() { + boolean visible = mapSideBar.isVisible(); + mapSideBar.setVisible(!visible); + mapSideBar.setManaged(!visible); + } + + private void updateMap() { + map.getChildren().clear(); + map.getRowConstraints().clear(); + map.getColumnConstraints().clear(); + + int rows = cities.length; + int cols = cities[0].length; + + // Make each row/column take equal space and grow + for (int i = 0; i < rows; i++) { + RowConstraints rc = new RowConstraints(); + rc.setPercentHeight(100.0 / rows); + rc.setVgrow(Priority.ALWAYS); + map.getRowConstraints().add(rc); + } + + for (int j = 0; j < cols; j++) { + ColumnConstraints cc = new ColumnConstraints(); + cc.setPercentWidth(100.0 / cols); + cc.setHgrow(Priority.ALWAYS); + map.getColumnConstraints().add(cc); + } + + for (int row = 0; row < rows; row++) { + for (int col = 0; col < cols; col++) { + final int currentRow = row; + final int currentCol = col; + StackPane cell = new StackPane(); + cell.setPrefSize(60, 60); + cell.setStyle("-fx-border-color: black; -fx-background-color: white;"); + City city = cities[currentRow][currentCol]; + Label label = new Label(city.getName()); + label.setStyle("-fx-font-size: 10px;"); + label.setWrapText(true); + final StackPane thisCell = cell; + + thisCell.getChildren().add(label); + cell.setOnMouseClicked( + e -> { + if (selectingStart) { + startCity = cities[currentRow][currentCol]; + startCityText.setText(startCity.getName()); + selectingStart = false; + updateMap(); // redraw grid with updated startCity style + } else if (selectingEnd) { + endCity = cities[currentRow][currentCol]; + endCityText.setText(endCity.getName()); + selectingEnd = false; + updateMap(); // redraw grid with updated endCity style + } + }); + thisCell.setStyle("-fx-border-color: black; -fx-background-color: white;"); + Location loc = cities[currentRow][currentCol].getLocation(); + + if (startCity != null) { + Location startLoc = startCity.getLocation(); + if (loc.getX() == startLoc.getX() && loc.getY() == startLoc.getY()) { + thisCell.setStyle( + "-fx-border-color: green; -fx-border-width: 3; -fx-background-color: white;"); + } + } + + if (endCity != null) { + Location endLoc = endCity.getLocation(); + if (loc.getX() == endLoc.getX() && loc.getY() == endLoc.getY()) { + thisCell.setStyle( + "-fx-border-color: red; -fx-border-width: 3; -fx-background-color: white;"); + } + } + map.add(cell, col, row); + } + } + } + + @FXML + private void selectStart() { + this.selectingEnd = false; + this.selectingStart = true; + updateMap(); + } + + @FXML + private void selectEnd() { + this.selectingStart = false; + this.selectingEnd = true; + updateMap(); + } + + private boolean cityExists(String name) { + for (int row = 0; row < cities.length; row++) { + for (int col = 0; col < cities[0].length; col++) { + City city = cities[row][col]; + if (city != null && city.getName().equalsIgnoreCase(name.trim())) { + return true; + } + } + } + return false; + } + + @FXML + public void initialize() { + endCityText + .textProperty() + .addListener( + (obs, oldText, newText) -> { + if (newText.isBlank()) { + endCity = null; + endCityText.setStyle("-fx-text-fill: black;"); + } else { + City match = cityManager.getCityByName(newText.trim()); + if (match != null) { + endCity = match; + endCityText.setStyle("-fx-text-fill: green;"); + } else { + endCity = null; + endCityText.setStyle("-fx-text-fill: red;"); + } + } + + updateMap(); // Re-draw with highlight if matched + }); + startCityText + .textProperty() + .addListener( + (obs, oldText, newText) -> { + if (newText.isBlank()) { + startCity = null; + startCityText.setStyle("-fx-text-fill: black;"); + } else { + City match = cityManager.getCityByName(newText.trim()); + if (match != null) { + startCity = match; + startCityText.setStyle("-fx-text-fill: green;"); + } else { + startCity = null; + startCityText.setStyle("-fx-text-fill: red;"); + } + } + + updateMap(); // Re-draw with highlight if matched + }); + } + + @FXML + void generateNewMap() { + if (!nTextField.getText().isEmpty() && !mTextField.getText().isEmpty()) { + System.out.println(nTextField.getText()); + System.out.println(mTextField.getText()); + System.out.println(departureTextField.getText()); + if (!departureTextField.getText().isEmpty()) { + TransportDataGenerator.generateNewMap( + Integer.parseInt(nTextField.getText()), + Integer.parseInt(mTextField.getText()), + Integer.parseInt(departureTextField.getText())); + } else { + TransportDataGenerator.generateNewMap( + Integer.parseInt(nTextField.getText()), Integer.parseInt(mTextField.getText())); + } + } + } + + private void getData() { + List cities = JsonParser.parseCities(selectedFile.toString(), "stations"); + List departures = JsonParser.getDeparturesList("transport_data.json", "departures"); + cities = JsonParser.loadDepartures(cities, departures); + City[][] map = JsonParser.loadMap("transport_data.json", "countryMap", cities); + + cities = JsonParser.loadDepartures(cities, departures); + for (City city : cities) { + System.out.println(city); + CityManager.addCity(city); + } + this.cities = map; + } + + @FXML + void loadMapFromFile() { + FileChooser fileChooser = new FileChooser(); + fileChooser.setTitle("Open File"); + + fileChooser + .getExtensionFilters() + .addAll( + new FileChooser.ExtensionFilter("Json Files", "*.json"), + new FileChooser.ExtensionFilter("All Files", "*.*")); + + Stage stage = (Stage) openFileButton.getScene().getWindow(); + selectedFile = fileChooser.showOpenDialog(stage); + if (selectedFile != null) { + + selectedFileText.setText(selectedFile.getAbsoluteFile().getName().toString()); + } + getData(); + updateMap(); + } + /* + @FXML + void openLoadedFileDesktop(){ + selectedFileText.setOnMouseClicked(event -> { + if(selectedFile != null && selectedFile.exists()){ + try{ + Desktop.getDesktop().open(selectedFile); + } + catch(Exception e){ + e.printStackTrace(); + } + } + }); + }*/ +} diff --git a/src/main/java/dev/ksan/travelpathoptimizer/controller/TransportPathOptimizerController.java b/src/main/java/dev/ksan/travelpathoptimizer/controller/TransportPathOptimizerController.java deleted file mode 100644 index 8fc2899..0000000 --- a/src/main/java/dev/ksan/travelpathoptimizer/controller/TransportPathOptimizerController.java +++ /dev/null @@ -1,14 +0,0 @@ -package dev.ksan.travelpathoptimizer.controller; - -import javafx.fxml.FXML; -import javafx.scene.control.Label; - -public class TransportPathOptimizerController { - @FXML - private Label welcomeText; - - @FXML - protected void onHelloButtonClick() { - welcomeText.setText("Welcome to JavaFX Application!"); - } -} \ No newline at end of file diff --git a/src/main/java/dev/ksan/travelpathoptimizer/graph/Graph.java b/src/main/java/dev/ksan/travelpathoptimizer/graph/Graph.java index f918d4b..bae67df 100644 --- a/src/main/java/dev/ksan/travelpathoptimizer/graph/Graph.java +++ b/src/main/java/dev/ksan/travelpathoptimizer/graph/Graph.java @@ -14,7 +14,7 @@ import java.util.PriorityQueue; public class Graph { private City[][] matrix; - +/* public static void main(String[] args) { List cities = JsonParser.parseCities("transport_data.json", "stations"); List departures = JsonParser.getDeparturesList("transport_data.json", "departures"); @@ -32,6 +32,7 @@ public class Graph { System.out.println( cities.getLast().getName() + " = " + result.get(cities.get(3).getLocation())); } + */ public Map calculateShortestPath(City startCity, City endCity, String type) { int n = matrix.length; diff --git a/src/main/java/dev/ksan/travelpathoptimizer/model/City.java b/src/main/java/dev/ksan/travelpathoptimizer/model/City.java index 10b2916..2f29e35 100644 --- a/src/main/java/dev/ksan/travelpathoptimizer/model/City.java +++ b/src/main/java/dev/ksan/travelpathoptimizer/model/City.java @@ -9,14 +9,14 @@ public class City { private Station busStation; private Location location; - City(String name, String bus, String train, int row, int col) { + public City(String name, String bus, String train, int row, int col) { this.name = name; this.trainStation = new Station(TransportType.TRAIN, train); this.busStation = new Station(TransportType.BUS, bus); this.location = new Location(row, col); } - City(String name, Station bus, Station train, int row, int col) { + public City(String name, Station bus, Station train, int row, int col) { this.name = name; this.trainStation = train; this.busStation = bus; diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 79d61a0..b579fe7 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -1,6 +1,7 @@ module dev.ksan.travelpathoptimizer { requires javafx.controls; requires javafx.fxml; + requires java.desktop; opens dev.ksan.travelpathoptimizer to javafx.fxml; diff --git a/src/main/resources/dev/ksan/travelpathoptimizer/app/application.css b/src/main/resources/dev/ksan/travelpathoptimizer/app/application.css new file mode 100644 index 0000000..e36bcfb --- /dev/null +++ b/src/main/resources/dev/ksan/travelpathoptimizer/app/application.css @@ -0,0 +1,41 @@ +#sideMenu{ + -fx-background-color: rgba(118, 140, 239, 0.53); +} +#header{ + -fx-background-color: rgb(132, 64, 234); + -fx-border-color: black; +} +#randomSideBar{ + -fx-background-color: red; +} +#headerBar{ + + -fx-alignment: center; + -fx-end-margin: 40; +} +#headerBar Button { + -fx-background-color: linear-gradient(to bottom, #6a1b9a, #8e24aa); + -fx-text-fill: white; + -fx-font-weight: bold; + -fx-font-size: 14px; + -fx-background-radius: 8px; + -fx-border-radius: 8px; + -fx-padding: 8 16; + -fx-cursor: hand; + -fx-effect: dropshadow(gaussian, rgba(0, 0, 0, 0.3), 4, 0, 0, 2); +} +#mapSideBar{ + -fx-background-color: #ba9be3; +} +#headerBar Button:hover { + -fx-background-color: linear-gradient(to bottom, #8e24aa, #9c27b0); +} + +#headerBar Button:pressed { + -fx-background-color: linear-gradient(to bottom, #4a148c, #6a1b9a); + -fx-effect: innershadow(gaussian, rgba(0,0,0,0.5), 3, 0, 0, 1); +} +#sectionText{ + -fx-font-size: 18; + -fx-underline: true; +} \ No newline at end of file diff --git a/src/main/resources/dev/ksan/travelpathoptimizer/app/main.fxml b/src/main/resources/dev/ksan/travelpathoptimizer/app/main.fxml new file mode 100644 index 0000000..12bc983 --- /dev/null +++ b/src/main/resources/dev/ksan/travelpathoptimizer/app/main.fxml @@ -0,0 +1,179 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/dev/ksan/travelpathoptimizer/app/test.fxml b/src/main/resources/dev/ksan/travelpathoptimizer/app/test.fxml new file mode 100644 index 0000000..cd48885 --- /dev/null +++ b/src/main/resources/dev/ksan/travelpathoptimizer/app/test.fxml @@ -0,0 +1,14 @@ + + + + + + + + + + + diff --git a/src/main/resources/dev/ksan/travelpathoptimizer/hello-view.fxml b/src/main/resources/dev/ksan/travelpathoptimizer/hello-view.fxml deleted file mode 100644 index 22bad9d..0000000 --- a/src/main/resources/dev/ksan/travelpathoptimizer/hello-view.fxml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - -