From b591061ec982ea087488afe39ce55fff6fa4bfa4 Mon Sep 17 00:00:00 2001 From: Jonas Smedegaard Date: Wed, 30 Apr 2025 22:21:28 +0200 Subject: merge project portfolio2 into bachelorizer, except class myDB --- Makefile | 23 +- .../com/example/portfolio2/Controller.java | 137 ----------- .../com/example/portfolio2/Database.java | 144 ------------ .../com/example/portfolio2/GUI.java | 48 ---- .../com/example/portfolio2/Main.java | 22 -- .../com/example/portfolio2/Person.java | 18 -- .../com/example/portfolio2/UI.java | 38 ---- src/com.example.portfolio2/module-info.java | 3 +- .../dk/biks/bachelorizer/Controller.java | 156 ++++++++++--- .../dk/biks/bachelorizer/Database.java | 146 ++++++++++++ .../dk/biks/bachelorizer/GUI.java | 66 +++--- .../dk/biks/bachelorizer/UI.java | 38 ++++ .../dk/biks/bachelorizer/Window.java | 252 +++++++++++++++------ src/dk.biks.bachelorizer/module-info.java | 2 + 14 files changed, 531 insertions(+), 562 deletions(-) delete mode 100644 src/com.example.portfolio2/com/example/portfolio2/Controller.java delete mode 100644 src/com.example.portfolio2/com/example/portfolio2/Database.java delete mode 100644 src/com.example.portfolio2/com/example/portfolio2/GUI.java delete mode 100644 src/com.example.portfolio2/com/example/portfolio2/Main.java delete mode 100644 src/com.example.portfolio2/com/example/portfolio2/Person.java delete mode 100644 src/com.example.portfolio2/com/example/portfolio2/UI.java create mode 100644 src/dk.biks.bachelorizer/dk/biks/bachelorizer/Database.java create mode 100644 src/dk.biks.bachelorizer/dk/biks/bachelorizer/UI.java diff --git a/Makefile b/Makefile index 00cc814..5dc2c49 100644 --- a/Makefile +++ b/Makefile @@ -2,19 +2,17 @@ DOCUMENTS = delivery1 delivery2 JAVA_PROJECTMODULES = \ com.example.portfolio2 com.example.portfolio3 dk.biks.bachelorizer -JAVA_MODULEPATHS_portfolio2 = \ - /usr/share/openjfx/lib /usr/share/java/sqlite-jdbc.jar -JAVA_MODULES_portfolio2 = $(addprefix javafx.,base controls graphics) +JAVA_MODULEPATHS_portfolio2 = /usr/share/java/sqlite-jdbc.jar JAVA_ROOT_portfolio2 = src/com.example.portfolio2 -JAVA_MAINCLASSES_portfolio2 = Main -JAVA_EXTRACLASSES_portfolio2 = Controller Database GUI MyDB UI Window +JAVA_EXTRACLASSES_portfolio2 = MyDB JAVA_ROOT_portfolio3 = src/com.example.portfolio3 JAVA_EXTRACLASSES_portfolio3 = AbstractGraph AdjListGraph AdjMapGraph \ Edge EdgeGraph GraphAlgorithms Graph Graphs MatrixGraph Vertex -JAVA_MODULEPATHS_bachelorizer = /usr/share/openjfx/lib +JAVA_MODULEPATHS_bachelorizer = \ + /usr/share/openjfx/lib /usr/share/java/sqlite-jdbc.jar JAVA_ROOT_bachelorizer = src/dk.biks.bachelorizer JAVA_MAINCLASSES_bachelorizer = Main Graph Window -JAVA_EXTRACLASSES_bachelorizer = Controller GUI Person +JAVA_EXTRACLASSES_bachelorizer = Controller Database GUI Person UI JAVA_MODULES_bachelorizer = $(addprefix javafx.,base controls graphics) ZIPNAME = bachelorizer @@ -23,8 +21,7 @@ ZIPFILES += $(STEMS:=.java) include _make/*.mk # silence security restriction warning -JAVAFLAGS += --enable-native-access=javafx.graphics -JAVAFLAGS_portfolio2 += --enable-native-access=javafx.graphics \ +JAVAFLAGS += --enable-native-access=javafx.graphics \ --enable-native-access=sqlite.jdbc # silence unsafe memory-access methods warning on recent JDKs @@ -35,11 +32,13 @@ endif # loading as modules works with JDK 22+, and is required with JDK 23+ ifeq ($(shell expr $(JAVA_MAJOR_VERSION) \>= 22), 1) -JAVA_MODULEPATHS_bachelorizer += mods/com.example.portfolio3 +JAVA_MODULEPATHS_bachelorizer += \ + mods/com.example.portfolio2 mods/com.example.portfolio3 else -JAVA_CLASSPATHS_bachelorizer += mods/com.example.portfolio3 +JAVA_CLASSPATHS_bachelorizer += \ + mods/com.example.portfolio2 mods/com.example.portfolio3 endif # TODO: fix properly declare and resolve local interdependencies runsrc-dk.biks.bachelorizer build-dk.biks.bachelorizer: \ - build-com.example.portfolio3 + build-com.example.portfolio2 build-com.example.portfolio3 diff --git a/src/com.example.portfolio2/com/example/portfolio2/Controller.java b/src/com.example.portfolio2/com/example/portfolio2/Controller.java deleted file mode 100644 index 3d19efb..0000000 --- a/src/com.example.portfolio2/com/example/portfolio2/Controller.java +++ /dev/null @@ -1,137 +0,0 @@ -// SPDX-FileCopyrightText: 2025 Jonas Smedegaard -// SPDX-FileCopyrightText: 2025 -// SPDX-FileCopyrightText: 2025 -// SPDX-FileCopyrightText: 2025 -// SPDX-License-Identifier: GPL-3.0-or-later - -package com.example.portfolio2; - -import javafx.scene.control.ComboBox; -import javafx.scene.control.Label; -import javafx.scene.control.TextArea; - -/// Bachelorizer - Controller -class Controller { - - /// Storage model - private Database store; - - /// UI model - private UI ui; - - /// Application view - private Window view; - - /// clear the participation database at program launch - void initialize() { - store.initialize(); - } - - /// default constructor - /// - /// @param store Storage model - /// @param ui UI model - /// @param view Application view - Controller( - final Database store, final UI ui, final Window view - ) { - this.store = store; - this.ui = ui; - this.view = view; - } - - /// callback when category has been selected - /// - /// @param section section the category is tied to - /// @param category selected category - // TODO: require a UI instead - void onCategorySelected( - final GUI.Section section, - final String category - ) { - view.clearSelections(section); - view.setOptions(section, store.selectProgram(category)); - } - - /// callback when activity has been selected - /// - /// @param combo involved activity box - /// @param select selected item - /// @param area whole text area - void onActivitySelected( - final ComboBox combo, - final ComboBox select, - final TextArea area - ) { - - // pass the value chosen in the box - addActivity(select.getValue(), area); - - // update text area based on category choice - // - // Users can choose from the ComboBox, - // and string (activity) and the area will then update. - updateArea(combo, area); - } - - /// callback when subject module has been selected - /// - /// @param subject1 involved 1st column subject module box - /// @param subject2 involved 2nd column subject module box - void onSubjectModuleSelected( - final ComboBox subject1, - final ComboBox subject2 - ) { - - // remove chosen option from opposite subject module box - for (String sub: store.getAllSubjects()) { - if (sub.equals(subject1.getValue())) { - subject2.getItems().remove( - subject1.getValue()); - } else if ( - !sub.equals(subject1.getValue()) - && !subject2.getItems().contains(sub) - ) { - subject2.getItems().add(sub); - } - } - } - - /// add participation to database - /// @param s activity identifier - /// @param textArea whole text area - void addActivity(final String s, final TextArea textArea) { - store.addParticipation(store.getActivityIndeks(s)); - } - - /// update text area for an activity box - /// - /// Clears the text area - /// and adds all activity names from activities in participation. - /// - /// @param combo involved activity box - /// @param textArea whole text area - void updateArea( - final ComboBox combo, final TextArea textArea - ) { - textArea.clear(); - for (String s: store.getParticipation(combo.getValue()) - ) { - textArea.appendText(s + "\n"); - } - } - - /// update label with current ECTS of program type - /// @param ectslabel text display area for ECTS points - /// @param comboBox involved activity box - void updateEcts( - final Label ectslabel, final ComboBox comboBox - ) { - ectslabel.setText("ECTS: " - + store.getSumEcts(comboBox.getValue())); - } - - void fillElective(final ComboBox electiveBox) { - electiveBox.getItems().addAll(store.getAllActivities()); - } -} diff --git a/src/com.example.portfolio2/com/example/portfolio2/Database.java b/src/com.example.portfolio2/com/example/portfolio2/Database.java deleted file mode 100644 index 8b8f93a..0000000 --- a/src/com.example.portfolio2/com/example/portfolio2/Database.java +++ /dev/null @@ -1,144 +0,0 @@ -// SPDX-FileCopyrightText: 2025 Jonas Smedegaard -// SPDX-FileCopyrightText: 2025 -// SPDX-FileCopyrightText: 2025 -// SPDX-FileCopyrightText: 2025 -// SPDX-License-Identifier: GPL-3.0-or-later - -package com.example.portfolio2; - -import java.util.ArrayList; -import java.util.List; - -/// Bachelorizer - database model -/// -/// This model handles all interaction with the database. -class Database { - - /// database singleton - private MyDB db = new MyDB(); - - /// default constructor - // (declared explicitly only to silence javadoc) - Database() { } - - /// student object - // TODO: replace this dummy placeholder with database query - private Person student; - - /// clear the participation database at program launch - void initialize() { - clearParticipation(); - } - - /// Add student - /// - /// @param name Name of student - // TODO: replace this dummy placeholder with database query - public final void addStudent(final String name) { - student = new Person(name); - } - - /// Get student name - /// - /// @return name of student - // TODO: replace this dummy placeholder with database query - public final String getStudentName() { - return student.name; - } - - /// resolve activity index from name - /// - /// @param name activity name - /// @return index of activity as integer - int getActivityIndeks(final String name) { - if (name == null) { - return -1; - } - ArrayList result = db.query( - "SELECT indeks FROM activity" - + " WHERE name IS '" + name + "';", - "indeks"); - - return Integer.parseInt(result.getFirst()); - } - - /// insert activity into participation - /// - /// @param activityIndex index of activity - void addParticipation(final int activityIndex) { - db.cmd("INSERT INTO participation VALUES(123, " - + activityIndex + ");"); - } - - /// list currently participating activities - /// - /// @param program programme name - /// @return names of participating activities - ArrayList getParticipation(final String program) { - return db.query( - "SELECT name FROM participation p" - + " INNER JOIN activity a ON p.indeks = a.indeks" - + " WHERE program IS '" + program + "';", - "name"); - } - - /// purge participation database - void clearParticipation() { - db.cmd("DELETE FROM participation"); - } - - /// list activities within a program - /// - /// @param program programme name - /// @return names of contained activities - ArrayList selectProgram(final String program) { - return db.query( - "SELECT name FROM activity" - + " WHERE program IS '" + program + "';", - "name"); - } - - /// sum of ECTS points under the given category - /// - /// @param program programme name - /// @return ECTS points as String - String getSumEcts(final String program) { - if (program == null) { - return "0"; - } - ArrayList result = db.query( - "SELECT SUM(activity.ects)" - + " AS total_ects,student.name" - + " FROM student LEFT OUTER JOIN participation" - + " ON student.studid = participation.studid" - + " INNER JOIN activity" - + " ON participation.indeks = activity.indeks" - + " WHERE program IS '" + program + "'" - + " GROUP BY student.studid ;", - "total_ects"); - if (result.isEmpty()) { - return "0"; - } - - return result.getFirst(); - } - - /// list of available subject modules - /// - /// @return names of all subject modules as list of strings - List getAllSubjects() { - return db.query( - "SELECT DISTINCT program FROM activity" - + " WHERE program NOT IN (" - + " SELECT program from activity" - + " WHERE name LIKE 'BP1 %')", - "program"); - } - - /// list of available activities - /// - /// @return names of all activities as list of strings - ArrayList getAllActivities() { - return db.query("SELECT name FROM activity;", "name"); - } -} diff --git a/src/com.example.portfolio2/com/example/portfolio2/GUI.java b/src/com.example.portfolio2/com/example/portfolio2/GUI.java deleted file mode 100644 index de05873..0000000 --- a/src/com.example.portfolio2/com/example/portfolio2/GUI.java +++ /dev/null @@ -1,48 +0,0 @@ -// SPDX-FileCopyrightText: 2025 Jonas Smedegaard -// SPDX-License-Identifier: GPL-3.0-or-later - -package com.example.portfolio2; - -/// Bachelorizer - graphical user interface model -public class GUI extends UI { - - /// Default constructor - // (declared explicitly only to silence javadoc) - public GUI() { } - - /// structural sections of user interface - public enum Section { - - /// main programme - PROGRAM("Program", 0), - - /// first subject module - SUBJECT1("Subject 1", 1), - - /// second subject module - SUBJECT2("Subject 2", 2), - - /// elective courses - ELECTIVE("Elective", 3); - - /// text label - final String label; - - /// column position - final int column; - - /// instantiation - /// - /// @param label text label - /// @param column column position - Section(final String label, final int column) { - this.label = label; - this.column = column; - } - } - -/* public static UI.Section asUISection () { - return UI.Section.valueOf(this); - } -*/ -} diff --git a/src/com.example.portfolio2/com/example/portfolio2/Main.java b/src/com.example.portfolio2/com/example/portfolio2/Main.java deleted file mode 100644 index 5f79c22..0000000 --- a/src/com.example.portfolio2/com/example/portfolio2/Main.java +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-FileCopyrightText: 2025 Jonas Smedegaard -// SPDX-FileCopyrightText: 2025 -// SPDX-FileCopyrightText: 2025 -// SPDX-FileCopyrightText: 2025 -// SPDX-License-Identifier: GPL-3.0-or-later - -package com.example.portfolio2; - -/// Bachelorizer - bachelor programme registrar -public final class Main { - - /// Default constructor - // (declared explicitly only to silence javadoc) - public Main() { } - - /// JVM entry point - /// - /// @param args command-line arguments - public static void main(final String[] args) { - Window.main(args); - } -} diff --git a/src/com.example.portfolio2/com/example/portfolio2/Person.java b/src/com.example.portfolio2/com/example/portfolio2/Person.java deleted file mode 100644 index aaf4c59..0000000 --- a/src/com.example.portfolio2/com/example/portfolio2/Person.java +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-FileCopyrightText: 2025 Jonas Smedegaard -// SPDX-License-Identifier: GPL-3.0-or-later - -package com.example.portfolio2; - -/// Bachelorizer - Person model -public class Person { - - /// Person name - public String name; - - /// Constructor - /// - /// @param name Name of person - public Person(final String name) { - this.name = name; - } -} diff --git a/src/com.example.portfolio2/com/example/portfolio2/UI.java b/src/com.example.portfolio2/com/example/portfolio2/UI.java deleted file mode 100644 index a70bf8e..0000000 --- a/src/com.example.portfolio2/com/example/portfolio2/UI.java +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-FileCopyrightText: 2025 Jonas Smedegaard -// SPDX-License-Identifier: GPL-3.0-or-later - -package com.example.portfolio2; - -/// Bachelorizer - reference user interface model -public abstract class UI { - - /// Default constructor - // (declared explicitly only to silence javadoc) - public UI() { } - - /// structural sections of user interface - public enum Section { - - /// main programme - PROGRAM("Program"), - - /// first subject module - SUBJECT1("Subject 1"), - - /// second subject module - SUBJECT2("Subject 2"), - - /// elective courses - ELECTIVE("Elective"); - - /// text label - final String label; - - /// instantiation - /// - /// @param label text label - Section(final String label) { - this.label = label; - } - } -} diff --git a/src/com.example.portfolio2/module-info.java b/src/com.example.portfolio2/module-info.java index 1f6940d..1456b90 100644 --- a/src/com.example.portfolio2/module-info.java +++ b/src/com.example.portfolio2/module-info.java @@ -1,6 +1,5 @@ -/// Bachelorizer - bachelor programme registrar +/// foo module com.example.portfolio2 { - requires transitive javafx.controls; requires java.sql; exports com.example.portfolio2; diff --git a/src/dk.biks.bachelorizer/dk/biks/bachelorizer/Controller.java b/src/dk.biks.bachelorizer/dk/biks/bachelorizer/Controller.java index ab62bfa..63eac9d 100644 --- a/src/dk.biks.bachelorizer/dk/biks/bachelorizer/Controller.java +++ b/src/dk.biks.bachelorizer/dk/biks/bachelorizer/Controller.java @@ -1,16 +1,25 @@ +// SPDX-FileCopyrightText: 2025 +// SPDX-FileCopyrightText: 2025 // SPDX-FileCopyrightText: 2025 Jonas Smedegaard +// SPDX-FileCopyrightText: 2025 // SPDX-License-Identifier: GPL-3.0-or-later package dk.biks.bachelorizer; import java.util.List; +import javafx.scene.control.ComboBox; +import javafx.scene.control.Label; +import javafx.scene.control.TextArea; + /// Bachelorizer - Controller -public class Controller { +class Controller { + + /// Storage model + private Database store; - /// Application model - // (declared explicitly only to silence javadoc) - private GUI model; + /// UI model + private UI ui; /// Application view private Window view; @@ -18,75 +27,148 @@ public class Controller { /// Parameters passed on command-line and in JNLP file private List parameters; - /// Default constructor + /// clear the participation database at program launch + void initialize() { + store.initialize(); + } + + /// default constructor /// - /// @param model Application model + /// @param store Storage model + /// @param ui UI model /// @param view Application view - public Controller(final GUI model, final Window view) { - this.model = model; + Controller( + final Database store, final UI ui, final Window view + ) { + this.store = store; + this.ui = ui; this.view = view; } /// parse application parameters /// - /// parse parameters as GNU-style options and arguments, + /// Parse parameters as GNU-style options and arguments, /// i.e. treat dash-prefixed words as options /// until an optional first bare "--", /// taking first non-option argument as name of student - /// and remaining ones as activity selections + /// and remaining ones as activity selections. /// /// @param parameters Application parameters public final void setParameters(final List parameters) { boolean optionsDone = false; boolean studentAssigned = false; +/* TODO for (String item: parameters) { if (!optionsDone && item.matches("--")) { optionsDone = true; } else if (!item.startsWith("-")) { if (!studentAssigned) { - model.addStudent(item); + store.addStudent(item); studentAssigned = true; - showStudent(); +// TODO ui.showStudent( +// model.getStudentName()); } else { - model.addActivity(item); - showActivities(); + store.addParticipation( + store.getActivityIndeks(item)); +// TODO ui.showActivities(); } } } +*/ } - /// Enter activity + /// callback when category has been selected /// - /// @param s String entered - public final void enterActivity(final String s) { - model.addActivity(s); - view.clearActivityEntry(); - showActivities(); + /// @param section section the category is tied to + /// @param category selected category + // TODO: require a UI instead + void onCategorySelected( + final GUI.Section section, + final String category + ) { + view.clearSelections(section); + view.setOptions(section, store.selectProgram(category)); } - /// Display student - public final void showStudent() { - view.setStudentName(model.getStudentName()); + /// callback when activity has been selected + /// + /// @param combo involved activity box + /// @param select selected item + /// @param area whole text area + void onActivitySelected( + final ComboBox combo, + final ComboBox select, + final TextArea area + ) { + + // pass the value chosen in the box + addActivity(select.getValue(), area); + + // update text area based on category choice + // + // Users can choose from the ComboBox, + // and string (activity) and the area will then update. + updateArea(combo, area); } - /// Display list of activity entries - public final void showActivities() { - String toarea = ""; - for (String t: model.getActivities()) { - toarea += t + "\n"; + /// callback when subject module has been selected + /// + /// @param subject1 involved 1st column subject module box + /// @param subject2 involved 2nd column subject module box + void onSubjectModuleSelected( + final ComboBox subject1, + final ComboBox subject2 + ) { + + // remove chosen option from opposite subject module box + for (String sub: store.getAllSubjects()) { + if (sub.equals(subject1.getValue())) { + subject2.getItems().remove( + subject1.getValue()); + } else if ( + !sub.equals(subject1.getValue()) + && !subject2.getItems().contains(sub) + ) { + subject2.getItems().add(sub); + } + } + } + + /// add participation to database + /// @param s activity identifier + /// @param textArea whole text area + void addActivity(final String s, final TextArea textArea) { + store.addParticipation(store.getActivityIndeks(s)); + } + + /// update text area for an activity box + /// + /// Clears the text area + /// and adds all activity names from activities in participation. + /// + /// @param combo involved activity box + /// @param textArea whole text area + void updateArea( + final ComboBox combo, final TextArea textArea + ) { + textArea.clear(); + for (String s: store.getParticipation(combo.getValue()) + ) { + textArea.appendText(s + "\n"); } - view.setArea(toarea); } - /// drop last activity entry - public final void delOne() { - model.delOneActivity(); - showActivities(); + /// update label with current ECTS of program type + /// @param ectslabel text display area for ECTS points + /// @param comboBox involved activity box + void updateEcts( + final Label ectslabel, final ComboBox comboBox + ) { + ectslabel.setText("ECTS: " + + store.getSumEcts(comboBox.getValue())); } - /// drop all activity entries - public final void delAll() { - model.delAllActivities(); - showActivities(); + void fillElective(final ComboBox electiveBox) { + electiveBox.getItems().addAll(store.getAllActivities()); } } diff --git a/src/dk.biks.bachelorizer/dk/biks/bachelorizer/Database.java b/src/dk.biks.bachelorizer/dk/biks/bachelorizer/Database.java new file mode 100644 index 0000000..f746649 --- /dev/null +++ b/src/dk.biks.bachelorizer/dk/biks/bachelorizer/Database.java @@ -0,0 +1,146 @@ +// SPDX-FileCopyrightText: 2025 +// SPDX-FileCopyrightText: 2025 +// SPDX-FileCopyrightText: 2025 Jonas Smedegaard +// SPDX-FileCopyrightText: 2025 +// SPDX-License-Identifier: GPL-3.0-or-later + +package dk.biks.bachelorizer; + +import java.util.ArrayList; +import java.util.List; + +import com.example.portfolio2.MyDB; + +/// Bachelorizer - database model +/// +/// This model handles all interaction with the database. +class Database { + + /// database singleton + private MyDB db = new MyDB(); + + /// default constructor + // (declared explicitly only to silence javadoc) + Database() { } + + /// student object + // TODO: replace this dummy placeholder with database query + private Person student; + + /// clear the participation database at program launch + void initialize() { + clearParticipation(); + } + + /// Add student + /// + /// @param name Name of student + // TODO: replace this dummy placeholder with database query + public final void addStudent(final String name) { + student = new Person(name); + } + + /// Get student name + /// + /// @return name of student + // TODO: replace this dummy placeholder with database query + public final String getStudentName() { + return student.name; + } + + /// resolve activity index from name + /// + /// @param name activity name + /// @return index of activity as integer + int getActivityIndeks(final String name) { + if (name == null) { + return -1; + } + ArrayList result = db.query( + "SELECT indeks FROM activity" + + " WHERE name IS '" + name + "';", + "indeks"); + + return Integer.parseInt(result.getFirst()); + } + + /// insert activity into participation + /// + /// @param activityIndex index of activity + void addParticipation(final int activityIndex) { + db.cmd("INSERT INTO participation VALUES(123, " + + activityIndex + ");"); + } + + /// list currently participating activities + /// + /// @param program programme name + /// @return names of participating activities + ArrayList getParticipation(final String program) { + return db.query( + "SELECT name FROM participation p" + + " INNER JOIN activity a ON p.indeks = a.indeks" + + " WHERE program IS '" + program + "';", + "name"); + } + + /// purge participation database + void clearParticipation() { + db.cmd("DELETE FROM participation"); + } + + /// list activities within a program + /// + /// @param program programme name + /// @return names of contained activities + ArrayList selectProgram(final String program) { + return db.query( + "SELECT name FROM activity" + + " WHERE program IS '" + program + "';", + "name"); + } + + /// sum of ECTS points under the given category + /// + /// @param program programme name + /// @return ECTS points as String + String getSumEcts(final String program) { + if (program == null) { + return "0"; + } + ArrayList result = db.query( + "SELECT SUM(activity.ects)" + + " AS total_ects,student.name" + + " FROM student LEFT OUTER JOIN participation" + + " ON student.studid = participation.studid" + + " INNER JOIN activity" + + " ON participation.indeks = activity.indeks" + + " WHERE program IS '" + program + "'" + + " GROUP BY student.studid ;", + "total_ects"); + if (result.isEmpty()) { + return "0"; + } + + return result.getFirst(); + } + + /// list of available subject modules + /// + /// @return names of all subject modules as list of strings + List getAllSubjects() { + return db.query( + "SELECT DISTINCT program FROM activity" + + " WHERE program NOT IN (" + + " SELECT program from activity" + + " WHERE name LIKE 'BP1 %')", + "program"); + } + + /// list of available activities + /// + /// @return names of all activities as list of strings + ArrayList getAllActivities() { + return db.query("SELECT name FROM activity;", "name"); + } +} diff --git a/src/dk.biks.bachelorizer/dk/biks/bachelorizer/GUI.java b/src/dk.biks.bachelorizer/dk/biks/bachelorizer/GUI.java index f3a399c..66c2565 100644 --- a/src/dk.biks.bachelorizer/dk/biks/bachelorizer/GUI.java +++ b/src/dk.biks.bachelorizer/dk/biks/bachelorizer/GUI.java @@ -3,58 +3,46 @@ package dk.biks.bachelorizer; -import java.util.ArrayList; - -/// Bachelorizer - GUI model -public class GUI { +/// Bachelorizer - graphical user interface model +public class GUI extends UI { /// Default constructor // (declared explicitly only to silence javadoc) public GUI() { } - /// Activity list - private Person student; + /// structural sections of user interface + public enum Section { - /// Activity list - private ArrayList list = new ArrayList<>(); + /// main programme + PROGRAM("Program", 0), - /// Add student - /// - /// @param name Name of student - public final void addStudent(final String name) { - student = new Person(name); - } + /// first subject module + SUBJECT1("Subject 1", 1), - /// Get student name - /// - /// @return name of student - public final String getStudentName() { - return student.name; - } + /// second subject module + SUBJECT2("Subject 2", 2), - /// Add activity to list - /// - /// @param s Activity to add - public final void addActivity(final String s) { - list.add(s); - } + /// elective courses + ELECTIVE("Elective", 3); - /// Get list of activities - /// - /// @return activity list - public final ArrayList getActivities() { - return list; - } + /// text label + final String label; + + /// column position + final int column; - /// Delete last activity from list - public final void delOneActivity() { - if (list.size() > 0) { - list.remove(list.size() - 1); + /// instantiation + /// + /// @param label text label + /// @param column column position + Section(final String label, final int column) { + this.label = label; + this.column = column; } } - /// Delete all activities from list - public final void delAllActivities() { - list.clear(); +/* public static UI.Section asUISection () { + return UI.Section.valueOf(this); } +*/ } diff --git a/src/dk.biks.bachelorizer/dk/biks/bachelorizer/UI.java b/src/dk.biks.bachelorizer/dk/biks/bachelorizer/UI.java new file mode 100644 index 0000000..be092a5 --- /dev/null +++ b/src/dk.biks.bachelorizer/dk/biks/bachelorizer/UI.java @@ -0,0 +1,38 @@ +// SPDX-FileCopyrightText: 2025 Jonas Smedegaard +// SPDX-License-Identifier: GPL-3.0-or-later + +package dk.biks.bachelorizer; + +/// Bachelorizer - reference user interface model +public abstract class UI { + + /// Default constructor + // (declared explicitly only to silence javadoc) + public UI() { } + + /// structural sections of user interface + public enum Section { + + /// main programme + PROGRAM("Program"), + + /// first subject module + SUBJECT1("Subject 1"), + + /// second subject module + SUBJECT2("Subject 2"), + + /// elective courses + ELECTIVE("Elective"); + + /// text label + final String label; + + /// instantiation + /// + /// @param label text label + Section(final String label) { + this.label = label; + } + } +} diff --git a/src/dk.biks.bachelorizer/dk/biks/bachelorizer/Window.java b/src/dk.biks.bachelorizer/dk/biks/bachelorizer/Window.java index c129aad..6c21db5 100644 --- a/src/dk.biks.bachelorizer/dk/biks/bachelorizer/Window.java +++ b/src/dk.biks.bachelorizer/dk/biks/bachelorizer/Window.java @@ -1,18 +1,23 @@ +// SPDX-FileCopyrightText: 2025 +// SPDX-FileCopyrightText: 2025 // SPDX-FileCopyrightText: 2025 Jonas Smedegaard +// SPDX-FileCopyrightText: 2025 // SPDX-License-Identifier: GPL-3.0-or-later package dk.biks.bachelorizer; import javafx.application.Application; -import javafx.scene.control.Button; +import javafx.scene.Scene; +import javafx.scene.control.ComboBox; import javafx.scene.control.Label; import javafx.scene.control.TextArea; -import javafx.scene.control.TextField; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; -import javafx.scene.Scene; import javafx.stage.Stage; +import java.io.IOException; +import java.util.List; + /// Bachelorizer - JavaFX Window view // Class is final to forbid subclassing, // because object is passed to controller during instantiation @@ -20,42 +25,39 @@ public final class Window extends Application { /// Default constructor // (declared explicitly only to silence javadoc) - public Window() { - } + public Window() { } /// window width - private static final int WINDOW_WIDTH = 500; + private static final int WINDOW_WIDTH = 1000; /// window height private static final int WINDOW_HEIGHT = 500; + /// box width + private static final int LIST_WIDTH = 250; + /// box height - private static final int BOX_HEIGHT = 10; + private static final int LIST_HEIGHT = 35; /// Label styling private static final String LABEL_STYLE = - "-fx-font-weight: bold; -fx-font-size: 20;"; - - /// Application model - private GUI model = new GUI(); - - /// Application controller - private Controller control = new Controller(model, this); - - /// Name of student - private TextField nameEntry = new TextField(); + "-fx-font-weight: bold;" + + "-fx-font-size: 18;" + + "-fx-padding: 10"; - /// Text entry for adding an activity - private TextField activityEntry = new TextField(); + /// Storage model + private Database store = new Database(); - /// Text area for activity entries - private TextArea area = new TextArea(); + /// UI model + /// + /// Must be subclass GUI to cover columns. + private GUI ui = new GUI(); - /// Button to delete one activity - private Button delOne = new Button("Delete one"); + /// Application controller + private Controller control = new Controller(store, ui, this); - /// Button to delete all activities - private Button delAll = new Button("Delete all"); + /// column state data as List of ActivityColumn objects + private List columns; /// Application instantiation /// @@ -65,62 +67,182 @@ public final class Window extends Application { } @Override - public void start(final Stage stage) { + public void start(final Stage stage) throws IOException { // pass application parameters to controller control.setParameters(getParameters().getRaw()); - // add listeners -// NameEntry.setOnAction(e -> control.enterName( -// activityEntry.getText())); - activityEntry.setOnAction(e -> control.enterActivity( - activityEntry.getText())); - delOne.setOnAction(e -> control.delOne()); - delAll.setOnAction(e -> control.delAll()); - - // add buttons - VBox root = new VBox(BOX_HEIGHT, - ourHBox("Student", nameEntry), - ourHBox("Add activity", activityEntry), - new HBox(BOX_HEIGHT, delOne, delAll), - area); - - // compose stage + // clear old insertions into participation table + control.initialize(); + + // define list of columns based on their names + columns = List.of( + new ActivityColumn(GUI.Section.PROGRAM), + new ActivityColumn(GUI.Section.SUBJECT1), + new ActivityColumn(GUI.Section.SUBJECT2), + new ActivityColumn(GUI.Section.ELECTIVE) + ); + + // define button functionality for each activity column + for (ActivityColumn col : columns) { + col.nameLabel.setStyle(LABEL_STYLE); + col.ectsLabel.setStyle(LABEL_STYLE); + col.categoryCombo.setPrefSize( + LIST_WIDTH, LIST_HEIGHT); + col.activitySelect.setPrefSize( + LIST_WIDTH, LIST_HEIGHT); + col.area.setPrefWidth(LIST_WIDTH); + + // all boxes share same activity logic + col.activitySelect.setOnAction(event -> { + control.onActivitySelected( + col.categoryCombo, + col.activitySelect, + col.area); + control.updateEcts( + col.ectsLabel, + col.categoryCombo); + }); + + // handle each category box + switch (col.section) { + case GUI.Section.PROGRAM -> { + col.categoryCombo.getItems().addAll( + "HumTek", "NatBach"); + col.categoryCombo.setOnAction(event -> { + control.onCategorySelected( + col.section, + col.categoryCombo.getValue()); + }); + } + // TODO: use the list for filling the box + case GUI.Section.SUBJECT1 -> { + col.categoryCombo.getItems().addAll( + "Computer Science", + "Informatik", + "Astrology"); + col.categoryCombo.setOnAction(event -> { + control.onSubjectModuleSelected( + col.categoryCombo, + columns.get( + GUI.Section.SUBJECT2.column) + .categoryCombo); + control.onCategorySelected( + col.section, + col.categoryCombo.getValue()); + }); + } + case GUI.Section.SUBJECT2 -> { + col.categoryCombo.getItems().addAll( + "Computer Science", + "Informatik", + "Astrology"); + // TODO: figure out a better way... + col.categoryCombo.setOnAction(event -> { + control.onSubjectModuleSelected( + col.categoryCombo, + columns.get( + GUI.Section.SUBJECT1.column) + .categoryCombo); + control.onCategorySelected( + col.section, + col.categoryCombo.getValue()); + }); + } + case GUI.Section.ELECTIVE -> { + + // hide useless box + col.categoryCombo.setVisible(false); + + control.fillElective(col.activitySelect); + } + } + } + + // define HBox and scene for columns + HBox root = new HBox( + columns.get(GUI.Section.PROGRAM.column) + .asVBox(), + columns.get(GUI.Section.SUBJECT1.column) + .asVBox(), + columns.get(GUI.Section.SUBJECT2.column) + .asVBox(), + columns.get(GUI.Section.ELECTIVE.column) + .asVBox()); Scene scene = new Scene( root, WINDOW_WIDTH, WINDOW_HEIGHT); - stage.setTitle("JavaFX Demo"); + stage.setTitle("Bachelorizer - RUC Course Selector"); stage.setScene(scene); stage.show(); } - /// action to apply student name + /// column of activities /// - /// @param s Text to apply - public void setStudentName(final String s) { - nameEntry.setText(s); + /// @param section structural section for column + /// @param nameLabel display text + /// @param categoryCombo dropdown list for categories + /// @param activitySelect dropdown list for activities + /// @param area description of chosen activities + /// @param ectsLabel text to display ECTS points + private record ActivityColumn( + GUI.Section section, + Label nameLabel, + ComboBox categoryCombo, + ComboBox activitySelect, + TextArea area, + Label ectsLabel + ) { + + /// column of activities + /// + /// @param section structural section for column + ActivityColumn(final GUI.Section section) { + this( + section, + new Label(section.label), + new ComboBox<>(), + new ComboBox<>(), + new TextArea(), + new Label() + ); + } + + /// activity columne as VBox + /// + /// @return column of activities as VBox + VBox asVBox() { + return new VBox( + nameLabel, + categoryCombo, + activitySelect, + area, + ectsLabel); + } } - /// action to apply text to area + /// populate activities for a category /// - /// @param s Text to apply - public void setArea(final String s) { - area.setText(s); + /// @param section structural section to operate on + /// @param activities activities to apply as string + public void setOptions( + final GUI.Section section, final List activities + ) { + + // clear the activity selection box + columns.get(section.column).activitySelect + .getItems().clear(); + + // fill activity box from data in store + columns.get(section.column).activitySelect + .getItems().addAll(activities); } - /// Button action to clear field - public void clearActivityEntry() { - activityEntry.setText(""); - } - - /// Styled HBox with label and TextField + /// remove selections from a category /// - /// @param s Label string - /// @param f Text field - /// @return HBox containing styled label and text field - public HBox ourHBox(final String s, final TextField f) { - Label label = new Label(s + ":"); - label.setStyle(LABEL_STYLE); - - return new HBox(BOX_HEIGHT, label, f); + /// @param section structural section to operate on + public void clearSelections(final GUI.Section section) { + + // clear text area + columns.get(section.column).area.clear(); } } diff --git a/src/dk.biks.bachelorizer/module-info.java b/src/dk.biks.bachelorizer/module-info.java index 1258a43..1f68a71 100644 --- a/src/dk.biks.bachelorizer/module-info.java +++ b/src/dk.biks.bachelorizer/module-info.java @@ -22,8 +22,10 @@ module dk.biks.bachelorizer { requires javafx.base; requires transitive javafx.controls; requires javafx.graphics; + requires java.sql; // re-export, as types are used in public API + requires transitive com.example.portfolio2; requires transitive com.example.portfolio3; exports dk.biks.bachelorizer; -- cgit v1.2.3