From a2797e54a658f13a7334b5c6fb9c20eee6296f90 Mon Sep 17 00:00:00 2001 From: andrewlalis Date: Mon, 22 Oct 2018 15:47:54 +0200 Subject: [PATCH] Implemented a basic detail view. --- src/main/java/nl/andrewlalis/Main.java | 63 +++++++----- .../java/nl/andrewlalis/model/Person.java | 26 ++++- .../andrewlalis/model/database/DbHelper.java | 20 ++++ .../FileSelectListener.java | 24 +---- .../andrewlalis/ui/view/ManagementView.java | 65 +++++++++---- .../ui/view/components/DetailPanel.java | 95 +++++++++++++++++++ .../ui/view/components/Detailable.java | 27 ++++++ .../view/table_models/DetailPairsModel.java | 64 +++++++++++++ .../view/table_models/StudentTableModel.java | 11 ++- src/main/java/nl/andrewlalis/util/Pair.java | 25 +++++ 10 files changed, 355 insertions(+), 65 deletions(-) create mode 100644 src/main/java/nl/andrewlalis/ui/view/components/DetailPanel.java create mode 100644 src/main/java/nl/andrewlalis/ui/view/components/Detailable.java create mode 100644 src/main/java/nl/andrewlalis/ui/view/table_models/DetailPairsModel.java create mode 100644 src/main/java/nl/andrewlalis/util/Pair.java diff --git a/src/main/java/nl/andrewlalis/Main.java b/src/main/java/nl/andrewlalis/Main.java index 834af58..0f3658a 100644 --- a/src/main/java/nl/andrewlalis/Main.java +++ b/src/main/java/nl/andrewlalis/Main.java @@ -3,12 +3,17 @@ package nl.andrewlalis; import nl.andrewlalis.command.CommandExecutor; import nl.andrewlalis.command.executables.*; import nl.andrewlalis.git_api.GithubManager; +import nl.andrewlalis.model.StudentTeam; +import nl.andrewlalis.model.database.DbHelper; import nl.andrewlalis.ui.view.InitializerApp; import nl.andrewlalis.ui.view.ManagementView; import nl.andrewlalis.ui.view.StartView; import nl.andrewlalis.util.CommandLine; import nl.andrewlalis.util.Logging; +import nl.andrewlalis.util.TeamGenerator; +import java.io.IOException; +import java.util.List; import java.util.Map; import java.util.logging.Logger; @@ -32,6 +37,41 @@ public class Main { // Initialize logger. Logging.setup(); + //startOldVersion(userOptions); + + logger.info("GithubManager for Github Repositories in Educational Organizations.\n" + + "© Andrew Lalis (2018), All rights reserved.\n" + + "Program initialized."); + + GithubManager manager = new GithubManager(); + managementView = new ManagementView(manager); + + initializeTestingData(); + StartView startView = new StartView(manager, "InitializerTesting", userOptions.get("token")); + } + + /** + * @return The management view used for the application. + */ + public static ManagementView getManagementView() { + return managementView; + } + + private static void initializeTestingData() { + try { + List teams = TeamGenerator.generateFromCSV("/home/andrew/Documents/School/ta/GithubInitializer/sampleAOOP.csv", 2); + DbHelper.saveStudentTeams(teams); + managementView.updateModels(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * Legacy code to run the old version of the application. + * @param userOptions The options the user has entered in the command line. + */ + public static void startOldVersion(Map userOptions) { // Command executor which will be used by all actions the user can do. CommandExecutor executor = new CommandExecutor(); @@ -50,29 +90,6 @@ public class Main { executor.registerCommand("delegate_student_teams", new DelegateStudentTeams(app)); executor.registerCommand("setup_student_repos", new SetupStudentRepos(app)); executor.registerCommand("list_repos", new ListRepos()); - - logger.info("GithubManager for Github Repositories in Educational Organizations.\n" + - "© Andrew Lalis (2018), All rights reserved.\n" + - "Program initialized."); - - GithubManager manager = new GithubManager(); - managementView = new ManagementView(manager); - -// SessionFactory factory = DbUtil.getSessionFactory(); -// Session session = factory.openSession(); -// session.beginTransaction(); -// System.out.println(session.save(new Student(1, "a", "a@e.com", "git", null))); -// session.getTransaction().commit(); -// session.close(); - - StartView startView = new StartView(manager, "InitializerTesting", userOptions.get("token")); - } - - /** - * @return The management view used for the application. - */ - public static ManagementView getManagementView() { - return managementView; } } diff --git a/src/main/java/nl/andrewlalis/model/Person.java b/src/main/java/nl/andrewlalis/model/Person.java index 62639b9..10b2488 100644 --- a/src/main/java/nl/andrewlalis/model/Person.java +++ b/src/main/java/nl/andrewlalis/model/Person.java @@ -1,10 +1,14 @@ package nl.andrewlalis.model; import nl.andrewlalis.model.database.BaseEntity; +import nl.andrewlalis.ui.view.components.Detailable; +import nl.andrewlalis.util.Pair; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Table; +import java.util.ArrayList; +import java.util.List; /** * A generic object that students, teaching assistants, and professors can extend from. This covers all the basic @@ -12,7 +16,7 @@ import javax.persistence.Table; */ @Entity(name = "Person") @Table(name = "persons") -public abstract class Person extends BaseEntity { +public abstract class Person extends BaseEntity implements Detailable { /** * The unique identification number for this person. (P- or S-Number) @@ -138,4 +142,24 @@ public abstract class Person extends BaseEntity { public String toString() { return this.getName() + ", " + this.getNumber() + ", " + this.getEmailAddress() + ", " + this.getGithubUsername(); } + + @Override + public String getDetailName() { + return this.getName() + ", " + this.getNumber(); + } + + @Override + public String getDetailDescription() { + return null; + } + + @Override + public List> getDetailPairs() { + List> pairs = new ArrayList<>(); + pairs.add(new Pair<>("Name", this.getName())); + pairs.add(new Pair<>("Number", String.valueOf(this.getNumber()))); + pairs.add(new Pair<>("Email Address", this.getEmailAddress())); + pairs.add(new Pair<>("Github Username", this.getGithubUsername())); + return pairs; + } } diff --git a/src/main/java/nl/andrewlalis/model/database/DbHelper.java b/src/main/java/nl/andrewlalis/model/database/DbHelper.java index fde57e2..e9e163a 100644 --- a/src/main/java/nl/andrewlalis/model/database/DbHelper.java +++ b/src/main/java/nl/andrewlalis/model/database/DbHelper.java @@ -1,8 +1,10 @@ package nl.andrewlalis.model.database; import nl.andrewlalis.model.Student; +import nl.andrewlalis.model.StudentTeam; import org.hibernate.Session; import org.hibernate.SessionFactory; +import org.hibernate.Transaction; import java.util.List; @@ -23,4 +25,22 @@ public class DbHelper { return students; } + /** + * Saves a list of student teams to the database. + */ + public static void saveStudentTeams(List teams) { + Session session = DbUtil.getSessionFactory().openSession(); + Transaction tx = session.beginTransaction(); + + for (StudentTeam team : teams) { + for (Student s : team.getStudents()) { + session.save(s); + } + session.save(team); + } + + tx.commit(); + session.close(); + } + } diff --git a/src/main/java/nl/andrewlalis/ui/control/listeners/input_students_file_view/FileSelectListener.java b/src/main/java/nl/andrewlalis/ui/control/listeners/input_students_file_view/FileSelectListener.java index afc053b..3c014b5 100644 --- a/src/main/java/nl/andrewlalis/ui/control/listeners/input_students_file_view/FileSelectListener.java +++ b/src/main/java/nl/andrewlalis/ui/control/listeners/input_students_file_view/FileSelectListener.java @@ -1,13 +1,10 @@ package nl.andrewlalis.ui.control.listeners.input_students_file_view; import nl.andrewlalis.Main; -import nl.andrewlalis.model.Student; import nl.andrewlalis.model.StudentTeam; -import nl.andrewlalis.model.database.DbUtil; +import nl.andrewlalis.model.database.DbHelper; import nl.andrewlalis.ui.view.InputStudentsFileView; import nl.andrewlalis.util.TeamGenerator; -import org.hibernate.Session; -import org.hibernate.Transaction; import javax.swing.*; import javax.swing.filechooser.FileFilter; @@ -42,10 +39,7 @@ public class FileSelectListener implements ActionListener { chooser.addChoosableFileFilter(new FileFilter() { @Override public boolean accept(File file) { - if (file.isDirectory()) { - return true; - } - return file.getName().toLowerCase().endsWith(".csv"); + return file.isDirectory() || file.getName().toLowerCase().endsWith(".csv"); } @Override @@ -59,19 +53,7 @@ public class FileSelectListener implements ActionListener { int teamSize = this.fileView.getStudentsPerTeam(); try { List teams = TeamGenerator.generateFromCSV(chooser.getSelectedFile().getAbsolutePath(), teamSize); - Session session = DbUtil.getSessionFactory().openSession(); - Transaction tx = session.beginTransaction(); - - for (StudentTeam team : teams) { - for (Student s : team.getStudents()) { - session.save(s); - } - session.save(team); - } - - tx.commit(); - session.close(); - + DbHelper.saveStudentTeams(teams); Main.getManagementView().updateModels(); } catch (IOException e) { e.printStackTrace(); diff --git a/src/main/java/nl/andrewlalis/ui/view/ManagementView.java b/src/main/java/nl/andrewlalis/ui/view/ManagementView.java index e0462a8..f76005f 100644 --- a/src/main/java/nl/andrewlalis/ui/view/ManagementView.java +++ b/src/main/java/nl/andrewlalis/ui/view/ManagementView.java @@ -3,6 +3,7 @@ package nl.andrewlalis.ui.view; import nl.andrewlalis.git_api.GithubManager; import nl.andrewlalis.model.database.DbHelper; import nl.andrewlalis.model.database.DbUtil; +import nl.andrewlalis.ui.view.components.DetailPanel; import nl.andrewlalis.ui.view.table_models.StudentTableModel; import javax.swing.*; @@ -20,6 +21,11 @@ public class ManagementView extends AbstractView { */ private StudentTableModel studentsModel; + /** + * A panel which displays the details of selected entities. + */ + private DetailPanel detailPanel; + public ManagementView(GithubManager githubManager) { super( "Course Management", @@ -30,14 +36,14 @@ public class ManagementView extends AbstractView { ); this.setExtendedState(this.getExtendedState() | JFrame.MAXIMIZED_BOTH); - // Dispose of all parents when this window closes. + // Dispose of all parents when this window closes. This is unique to the management view. this.addWindowListener(new WindowAdapter() { @Override public void windowClosed(WindowEvent windowEvent) { for (AbstractView parent : getParentViews()) { parent.dispose(); } - DbUtil.tearDown(); + DbUtil.tearDown(); // Shut down the database session factory once everything is done. } }); } @@ -45,9 +51,12 @@ public class ManagementView extends AbstractView { @Override protected JPanel buildContentPane() { JPanel contentPane = new JPanel(new BorderLayout()); + contentPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); + + this.detailPanel = new DetailPanel(); contentPane.add(this.buildCommandPanel(), BorderLayout.WEST); - contentPane.add(this.buildDetailPanel(), BorderLayout.EAST); + contentPane.add(this.detailPanel, BorderLayout.EAST); contentPane.add(this.buildOverviewPanel(), BorderLayout.CENTER); return contentPane; @@ -58,6 +67,7 @@ public class ManagementView extends AbstractView { */ private JPanel buildCommandPanel() { JPanel commandPanel = new JPanel(new BorderLayout()); + commandPanel.setBorder(BorderFactory.createLoweredBevelBorder()); commandPanel.add(new JLabel("Commands", SwingConstants.CENTER), BorderLayout.NORTH); commandPanel.add(new JTextArea("Command prompt area goes here."), BorderLayout.CENTER); @@ -72,38 +82,55 @@ public class ManagementView extends AbstractView { return commandPanel; } - /** - * @return A JPanel for the entity details section. - */ - private JPanel buildDetailPanel() { - JPanel detailPanel = new JPanel(new BorderLayout()); - - detailPanel.add(new JLabel("Details", SwingConstants.CENTER), BorderLayout.NORTH); - - return detailPanel; - } - /** * @return Builds the overview panel, containing a listing of entities. */ private JPanel buildOverviewPanel() { JPanel overviewPanel = new JPanel(new BorderLayout()); + overviewPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); - overviewPanel.add(new JLabel("Overview"), BorderLayout.NORTH); + overviewPanel.add(new JLabel("Overview", SwingConstants.CENTER), BorderLayout.NORTH); // The real container for all the data views. JTabbedPane tabbedPane = new JTabbedPane(); - this.studentsModel = new StudentTableModel(DbHelper.getStudents()); - JTable studentsTable = new JTable(this.studentsModel); - JScrollPane studentsScrollPane = new JScrollPane(studentsTable); - tabbedPane.addTab("Students", studentsScrollPane); + tabbedPane.addTab("Students", this.buildStudentsTablePanel()); + tabbedPane.addTab("Student Teams", this.buildStudentTeamsTablePanel()); + tabbedPane.addTab("Teaching Assistants", this.buildTAsTablePanel()); overviewPanel.add(tabbedPane, BorderLayout.CENTER); return overviewPanel; } + /** + * @return A JPanel to be put into a tab for display of a list of students. + */ + private JPanel buildStudentsTablePanel() { + // Initialize the model, table, and a surrounding scroll pane. + this.studentsModel = new StudentTableModel(DbHelper.getStudents()); + + JPanel surroundingPanel = new JPanel(new BorderLayout()); + + JTable table = new JTable(this.studentsModel); + table.setFillsViewportHeight(true); + table.getSelectionModel().addListSelectionListener(listSelectionEvent -> { + detailPanel.setDetailableEntity(studentsModel.getStudentAt(table.getSelectedRow())); + }); + JScrollPane scrollPane = new JScrollPane(table); + + surroundingPanel.add(scrollPane, BorderLayout.CENTER); + return surroundingPanel; + } + + private JPanel buildStudentTeamsTablePanel() { + return new JPanel(); + } + + private JPanel buildTAsTablePanel() { + return new JPanel(); + } + /** * Updates all models in the management view in accordance with the database. */ diff --git a/src/main/java/nl/andrewlalis/ui/view/components/DetailPanel.java b/src/main/java/nl/andrewlalis/ui/view/components/DetailPanel.java new file mode 100644 index 0000000..fe279cb --- /dev/null +++ b/src/main/java/nl/andrewlalis/ui/view/components/DetailPanel.java @@ -0,0 +1,95 @@ +package nl.andrewlalis.ui.view.components; + +import nl.andrewlalis.ui.view.table_models.DetailPairsModel; + +import javax.swing.*; +import java.awt.*; + +/** + * The detail panel is meant for displaying the details of a specific entity. The actual content/details to display is + * given by classes which implement the Detailable interface. + */ +public class DetailPanel extends JPanel { + + /** + * The name field shows the entity's name. + */ + private JTextField nameField; + + /** + * The description area shows the entity's description. + */ + private JTextArea descriptionTextArea; + + /** + * A model to represent the key-value pairs of this entity. + */ + private DetailPairsModel detailPairsModel; + + /** + * Creates the panel with some basic empty components. + */ + public DetailPanel() { + super(); + this.setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); + this.add(new JLabel("Details", SwingConstants.CENTER)); + this.add(this.buildNamePanel()); + this.add(this.buildDescriptionPanel()); + this.add(this.buildPairsTablePanel()); + } + + /** + * Sets this panel's properties according to the given entity. + * @param entity The entity to get details from. + */ + public void setDetailableEntity(Detailable entity) { + this.nameField.setText(entity.getDetailName()); + this.descriptionTextArea.setText(entity.getDetailDescription()); + this.detailPairsModel.setPairs(entity.getDetailPairs()); + } + + /** + * @return A JPanel containing the name field. + */ + private JPanel buildNamePanel() { + this.nameField = new JTextField(); + this.nameField.setEditable(false); + + JPanel namePanel = new JPanel(new BorderLayout()); + namePanel.add(new JLabel("Name:", SwingConstants.LEFT), BorderLayout.WEST); + namePanel.add(this.nameField, BorderLayout.CENTER); + + return namePanel; + } + + /** + * @return A JPanel containing the description text area. + */ + private JPanel buildDescriptionPanel() { + this.descriptionTextArea = new JTextArea(); + this.descriptionTextArea.setEditable(false); + + JPanel descriptionPanel = new JPanel(new BorderLayout()); + descriptionPanel.add(new JLabel("Description:", SwingConstants.CENTER), BorderLayout.NORTH); + descriptionPanel.add(this.descriptionTextArea, BorderLayout.CENTER); + + return descriptionPanel; + } + + /** + * @return A JPanel containing a table of properties. + */ + private JPanel buildPairsTablePanel() { + this.detailPairsModel = new DetailPairsModel(); + + JPanel tablePanel = new JPanel(new BorderLayout()); + tablePanel.add(new JLabel("Properties:", SwingConstants.LEFT), BorderLayout.NORTH); + + JTable pairsTable = new JTable(this.detailPairsModel); + JScrollPane scrollPane = new JScrollPane(pairsTable); + tablePanel.add(scrollPane, BorderLayout.CENTER); + + return tablePanel; + } + +} diff --git a/src/main/java/nl/andrewlalis/ui/view/components/Detailable.java b/src/main/java/nl/andrewlalis/ui/view/components/Detailable.java new file mode 100644 index 0000000..241c29b --- /dev/null +++ b/src/main/java/nl/andrewlalis/ui/view/components/Detailable.java @@ -0,0 +1,27 @@ +package nl.andrewlalis.ui.view.components; + +import nl.andrewlalis.util.Pair; + +import java.util.List; + +/** + * Objects which implement this interface must provide + */ +public interface Detailable { + + /** + * @return The display name for this object. + */ + String getDetailName(); + + /** + * @return Some more information to display below the name for this object. + */ + String getDetailDescription(); + + /** + * @return A String-to-String mapping for some key value pairs of properties to display. + */ + List> getDetailPairs(); + +} diff --git a/src/main/java/nl/andrewlalis/ui/view/table_models/DetailPairsModel.java b/src/main/java/nl/andrewlalis/ui/view/table_models/DetailPairsModel.java new file mode 100644 index 0000000..ccf5951 --- /dev/null +++ b/src/main/java/nl/andrewlalis/ui/view/table_models/DetailPairsModel.java @@ -0,0 +1,64 @@ +package nl.andrewlalis.ui.view.table_models; + +import nl.andrewlalis.util.Pair; + +import javax.swing.table.AbstractTableModel; +import java.util.ArrayList; +import java.util.List; + +/** + * Represents the small (2 column) table to display properties of a detailable entity. + */ +public class DetailPairsModel extends AbstractTableModel { + + /** + * The pairs of properties. + */ + private List> pairs; + + /** + * Columns for this model. + */ + private String[] columns = {"Property", "Value"}; + + /** + * Constructs an empty list of pairs. + */ + public DetailPairsModel() { + this.pairs = new ArrayList<>(); + } + + public void setPairs(List> pairs) { + this.pairs = pairs; + this.fireTableDataChanged(); + } + + @Override + public int getRowCount() { + return this.pairs.size(); + } + + @Override + public int getColumnCount() { + return this.columns.length; + } + + @Override + public String getColumnName(int i) { + return this.columns[i]; + } + + @Override + public Object getValueAt(int i, int i1) { + Pair pair = this.pairs.get(i); + + switch (i1) { + case 0: + return pair.getFirst(); + case 1: + return pair.getSecond(); + default: + return null; + } + } +} diff --git a/src/main/java/nl/andrewlalis/ui/view/table_models/StudentTableModel.java b/src/main/java/nl/andrewlalis/ui/view/table_models/StudentTableModel.java index 03fb2a3..5361704 100644 --- a/src/main/java/nl/andrewlalis/ui/view/table_models/StudentTableModel.java +++ b/src/main/java/nl/andrewlalis/ui/view/table_models/StudentTableModel.java @@ -37,6 +37,15 @@ public class StudentTableModel extends AbstractTableModel { this.fireTableDataChanged(); } + /** + * Gets the student in a particular row. + * @param row The row of the table. + * @return The student object at the specified row, or null if none is found. + */ + public Student getStudentAt(int row) { + return this.studentsList.get(row); + } + @Override public int getRowCount() { return studentsList.size(); @@ -54,7 +63,7 @@ public class StudentTableModel extends AbstractTableModel { @Override public Object getValueAt(int row, int col) { - Student student = studentsList.get(row); + Student student = this.getStudentAt(row); switch(col) { case 0: diff --git a/src/main/java/nl/andrewlalis/util/Pair.java b/src/main/java/nl/andrewlalis/util/Pair.java new file mode 100644 index 0000000..518a5e6 --- /dev/null +++ b/src/main/java/nl/andrewlalis/util/Pair.java @@ -0,0 +1,25 @@ +package nl.andrewlalis.util; + +/** + * A pair of objects. + * @param The first object. + * @param The second object. + */ +public class Pair { + + private T1 first; + private T2 second; + + public Pair(T1 first, T2 second) { + this.first = first; + this.second = second; + } + + public T1 getFirst() { + return first; + } + + public T2 getSecond() { + return second; + } +}