diff --git a/.gitignore b/.gitignore index a1c2a23..1cdb928 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,10 @@ # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* + +.out/ +.idea/ + +*.name + +*iml diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..6073398 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,4 @@ +# Default ignored files +/shelf/ +/workspace.xml +/save/model.ser diff --git a/.idea/libraries/javafx.xml b/.idea/libraries/javafx.xml new file mode 100644 index 0000000..12d7e02 --- /dev/null +++ b/.idea/libraries/javafx.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..3b29b6e --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,12 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..2b63946 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Main.java b/Main.java new file mode 100644 index 0000000..e791bd0 --- /dev/null +++ b/Main.java @@ -0,0 +1,37 @@ +import javafx.application.Application; +import javafx.stage.Stage; +import model.CalendarModel; +import views.CalendarView; + + +/** + * Main Class for the Application. + */ +public class Main extends Application +{ + CalendarView view; // the calendar view to render for the application. + + /** + * The Main function of the class. + * + * The launcher for JavaFx application. + * @param args arguments + */ + public static void main(String[] args) + { + launch(args); + } + + + /** + * To Start the application. + * + * @param primaryStage the stage for the JavaFx application. + * @throws Exception any exception that is to be thrown + */ + @Override + public void start(Stage primaryStage) throws Exception + { + this.view = CalendarView.getView(new CalendarModel(),primaryStage); + } +} diff --git a/The-Hamburglars.iml b/The-Hamburglars.iml new file mode 100644 index 0000000..6bd887c --- /dev/null +++ b/The-Hamburglars.iml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/event/Event.java b/event/Event.java new file mode 100644 index 0000000..5aa1695 --- /dev/null +++ b/event/Event.java @@ -0,0 +1,167 @@ +package event; + +import observer.*; +import timeBehaviour.*; +import model.CalendarModel; +import views.GoalCompleteView; + +import java.io.Serializable; +import java.util.ArrayList; + + +/** + * An event class that stores the data of an Event. + */ +public class Event implements Serializable +{ + private String name; // name of the event, this shows on the calendar. + private String description; // detailed description of the event. + private int pointValue; // the points are awarded upon completion. + private TimeBehaviour timeBehaviour; // the TimeBehaviour of the event. + private static ArrayList observerList = new ArrayList<>(); // the list of EventObservers for a particular event. + + + /** + * Constructor for a new Event. A new event requires a name, description, points and a timeBehaviour. + * + * @param name the name of the new Event + * @param timeBehaviour the Event's time behaviour. Contains the Event's time or start/end times + * @param description the description of the new Event + * @param points the points associated with the new Event + */ + public Event(String name, String description, int points, TimeBehaviour timeBehaviour) + { + this.name = name; + this.description = description; + this.pointValue = points; + this.timeBehaviour = timeBehaviour; + } + + + /** + * Set this Event as "completed", and notify observers. + */ + public void complete() + { + ArrayList completed = new ArrayList<>(); + for (EventObserver o : observerList) + if (o.addPoints(this.pointValue)) + { + GoalCompleteView gcv = new GoalCompleteView((Goal) o); + CalendarModel.getCompletedGoals().add(o); + completed.add(o); + } + for (EventObserver o : completed) + observerList.remove(o); + } + + + /** + * Get the list of observers for events. + * + * @return observerList + */ + public static ArrayList getObserverList() + { + return observerList; + } + + + /** + * Get the Event's name. + * + * @return name + */ + public String getName() + { + return this.name; + } + + + /** + * Get the Event's description. + * + * @return description + */ + public String getDescription() + { + return this.description; + } + + + /** + * Get the Event's associated points. + * + * @return pointValue + */ + public int getPointValue() + { + return this.pointValue; + } + + + /** + * Get the Event's timebehaviour. + * + * @return timeBehaviour + */ + public TimeBehaviour getTimeBehaviour() + { + return this.timeBehaviour; + } + + + /** + * Set the list of observers for events. Useful for loading files. + * + * @param oList the list of observers + */ + public static void setObserverList(ArrayList oList) + { + observerList = oList; + } + + + /** + * Set the Event's name to a new name. + * + * @param name the new Event's name + */ + public void setName(String name) + { + this.name = name; + } + + + /** + * Set the Event's description to a new description. + * + * @param description the new Event's description + */ + public void setDescription(String description) + { + this.description = description; + } + + + /** + * Set the Event's associated points to a new pointValue + * + * @param pointValue the new Event's associated points + */ + public void setPointValue(int pointValue) + { + this.pointValue = pointValue; + } + + + /** + * Change this Event's time with a new time-behaviour. + * + * @param timeBehaviour the new timeBehaviour to set for the event. + */ + public void setTimeBehaviour(TimeBehaviour timeBehaviour) + { + this.timeBehaviour = timeBehaviour; + } +} diff --git a/event/EventTest.java b/event/EventTest.java new file mode 100644 index 0000000..671c2c7 --- /dev/null +++ b/event/EventTest.java @@ -0,0 +1,28 @@ +package event; + +import org.junit.jupiter.api.Test; +import timeBehaviour.TimePoint; + +import java.time.LocalDateTime; + +import static org.junit.jupiter.api.Assertions.assertEquals; + + +/** + * A Unit Test Class for Event.java. + */ +class EventTest +{ + /** + * A Unit Test for Event.complete(). + */ + @Test + void completeTest() + { + Event e = new Event("Event1", "testing", 100, new TimePoint(LocalDateTime.now())); + + e.complete(); + + assertEquals(0, Event.getObserverList().size()); + } +} diff --git a/model/CalendarModel.java b/model/CalendarModel.java new file mode 100644 index 0000000..2640765 --- /dev/null +++ b/model/CalendarModel.java @@ -0,0 +1,68 @@ +package model; + +import event.Event; +import observer.EventObserver; + +import java.time.LocalDateTime; +import java.io.Serializable; +import java.util.ArrayList; + +// Class to store app information behind the scene +public class CalendarModel implements Serializable { + + // list of events + ArrayList events; + + // color settings + public String colour; + public String colour_font; + + // list of goals that remain the same + private static ArrayList completedGoals = new ArrayList<>(); + + + // Constructor for no events + public CalendarModel() + { + this.events = new ArrayList(); + } + + // Constructor if some events are there + public CalendarModel(ArrayList events){ + this.events = events; + } + + // get list of completed goals + public static ArrayList getCompletedGoals() { + return completedGoals; + } + + // set completed goals + public static void setCompletedGoals(ArrayList oList) {completedGoals = oList;} + + // add an event to the calendar + public void addEvent(Event e) + { + this.events.add(e); + } + + // get the list of all events + public ArrayList getAllEvents(){ + return this.events; + } + + /** + * get events filtered by a date + */ + public ArrayList getEventsInTime(LocalDateTime time) + { + ArrayList filteredEvents = new ArrayList<>(); + for (Event e: this.events) + if (e.getTimeBehaviour().inTime(time)) + { + System.out.println(e.getName()); + filteredEvents.add(e); + } + return filteredEvents; + } +} diff --git a/observer/EventObserver.java b/observer/EventObserver.java new file mode 100644 index 0000000..fd0203e --- /dev/null +++ b/observer/EventObserver.java @@ -0,0 +1,15 @@ +package observer; + +/** + * Interface for Event Observers. Event Observers must be able to add an Event's points to themselves when they are + * notified that and Event is complete. + */ +public interface EventObserver { + + /** + * Add points to this observer's current point total. + * + * @param points the amount of points to be added + */ + boolean addPoints(int points); +} diff --git a/observer/Goal.java b/observer/Goal.java new file mode 100644 index 0000000..271dbfc --- /dev/null +++ b/observer/Goal.java @@ -0,0 +1,64 @@ +package observer; + +import java.io.Serializable; + +/** + * Class for the user's goals, which act as concrete Event Observers. A goal contains a name, amount of points currently + * gained, and amount of points needed. + */ +public class Goal implements EventObserver, Serializable { + + private String name; // The goal's name + private int currentPoints; // The amount of points the user has currently earned toward this goal + private final int pointsToBadge; // The amount of points that are required to complete this goal + + /** + * Constructor for the Goal class. Takes a name and a point value. + * + * @param name the name of the Goal + * @param p the amount of points required for completion + */ + public Goal(String name, int p) { + this.name = name; + this.pointsToBadge = p; + this.currentPoints = 0; + } + + + /** + * Add points to this observer's current point total. + * + * @param points the amount of points to be added + * @return true if the goal is complete, or false otherwise + */ + @Override + public boolean addPoints(int points) { + this.currentPoints += points; + return this.currentPoints >= this.pointsToBadge; + } + + /** + * Get this Goal's name + * + * @return this.name + */ + public String getName() {return this.name;} + + + /** + * Get the string representation of this goal. If the goal is incomplete, its string representation looks like this: + * name: currentPoints/pointsToBadge + * If the goal is complete, its string representation is only the name of the goal. + * + * @return the string representation of this goal + */ + @Override + public String toString() { + if (this.currentPoints >= this.pointsToBadge) { + return this.name; + } + else { + return this.name + ": " + this.currentPoints + "/" + this.pointsToBadge; + } + } +} diff --git a/observer/GoalTests.java b/observer/GoalTests.java new file mode 100644 index 0000000..acb5c36 --- /dev/null +++ b/observer/GoalTests.java @@ -0,0 +1,34 @@ +package observer; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class GoalTests { + + @Test + public void addPointsTest() { + Goal goalA = new Goal("goalA", 50); + goalA.addPoints(30); + goalA.addPoints(5); + assertEquals("goalA: 35/50", goalA.toString()); + } + + @Test + public void goalCompleteTest() { + Goal goalB = new Goal("goalB", 60); + assertEquals(true, goalB.addPoints(60)); + } + + @Test + public void testGoalToString() { + Goal goalC = new Goal("goalC", 100); + assertEquals("goalC: 0/100", goalC.toString()); + goalC.addPoints(50); + assertEquals("goalC: 50/100", goalC.toString()); + goalC.addPoints(50); + assertEquals("goalC", goalC.toString()); + goalC.addPoints(50); + assertEquals("goalC", goalC.toString()); + } +} diff --git a/out/production/The-Hamburglars/.gitignore b/out/production/The-Hamburglars/.gitignore new file mode 100644 index 0000000..1cdb928 --- /dev/null +++ b/out/production/The-Hamburglars/.gitignore @@ -0,0 +1,30 @@ +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +.out/ +.idea/ + +*.name + +*iml diff --git a/out/production/The-Hamburglars/.idea/.gitignore b/out/production/The-Hamburglars/.idea/.gitignore new file mode 100644 index 0000000..6073398 --- /dev/null +++ b/out/production/The-Hamburglars/.idea/.gitignore @@ -0,0 +1,4 @@ +# Default ignored files +/shelf/ +/workspace.xml +/save/model.ser diff --git a/out/production/The-Hamburglars/.idea/libraries/javafx.xml b/out/production/The-Hamburglars/.idea/libraries/javafx.xml new file mode 100644 index 0000000..12d7e02 --- /dev/null +++ b/out/production/The-Hamburglars/.idea/libraries/javafx.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/out/production/The-Hamburglars/.idea/misc.xml b/out/production/The-Hamburglars/.idea/misc.xml new file mode 100644 index 0000000..3b29b6e --- /dev/null +++ b/out/production/The-Hamburglars/.idea/misc.xml @@ -0,0 +1,12 @@ + + + + + + + + \ No newline at end of file diff --git a/out/production/The-Hamburglars/.idea/uiDesigner.xml b/out/production/The-Hamburglars/.idea/uiDesigner.xml new file mode 100644 index 0000000..2b63946 --- /dev/null +++ b/out/production/The-Hamburglars/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/out/production/The-Hamburglars/The-Hamburglars.iml b/out/production/The-Hamburglars/The-Hamburglars.iml new file mode 100644 index 0000000..5d52380 --- /dev/null +++ b/out/production/The-Hamburglars/The-Hamburglars.iml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +<<<<<<< HEAD + + + + + + + + + + + + + + + + +======= +>>>>>>> e4b52f77b1e1669b3b2bf81452780ef1c69c30fe + + \ No newline at end of file diff --git a/out/production/The-Hamburglars/save/model.ser b/out/production/The-Hamburglars/save/model.ser new file mode 100644 index 0000000..c0489c7 Binary files /dev/null and b/out/production/The-Hamburglars/save/model.ser differ diff --git a/out/production/The-Hamburglars/views/ColorPick.fxml b/out/production/The-Hamburglars/views/ColorPick.fxml new file mode 100644 index 0000000..a78f9a5 --- /dev/null +++ b/out/production/The-Hamburglars/views/ColorPick.fxml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + diff --git a/save/model.ser b/save/model.ser new file mode 100644 index 0000000..ced79fe Binary files /dev/null and b/save/model.ser differ diff --git a/timeBehaviour/TimeBehaviour.java b/timeBehaviour/TimeBehaviour.java new file mode 100644 index 0000000..5b7dc49 --- /dev/null +++ b/timeBehaviour/TimeBehaviour.java @@ -0,0 +1,28 @@ +package timeBehaviour; + +import java.io.Serializable; +import java.time.LocalDateTime; + + +/** + * A TimeBehaviour interface. + */ +public interface TimeBehaviour extends Serializable +{ + + /** + * To get the time of the TimeBehaviour object. + * + * @return LocalDateTime time + */ + LocalDateTime getTime(); + + + /** + * To check if the timebehaviour is still in-time or not. + * + * @param time the time to check of the timeBehaviour is still in time or not. + * @return boolean true if the timebehaviour is still within the deadline, false otherwise. + */ + boolean inTime(LocalDateTime time); +} diff --git a/timeBehaviour/TimePoint.java b/timeBehaviour/TimePoint.java new file mode 100644 index 0000000..9a24726 --- /dev/null +++ b/timeBehaviour/TimePoint.java @@ -0,0 +1,48 @@ +package timeBehaviour; + +import java.time.LocalDateTime; + + +/** + * A TimePoint Class, a concrete class for TimeBehaviour with deadline. + */ +public class TimePoint implements TimeBehaviour +{ + private final LocalDateTime deadlineTime; // the deadline of the TimeBehaviour object. + + + /** + * Constructor for initializing the TimePoint timebehavior with the given deadline time. + * + * @param time LocalDateTime + */ + public TimePoint(LocalDateTime time) + { + this.deadlineTime = time; + } + + + /** + * To get the deadline time of an TimeBehaviour object. + * + * @return LocalDateTime deadline of the event. + */ + @Override + public LocalDateTime getTime() + { + return this.deadlineTime; + } + + + /** + * To check if the timebehaviour is still in-time or not. + * + * @param time the time to check of the timeBehaviour is still in time or not. + * @return boolean true if the timebehaviour is still within the deadline, false otherwise. + */ + @Override + public boolean inTime(LocalDateTime time) + { + return this.deadlineTime.toLocalDate().equals(time.toLocalDate()); + } +} diff --git a/timeBehaviour/TimeRange.java b/timeBehaviour/TimeRange.java new file mode 100644 index 0000000..e71c121 --- /dev/null +++ b/timeBehaviour/TimeRange.java @@ -0,0 +1,78 @@ +package timeBehaviour; + +import java.time.LocalDateTime; + + +/** + * A TimeRange Class, a concrete class for TimeBehaviour with a range of start time and end time. + */ +public class TimeRange implements TimeBehaviour +{ + private final LocalDateTime startTime; // the start time of the TimeBehaviour object. + + private final LocalDateTime endTime; // the end time of the TimeBehaviour object. + + + /** + * Constructor for initializing a TimeRange timebehaviour with given range of time. + * + * @param start_time_block the start time of the range. + * @param end_time_block the end time of the range. + */ + public TimeRange(LocalDateTime start_time_block, LocalDateTime end_time_block) + { + this.startTime = start_time_block; + this.endTime = end_time_block; + } + + + /** + * To get the Start time of the timebehaviour instance. + * + * @return startTime + */ + public LocalDateTime getStartTime() + { + return this.startTime; + } + + + /** + * To get the End Time of the timebehaviour instance. + * + * @return endTime + */ + public LocalDateTime getEndTime() + { + return this.endTime; + } + + + /** + * To get the time of the TimeBehaviour object. + * + * @return LocalDateTime time + */ + @Override + public LocalDateTime getTime() + { + return this.startTime; + } + + + /** + * To check if the timebehaviour is still in-time or not. + * + * @param time the time to check of the timeBehaviour is still in time or not. + * @return boolean true if the timebehaviour is still within the deadline, false otherwise. + */ + @Override + public boolean inTime(LocalDateTime time) + { + System.out.println(this.startTime.isBefore(time)); + System.out.println(this.endTime.isAfter(time)); + return (this.startTime.isBefore(time) && this.endTime.isAfter(time)) || + this.startTime.toLocalDate().equals(time.toLocalDate()) || + this.endTime.toLocalDate().equals(time.toLocalDate()); + } +} diff --git a/views/CalendarView.java b/views/CalendarView.java new file mode 100644 index 0000000..b0788e0 --- /dev/null +++ b/views/CalendarView.java @@ -0,0 +1,331 @@ +package views; + +import event.Event; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.fxml.FXMLLoader; +import javafx.geometry.Insets; +import javafx.geometry.Pos; +import javafx.scene.Node; +import javafx.scene.Parent; +import javafx.scene.Scene; +import javafx.scene.control.Button; +import javafx.scene.control.DatePicker; +import javafx.scene.control.Label; +import javafx.scene.control.ListView; +import javafx.scene.control.skin.DatePickerSkin; +import javafx.scene.paint.Paint; +import javafx.scene.text.Font; +import javafx.scene.layout.*; +import javafx.stage.Stage; +import model.CalendarModel; +import observer.EventObserver; + + +import java.io.*; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.ArrayList; + + +public class CalendarView { + + //Below defines all the components we'll need + + //The main root + Stage stage; + + //The model that stores event information + CalendarModel model; + + //The sublayout that contains our calendar + AnchorPane calendarLayout; + + //The overall layout that contains everything + BorderPane realLayout; + + //Buttons used for functionality + Button makeEventButton; + Button makeGoalButton; + Button changeThemeButton; + Button viewGoalButton; + + //The calendar used to access events + DatePicker calendar; + + //A wrapper class used to help display the calendar in a better way + DatePickerSkin calendarSkin; + + // A node that takes the calendar and makes it always visible + Node calendarDisplay; + Button editButton; + + //Label showing the selected date + Label dateDisplay; + Button completeEventButton; + + //Variables for getting the background and text color to change window theme + static Paint colour = javafx.scene.paint.Color.valueOf("#FFFFFF"); + static Paint colour_font = javafx.scene.paint.Color.valueOf("#000000") ; + + // ListView to display event names for a specific date + ListView eventsView = new ListView<>(); + + // List to store events for a given date + ArrayList events = new ArrayList<>(); + + // static instance + static CalendarView instance; + + //Method to implement singleton design pattern + public static CalendarView getView(CalendarModel model, Stage stage){ + if (instance == null){ + instance = new CalendarView(model, stage); + } + return instance; + } + + // private constructor to enforce Singleton + private CalendarView(CalendarModel model, Stage stage){ + // Get a model + this.model = model; + + // load stored model info + loadModel(); + this.stage = stage; + + // Set up the layouts + this.calendarLayout = new AnchorPane(); + this.realLayout = new BorderPane(); + + // Create the UI + initUI(); + } + + // load stored info + public void loadModel() { + File folder = new File("save/"); + if (!folder.exists()) { + return; + } + File[] fileList = folder.listFiles(); + assert fileList != null; + for (File f : fileList) { + if (f.isFile() && f.getName().equals("model.ser")) { + try { + FileInputStream file = new FileInputStream("save/model.ser"); + ObjectInputStream in = new ObjectInputStream(file); + ArrayList loadList = (ArrayList) in.readObject(); + this.model = (CalendarModel) loadList.get(0); + Event.setObserverList((ArrayList) loadList.get(1)); + CalendarModel.setCompletedGoals((ArrayList) loadList.get(2)); + CalendarView.colour = javafx.scene.paint.Color.valueOf(this.model.colour); + CalendarView.colour_font = javafx.scene.paint.Color.valueOf(this.model.colour_font); + } catch (IOException | ClassNotFoundException e) { + throw new RuntimeException(e); + } + + } + } + } + + // Save our model + public void saveModel() { + this.model.colour = colour.toString(); + this.model.colour_font = colour_font.toString(); + File folder = new File("save/"); + if (!folder.exists()) { + folder.mkdir(); + } + File fModel = new File("save/model.ser"); + ArrayList saveList = new ArrayList<>(); + try { + saveList.add(this.model); + saveList.add(Event.getObserverList()); + saveList.add(CalendarModel.getCompletedGoals()); + FileOutputStream fout = new FileOutputStream(fModel); + ObjectOutputStream oos = new ObjectOutputStream(fout); + oos.writeObject(saveList); + } catch (IOException e) { + throw new RuntimeException(e); + } + + } + + private void initUI(){ + + // set the title of the screen + this.stage.setTitle("Chronos"); + + + //Make core screen + this.calendarLayout = new AnchorPane(); + this.realLayout = new BorderPane(); + + //make a DatePicker for our calendar, and then set up a display that keeps + // the calendar always active + calendar = new DatePicker(LocalDate.now()); + calendarSkin = new DatePickerSkin(calendar); + calendarDisplay = calendarSkin.getPopupContent(); + calendarDisplay.setScaleX(1.5); + calendarDisplay.setScaleY(1.5); + calendarDisplay.setLayoutX(100); + calendarDisplay.setLayoutY(100); + calendarLayout.getChildren().add(calendarDisplay); + calendarLayout.setPrefSize(400, 400); + calendarLayout.setBackground(new Background(new BackgroundFill(colour,null,null))); + + //Create the label to display the date + this.dateDisplay = new Label(calendar.getValue().toString()); + dateDisplay.setTextFill(colour_font); + dateDisplay.setFont(new Font(20)); + dateDisplay.setAlignment(Pos.TOP_CENTER); + //When a date is selected, update our list of events in the below + calendar.setOnAction(e ->{ + dateDisplay.setText(calendar.getValue().toString()); + this.displayEvents(calendar.getValue().atStartOfDay()); + }); + + //Create the button to make events + this.makeEventButton = new Button("Make Event"); + makeEventButton.setScaleX(1.15); + makeEventButton.setScaleY(1.15); + makeEventButton.setTextFill(colour_font); + makeEventButton.setOnAction(e -> { + EventCreatorView ecv = new EventCreatorView(this); + this.displayEvents(calendar.getValue().atStartOfDay()); + }); + + //Create the button to make goals + this.makeGoalButton = new Button("Make Goal"); + makeGoalButton.setScaleX(1.15); + makeGoalButton.setScaleY(1.15); + makeGoalButton.setTextFill(colour_font); + makeGoalButton.setOnAction(e -> { + NewGoalView ngv = new NewGoalView(this); + }); + + //Create the button to view + this.viewGoalButton = new Button("View Goal"); + viewGoalButton.setScaleX(1.15); + viewGoalButton.setScaleY(1.15); + viewGoalButton.setTextFill(colour_font); + viewGoalButton.setOnAction(e -> { + GoalListView glv = new GoalListView(this); + }); + + //Create Button for changing the theme + this.changeThemeButton = new Button("Change Theme"); + changeThemeButton.setTextFill(colour_font); + changeThemeButton.setScaleX(1.15); + changeThemeButton.setScaleY(1.15); + changeThemeButton.setOnAction(e -> { + // Configure the Color + FXMLLoader fxmlLoader = new FXMLLoader(CalendarView.class.getResource("ColorPick.fxml")); + Scene scene = null; + try { + Parent root1 = (Parent) fxmlLoader.load(); + Stage stage = new Stage(); + stage.setTitle("Chronos"); + stage.setScene(new Scene(root1)); + stage.show(); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + Color.cv = this; + }); + + //Create button bar + HBox buttons = new HBox(10); + buttons.setPadding(new Insets(30)); + buttons.getChildren().addAll(makeEventButton, makeGoalButton, viewGoalButton, changeThemeButton); + buttons.setPadding(new Insets(20)); + + //Create buttons for editing and completing events + this.editButton = new Button("Edit Event"); + this.editButton.setTextFill(colour_font); + editButton.setOnAction(e -> { + if (this.eventsView.getSelectionModel().getSelectedItem() != null){ + + for(Event i: this.events) + { + if(i.getName().equals(this.eventsView.getSelectionModel().getSelectedItem())) + { + EventEditorView editorView = new EventEditorView(this, i); + break; + } + } + } + else{ + System.out.println("Need to select an item"); + } + }); + + this.completeEventButton = new Button("Complete Event"); + this.completeEventButton.setTextFill(colour_font); + completeEventButton.setOnAction(e -> { + String eventName = this.eventsView.getSelectionModel().getSelectedItem(); + if (eventName == null){ + return; + } + //int index = 0; + Event completed = null; + for (Event event: this.events){ + if (event.getName() == eventName){ + completed = event; + completed.complete(); + break; + } + } + if (!(completed == null)){ + this.events.remove(completed); + this.model.getAllEvents().remove(completed); + this.saveModel(); + } + }); + + //Create bar for editing and completing events + HBox eventsManaging = new HBox(); + eventsManaging.getChildren().addAll(editButton, completeEventButton); + eventsManaging.setPadding(new Insets(20)); + + //Create view for events + VBox eventDisplay = new VBox(); + eventDisplay.setPadding(new Insets(20)); + this.displayEvents(LocalDateTime.now()); + eventDisplay.getChildren().addAll(dateDisplay, eventsView, eventsManaging); + + + //put everything together + realLayout.setCenter(calendarLayout); + realLayout.setBottom(buttons); + realLayout.setRight(eventDisplay); + realLayout.setBackground(new Background(new BackgroundFill(colour,null,null))); + + + + //Finally, display everything + Scene scene = new Scene(realLayout); + this.stage.setScene(scene); + this.stage.show(); + + } + + //Method to display events in the event list + private void displayEvents(LocalDateTime time) + { + //Get events that match the date + this.events = this.model.getEventsInTime(time); + + //Get their names + ArrayList eventNames = new ArrayList<>(); + for (Event e: this.events){ + eventNames.add(e.getName()); + } + + //Set the ListView to contain those names + ObservableList namesToDisplay = FXCollections.observableArrayList(eventNames); + this.eventsView.setItems(namesToDisplay); + } + +} diff --git a/views/Color.java b/views/Color.java new file mode 100644 index 0000000..46ab8f0 --- /dev/null +++ b/views/Color.java @@ -0,0 +1,92 @@ +package views; + +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.fxml.Initializable; +import javafx.scene.control.ColorPicker; +import javafx.scene.layout.AnchorPane; +import javafx.scene.layout.Background; +import javafx.scene.layout.BackgroundFill; +import javafx.scene.shape.Circle; +import javafx.scene.text.Text; + +import java.net.URL; +import java.util.ResourceBundle; + + +/** + * Color class for handling color picker to choose background and font color as per user's choice + * + */ +public class Color implements Initializable +{ + public AnchorPane myPane2; // color picker for font change pane + public Circle circle2; // chosen color reflected shape for font + public Text text1; // text in color picker window + public Text text2; // text in color picker window + public AnchorPane myPane; // color picker for background change pane + @FXML + private Circle circle; // chosen color reflected shape for background + @FXML + private ColorPicker cp; // chosen color for background + @FXML + private ColorPicker cp2; // chosen color for font + @FXML + static CalendarView cv; // calendar view access + + + /** + * Choose a background theme for the application as per choice of user. + * + * @param actionEvent application's response if the user chooses his desired background color. + */ + public void handleColorPicker(ActionEvent actionEvent) + { + // Change the fill color for the circle when you pick a new color and get color value from user to change + // the background color for calendar's background and border layout. + circle.setFill(cp.getValue()); + cv.calendarLayout.setBackground(new Background(new BackgroundFill(cp.getValue(),null,null))); + cv.realLayout.setBackground(new Background(new BackgroundFill(cp.getValue(),null,null))); + + //Change the fill color for the circle when you pick a new color and get color value from the user to + // change background color for color picker window. + CalendarView.colour = cp.getValue(); + myPane.setBackground(new Background(new BackgroundFill(CalendarView.colour,null,null))); + cv.saveModel(); + } + + + /** + * Choose a font color for the application as per choice of user. + * + * @param actionEvent application's response if user chooses his desired font color. + */ + public void handleFontColor(ActionEvent actionEvent) { + // Colour Picker UI + circle2.setFill(cp2.getValue()); + CalendarView.colour_font = cp2.getValue(); + cv.makeEventButton.setTextFill(cp2.getValue()); + cv.makeGoalButton.setTextFill(cp2.getValue()); + cv.viewGoalButton.setTextFill(cp2.getValue()); + cv.changeThemeButton.setTextFill(cp2.getValue()); + cv.editButton.setTextFill(cp2.getValue()); + cv.completeEventButton.setTextFill(cp2.getValue()); + cv.dateDisplay.setTextFill(cp2.getValue()); + text1.setFill(cp2.getValue()); + text2.setFill(cp2.getValue()); + cv.saveModel(); + } + + /** + * Change the style of color picker + * + * @param url The location used to resolve relative paths for the root object, or null if the location is not known. + * @param resourceBundle The resources used to localize the root object,or null if the root object was not localized. + */ + @Override + public void initialize(URL url, ResourceBundle resourceBundle) + { + cp.getStyleClass().add(ColorPicker.STYLE_CLASS_SPLIT_BUTTON); + myPane.setBackground(new Background(new BackgroundFill(CalendarView.colour,null,null))); + } +} diff --git a/views/ColorPick.fxml b/views/ColorPick.fxml new file mode 100644 index 0000000..a78f9a5 --- /dev/null +++ b/views/ColorPick.fxml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + diff --git a/views/EventCreatorView.java b/views/EventCreatorView.java new file mode 100644 index 0000000..f83c7ec --- /dev/null +++ b/views/EventCreatorView.java @@ -0,0 +1,270 @@ +package views; + +import event.Event; +import timeBehaviour.TimeBehaviour; +import timeBehaviour.TimePoint; +import timeBehaviour.TimeRange; + +import javafx.geometry.Insets; +import javafx.scene.Scene; +import javafx.scene.control.Button; +import javafx.scene.control.DatePicker; +import javafx.scene.control.Label; +import javafx.scene.control.TextField; +import javafx.scene.layout.Background; +import javafx.scene.layout.BackgroundFill; +import javafx.scene.layout.VBox; +import javafx.scene.text.Font; +import javafx.stage.Modality; +import javafx.stage.Stage; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + + +/** + * A EventCreatorView class for handling the creation of events. + */ +public class EventCreatorView { + private final CalendarView calendarView; // the calendar view + private final TextField nameTextField = new TextField("Name"); // the name of the event + private final TextField pointsTextField = new TextField("Points"); // the points associated with the event + private final TextField descTextField = new TextField("Description"); // the description of the event + private final Button changeTimeButton = new Button("Choose start/end time"); // Button for changing the type of time of the event + private final DatePicker pointDatePicker = new DatePicker(LocalDate.now()); // DatePicker for TimePoint event + private final TextField pointTimePicker = new TextField("Time (hh:mm)"); // Deadline time for TimePoint event + private final DatePicker startDatePicker = new DatePicker(LocalDate.now()); // Start time DatePicker for TimeRange event + private final TextField startTimePicker = new TextField("Start time (hh:mm)"); // Start time for TimeRange event + private final DatePicker endDatePicker = new DatePicker(LocalDate.now()); // End time DatePicker for TimeRange event + private final TextField endTimePicker = new TextField("End time (hh:mm)"); // End time for TimeRange event + private final Button saveButton = new Button("Save Changes"); // Button for Saving the edited event + private final Label errorLabel = new Label(""); // the error message to display + + /** + * Constructor for the EventCreatorView Class. + * + * @param calendarView the application's CalendarView + */ + public EventCreatorView(CalendarView calendarView) { + this.calendarView = calendarView; + + + // Set up the stage + final Stage dialog = new Stage(); + dialog.initModality(Modality.APPLICATION_MODAL); + dialog.initOwner(calendarView.stage); + VBox dialogVbox = new VBox(20); + dialogVbox.setBackground(new Background(new BackgroundFill(CalendarView.colour,null,null))); + dialogVbox.setPadding(new Insets(20, 20, 20, 20)); + + + + // Font UI + Font f = new Font(16); + Label createEventLabel = new Label("Create a new event!"); + createEventLabel.setFont(f); + nameTextField.setFont(f); + pointsTextField.setFont(f); + descTextField.setFont(f); + changeTimeButton.setFont(f); + pointTimePicker.setFont(f); + pointDatePicker.setValue(this.calendarView.calendar.getValue()); + startTimePicker.setFont(f); + startDatePicker.setValue(this.calendarView.calendar.getValue()); + endDatePicker.setValue(this.calendarView.calendar.getValue()); + endTimePicker.setFont(f); + saveButton.setFont(f); + + + + // Buttons, TextFields, and Labels UI. + createEventLabel.setTextFill(CalendarView.colour_font); + changeTimeButton.setTextFill(CalendarView.colour_font); + saveButton.setTextFill(CalendarView.colour_font); + VBox vbox = new VBox(10, createEventLabel, nameTextField, pointsTextField, descTextField, changeTimeButton, pointDatePicker, pointTimePicker, saveButton, errorLabel); + dialogVbox.getChildren().add(vbox); + Scene scene = new Scene(dialogVbox, 400, 500); + dialog.setScene(scene); + dialog.show(); + dialog.setAlwaysOnTop(true); + + + + // On Action Function Calls. + saveButton.setOnAction(e -> createEvent()); + changeTimeButton.setOnAction(e -> { + if (vbox.getChildren().contains(pointDatePicker)) { + vbox.getChildren().remove(pointDatePicker); + vbox.getChildren().remove(pointTimePicker); + vbox.getChildren().remove(saveButton); + vbox.getChildren().remove(errorLabel); + pointDatePicker.setValue(this.calendarView.calendar.getValue()); + pointTimePicker.setText("Time (hh:mm)"); + changeTimeButton.setText("Choose single time"); + vbox.getChildren().add(startDatePicker); + vbox.getChildren().add(startTimePicker); + vbox.getChildren().add(endDatePicker); + vbox.getChildren().add(endTimePicker); + } else { + vbox.getChildren().remove(startDatePicker); + vbox.getChildren().remove(startTimePicker); + vbox.getChildren().remove(endDatePicker); + vbox.getChildren().remove(endTimePicker); + vbox.getChildren().remove(saveButton); + vbox.getChildren().remove(errorLabel); + startDatePicker.setValue(this.calendarView.calendar.getValue()); + startTimePicker.setText("Start time (hh:mm)"); + endDatePicker.setValue(this.calendarView.calendar.getValue()); + endTimePicker.setText("End time (hh:mm)"); + changeTimeButton.setText("Choose start/end time"); + vbox.getChildren().add(pointDatePicker); + vbox.getChildren().add(pointTimePicker); + } + vbox.getChildren().add(saveButton); + vbox.getChildren().add(errorLabel); + + }); + + } + + /** + * Create a new Event using the parameters given in the text fields and date pickers. + * Store this new Event in the CalendarModel's list of Events. + * + * @throws NumberFormatException for invalid input of integer in points field. + */ + private void createEvent() throws NumberFormatException { + + // Check if the Event's Name is not empty. + if (this.nameTextField.getText().trim().isEmpty() || this.nameTextField.getText().trim().isBlank()) { + this.errorLabel.setText("Please enter the Event Name. It can NOT be Blank!"); + return; + } + // Check if the event name is already in the events list. + else + { + String temp = this.nameTextField.getText().trim(); + for(Event i: this.calendarView.model.getAllEvents()) + { + if (temp.equals(i.getName())) + { + this.errorLabel.setText("Event Name already taken!"); + return; + } + } + } + // store the valid name + String event_name = this.nameTextField.getText().trim(); + + + // Check if the Event's Description is not empty. + if (this.descTextField.getText().trim().isEmpty() || this.descTextField.getText().trim().isBlank()) { + this.errorLabel.setText("Please enter the Event's Description. It can NOT be Blank!"); + return; + } + //Store the valid description + String event_description = this.descTextField.getText().trim(); + + + String points = String.valueOf(this.pointsTextField.getText()).trim(); + int event_points = 0; + // Check if the Event's associated Points are of integer type. + try { + event_points += Integer.parseInt(points); // store the valid points associated with the event. + } + catch (NumberFormatException e) + { + this.errorLabel.setText("Please enter a Integer value for the points associated with the event."); + return; + } + + + //Check the type of the time and create time range or time point based on that. + if (this.endTimePicker.getText().trim().isBlank() || this.endTimePicker.getText().trim().isEmpty() || this.startTimePicker.getText().trim().equals("Start time (hh:mm)") || this.endTimePicker.getText().trim().equals("End time (hh:mm)")) { + // Create a new Time Point object based on the deadline of the user. + + String deadline_hours = this.pointTimePicker.getText().trim(); + + Pattern pattern = Pattern.compile("^(0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$"); + Matcher matcher = pattern.matcher(deadline_hours); + if (matcher.find()) { + // match found, valid deadline HH:mm. + String yyyy_mm_dd = this.pointDatePicker.getValue().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); + String yyyy_mm_dd_HH_mm = yyyy_mm_dd + " " + deadline_hours; + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); + LocalDateTime pointTime = LocalDateTime.parse(yyyy_mm_dd_HH_mm, formatter); + + + // Create a TimePoint object. + TimeBehaviour tp = new TimePoint(pointTime); + + // Finally, create a new Event with the new TimePoint deadline time of the event. + Event e = new Event(event_name, event_description, event_points, tp); + + + // Add the event to the events list of CalendarView.model.events + this.calendarView.model.addEvent(e); + + // Save the event + this.calendarView.saveModel(); + + + //Success Message! + this.errorLabel.setText("Event Added to the Calendar!"); + } + else // Invalid Format of HH:mm + this.errorLabel.setText("Please Re-enter the time of the event. Enter in HH:mm format."); + } + else + { + // Create a new Time Range object based on the start-time and end-time of the user. + + String start_time = this.startTimePicker.getText().trim(); + String end_time = this.endTimePicker.getText().trim(); + + + Pattern pattern = Pattern.compile("^(0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$"); + Matcher matcher = pattern.matcher(start_time); + Matcher matcher1 = pattern.matcher(end_time); + + if (matcher1.find() && matcher.find()) + { + // match found, valid deadline HH:mm. + String yyyy_mm_dd = this.startDatePicker.getValue().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); + String yyyy_mm_dd2 = this.endDatePicker.getValue().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); + String yyyy_mm_dd_HH_mm = yyyy_mm_dd + " " + start_time; + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); + LocalDateTime start_time_block = LocalDateTime.parse(yyyy_mm_dd_HH_mm, formatter); + + String yyyy_mm_dd_HH_mm2 = yyyy_mm_dd2 + " " + end_time; + DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); + LocalDateTime end_time_block = LocalDateTime.parse(yyyy_mm_dd_HH_mm2, formatter2); + + System.out.println(start_time_block + " " + end_time_block); + + + // Create a TimeRange object. + TimeBehaviour tr = new TimeRange(start_time_block, end_time_block); + + // Finally, create a new Event with the new TimeRange start and end time of the event block. + Event e = new Event(event_name, event_description, event_points, tr); + + + // Add the event to the events list of CalendarView.model.events + this.calendarView.model.addEvent(e); + + // Save the event + this.calendarView.saveModel(); + + //Success Message! + this.errorLabel.setText("Event Added to the Calendar!"); + } + else // Invalid Format of HH:mm + this.errorLabel.setText("Invalid Start/End time of the event. Enter in HH:mm format."); + } + } +} diff --git a/views/EventEditorView.java b/views/EventEditorView.java new file mode 100644 index 0000000..b799e11 --- /dev/null +++ b/views/EventEditorView.java @@ -0,0 +1,307 @@ +package views; + +import event.Event; +import timeBehaviour.TimeBehaviour; +import timeBehaviour.TimePoint; +import timeBehaviour.TimeRange; +import static views.CalendarView.colour; + +import javafx.geometry.Insets; +import javafx.scene.Scene; +import javafx.scene.control.Button; +import javafx.scene.control.DatePicker; +import javafx.scene.control.Label; +import javafx.scene.control.TextField; +import javafx.scene.layout.Background; +import javafx.scene.layout.BackgroundFill; +import javafx.scene.layout.VBox; +import javafx.scene.text.Font; +import javafx.stage.Modality; +import javafx.stage.Stage; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + + +/** + * A EventEditorView class for handling the editing of events. + */ +public class EventEditorView +{ + private final CalendarView calendarView; // the calendar view + private final Event event; // the event to edit + private final TextField nameTextField = new TextField("Name"); // the name of the event + private final TextField pointsTextField = new TextField("Points"); // the points associated with the event + private final TextField descTextField = new TextField("Description"); // the description of the event + private final Button changeTimeButton = new Button("Choose start/end time"); // Button for changing the type of time of the event + private final DatePicker pointDatePicker = new DatePicker(LocalDate.now()); // DatePicker for TimePoint event + private final TextField pointTimePicker = new TextField("Time (hh:mm)"); // Deadline time for TimePoint event + private final DatePicker startDatePicker = new DatePicker(LocalDate.now()); // Start time DatePicker for TimeRange event + private final TextField startTimePicker = new TextField("Start time (hh:mm)"); // Start time for TimeRange event + private final DatePicker endDatePicker = new DatePicker(LocalDate.now()); // End time DatePicker for TimeRange event + private final TextField endTimePicker = new TextField("End time (hh:mm)"); // End time for TimeRange event + private final Button saveButton = new Button("Save Changes"); // Button for Saving the edited event + private final Label errorLabel = new Label(""); // the error message to display + + + /** + * Constructor for the EventEditorView Class. + * + * @param calendarView the application's CalendarView + * @param event the event to edit + */ + public EventEditorView(CalendarView calendarView, Event event) + { + this.calendarView = calendarView; + this.event = event; + + + + // Set up the stage + final Stage dialog = new Stage(); + dialog.initModality(Modality.APPLICATION_MODAL); + dialog.initOwner(calendarView.stage); + VBox dialogVbox = new VBox(20); + dialogVbox.setPadding(new Insets(20, 20, 20, 20)); + + + + // Font UI + Font f = new Font(16); + Label editEventLabel = new Label(""); + editEventLabel.setFont(f); + nameTextField.setFont(f); + pointsTextField.setFont(f); + descTextField.setFont(f); + changeTimeButton.setFont(f); + pointTimePicker.setFont(f); + startTimePicker.setFont(f); + endTimePicker.setFont(f); + saveButton.setFont(f); + errorLabel.setFont(f); + + + + // Buttons, TextFields, and Labels UI. + saveButton.setTextFill(CalendarView.colour_font); + editEventLabel.setTextFill(CalendarView.colour_font); + changeTimeButton.setTextFill(CalendarView.colour_font); + errorLabel.setTextFill(CalendarView.colour_font); + editEventLabel.setText("Edit Event: " + event.getName()); + nameTextField.setText(event.getName()); + pointsTextField.setText(String.valueOf(event.getPointValue())); + descTextField.setText(event.getDescription()); + dialogVbox.setBackground(new Background(new BackgroundFill(colour,null,null))); + VBox vbox = new VBox(10, editEventLabel, nameTextField, pointsTextField, descTextField, changeTimeButton, pointDatePicker, pointTimePicker, saveButton, errorLabel); + dialogVbox.getChildren().add(vbox); + Scene scene = new Scene(dialogVbox, 400, 500); + dialog.setScene(scene); + dialog.show(); + dialog.setAlwaysOnTop(true); + + + + // On Action Function Calls. + saveButton.setOnAction(e -> editEvent()); + changeTimeButton.setOnAction(e -> changeTime(vbox)); + + + + //If event has a time point: + if(event.getTimeBehaviour() instanceof TimePoint tp) + { + //set values of pointDatePicker and pointTimePicker to event's time + this.pointDatePicker.setValue(tp.getTime().toLocalDate()); + this.pointTimePicker.setText(tp.getTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")).substring(11,16)); + } + + //If event has a time range: + else + { + this.changeTime(vbox); + + //set values of startDatePicker, startTimePicker, endDatePicker and endTimePicker + TimeRange tr = (TimeRange) event.getTimeBehaviour(); + + this.startDatePicker.setValue(tr.getStartTime().toLocalDate()); + this.endDatePicker.setValue(tr.getEndTime().toLocalDate()); + + this.startTimePicker.setText(tr.getStartTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")).substring(11,16)); + this.endTimePicker.setText(tr.getEndTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")).substring(11,16)); + } + } + + + /** + * Edit the details of the event and save accordingly. + */ + private void editEvent() { + + // Check if the Event's Name is not empty. + if (this.nameTextField.getText().trim().isEmpty() || this.nameTextField.getText().trim().isBlank()) { + this.errorLabel.setText("Please enter the Event Name. It can NOT be Blank!"); + return; + } + // Check if the event name is already in the events list. + else + { + String temp = this.nameTextField.getText().trim(); + for(Event i: this.calendarView.model.getAllEvents()) + { + if (temp.equals(i.getName())) + { + this.errorLabel.setText("Event Name already taken!"); + return; + } + } + } + this.event.setName(this.nameTextField.getText().trim()); // edit name + + + // Check if the Event's Description is not empty. + if (this.descTextField.getText().trim().isEmpty() || this.descTextField.getText().trim().isBlank()) { + this.errorLabel.setText("Please enter the Event's Description. It can NOT be Blank!"); + return; + } + this.event.setDescription(this.descTextField.getText().trim()); // edit the description + + + String points = String.valueOf(this.pointsTextField.getText()).trim(); + int event_points = 0; + // Check if the Event's associated Points are of integer type. + try { + event_points += Integer.parseInt(points); + } catch (NumberFormatException e) { + this.errorLabel.setText("Please enter a Integer value for the points associated with the event."); + return; + } + this.event.setPointValue(event_points); // edit the points associated + + + + + if (this.endTimePicker.getText().trim().isBlank() || this.endTimePicker.getText().trim().isEmpty() || this.startTimePicker.getText().trim().equals("Start time (hh:mm)") || this.endTimePicker.getText().trim().equals("End time (hh:mm)")) + { + // Create a new Time Point object based on the deadline of the user. + String deadline_hours = this.pointTimePicker.getText().trim(); + + Pattern pattern = Pattern.compile("^(0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$"); + Matcher matcher = pattern.matcher(deadline_hours); + + if (matcher.find()) + { + // match found, valid deadline HH:mm. + String yyyy_mm_dd = this.pointDatePicker.getValue().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); + + String yyyy_mm_dd_HH_mm = yyyy_mm_dd + " " + deadline_hours; + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); + LocalDateTime pointTime = LocalDateTime.parse(yyyy_mm_dd_HH_mm, formatter); + + + // Create a TimePoint object. + TimeBehaviour tp = new TimePoint(pointTime); + this.event.setTimeBehaviour(tp); // edit the new deadline with timepoint object + + + //Success Message + this.errorLabel.setText("Event Added to the Calendar!"); + + // Save the event + this.calendarView.saveModel(); + } + + else // Invalid Format of HH:mm + this.errorLabel.setText("Please Re-enter the time of the event. Enter in HH:mm format."); + } + + else + { + // Create a new Time Range object based on the start-time and end-time of the user. + + String start_time = this.startTimePicker.getText().trim(); + String end_time = this.endTimePicker.getText().trim(); + + + Pattern pattern = Pattern.compile("^(0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$"); + Matcher matcher = pattern.matcher(start_time); + Matcher matcher1 = pattern.matcher(end_time); + + if (matcher1.find() && matcher.find()) + { + // match found, valid deadline HH:mm. + String yyyy_mm_dd = this.startDatePicker.getValue().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); + String yyyy_mm_dd2 = this.endDatePicker.getValue().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); + + String yyyy_mm_dd_HH_mm = yyyy_mm_dd + " " + start_time; + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); + LocalDateTime start_time_block = LocalDateTime.parse(yyyy_mm_dd_HH_mm, formatter); + + String yyyy_mm_dd_HH_mm2 = yyyy_mm_dd2 + " " + end_time; + DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); + LocalDateTime end_time_block = LocalDateTime.parse(yyyy_mm_dd_HH_mm2, formatter2); + + System.out.println(start_time_block + " " + end_time_block); + + // Create a TimeRange object. + TimeBehaviour tr = new TimeRange(start_time_block, end_time_block); + + this.event.setTimeBehaviour(tr); // edit the timerange of the event. + + //Success Message! + this.errorLabel.setText("Event Added to the Calendar!"); + + // Save the event + this.calendarView.saveModel(); + } + + else // Invalid Format of HH:mm + this.errorLabel.setText("Invalid Start/End time of the event. Enter in HH:mm format."); + } + } + + + /** + * Switches between displaying input for time points/time ranges + * + * @param vbox a Vertical JavaFx Box + */ + private void changeTime(VBox vbox) + { + if (vbox.getChildren().contains(pointDatePicker)) + { + vbox.getChildren().remove(pointDatePicker); + vbox.getChildren().remove(pointTimePicker); + vbox.getChildren().remove(saveButton); + vbox.getChildren().remove(errorLabel); + pointDatePicker.setValue(LocalDate.now()); + pointTimePicker.setText("Time (hh:mm)"); + changeTimeButton.setText("Choose single time"); + vbox.getChildren().add(startDatePicker); + vbox.getChildren().add(startTimePicker); + vbox.getChildren().add(endDatePicker); + vbox.getChildren().add(endTimePicker); + } + else // Switch to Time-Range entry field. + { + vbox.getChildren().remove(startDatePicker); + vbox.getChildren().remove(startTimePicker); + vbox.getChildren().remove(endDatePicker); + vbox.getChildren().remove(endTimePicker); + vbox.getChildren().remove(saveButton); + vbox.getChildren().remove(errorLabel); + startDatePicker.setValue(LocalDate.now()); + startTimePicker.setText("Start time (hh:mm)"); + endDatePicker.setValue(LocalDate.now()); + endTimePicker.setText("End time (hh:mm)"); + changeTimeButton.setText("Choose start/end time"); + vbox.getChildren().add(pointDatePicker); + vbox.getChildren().add(pointTimePicker); + } + vbox.getChildren().add(saveButton); + vbox.getChildren().add(errorLabel); + } +} diff --git a/views/GoalCompleteView.java b/views/GoalCompleteView.java new file mode 100644 index 0000000..8b5e4e0 --- /dev/null +++ b/views/GoalCompleteView.java @@ -0,0 +1,56 @@ +package views; + +import javafx.geometry.Insets; +import javafx.scene.Scene; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.layout.Background; +import javafx.scene.layout.BackgroundFill; +import javafx.scene.layout.VBox; +import javafx.scene.text.Font; +import javafx.stage.Stage; +import observer.EventObserver; +import observer.Goal; + +import static views.CalendarView.colour; + +/** + * A window that notifies the user when they have completed one of their goals. + */ +public class GoalCompleteView { + + private Label completeLabel = new Label(""); // Message that tells the user which goal has been completed + private Button okButton = new Button("OK"); // Button to close this window + + /** + * Constructor + * + * @param o the goal which has been completed + */ + public GoalCompleteView(Goal o) { + final Stage dialog = new Stage(); + VBox dialogVbox = new VBox(20); + dialogVbox.setPadding(new Insets(20, 20, 20, 20)); + dialogVbox.setBackground(new Background(new BackgroundFill(colour,null,null))); + completeLabel.setText("Congratulations! You completed your goal: " + o.getName()); + Font f = new Font(16); + completeLabel.setFont(f); + completeLabel.setTextFill(CalendarView.colour_font); + okButton.setFont(f); + okButton.setTextFill(CalendarView.colour_font); + + + okButton.setOnAction(e -> { + dialog.close(); + }); + + VBox vbox = new VBox(10, completeLabel, okButton); + dialogVbox.getChildren().add(vbox); + Scene scene = new Scene(dialogVbox, 400, 100); + dialog.setScene(scene); + dialog.show(); + dialog.setAlwaysOnTop(true); + } + + +} \ No newline at end of file diff --git a/views/GoalListView.java b/views/GoalListView.java new file mode 100644 index 0000000..173c373 --- /dev/null +++ b/views/GoalListView.java @@ -0,0 +1,85 @@ +package views; + +import javafx.scene.layout.Background; +import javafx.scene.layout.BackgroundFill; +import javafx.scene.paint.Paint; +import model.CalendarModel; +import event.Event; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.geometry.Insets; +import javafx.scene.Scene; +import javafx.scene.control.Label; +import javafx.scene.control.ListView; +import javafx.scene.layout.HBox; +import javafx.scene.layout.VBox; +import javafx.scene.text.Font; +import javafx.stage.Stage; +import observer.EventObserver; + +import java.util.ArrayList; + +import static views.CalendarView.colour; + +/** + * GUI for the user to view their existing Goals. Shows ongoing Goals and completed Goals separately. + */ +public class GoalListView { + + CalendarView calendarView; // The application's CalendarView + private Paint colour; // The background colour + + /** + * Constructor + * + * @param calendarView the application's CalendarView + */ + public GoalListView(CalendarView calendarView) { + this.calendarView = calendarView; + this.colour = CalendarView.colour; + + final Stage dialog = new Stage(); + Label labelOngoing = new Label("Ongoing goals:"); + labelOngoing.setFont(new Font(16)); + labelOngoing.setTextFill(CalendarView.colour_font); + Label labelComplete = new Label("Completed goals:"); + labelComplete.setFont(new Font(16)); + labelComplete.setTextFill(CalendarView.colour_font); + + ArrayList goalsOngoingList = new ArrayList<>(); + for (EventObserver o : Event.getObserverList()) { + goalsOngoingList.add(o.toString()); + } + ObservableList goalsOngoing = FXCollections.observableArrayList(goalsOngoingList); + ListView listViewOngoing = new ListView<>(goalsOngoing); + listViewOngoing.setMaxSize(200, 200); + + ArrayList goalsCompleteList = new ArrayList<>(); + for (EventObserver o : CalendarModel.getCompletedGoals()) { + goalsCompleteList.add(o.toString()); + } + ObservableList goalsComplete = FXCollections.observableArrayList(goalsCompleteList); + ListView listViewComplete = new ListView<>(goalsComplete); + listViewComplete.setMaxSize(200, 200); + + VBox vboxOngoing = new VBox(20); + vboxOngoing.setPadding(new Insets(20, 20, 20, 20)); + vboxOngoing.getChildren().addAll(labelOngoing, listViewOngoing); + vboxOngoing.setBackground(new Background(new BackgroundFill(CalendarView.colour,null,null))); + + VBox vboxComplete = new VBox(20); + vboxComplete.setPadding(new Insets(20, 20, 20, 20)); + vboxComplete.getChildren().addAll(labelComplete, listViewComplete); + vboxComplete.setBackground(new Background(new BackgroundFill(CalendarView.colour,null,null))); + + HBox hbox = new HBox(20); + hbox.setPadding(new Insets(20, 20, 20, 20)); + hbox.getChildren().addAll(vboxOngoing, vboxComplete); + hbox.setBackground(new Background(new BackgroundFill(CalendarView.colour,null,null))); + + Scene scene = new Scene(hbox, 400, 400); + dialog.setScene(scene); + dialog.show(); + dialog.setAlwaysOnTop(true); + } +} diff --git a/views/NewGoalView.java b/views/NewGoalView.java new file mode 100644 index 0000000..de83a6d --- /dev/null +++ b/views/NewGoalView.java @@ -0,0 +1,109 @@ +package views; + +import event.Event; +import javafx.geometry.Insets; +import javafx.scene.Scene; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.TextField; +import javafx.scene.layout.Background; +import javafx.scene.layout.BackgroundFill; +import javafx.scene.layout.VBox; +import javafx.scene.paint.Paint; +import javafx.scene.text.Font; +import javafx.stage.Modality; +import javafx.stage.Stage; +import observer.Goal; + +import static views.CalendarView.colour; + +/** + * GUI for the user to create new Goals. Allows the user to choose a name and amount of points required to complete the + * goal. + */ +public class NewGoalView { + + CalendarView calendarView; // The application's CalendarView + private Paint colour; // The background colour + private Label createGoalLabel = new Label("Create a new goal! Enter a name and point value."); // Text label at the top of the window + private TextField goalNameTextField = new TextField("Name"); // Text field to enter the new goal's name + private TextField goalPointsTextField = new TextField("Points"); // Text field to enter a number of points + private Label errorLabel = new Label(""); // Label to display whether the goal was created successfully or not + private Button saveButton = new Button("Save Goal"); // Button to create and save the new goal + + /** + * Constructor + * + * @param calendarView the application's CalendarView + */ + public NewGoalView(CalendarView calendarView) { + this.calendarView = calendarView; + this.colour = CalendarView.colour; + + final Stage dialog = new Stage(); + dialog.initModality(Modality.APPLICATION_MODAL); + dialog.initOwner(calendarView.stage); + VBox dialogVbox = new VBox(20); + dialogVbox.setPadding(new Insets(20, 20, 20, 20)); + + createGoalLabel.setId("createGoalLabel"); + createGoalLabel.setTextFill(CalendarView.colour_font); + createGoalLabel.setFont(new Font(16)); + createGoalLabel.setTextFill(CalendarView.colour_font); + goalNameTextField.setId("goalNameTextField"); + goalNameTextField.setFont(new Font(16)); + goalPointsTextField.setId("goalPointsTextField"); + goalPointsTextField.setFont(new Font(16)); + errorLabel.setId("errorLabel"); + errorLabel.setTextFill(CalendarView.colour_font); + errorLabel.setFont(new Font(16)); + saveButton.setId("saveButton"); + saveButton.setTextFill(CalendarView.colour_font); + saveButton.setFont(new Font(16)); + dialogVbox.setBackground(new Background(new BackgroundFill(colour,null,null))); + + saveButton.setOnAction(e -> createGoal()); + errorLabel.setTextFill(CalendarView.colour_font); + + VBox createGoalBox = new VBox(10, createGoalLabel, goalNameTextField, goalPointsTextField, errorLabel, saveButton); + createGoalBox.setBackground(new Background(new BackgroundFill(CalendarView.colour,null,null))); + + + dialogVbox.getChildren().add(createGoalBox); + dialogVbox.setBackground(new Background(new BackgroundFill(CalendarView.colour,null,null))); + Scene dialogScene = new Scene(dialogVbox, 400, 400); + dialog.setScene(dialogScene); + dialog.show(); + dialog.setAlwaysOnTop(true); + } + + + /** + * Create a new Goal using the configurations given in goalNameTextField and goalPointsTextField. Add the new Goal + * to the observerLists of all Events. + */ + private void createGoal() { + try { + int points = Integer.parseInt(goalPointsTextField.getText()); + + String name; + if (!goalNameTextField.getText().isEmpty()) { + name = goalNameTextField.getText(); + } + else { + errorLabel.setText("Enter a name for the goal!"); + return; + } + + Goal goal = new Goal(name, points); + Event.getObserverList().add(goal); + this.calendarView.saveModel(); + errorLabel.setText("Goal " + "\"" + goal.getName() + "\"" + " created!"); + + } + catch (NumberFormatException e) { + errorLabel.setText("Invalid number of points!"); + } + + } +} \ No newline at end of file