Implemented a basic detail view.

This commit is contained in:
Andrew Lalis 2018-10-22 15:47:54 +02:00
parent e57897a005
commit a2797e54a6
10 changed files with 355 additions and 65 deletions

View File

@ -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<StudentTeam> 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<String, String> 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;
}
}

View File

@ -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<Pair<String, String>> getDetailPairs() {
List<Pair<String, String>> 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;
}
}

View File

@ -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<StudentTeam> 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();
}
}

View File

@ -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<StudentTeam> 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();

View File

@ -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.
*/

View File

@ -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;
}
}

View File

@ -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<Pair<String, String>> getDetailPairs();
}

View File

@ -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<Pair<String, String>> 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<Pair<String, String>> 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;
}
}
}

View File

@ -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:

View File

@ -0,0 +1,25 @@
package nl.andrewlalis.util;
/**
* A pair of objects.
* @param <T1> The first object.
* @param <T2> The second object.
*/
public class Pair<T1, T2> {
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;
}
}