Skip to content

Commit

Permalink
Merge pull request #84 from Team-40-IDATT2003/75-mvc-and-publishersub…
Browse files Browse the repository at this point in the history
…scriber

75 mvc and publishersubscriber
  • Loading branch information
etsorens authored Apr 30, 2026
2 parents b6897ab + aaa2398 commit b309fd9
Show file tree
Hide file tree
Showing 17 changed files with 813 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,6 @@ failsafe-reports/
# ===== Coverage tools =====
coverage/
jacoco.exec

# ====== Stock data files ======= #
.txt
28 changes: 28 additions & 0 deletions src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,21 @@
import edu.ntnu.idi.idatt2003.g40.mappe.model.Stock;
import edu.ntnu.idi.idatt2003.g40.mappe.service.FileConverter;
import edu.ntnu.idi.idatt2003.g40.mappe.service.FileParser;
import edu.ntnu.idi.idatt2003.g40.mappe.service.event.EventManager;
import edu.ntnu.idi.idatt2003.g40.mappe.utils.ConfigValues;
import edu.ntnu.idi.idatt2003.g40.mappe.view.ViewManager;
import edu.ntnu.idi.idatt2003.g40.mappe.view.ingame.InGameView;
import edu.ntnu.idi.idatt2003.g40.mappe.view.mainmenu.MainMenuController;
import edu.ntnu.idi.idatt2003.g40.mappe.view.mainmenu.MainMenuView;
import javafx.application.Application;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;

import java.io.IOException;
import java.util.List;
import java.util.Objects;

public class Main extends Application {
static void main() {
Expand All @@ -24,6 +34,24 @@ static void main() {

@Override
public void start(final Stage stage) throws Exception {
Scene scene = new Scene(new Pane());
scene.getStylesheets()
.add(Objects.requireNonNull(getClass().getResource("/styles.css")).toExternalForm());
stage.setScene(scene);
stage.setWidth(ConfigValues.VIEWPORT_WIDTH.getValue());
stage.setHeight(ConfigValues.VIEWPORT_HEIGHT.getValue());
EventManager eventManager = new EventManager();
ViewManager viewManager = new ViewManager(stage, eventManager);

MainMenuView mainMenuView = new MainMenuView();
new MainMenuController(mainMenuView, eventManager);

InGameView inGameView = new InGameView();


viewManager.addView(mainMenuView);
viewManager.addView(inGameView);
viewManager.setScene(mainMenuView);
stage.show();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package edu.ntnu.idi.idatt2003.g40.mappe.service.event;

/**
* Data object sent through the event system by the {@link EventManager}.
*
* @param <T> the type of data this object represents.
* @param eventType the event type this object represents.
* @param data the data this object contains.
*
*/
public record EventData<T>(EventType eventType, T data) {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package edu.ntnu.idi.idatt2003.g40.mappe.service.event;

import java.util.ArrayList;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;

/**
* Event broker in the pub/sub model.
*
* <p>Read more about pub/sub
* <a href = "https://www.geeksforgeeks.org/system-design/what-is-pub-sub/">
* Here
* </a>
* </p>
*
* @see EventSubscriber
* @see EventPublisher
*
*/
public final class EventManager {

/**
* Map where key is {@link EventType} and value is list of {@link EventSubscriber} objects.
*
* <p>Used to identify which subscribers to fire the event towards.</p>
*
*/
private final Map<EventType, List<EventSubscriber>> subscriberMap =
new EnumMap<>(EventType.class);

/**
* Method for adding a subscriber to the subscriber map given an event type.
*
* @param subscriber the {@link EventSubscriber} object to add.
* @param eventType the {@link EventType} this subscriber should subscribe to.
*
*
*/
public void addSubscriber(final EventSubscriber subscriber, final EventType eventType) {
subscriberMap.computeIfAbsent(eventType, k -> new ArrayList<>()).add(subscriber);
}

/**
* Method for invoking event to all subscriber of that type.
*
* @param <T> the type of event data to send.
* @param data the data to send.
*
*
*/
public <T> void invokeEvent(final EventData<T> data) {
for (EventSubscriber e : subscriberMap.get(data.eventType())) {
e.handleEvent(data);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package edu.ntnu.idi.idatt2003.g40.mappe.service.event;

/**
* Interface representing a publisher in the pub/sub model (observer pattern).
*
* @see EventManager
* @see EventSubscriber
*/
public interface EventPublisher {

/**
* Method for triggering (invoking) the event.
*
* @param <T> the type of event data to invoke.
* @param data the data to invoke.
* @param eventManager the {@link EventManager} object to use as broker when invoking event.
*/
<T> void invoke(EventData<T> data, EventManager eventManager);
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package edu.ntnu.idi.idatt2003.g40.mappe.service.event;

/**
* Interface representing a subscriber in a pub/sub model.
*
* @see EventManager
* @see EventSubscriber
*/
public interface EventSubscriber {

/**
* Method for handling the event subscribed to.
*
* @param <T> the type of event data to handle.
* @param data the actual data to handle.
*/
<T> void handleEvent(EventData<T> data);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package edu.ntnu.idi.idatt2003.g40.mappe.service.event;

/**
* Enum representing different event types.
*
* <p>Examples:</p>
* <ul>
* <li>Scene changes</li>
* <li>Database operations</li>
* <li>Other</li>
* </ul>
*
*
*/
public enum EventType {

/**
* Event type representing events that causes the current scene to change.
*
* <p>Primarily handled by the active
* {@link edu.ntnu.idi.idatt2003.g40.mappe.view.ViewManager} object.</p>
*
* @see edu.ntnu.idi.idatt2003.g40.mappe.view.ViewManager
*
*/
SCENE_CHANGE,

/**
* Event type representing events that causes the scene to change to the previous one.
*
* <p>Primarily handled by the active
* {@link edu.ntnu.idi.idatt2003.g40.mappe.view.ViewManager} object.</p>
*
* @see edu.ntnu.idi.idatt2003.g40.mappe.view.ViewManager
*
*/
SCENE_BACK,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package edu.ntnu.idi.idatt2003.g40.mappe.utils;

public enum ConfigValues {
VIEWPORT_WIDTH(600),
VIEWPORT_HEIGHT(600);

private int value;

ConfigValues(final int value) {
this.value = value;
}

public int getValue() {
return value;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package edu.ntnu.idi.idatt2003.g40.mappe.view;

import edu.ntnu.idi.idatt2003.g40.mappe.service.event.EventData;
import edu.ntnu.idi.idatt2003.g40.mappe.service.event.EventManager;
import edu.ntnu.idi.idatt2003.g40.mappe.service.event.EventPublisher;

/**
* Handles logic and event publishing for {@link ViewElement} objects.
*
* <p>Implements {@link EventPublisher}</p>
*
* @param <T1> The type of {@link ViewElement} this controller is attached to. We use generics
* because we want to call methods that may be specific for certain view element
* objects, and we want to reduce casting.
* @see ViewElement
* @see EventPublisher
* @see EventManager
*
*/
public abstract class ViewController<T1 extends ViewElement<?>>
implements EventPublisher {

/**
* The {@link ViewElement} object this controller is associated with.
*
*/
private final T1 viewElement;
/**
* The {@link EventManager} object to send events to.
*
*/
private final EventManager eventManager;

/**
* Constructor.
*
* @param viewElement the instance of type T1 this controller is attached to.
* @param eventManager the {@link EventManager} object this controller communicates with.
*
*/
protected ViewController(final T1 viewElement, final EventManager eventManager) {
this.viewElement = viewElement;
this.eventManager = eventManager;
initInteractions();
}

/**
* Getter method for the event manager.
*
* @return the {@link EventManager} object.
*
*/
protected EventManager getEventManager() {
return eventManager;
}

/**
* Getter method for the current view element.
*
* @return the {@link ViewElement} object.
*
*/
public T1 getViewElement() {
return viewElement;
}

/**
* Abstract method to initialize logic for the view element.
*
*/
protected abstract void initInteractions();

@Override
public final <T> void invoke(final EventData<T> data, final EventManager eventManager) {
eventManager.invokeEvent(data);
}
}
39 changes: 39 additions & 0 deletions src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/ViewData.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package edu.ntnu.idi.idatt2003.g40.mappe.view;

/**
* Object containing data about {@link ViewElement} objects.
*
* <p>Sent in {@link edu.ntnu.idi.idatt2003.g40.mappe.service.event.EventData}
* objects of type SCENE_CHANGE</p>
*
* <p>Handled by the {@link ViewManager} to update and change views</p>
*
*/
public class ViewData {

/**
* Name of the scene.
*
*/
private final String sceneName;

/**
* Constructor.
*
* @param sceneName the name of the scene.
*
*/
public ViewData(final String sceneName) {
this.sceneName = sceneName;
}

/**
* Getter method for the scene name.
*
* @return scene name.
*
*/
public String getSceneName() {
return sceneName;
}
}
Loading

0 comments on commit b309fd9

Please sign in to comment.