/*
* Copyright (c) 2017 The MegaMek Team. All rights reserved.
*
* This file is part of MekHQ.
*
* MekHQ is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MekHQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MekHQ. If not, see <http://www.gnu.org/licenses/>.
*/
package mekhq.gui;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.image.ImageObserver;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.ResourceBundle;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import megamek.common.TargetRoll;
import megamek.common.event.Subscribe;
import megamek.common.util.EncodeControl;
import mekhq.MekHQ;
import mekhq.campaign.event.MedicPoolChangedEvent;
import mekhq.campaign.event.PersonEvent;
import mekhq.campaign.event.PersonMedicalAssignmentEvent;
import mekhq.campaign.event.ScenarioResolvedEvent;
import mekhq.campaign.personnel.Person;
import mekhq.gui.model.DocTableModel;
import mekhq.gui.model.PatientTableModel;
/**
* Shows injured and medical personnel
*/
public final class InfirmaryTab extends CampaignGuiTab {
private static final long serialVersionUID = 7558886712192449186L;
private JTable docTable;
private JButton btnAssignDoc;
private JButton btnUnassignDoc;
private JList<Person> listAssignedPatient;
private JList<Person> listUnassignedPatient;
private PatientTableModel assignedPatientModel;
private PatientTableModel unassignedPatientModel;
private DocTableModel doctorsModel;
private Image bgImage;
InfirmaryTab(CampaignGUI gui, String name) {
super(gui, name);
MekHQ.registerHandler(this);
}
/*
* (non-Javadoc)
*
* @see mekhq.gui.CampaignGuiTab#initTab()
*/
@Override
public void initTab() {
ResourceBundle resourceMap = ResourceBundle.getBundle("mekhq.resources.CampaignGUI", //$NON-NLS-1$ ;
new EncodeControl());
GridBagConstraints gridBagConstraints;
setLayout(new GridBagLayout());
String bgImageFile = getIconPackage().getGuiElement("infirmary_background");
if (null != bgImageFile && !bgImageFile.isEmpty()) {
bgImage = Toolkit.getDefaultToolkit().createImage(bgImageFile);
}
doctorsModel = new DocTableModel(getCampaign());
docTable = new JTable(doctorsModel);
docTable.setRowHeight(60);
docTable.getColumnModel().getColumn(0).setCellRenderer(doctorsModel.getRenderer(getIconPackage()));
docTable.getSelectionModel().addListSelectionListener(ev -> docTableValueChanged());
docTable.setOpaque(false);
JScrollPane scrollDocTable = new JScrollPane(docTable);
scrollDocTable.setMinimumSize(new java.awt.Dimension(300, 300));
scrollDocTable.setPreferredSize(new java.awt.Dimension(300, 300));
scrollDocTable.setOpaque(false);
scrollDocTable.getViewport().setOpaque(false);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.gridheight = 3;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 0.0;
gridBagConstraints.weighty = 1.0;
add(scrollDocTable, gridBagConstraints);
btnAssignDoc = new JButton(resourceMap.getString("btnAssignDoc.text")); // NOI18N
btnAssignDoc.setToolTipText(resourceMap.getString("btnAssignDoc.toolTipText")); // NOI18N
btnAssignDoc.setEnabled(false);
btnAssignDoc.addActionListener(ev -> assignDoctor());
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 1;
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
add(btnAssignDoc, gridBagConstraints);
btnUnassignDoc = new JButton(resourceMap.getString("btnUnassignDoc.text")); // NOI18N
btnUnassignDoc.setEnabled(false);
btnUnassignDoc.addActionListener(ev -> unassignDoctor());
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 2;
gridBagConstraints.gridy = 1;
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
add(btnUnassignDoc, gridBagConstraints);
assignedPatientModel = new PatientTableModel(getCampaign());
listAssignedPatient = new JList<Person>(assignedPatientModel);
listAssignedPatient.setCellRenderer(assignedPatientModel.getRenderer(getIconPackage()));
listAssignedPatient.setLayoutOrientation(JList.HORIZONTAL_WRAP);
listAssignedPatient.setVisibleRowCount(-1);
listAssignedPatient.getSelectionModel().addListSelectionListener(ev -> updateAssignDoctorEnabled());
listAssignedPatient.setOpaque(false);
JScrollPane scrollAssignedPatient = new JScrollPane(listAssignedPatient);
scrollAssignedPatient.setMinimumSize(new java.awt.Dimension(300, 360));
scrollAssignedPatient.setPreferredSize(new java.awt.Dimension(300, 360));
scrollAssignedPatient.setOpaque(false);
scrollAssignedPatient.getViewport().setOpaque(false);
unassignedPatientModel = new PatientTableModel(getCampaign());
listUnassignedPatient = new JList<Person>(unassignedPatientModel);
listUnassignedPatient.setCellRenderer(unassignedPatientModel.getRenderer(getIconPackage()));
listUnassignedPatient.setLayoutOrientation(JList.HORIZONTAL_WRAP);
listUnassignedPatient.setVisibleRowCount(-1);
listUnassignedPatient.getSelectionModel().addListSelectionListener(ev -> updateAssignDoctorEnabled());
listUnassignedPatient.setOpaque(false);
JScrollPane scrollUnassignedPatient = new JScrollPane(listUnassignedPatient);
scrollUnassignedPatient.setMinimumSize(new java.awt.Dimension(300, 200));
scrollUnassignedPatient.setPreferredSize(new java.awt.Dimension(300, 300));
scrollUnassignedPatient.setOpaque(false);
scrollUnassignedPatient.getViewport().setOpaque(false);
listAssignedPatient
.setBorder(BorderFactory.createTitledBorder(resourceMap.getString("panAssignedPatient.title")));
listUnassignedPatient
.setBorder(BorderFactory.createTitledBorder(resourceMap.getString("panUnassignedPatient.title")));
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 0;
gridBagConstraints.gridwidth = 2;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 0.0;
add(scrollAssignedPatient, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 2;
gridBagConstraints.gridwidth = 2;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
add(scrollUnassignedPatient, gridBagConstraints);
}
/*
* (non-Javadoc)
*
* @see mekhq.gui.CampaignGuiTab#refreshAll()
*/
@Override
public void refreshAll() {
refreshPatientList();
refreshDoctorsList();
}
/*
* (non-Javadoc)
*
* @see mekhq.gui.CampaignGuiTab#tabType()
*/
@Override
public GuiTabType tabType() {
return GuiTabType.INFIRMARY;
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (null == bgImage) {
return;
}
int size = Math.max(getWidth(), getHeight());
g.drawImage(bgImage, 0, 0, size, size, (img, infoflags, x, y, width, height) -> {
if ((infoflags & ImageObserver.ALLBITS) != 0) {
repaint();
return false;
}
return true;
});
}
private Person getSelectedDoctor() {
int row = docTable.getSelectedRow();
if (row < 0) {
return null;
}
return doctorsModel.getDoctorAt(docTable.convertRowIndexToModel(row));
}
protected ArrayList<Person> getSelectedAssignedPatients() {
ArrayList<Person> patients = new ArrayList<Person>();
int[] indices = listAssignedPatient.getSelectedIndices();
if (assignedPatientModel.getSize() == 0) {
return patients;
}
for (int idx : indices) {
Person p = assignedPatientModel.getElementAt(idx);
if (p == null) {
continue;
}
patients.add(p);
}
return patients;
}
protected ArrayList<Person> getSelectedUnassignedPatients() {
ArrayList<Person> patients = new ArrayList<Person>();
int[] indices = listUnassignedPatient.getSelectedIndices();
if (unassignedPatientModel.getSize() == 0) {
return patients;
}
for (int idx : indices) {
Person p = unassignedPatientModel.getElementAt(idx);
if (p == null) {
continue;
}
patients.add(p);
}
return patients;
}
private void updateAssignDoctorEnabled() {
Person doctor = getSelectedDoctor();
btnAssignDoc.setEnabled((null != doctor) && (getCampaign().getPatientsFor(doctor) < 25)
&& (unassignedPatientModel.getSize() > 0));
btnUnassignDoc.setEnabled(!getSelectedAssignedPatients().isEmpty());
}
private void docTableValueChanged() {
refreshPatientList();
updateAssignDoctorEnabled();
}
private void assignDoctor() {
Person doctor = getSelectedDoctor();
if (null == doctor) {
return;
}
Collection<Person> selectedPatients = getSelectedUnassignedPatients();
if (selectedPatients.isEmpty()) {
// Pick the first in the list ... if there are any
int patientSize = unassignedPatientModel.getSize();
for (int i = 0; i < patientSize; ++i) {
Person p = unassignedPatientModel.getElementAt(i);
if ((null != p)
&& (p.needsFixing()
|| (getCampaign().getCampaignOptions().useAdvancedMedical() && p.needsAMFixing()))
&& (getCampaign().getPatientsFor(doctor) < 25)
&& (getCampaign().getTargetFor(p, doctor).getValue() != TargetRoll.IMPOSSIBLE)) {
p.setDoctorId(doctor.getId(), getCampaign().getCampaignOptions().getHealingWaitingPeriod());
MekHQ.triggerEvent(new PersonMedicalAssignmentEvent(doctor, p));
break;
}
}
} else {
for (Person p : selectedPatients) {
if ((null != p)
&& (p.needsFixing()
|| (getCampaign().getCampaignOptions().useAdvancedMedical() && p.needsAMFixing()))
&& (getCampaign().getPatientsFor(doctor) < 25)
&& (getCampaign().getTargetFor(p, doctor).getValue() != TargetRoll.IMPOSSIBLE)) {
p.setDoctorId(doctor.getId(), getCampaign().getCampaignOptions().getHealingWaitingPeriod());
MekHQ.triggerEvent(new PersonMedicalAssignmentEvent(doctor, p));
}
}
}
}
private void unassignDoctor() {
Person doctor = getSelectedDoctor();
for (Person p : getSelectedAssignedPatients()) {
if ((null != p)) {
p.setDoctorId(null, getCampaign().getCampaignOptions().getNaturalHealingWaitingPeriod());
if (doctor != null) {
MekHQ.triggerEvent(new PersonMedicalAssignmentEvent(doctor, p));
}
}
}
}
public void refreshDoctorsList() {
int selected = docTable.getSelectedRow();
doctorsModel.setData(getCampaign().getDoctors());
if ((selected > -1) && (selected < getCampaign().getDoctors().size())) {
docTable.setRowSelectionInterval(selected, selected);
}
}
public void refreshPatientList() {
Person doctor = getSelectedDoctor();
ArrayList<Person> assigned = new ArrayList<Person>();
ArrayList<Person> unassigned = new ArrayList<Person>();
for (Person patient : getCampaign().getPatients()) {
// Knock out inactive doctors
if ((patient != null) && (patient.getDoctorId() != null)
&& (getCampaign().getPerson(patient.getDoctorId()) != null)
&& getCampaign().getPerson(patient.getDoctorId()).isInActive()) {
patient.setDoctorId(null, getCampaign().getCampaignOptions().getNaturalHealingWaitingPeriod());
}
if (patient.getDoctorId() == null) {
unassigned.add(patient);
} else if ((doctor != null) && patient.getDoctorId().equals(doctor.getId())) {
assigned.add(patient);
}
}
List<Person> assignedPatients = getSelectedAssignedPatients();
List<Person> unassignedPatients = getSelectedUnassignedPatients();
int[] assignedIndices = new int[assignedPatients.size()];
Arrays.fill(assignedIndices, Integer.MAX_VALUE);
int[] unassignedIndices = new int[unassignedPatients.size()];
Arrays.fill(unassignedIndices, Integer.MAX_VALUE);
assignedPatientModel.setData(assigned);
unassignedPatientModel.setData(unassigned);
int i = 0;
for (Person patient : assignedPatients) {
int idx = assigned.indexOf(patient);
assignedIndices[i] = (idx >= 0) ? idx : Integer.MAX_VALUE;
++i;
}
i = 0;
for (Person patient : unassignedPatients) {
int idx = unassigned.indexOf(patient);
unassignedIndices[i] = (idx >= 0) ? idx : Integer.MAX_VALUE;
++i;
}
listAssignedPatient.setSelectedIndices(assignedIndices);
listUnassignedPatient.setSelectedIndices(unassignedIndices);
}
private ActionScheduler doctorListScheduler = new ActionScheduler(this::refreshDoctorsList);
private ActionScheduler patientListScheduler = new ActionScheduler(this::refreshPatientList);
@Subscribe
public void handle(ScenarioResolvedEvent ev) {
doctorListScheduler.schedule();
patientListScheduler.schedule();
}
@Subscribe
public void handle(PersonEvent ev) {
doctorListScheduler.schedule();
patientListScheduler.schedule();
}
@Subscribe
public void handle(MedicPoolChangedEvent ev) {
doctorListScheduler.schedule();
}
}