Added dialog to delegate a certain number of teams to each TA team.
This commit is contained in:
parent
a44814b1df
commit
7c6f2527c0
|
@ -43,6 +43,7 @@ public class Main {
|
|||
executor.registerCommand("define_ta_teams", new DefineTaTeams(app));
|
||||
executor.registerCommand("list_errors", new ListErrors());
|
||||
executor.registerCommand("delete_repos", new DeleteRepos());
|
||||
executor.registerCommand("delegate_student_teams", new DelegateStudentTeams(app));
|
||||
|
||||
logger.info("GithubManager for Github Repositories in Educational Organizations.\n" +
|
||||
"© Andrew Lalis (2018), All rights reserved.\n" +
|
||||
|
|
|
@ -19,6 +19,13 @@ public class Organization extends Observable {
|
|||
*/
|
||||
private List<StudentTeam> studentTeams;
|
||||
|
||||
/**
|
||||
* A list of all teaching assistant teams in this organization. These are generated from requests to the Github API
|
||||
* and possibly supplementary information. Each teaching assistant team maintains a list of all student teams for
|
||||
* which it is responsible.
|
||||
*/
|
||||
private List<TATeam> taTeams;
|
||||
|
||||
/**
|
||||
* A queue of errors that accumulates as the program runs. These will be output to the user after execution of
|
||||
* critical sections, so that inevitable errors due to input imperfections are not overlooked.
|
||||
|
@ -30,6 +37,7 @@ public class Organization extends Observable {
|
|||
*/
|
||||
public Organization() {
|
||||
this.studentTeams = new ArrayList<>();
|
||||
this.taTeams = new ArrayList<>();
|
||||
this.errors = new ArrayList<>();
|
||||
}
|
||||
|
||||
|
@ -41,22 +49,6 @@ public class Organization extends Observable {
|
|||
return this.studentTeams.isEmpty();
|
||||
}
|
||||
|
||||
// GETTERS
|
||||
public List<StudentTeam> getStudentTeams() {
|
||||
return this.studentTeams;
|
||||
}
|
||||
|
||||
public List<Error> getErrors() {
|
||||
return this.errors;
|
||||
}
|
||||
|
||||
// SETTERS
|
||||
public void setStudentTeams(List<StudentTeam> teams) {
|
||||
this.studentTeams = teams;
|
||||
this.setChanged();
|
||||
this.notifyObservers();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an error to the list of accumulated errors.
|
||||
* @param newError The newly generated error to add.
|
||||
|
@ -67,4 +59,30 @@ public class Organization extends Observable {
|
|||
this.notifyObservers();
|
||||
}
|
||||
|
||||
// GETTERS
|
||||
public List<StudentTeam> getStudentTeams() {
|
||||
return this.studentTeams;
|
||||
}
|
||||
|
||||
public List<Error> getErrors() {
|
||||
return this.errors;
|
||||
}
|
||||
|
||||
public List<TATeam> getTaTeams() {
|
||||
return this.taTeams;
|
||||
}
|
||||
|
||||
// SETTERS
|
||||
public void setStudentTeams(List<StudentTeam> teams) {
|
||||
this.studentTeams = teams;
|
||||
this.setChanged();
|
||||
this.notifyObservers();
|
||||
}
|
||||
|
||||
public void setTaTeams(List<TATeam> teams) {
|
||||
this.taTeams = teams;
|
||||
this.setChanged();
|
||||
this.notifyObservers();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -22,6 +22,11 @@ public class TATeam extends Team {
|
|||
*/
|
||||
private GHTeam githubTeam;
|
||||
|
||||
/**
|
||||
* A list of all student teams for which this TA team is responsible.
|
||||
*/
|
||||
private List<StudentTeam> studentTeams;
|
||||
|
||||
/**
|
||||
* Constructs a team without any teaching assistant members.
|
||||
* @param name The name of the team.
|
||||
|
@ -40,6 +45,15 @@ public class TATeam extends Team {
|
|||
return Arrays.copyOf(this.getMembers(), this.memberCount(), TeachingAssistant[].class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given student team to the list of teams that this TA team is responsible for.
|
||||
* @param team A student team.
|
||||
*/
|
||||
public void addStudentTeam(StudentTeam team) {
|
||||
this.studentTeams.add(team);
|
||||
}
|
||||
|
||||
// GETTERS
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
@ -48,6 +62,11 @@ public class TATeam extends Team {
|
|||
return this.githubTeam;
|
||||
}
|
||||
|
||||
public List<StudentTeam> getStudentTeams() {
|
||||
return this.studentTeams;
|
||||
}
|
||||
|
||||
// SETTERS
|
||||
public void setGithubTeam(GHTeam team) {
|
||||
this.githubTeam = team;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package nl.andrewlalis.ui.control.command.executables;
|
||||
|
||||
import nl.andrewlalis.git_api.GithubManager;
|
||||
import nl.andrewlalis.ui.view.DefineTaTeamsDialog;
|
||||
import nl.andrewlalis.ui.view.dialogs.DefineTaTeamsDialog;
|
||||
import nl.andrewlalis.ui.view.InitializerApp;
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
package nl.andrewlalis.ui.control.command.executables;
|
||||
|
||||
import nl.andrewlalis.git_api.GithubManager;
|
||||
import nl.andrewlalis.ui.view.InitializerApp;
|
||||
import nl.andrewlalis.ui.view.dialogs.DelegateStudentTeamsDialog;
|
||||
|
||||
/**
|
||||
* An executable which opens up a dialog to allow a user to delegate how many student teams each TATeam gets to manage,
|
||||
* and actually generate the student repositories using the manager.
|
||||
*/
|
||||
public class DelegateStudentTeams extends GithubExecutable {
|
||||
|
||||
/**
|
||||
* A reference to the main application frame, used as the parent for the dialog which is shown.
|
||||
*/
|
||||
private InitializerApp app;
|
||||
|
||||
public DelegateStudentTeams(InitializerApp app) {
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean executeWithManager(GithubManager manager, String[] args) {
|
||||
DelegateStudentTeamsDialog dialog = new DelegateStudentTeamsDialog(this.app, manager);
|
||||
dialog.begin();
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
package nl.andrewlalis.ui.control.command.executables;
|
||||
|
||||
import nl.andrewlalis.git_api.GithubManager;
|
||||
|
||||
/**
|
||||
* An executable which opens up a dialog to allow a user to delegate how many student teams each TATeam gets to manage,
|
||||
* and actually generate the student repositories using the manager.
|
||||
*/
|
||||
public class GenerateStudentRepos extends GithubExecutable {
|
||||
|
||||
@Override
|
||||
protected boolean executeWithManager(GithubManager manager, String[] args) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,9 +1,6 @@
|
|||
package nl.andrewlalis.ui.control.command.executables;
|
||||
|
||||
import nl.andrewlalis.model.Organization;
|
||||
import nl.andrewlalis.model.StudentTeam;
|
||||
import nl.andrewlalis.model.error.Error;
|
||||
import nl.andrewlalis.model.error.Severity;
|
||||
import nl.andrewlalis.ui.control.command.Executable;
|
||||
import nl.andrewlalis.ui.view.InitializerApp;
|
||||
import nl.andrewlalis.util.FileUtils;
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
package nl.andrewlalis.ui.control.listeners;
|
||||
|
||||
import nl.andrewlalis.ui.control.command.CommandExecutor;
|
||||
import nl.andrewlalis.ui.view.InitializerApp;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
|
||||
/**
|
||||
* Listens for when a user performs an action to open the dialog to delegate student teams amongst the TA teams.
|
||||
*/
|
||||
public class DelegateStudentTeamsListener extends ExecutableListener {
|
||||
|
||||
public DelegateStudentTeamsListener(CommandExecutor executor, InitializerApp app) {
|
||||
super(executor, app);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent actionEvent) {
|
||||
this.executor.executeCommand("delegate_student_teams", new String[]{
|
||||
app.getOrganizationName(),
|
||||
app.getAccessToken()
|
||||
});
|
||||
}
|
||||
}
|
|
@ -121,6 +121,7 @@ public class InitializerApp extends JFrame {
|
|||
|
||||
commonActionsPanel.add(this.generateButtonPanel("Archive All", new ArchiveAllListener(this.executor, this)));
|
||||
commonActionsPanel.add(this.generateButtonPanel("Read Students File", new ReadStudentsFileListener(this.executor, this)));
|
||||
commonActionsPanel.add(this.generateButtonPanel("Delegate Student Teams", new DelegateStudentTeamsListener(this.executor, this)));
|
||||
commonActionsPanel.add(this.generateButtonPanel("Generate Assignments Repo", new GenerateAssignmentsRepoListener(this.executor, this)));
|
||||
|
||||
// TODO: Enable this once the define teams dialog is complete.
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package nl.andrewlalis.ui.view;
|
||||
package nl.andrewlalis.ui.view.dialogs;
|
||||
|
||||
import nl.andrewlalis.git_api.GithubManager;
|
||||
import nl.andrewlalis.ui.view.InitializerApp;
|
||||
import nl.andrewlalis.ui.view.list_models.TATeamListCellRenderer;
|
||||
import nl.andrewlalis.ui.view.list_models.TATeamListModel;
|
||||
import nl.andrewlalis.ui.view.list_models.TeachingAssistantListCellRenderer;
|
|
@ -0,0 +1,130 @@
|
|||
package nl.andrewlalis.ui.view.dialogs;
|
||||
|
||||
import nl.andrewlalis.git_api.GithubManager;
|
||||
import nl.andrewlalis.model.StudentTeam;
|
||||
import nl.andrewlalis.model.TATeam;
|
||||
import nl.andrewlalis.ui.view.InitializerApp;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
import java.awt.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* This dialog shows a simple list of all teaching assistant teams, with a JSpinner next to the name, so that a user can
|
||||
* set how many student teams each teaching assistant team would like to manage.
|
||||
*/
|
||||
public class DelegateStudentTeamsDialog extends JDialog {
|
||||
|
||||
/**
|
||||
* The manager used to generate repositories.
|
||||
*/
|
||||
private GithubManager manager;
|
||||
|
||||
/**
|
||||
* Indicates how many student teams do not have an assigned team.
|
||||
*/
|
||||
private NumberIndicatorField unmatchedStudentsCounter;
|
||||
|
||||
/**
|
||||
* A list of JSpinner objects linked to specific team members.
|
||||
*/
|
||||
private List<TaTeamSpinner> teamSpinners;
|
||||
|
||||
/**
|
||||
* A number indicating the total number of student teams.
|
||||
*/
|
||||
private final int totalStudentTeamsCount;
|
||||
|
||||
public DelegateStudentTeamsDialog(InitializerApp parentApp, GithubManager manager) {
|
||||
super(parentApp, "Delegate Student Teams", true);
|
||||
this.manager = manager;
|
||||
this.teamSpinners = new ArrayList<>();
|
||||
this.totalStudentTeamsCount = InitializerApp.organization.getStudentTeams().size();
|
||||
this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
|
||||
|
||||
this.initUI();
|
||||
}
|
||||
|
||||
/**
|
||||
* Begins showing the dialog.
|
||||
*/
|
||||
public void begin() {
|
||||
this.setVisible(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the user interface components.
|
||||
*/
|
||||
private void initUI() {
|
||||
JPanel mainPanel = new JPanel(new BorderLayout());
|
||||
mainPanel.add(this.generateTopPanel(), BorderLayout.NORTH);
|
||||
mainPanel.add(this.generateSpinnersPanel(), BorderLayout.CENTER);
|
||||
|
||||
this.setContentPane(mainPanel);
|
||||
this.pack();
|
||||
this.setLocationRelativeTo(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A JPanel containing the top-most counter of how many student teams are unassigned, and a small label.
|
||||
*/
|
||||
private JPanel generateTopPanel() {
|
||||
JPanel panel = new JPanel(new BorderLayout());
|
||||
panel.add(new JLabel("Unassigned teams: "), BorderLayout.CENTER);
|
||||
this.unmatchedStudentsCounter = new NumberIndicatorField(this.totalStudentTeamsCount);
|
||||
panel.add(this.unmatchedStudentsCounter, BorderLayout.EAST);
|
||||
panel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
|
||||
return panel;
|
||||
}
|
||||
|
||||
private JPanel generateSpinnersPanel() {
|
||||
JPanel spinnersPanel = new JPanel();
|
||||
spinnersPanel.setLayout(new BoxLayout(spinnersPanel, BoxLayout.PAGE_AXIS));
|
||||
List<TATeam> taTeams = this.manager.getTeams();
|
||||
for (TATeam team : taTeams) {
|
||||
spinnersPanel.add(this.generateTeamSpinnerPanel(team));
|
||||
}
|
||||
return spinnersPanel;
|
||||
}
|
||||
|
||||
private JPanel generateTeamSpinnerPanel(TATeam team) {
|
||||
JPanel panel = new JPanel(new BorderLayout());
|
||||
JLabel teamLabel = new JLabel(team.getName());
|
||||
teamLabel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
|
||||
panel.add(teamLabel, BorderLayout.WEST);
|
||||
TaTeamSpinner spinner = new TaTeamSpinner(team, this.totalStudentTeamsCount);
|
||||
spinner.addChangeListener(changeEvent -> {
|
||||
JSpinner s = (JSpinner) changeEvent.getSource();
|
||||
int studentTeamsMatched = 0;
|
||||
for (TaTeamSpinner teamSpinner : this.teamSpinners) {
|
||||
studentTeamsMatched += (int)teamSpinner.getValue();
|
||||
}
|
||||
if (this.totalStudentTeamsCount - studentTeamsMatched < 0) {
|
||||
s.setValue((int)s.getValue() + 1); // TODO: FIX! Causes stack overflow.
|
||||
} else {
|
||||
this.unmatchedStudentsCounter.setValue(this.totalStudentTeamsCount - studentTeamsMatched);
|
||||
}
|
||||
});
|
||||
this.teamSpinners.add(spinner);
|
||||
panel.add(spinner, BorderLayout.EAST);
|
||||
return panel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a map containing an integer value for every TA team, which represents the number of student teams they will
|
||||
* be responsible for.
|
||||
* @return A map of TATeams and integer values.
|
||||
*/
|
||||
public Map<TATeam, Integer> getResult() {
|
||||
Map<TATeam, Integer> results = new HashMap<>();
|
||||
for (TaTeamSpinner spinner : this.teamSpinners) {
|
||||
results.put(spinner.getTeam(), (int) spinner.getValue());
|
||||
}
|
||||
return results;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package nl.andrewlalis.ui.view.dialogs;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
/**
|
||||
* A custom JTextField which displays an integer value, and can be set and read more efficiently than if one were to
|
||||
* parse back and forth between strings and integers.
|
||||
*/
|
||||
public class NumberIndicatorField extends JTextField {
|
||||
|
||||
/**
|
||||
* The value currently displayed in the text field.
|
||||
*/
|
||||
private int value;
|
||||
|
||||
public NumberIndicatorField(int initialValue) {
|
||||
this.setEditable(false);
|
||||
this.setValue(initialValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the displayed value to a new integer value.
|
||||
* @param newValue The new value to set.
|
||||
*/
|
||||
public void setValue(int newValue) {
|
||||
this.value = newValue;
|
||||
this.setText(String.valueOf(newValue));
|
||||
}
|
||||
|
||||
public void decrement() {
|
||||
this.setValue(this.value - 1);
|
||||
}
|
||||
|
||||
public void increment() {
|
||||
this.setValue(this.value + 1);
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package nl.andrewlalis.ui.view.dialogs;
|
||||
|
||||
import nl.andrewlalis.model.TATeam;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
/**
|
||||
* A modified JSpinner which keeps track of a TATeam, and also has a default spinner number model in use.
|
||||
*/
|
||||
public class TaTeamSpinner extends JSpinner {
|
||||
|
||||
private TATeam team;
|
||||
|
||||
public TaTeamSpinner(TATeam team, int max) {
|
||||
super(new SpinnerNumberModel(0, 0, max, 1));
|
||||
((DefaultEditor) this.getEditor()).getTextField().setEditable(false);
|
||||
this.team = team;
|
||||
}
|
||||
|
||||
public TATeam getTeam() {
|
||||
return this.team;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue