diff --git a/configurations/config-1/locations/location-1/location-1.json b/configurations/config-1/locations/location-1/location-1.json index 5e9bfa04..94025965 100644 --- a/configurations/config-1/locations/location-1/location-1.json +++ b/configurations/config-1/locations/location-1/location-1.json @@ -1,8 +1,8 @@ { "tag": "location-1", "objects": [ - { "tag": "object-1", "position": { "row": 0, "col": 5 }, "type": "collectible" }, - { "tag": "object-2", "position": { "row": 1, "col": 3 }, "type": "interactive" } + { "tag": "object-1", "position": { "row": 0, "col": 5 }, "type": "collectible", "assetPath": "assets/someDude.png" }, + { "tag": "object-2", "position": { "row": 1, "col": 3 }, "type": "dialog", "assetPath": "assets/someDude.png" } ], - "backgroundPath": "file:assets/map.png" + "backgroundPath": "assets/map.png" } diff --git a/configurations/config-1/locations/location-1/objects/object-1.json b/configurations/config-1/locations/location-1/objects/object-1.json index 6f2ed3ae..2ab6ba3f 100644 --- a/configurations/config-1/locations/location-1/objects/object-1.json +++ b/configurations/config-1/locations/location-1/objects/object-1.json @@ -2,4 +2,4 @@ "tag": "object-1", "assetPath": "/path/to/the/asset", "type": "" -} \ No newline at end of file +} diff --git a/configurations/config-1/locations/location-2/location-2.json b/configurations/config-1/locations/location-2/location-2.json index dc949d25..2d5eae12 100644 --- a/configurations/config-1/locations/location-2/location-2.json +++ b/configurations/config-1/locations/location-2/location-2.json @@ -1,8 +1,8 @@ { "tag": "location-2", "objects": [ - { "tag": "object-1", "position": { "row": 0, "col": 0 }, "type": "collectible" }, - { "tag": "object-3", "position": { "row": 0, "col": 1 }, "type": "navigable" } + { "tag": "object-1", "position": { "row": 0, "col": 5 }, "type": "collectible", "assetPath": "assets/someDude.png" }, + { "tag": "object-2", "position": { "row": 1, "col": 3 }, "type": "dialog", "assetPath": "assets/someDude.png" } ], - "backgroundPath": "file:assets/map.png" -} \ No newline at end of file + "backgroundPath": "assets/map.png" +} diff --git a/src/main/java/io/rpg/Initializer.java b/src/main/java/io/rpg/Initializer.java index 965c2ea9..77e325bc 100644 --- a/src/main/java/io/rpg/Initializer.java +++ b/src/main/java/io/rpg/Initializer.java @@ -7,7 +7,10 @@ import io.rpg.model.location.LocationModel; import io.rpg.model.object.GameObject; import io.rpg.config.model.GameObjectConfig; +import io.rpg.util.GameObjectFactory; +import io.rpg.util.GameObjectViewFactory; import io.rpg.util.Result; +import io.rpg.view.GameObjectView; import io.rpg.view.LocationView; import javafx.stage.Stage; import org.apache.logging.log4j.LogManager; @@ -17,14 +20,13 @@ import java.io.IOException; import java.nio.file.Path; -import java.util.LinkedHashMap; -import java.util.LinkedList; +import java.util.Iterator; import java.util.List; public class Initializer { private Path pathToConfigDir; private ConfigLoader configLoader; - private Stage mainStage; + private final Stage mainStage; private final Logger logger; @@ -56,7 +58,16 @@ public Result initialize() { assert worldConfig.getLocationConfigs().size() > 0 : "There must be at least one location config specified"; for (LocationConfig locationConfig : worldConfig.getLocationConfigs()) { - LocationModel model = loadLocationModelFromConfig(locationConfig); + + List gameObjects = loadGameObjectsForLocation(locationConfig); + List gameObjectViews = loadGameObjectViewsForLocation(locationConfig); + + registerGameObjectViewsToModel(gameObjects, gameObjectViews); + + LocationModel model = new LocationModel.Builder() + .setTag(locationConfig.getTag()) + .setGameObjects(gameObjects).build(); + LocationView view = loadLocationViewFromConfig(locationConfig); assert view != null; @@ -80,6 +91,32 @@ public Result initialize() { return Result.ok(gameBuilder.build()); } + public static List loadGameObjectsForLocation(LocationConfig config) { + return GameObjectFactory.fromConfigList(config.getObjects()); + } + + public static List loadGameObjectViewsForLocation(LocationConfig config) { + return GameObjectViewFactory.fromConfigList(config.getObjects()); + } + + public static void registerGameObjectViewsToModel(List gameObjects, + List gameObjectViews) { + assert gameObjects.size() == gameObjectViews.size() : "Arrays must be of the same length!"; + + Iterator gameObjectIterator = gameObjects.iterator(); + Iterator gameObjectViewIterator = gameObjectViews.iterator(); + + // we asserted earlier that both lists have the same length thus we don't + // need to check .hasNext() for both lists + while (gameObjectIterator.hasNext()) { + GameObject gameObject = gameObjectIterator.next(); + GameObjectView gameObjectView = gameObjectViewIterator.next(); + + // registration + gameObject.addGameObjectStateChangeObserver(gameObjectView); + } + } + @Nullable public static LocationView loadLocationViewFromConfig(LocationConfig config) { try { @@ -89,18 +126,4 @@ public static LocationView loadLocationViewFromConfig(LocationConfig config) { } return null; } - - public static LocationModel loadLocationModelFromConfig(LocationConfig config) { - List gameObjectConfigs = config.getObjects(); - List gameObjects = new LinkedList<>(); - - for (GameObjectConfig goconfig : gameObjectConfigs) { - gameObjects.add(GameObject.fromConfig(goconfig)); - } - - return new LocationModel( - config.getTag(), - gameObjects - ); - } } diff --git a/src/main/java/io/rpg/config/ConfigLoader.java b/src/main/java/io/rpg/config/ConfigLoader.java index 2ee4bce1..6919cf26 100644 --- a/src/main/java/io/rpg/config/ConfigLoader.java +++ b/src/main/java/io/rpg/config/ConfigLoader.java @@ -201,6 +201,9 @@ LocationConfig loadLocationConfig(@NotNull String locationTag) throws FileNotFou BufferedReader reader = new BufferedReader(new FileReader(locationConfigJson.toString())); LocationConfig config = gson.fromJson(reader, LocationConfig.class); config.setPath(locationDir); + + logger.info("Path to background for location"); + logger.info(config.getBackgroundPath()); return config; } diff --git a/src/main/java/io/rpg/config/model/GameObjectConfig.java b/src/main/java/io/rpg/config/model/GameObjectConfig.java index 7175de06..10f83ea4 100644 --- a/src/main/java/io/rpg/config/model/GameObjectConfig.java +++ b/src/main/java/io/rpg/config/model/GameObjectConfig.java @@ -12,14 +12,14 @@ */ public class GameObjectConfig extends GameObject { - private String type; public GameObjectConfig(@NotNull String tag, @NotNull Position position) { super(tag, position); } - public String getType() { + public String getTypeString() { + assert type != null : "Attempt to access uninitialized \"type\" field!"; return type; } diff --git a/src/main/java/io/rpg/model/data/GameObjectStateChange.java b/src/main/java/io/rpg/model/data/GameObjectStateChange.java index 20367182..e421cae8 100644 --- a/src/main/java/io/rpg/model/data/GameObjectStateChange.java +++ b/src/main/java/io/rpg/model/data/GameObjectStateChange.java @@ -2,16 +2,25 @@ import io.rpg.model.object.GameObject; -public record GameObjectStateChange ( +/** + * Event representing game object model change. + */ +public record GameObjectStateChange( GameObject source, - Object payload // TODO: what kind of data do we want? What changed? What can change? - // or maybe implement separate methods for observer & emitter for different kinds - // of event + Object payload // TODO: what kind of data do we want? What changed? What can change? + // or maybe implement separate methods for observer & emitter for different kinds + // of events ) { + /** + * Interface for {@link GameObjectStateChange} observer. + */ public interface Observer { void onGameObjectStateChange(GameObjectStateChange event); } + /** + * Interface for {@link GameObjectStateChange} event emitter. + */ public interface Emitter { void emitGameObjectStateChange(GameObjectStateChange event); diff --git a/src/main/java/io/rpg/model/data/KeyboardEvent.java b/src/main/java/io/rpg/model/data/KeyboardEvent.java index d7021da6..9d49aacb 100644 --- a/src/main/java/io/rpg/model/data/KeyboardEvent.java +++ b/src/main/java/io/rpg/model/data/KeyboardEvent.java @@ -3,11 +3,20 @@ import javafx.scene.Scene; import javafx.scene.input.KeyEvent; -final public record KeyboardEvent(Scene source, KeyEvent payload) { +/** + * Represents a keyboard clicked event. + */ +public final record KeyboardEvent(Scene source, KeyEvent payload) { + /** + * Interface for {@link KeyboardEvent} observer. + */ public interface Observer { void onKeyboardEvent(KeyboardEvent event); } + /** + * Interface for {@link KeyboardEvent} emitter. + */ public interface Emitter { void addKeyboardEventObserver(KeyboardEvent.Observer observer); diff --git a/src/main/java/io/rpg/model/data/LocationModelStateChange.java b/src/main/java/io/rpg/model/data/LocationModelStateChange.java index 0720837f..b8ff6e41 100644 --- a/src/main/java/io/rpg/model/data/LocationModelStateChange.java +++ b/src/main/java/io/rpg/model/data/LocationModelStateChange.java @@ -2,14 +2,23 @@ import io.rpg.model.location.LocationModel; +/** + * Event representing location model state change. + */ public record LocationModelStateChange( LocationModel source, Object payload // TODO: Same considerations as for GameObjectStateChange ) { + /** + * Interface for {@link LocationModelStateChange} observer. + */ public interface Observer { void onLocationModelStateChange(LocationModelStateChange event); } + /** + * Interface for {@link LocationModelStateChange} event emitter. + */ public interface Emitter { void addOnLocationModelStateChangeObserver(Observer observer); diff --git a/src/main/java/io/rpg/model/data/MouseClickedEvent.java b/src/main/java/io/rpg/model/data/MouseClickedEvent.java index 9bd59fa7..d07ed189 100644 --- a/src/main/java/io/rpg/model/data/MouseClickedEvent.java +++ b/src/main/java/io/rpg/model/data/MouseClickedEvent.java @@ -5,16 +5,22 @@ import org.jetbrains.annotations.NotNull; /** - * + * Represents mouse click event. */ -final public record MouseClickedEvent( +public record MouseClickedEvent( @NotNull GameObjectView source, @NotNull MouseEvent payload ) { + /** + * Interface for {@link MouseClickedEvent} observer. + */ public interface Observer { void onMouseClickedEvent(MouseClickedEvent event); } + /** + * Interface for {@link MouseClickedEvent} emitter. + */ public interface Emitter { void emitOnMouseClickedEvent(MouseClickedEvent event); diff --git a/src/main/java/io/rpg/model/location/LocationModel.java b/src/main/java/io/rpg/model/location/LocationModel.java index 6e4b240a..d031c456 100644 --- a/src/main/java/io/rpg/model/location/LocationModel.java +++ b/src/main/java/io/rpg/model/location/LocationModel.java @@ -3,14 +3,16 @@ import io.rpg.model.data.LocationModelStateChange; import io.rpg.model.object.Player; import io.rpg.model.object.GameObject; +import io.rpg.util.Result; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.UnmodifiableView; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; +import java.util.*; /** - * Represents single location in our game + * Represents single location in our game. */ public class LocationModel implements LocationModelStateChange.Emitter { private String tag; @@ -20,9 +22,12 @@ public class LocationModel implements LocationModelStateChange.Emitter { private final Set locationModelStateChangeObservers; public LocationModel(@NotNull String tag, @NotNull List gameObjects) { + this(); this.tag = tag; this.gameObjects = gameObjects; - this.player = null; + } + + private LocationModel() { this.locationModelStateChangeObservers = new LinkedHashSet<>(); } @@ -34,6 +39,31 @@ public String getTag() { return tag; } + /** + * Private setter for Builder usage only. + * + * @param tag tag for the location + */ + private void setTag(String tag) { + this.tag = tag; + } + + @UnmodifiableView + public List getGameObjects() { + return Collections.unmodifiableList(gameObjects); + } + + /** + * Private setter for Builder usage only. Notice that ownership of {@link GameObject}s is not + * transferred to LocationModel. + * TODO: Transfer ownership of objects to LoactionModel. + * + * @param gameObjects game object for location + */ + private void setGameObjects(List gameObjects) { + this.gameObjects = gameObjects; + } + @Override public void addOnLocationModelStateChangeObserver(LocationModelStateChange.Observer observer) { locationModelStateChangeObservers.add(observer); @@ -50,4 +80,44 @@ public void emitLocationModelStateChange(LocationModelStateChange event) { observer.onLocationModelStateChange(event); }); } + + public Result validate() { + if (tag == null || gameObjects == null) { + return Result.error(null); + } + return Result.ok(null); + } + + public static class Builder { + private final LocationModel locationModel; + + private final Logger logger; + + public Builder() { + logger = LogManager.getLogger(Builder.class); + locationModel = new LocationModel(); + } + + public Builder setGameObjects(@NotNull List gameObjects) { + locationModel.setGameObjects(gameObjects); + return this; + } + + public Builder setTag(@NotNull String tag) { + assert tag != null : "Location tag must not be null!"; + locationModel.setTag(tag); + return this; + } + + public LocationModel build() { + Result result = locationModel.validate(); + + // TODO(@kkafar): Handle this in better way. Consider returning the result. + if (result.isError()) { + logger.error("Error occurred while building LocationModel."); + } + + return locationModel; + } + } } diff --git a/src/main/java/io/rpg/model/object/CollectibleGameObject.java b/src/main/java/io/rpg/model/object/CollectibleGameObject.java index 60c437ff..3884f2e1 100644 --- a/src/main/java/io/rpg/model/object/CollectibleGameObject.java +++ b/src/main/java/io/rpg/model/object/CollectibleGameObject.java @@ -3,7 +3,7 @@ import io.rpg.model.data.Position; import org.jetbrains.annotations.NotNull; -final public class CollectibleGameObject extends InteractiveGameObject { +public final class CollectibleGameObject extends InteractiveGameObject { public CollectibleGameObject(@NotNull String tag, @NotNull Position position) { super(tag, position); } diff --git a/src/main/java/io/rpg/model/object/DialogGameObject.java b/src/main/java/io/rpg/model/object/DialogGameObject.java index 54a97023..ebcbc838 100644 --- a/src/main/java/io/rpg/model/object/DialogGameObject.java +++ b/src/main/java/io/rpg/model/object/DialogGameObject.java @@ -3,7 +3,7 @@ import io.rpg.model.data.Position; import org.jetbrains.annotations.NotNull; -final public class DialogGameObject extends InteractiveGameObject { +public final class DialogGameObject extends InteractiveGameObject { public DialogGameObject(@NotNull String tag, @NotNull Position position) { super(tag, position); } diff --git a/src/main/java/io/rpg/model/object/GameObject.java b/src/main/java/io/rpg/model/object/GameObject.java index ad4089ae..5cbafade 100644 --- a/src/main/java/io/rpg/model/object/GameObject.java +++ b/src/main/java/io/rpg/model/object/GameObject.java @@ -1,22 +1,26 @@ package io.rpg.model.object; import io.rpg.config.model.GameObjectConfig; +import io.rpg.model.data.GameObjectStateChange; import io.rpg.model.data.Position; import org.jetbrains.annotations.NotNull; +import java.util.LinkedHashSet; +import java.util.Set; + /** * Class representing common state properties for all - * objects appearing in the game + * objects appearing in the game. */ -public class GameObject { +public class GameObject implements GameObjectStateChange.Emitter { /** - * Position of game object in model's representation of location + * Position of game object in model's representation of location. */ @NotNull private final Position position; /** - * Unique identifier of this game object + * Unique identifier of this game object. */ @NotNull private final String tag; @@ -27,13 +31,16 @@ public class GameObject { @NotNull private String assetPath; + @NotNull + private final Set stateChangeObservers; + @NotNull public String getAssetPath() { return assetPath; } /** - * Unique identifier of this game object + * Unique identifier of this game object. */ @NotNull public String getTag() { @@ -41,7 +48,7 @@ public String getTag() { } /** - * Position of game object in model's representation of location + * Position of game object in model's representation of location. */ @NotNull public Position getPosition() { @@ -49,18 +56,42 @@ public Position getPosition() { } public GameObject(@NotNull String tag, @NotNull Position position) { - this.tag = tag; - this.position = position; - this.assetPath = ""; // TODO + this(tag, position, ""); } public GameObject(@NotNull String tag, @NotNull Position position, @NotNull String assetPath) { this.tag = tag; this.position = position; this.assetPath = assetPath; + this.stateChangeObservers = new LinkedHashSet<>(); + } + + @Override + public void emitGameObjectStateChange(GameObjectStateChange event) { + // TODO + // noop for now } - public static GameObject fromConfig(GameObjectConfig config) { - return new GameObject("XD", new Position(3, 3), "file:assets/someDude.png"); + @Override + public void addGameObjectStateChangeObserver(GameObjectStateChange.Observer observer) { + this.stateChangeObservers.add(observer); + } + + @Override + public void removeGameObjectStateChangeObserver(GameObjectStateChange.Observer observer) { + this.stateChangeObservers.remove(observer); + } + + public enum Type { + NAVIGABLE("navigable"), + DIALOG("dialog"), + PLAYER("player"), + COLLECTIBLE("collectible"); + + private final String asString; + + Type(String asString) { + this.asString = asString; + } } } diff --git a/src/main/java/io/rpg/model/object/InteractiveGameObject.java b/src/main/java/io/rpg/model/object/InteractiveGameObject.java index 8e73699a..c1be7799 100644 --- a/src/main/java/io/rpg/model/object/InteractiveGameObject.java +++ b/src/main/java/io/rpg/model/object/InteractiveGameObject.java @@ -3,10 +3,10 @@ import io.rpg.model.data.Position; import org.jetbrains.annotations.NotNull; -abstract public class InteractiveGameObject extends GameObject { - public InteractiveGameObject(@NotNull String tag, @NotNull Position position) { - super(tag, position); - } +public abstract class InteractiveGameObject extends GameObject { + public InteractiveGameObject(@NotNull String tag, @NotNull Position position) { + super(tag, position); + } - abstract public void onAction(); + abstract public void onAction(); } diff --git a/src/main/java/io/rpg/model/object/NavigationalGameObject.java b/src/main/java/io/rpg/model/object/NavigationalGameObject.java index e68e543d..28e8d64f 100644 --- a/src/main/java/io/rpg/model/object/NavigationalGameObject.java +++ b/src/main/java/io/rpg/model/object/NavigationalGameObject.java @@ -3,7 +3,7 @@ import io.rpg.model.data.Position; import org.jetbrains.annotations.NotNull; -final public class NavigationalGameObject extends InteractiveGameObject { +public final class NavigationalGameObject extends InteractiveGameObject { public NavigationalGameObject(@NotNull String tag, @NotNull Position position) { super(tag, position); diff --git a/src/main/java/io/rpg/util/GameObjectFactory.java b/src/main/java/io/rpg/util/GameObjectFactory.java new file mode 100644 index 00000000..48fd8f83 --- /dev/null +++ b/src/main/java/io/rpg/util/GameObjectFactory.java @@ -0,0 +1,49 @@ +package io.rpg.util; + +import io.rpg.config.model.GameObjectConfig; +import io.rpg.model.object.CollectibleGameObject; +import io.rpg.model.object.DialogGameObject; +import io.rpg.model.object.GameObject; +import io.rpg.model.object.NavigationalGameObject; + +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; + +/** + * Exposes collection of methods to create {@link io.rpg.model.object.GameObject} class instances. + */ +public class GameObjectFactory { + /** + * Creates {@link GameObject} instance basing on information contained in config. + * + * @param config description of object properties + * @return game object created based on information located in config + */ + public static GameObject fromConfig(GameObjectConfig config) { + // TODO: add case for Player type here! + switch (GameObject.Type.valueOf(config.getTypeString().toUpperCase())) { + case COLLECTIBLE -> { return new CollectibleGameObject(config.getTag(), config.getPosition()); } + case DIALOG -> { return new DialogGameObject(config.getTag(), config.getPosition()); } + case NAVIGABLE -> { return new NavigationalGameObject(config.getTag(), config.getPosition()); } + default -> throw new RuntimeException("Unknown GameObject type. This should not happen!"); + } + } + + /** + * Creates list of {@link GameObject} instances based on information contained in list of configs. + * This method guarantees that {@link GameObject}s located in result list are in the same order, + * i.e. first {@link GameObject} is created from first {@link GameObjectConfig}, second from second + * etc. + * + * @param configs descriptions of object properties + * @return game objects created based on information located in config list + */ + public static LinkedList fromConfigList(List configs) { + LinkedList gameObjects = new LinkedList<>(); + for (GameObjectConfig config : configs) { + gameObjects.add(fromConfig(config)); + } + return gameObjects; + } +} diff --git a/src/main/java/io/rpg/util/GameObjectViewFactory.java b/src/main/java/io/rpg/util/GameObjectViewFactory.java new file mode 100644 index 00000000..250db5d7 --- /dev/null +++ b/src/main/java/io/rpg/util/GameObjectViewFactory.java @@ -0,0 +1,41 @@ +package io.rpg.util; + +import io.rpg.config.model.GameObjectConfig; +import io.rpg.view.GameObjectView; + +import java.nio.file.Path; +import java.util.LinkedList; +import java.util.List; + +/** + * Exposes collection of methods to create {@link GameObjectView} class instances. + */ +public class GameObjectViewFactory { + /** + * Creates {@link GameObjectView} instance basing on information contained in config. + * + * @param config description of object properties + * @return game object view created based on information located in config + */ + public static GameObjectView fromConfig(GameObjectConfig config) { + // TODO: consider returning Result type & validate the construction + return new GameObjectView(Path.of(config.getAssetPath()), config.getPosition()); + } + + /** + * Creates list of {@link GameObjectView}s instances based on information contained in list of configs. + * This method guarantees that {@link GameObjectView}s located in result list are in the same order, + * i.e. first {@link GameObjectView} is created from first {@link GameObjectConfig}, second from second + * etc. + * + * @param configs descriptions of object properties + * @return game object views created based on information located in config list + */ + public static LinkedList fromConfigList(List configs) { + LinkedList gameObjects = new LinkedList<>(); + for (GameObjectConfig config : configs) { + gameObjects.add(fromConfig(config)); + } + return gameObjects; + } +} diff --git a/src/main/java/io/rpg/view/GameObjectView.java b/src/main/java/io/rpg/view/GameObjectView.java index b55aaad7..0ee8ae55 100644 --- a/src/main/java/io/rpg/view/GameObjectView.java +++ b/src/main/java/io/rpg/view/GameObjectView.java @@ -18,7 +18,8 @@ public class GameObjectView extends ImageView public GameObjectView(@NotNull Path assetPath, @NotNull Position position) { this.path = assetPath; - this.setImage(new Image(path.toString())); +// String xdpath = + this.setImage(new Image(resolvePathToJFXFormat(path.toString()))); // todo: better position class this.setX(position.col); this.setY(position.row); @@ -26,6 +27,11 @@ public GameObjectView(@NotNull Path assetPath, @NotNull Position position) { this.setOnMouseClicked(event -> emitOnMouseClickedEvent(new MouseClickedEvent(this, event))); } + public static String resolvePathToJFXFormat(String path) { + return "file:" + path; + } + + @Override public void emitOnMouseClickedEvent(MouseClickedEvent event) { onClickedObservers.forEach(listener -> listener.onMouseClickedEvent(event)); diff --git a/src/main/java/io/rpg/view/LocationView.java b/src/main/java/io/rpg/view/LocationView.java index a3d0b55a..332536fd 100644 --- a/src/main/java/io/rpg/view/LocationView.java +++ b/src/main/java/io/rpg/view/LocationView.java @@ -15,6 +15,7 @@ import java.io.IOException; import java.net.URL; +import java.nio.file.Path; import java.util.HashSet; import java.util.Set; @@ -60,11 +61,15 @@ public static LocationView fromConfig(LocationConfig config) throws IOException LocationView view = loadFromFXML(FXML_URL); System.out.println("BACKGROUND PATH"); System.out.println(config.getBackgroundPath()); - view.getViewModel().setBackground(new Image(config.getBackgroundPath())); + view.getViewModel().setBackground(new Image(resolvePathToJFXFormat(config.getBackgroundPath()))); // todo: na podstawie configu ustawić pola korzystając z view modelu return view; } + public static String resolvePathToJFXFormat(String path) { + return "file:" + path; + } + @Override public void addKeyboardEventObserver(KeyboardEvent.Observer observer) { onKeyPressedObservers.add(observer);