/*
* MegaMekLab - Copyright (C) 2008
*
* Original author - jtighe (torren@users.sourceforge.net)
*
* This program 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 2 of the License, or (at your option)
* any later version.
*
* This program 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.
*/
package megameklab.com.util.Mech;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
import javax.swing.JTable;
import javax.swing.TransferHandler;
import megamek.common.Aero;
import megamek.common.AmmoType;
import megamek.common.BattleArmor;
import megamek.common.CriticalSlot;
import megamek.common.Entity;
import megamek.common.EquipmentType;
import megamek.common.LocationFullException;
import megamek.common.Mech;
import megamek.common.MechFileParser;
import megamek.common.MiscType;
import megamek.common.Mounted;
import megamek.common.WeaponType;
import megamek.common.loaders.EntityLoadingException;
import megamek.common.verifier.TestAero;
import megamek.common.verifier.TestBattleArmor;
import megamek.common.weapons.infantry.InfantryWeapon;
import megameklab.com.ui.EntitySource;
import megameklab.com.util.CriticalTableModel;
import megameklab.com.util.RefreshListener;
import megameklab.com.util.UnitUtil;
public class CriticalTransferHandler extends TransferHandler {
/**
*
*/
private static final long serialVersionUID = -5215375829853683877L;
private EntitySource eSource;
private int location = -1;
private RefreshListener refresh;
public CriticalTransferHandler(EntitySource eSource, RefreshListener refresh) {
this.eSource = eSource;
this.refresh = refresh;
}
@Override
public void exportDone(JComponent source, Transferable data, int action) {
if (data == null) {
return;
}
Mounted mounted = null;
try {
mounted = getUnit().getEquipment(Integer.parseInt((String) data.getTransferData(DataFlavor.stringFlavor)));
} catch (NumberFormatException e) {
e.printStackTrace();
} catch (UnsupportedFlavorException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
if ((source instanceof DropTargetCriticalList)
&& (mounted.getLocation() != Entity.LOC_NONE)) {
DropTargetCriticalList<?> list = (DropTargetCriticalList<?>)source;
int loc;
if (getUnit() instanceof BattleArmor){
String[] split = list.getName().split(":");
loc = Integer.parseInt(split[0]);
} else {
loc = Integer.parseInt(list.getName());
if (loc == mounted.getLocation()) {
return;
}
}
int slot = list.getSelectedIndex();
int startSlot = slot;
mounted = list.getMounted();
if (mounted == null) {
return;
}
if (UnitUtil.isFixedLocationSpreadEquipment(mounted.getType())) {
return;
}
while (slot > 0) {
slot--;
CriticalSlot cs = getUnit().getCritical(loc, slot);
if ((cs != null) && (cs.getType() == CriticalSlot.TYPE_EQUIPMENT) && cs.getMount().equals(mounted)) {
startSlot = slot;
}
}
if (!(getUnit() instanceof BattleArmor)){
for (int i = startSlot; i < (startSlot+UnitUtil.getCritsUsed(getUnit(), mounted.getType())); i++) {
getUnit().setCritical(loc, i, null);
}
}
Mounted linkedBy = mounted.getLinkedBy();
if (linkedBy != null && !(getUnit() instanceof BattleArmor)) {
UnitUtil.removeCriticals(getUnit(), linkedBy);
try {
UnitUtil.addMounted(getUnit(), linkedBy, mounted.getLocation(), linkedBy.isRearMounted());
} catch (LocationFullException e) {
UnitUtil.changeMountStatus(getUnit(), linkedBy, Entity.LOC_NONE, Entity.LOC_NONE, false);
linkedBy.setLinked(null);
mounted.setLinkedBy(null);
}
}
//UnitUtil.compactCriticals(unit);
refresh.refreshBuild();
}
}
/**
*
* @param mech
* @param eq
* @return
*/
private boolean addEquipmentMech(Mech mech, Mounted eq, int slotNumber)
throws LocationFullException{
int totalCrits = UnitUtil.getCritsUsed(getUnit(), eq.getType());
// How much space we have in the selected location
int primaryLocSpace =
UnitUtil.getContiguousNumberOfCrits(getUnit(), location, slotNumber);
if ((eq.getType().isSpreadable() || eq.isSplitable()) &&
(totalCrits > 1)) {
int critsUsed = 0;
int primaryLocation = location;
int nextLocation = getUnit().getTransferLocation(location);
// Determine if we should spread equipment over multiple locations
if (eq.getType().getCriticals(getUnit()) > primaryLocSpace) {
if (location == Mech.LOC_RT) {
String[] locations =
{ "Center Torso", "Right Leg", "Right Arm" };
JComboBox<String> combo = new JComboBox<String>(locations);
JOptionPane jop = new JOptionPane(combo,
JOptionPane.QUESTION_MESSAGE,
JOptionPane.OK_CANCEL_OPTION);
JDialog dlg = jop.createDialog("Select secondary location.");
combo.grabFocus();
combo.getEditor().selectAll();
dlg.setVisible(true);
int value = ((Integer) jop.getValue()).intValue();
if (value == JOptionPane.CANCEL_OPTION) {
return false;
}
if (combo.getSelectedIndex() == 1) {
nextLocation = Mech.LOC_RLEG;
} else if (combo.getSelectedIndex() == 2) {
nextLocation = Mech.LOC_RARM;
}
} else if (location == Mech.LOC_LT) {
String[] locations =
{ "Center Torso", "Left Leg", "Left Arm" };
JComboBox<String> combo = new JComboBox<String>(locations);
JOptionPane jop = new JOptionPane(combo,
JOptionPane.QUESTION_MESSAGE,
JOptionPane.OK_CANCEL_OPTION);
JDialog dlg = jop.createDialog("Select secondary location.");
combo.grabFocus();
combo.getEditor().selectAll();
dlg.setVisible(true);
int value = ((Integer) jop.getValue()).intValue();
if (value == JOptionPane.CANCEL_OPTION) {
return false;
}
if (combo.getSelectedIndex() == 1) {
nextLocation = Mech.LOC_LLEG;
} else if (combo.getSelectedIndex() == 2) {
nextLocation = Mech.LOC_LARM;
}
} else if (location == Mech.LOC_CT) {
String[] locations =
{ "Left Torso", "Right Torso" };
JComboBox<String> combo = new JComboBox<String>(locations);
JOptionPane jop = new JOptionPane(combo,
JOptionPane.QUESTION_MESSAGE,
JOptionPane.OK_CANCEL_OPTION);
JDialog dlg = jop.createDialog(null,
"Select secondary location.");
combo.grabFocus();
combo.getEditor().selectAll();
dlg.setVisible(true);
int value = ((Integer) jop.getValue()).intValue();
if (value == JOptionPane.CANCEL_OPTION) {
return false;
}
if (combo.getSelectedIndex() == 1) {
nextLocation = Mech.LOC_RT;
} else {
nextLocation = Mech.LOC_LT;
}
}
}
// Determine how much usable space we have in both locations
int secondarySpace = UnitUtil.getHighestContinuousNumberOfCrits(
getUnit(), nextLocation);
// Check for available space
if ((primaryLocSpace < totalCrits) &&
((nextLocation == Entity.LOC_DESTROYED)
|| ((primaryLocSpace + secondarySpace) < totalCrits))) {
throw new LocationFullException(eq.getName() +
" does not fit there in "
+ getUnit().getLocationAbbr(location)
+ " on " + getUnit().getDisplayName());
}
for (; critsUsed < totalCrits; critsUsed++) {
mech.addEquipment(eq, location, false, slotNumber);
slotNumber =
(slotNumber + 1) % mech.getNumberOfCriticals(location);
primaryLocSpace--;
if (primaryLocSpace == 0) {
slotNumber = 0;
location = nextLocation;
totalCrits -= critsUsed;
critsUsed = 0;
}
}
changeMountStatus(eq, primaryLocation, nextLocation, false);
} else if (primaryLocSpace >= totalCrits) {
if ((eq.getType() instanceof WeaponType)
&& eq.getType().hasFlag(WeaponType.F_VGL)) {
String[] facings;
if (location == Mech.LOC_LT) {
facings = new String[4];
facings[0] = "Front";
facings[1] = "Front-Left";
facings[2] = "Rear-Left";
facings[3] = "Rear";
} else if (location == Mech.LOC_RT) {
facings = new String[4];
facings[0] = "Front";
facings[1] = "Front-Right";
facings[2] = "Rear-Right";
facings[3] = "Rear";
} else if (location == Mech.LOC_CT) {
facings = new String[2];
facings[0] = "Front";
facings[1] = "Rear";
} else {
JOptionPane.showMessageDialog(null,
"VGL must be placed in torso location!",
"Invalid location",
JOptionPane.WARNING_MESSAGE);
return false;
}
String facing = (String)JOptionPane.showInputDialog(null,
"Please choose the facing of the VGL",
"Choose Facing", JOptionPane.QUESTION_MESSAGE,
null, facings, facings[0]);
if (facing == null) {
return false;
}
mech.addEquipment(eq, location, false, slotNumber);
if (facing.equals("Front-Left")) {
eq.setFacing(5);
} else if (facing.equals("Front-Right")) {
eq.setFacing(1);
} else if (facing.equals("Rear-Right")) {
eq.setFacing(2);
} else if (facing.equals("Rear-Left")) {
eq.setFacing(4);
} else if (facing.equals("Rear")) {
eq.setFacing(3);
UnitUtil.changeMountStatus(getUnit(), eq, location, -1, true);
}
} else {
mech.addEquipment(eq, location, false, slotNumber);
}
changeMountStatus(eq, location, false);
} else {
throw new LocationFullException(eq.getName() +
" does not fit there in " + getUnit().getLocationAbbr(location) +
" on " + getUnit().getDisplayName());
}
return true;
}
/**
*
* @param ba
* @param m
* @return
*/
private boolean addEquipmentBA(BattleArmor ba, Mounted newMount, int trooper) {
if (TestBattleArmor.isMountLegal(ba, newMount, location, trooper)){
newMount.setBaMountLoc(location);
if (newMount.getLocation() == BattleArmor.LOC_SQUAD){
changeMountStatus(newMount, newMount.getLocation(), false);
} else {
changeMountStatus(newMount, trooper, false);
}
return true;
} else {
return false;
}
}
/**
*
* @param aero
* @return
*/
private boolean addEquipmentAero(Aero aero, Mounted eq)
throws LocationFullException{
if (eq.getType() instanceof WeaponType){
int[] availSpace = TestAero.availableSpace(aero);
int[] weapCount = new int[aero.locations() - 1];
for (Mounted m : aero.getWeaponList()){
if (m.getLocation() != Entity.LOC_NONE){
weapCount[m.getLocation()]++;
}
}
if ((weapCount[location] +1) > availSpace[location]){
throw new LocationFullException(eq.getName() +
" does not fit in " + getUnit().getLocationAbbr(location) +
" on " + getUnit().getDisplayName());
} else {
UnitUtil.addMounted(getUnit(), eq, location, false);
}
} else {
UnitUtil.addMounted(getUnit(), eq, location, false);
}
changeMountStatus(eq, location, false);
return true;
}
/**
*
*/
@Override
public boolean importData(TransferSupport info) {
if (!info.isDrop() || !((getUnit() instanceof Mech) || (getUnit() instanceof Aero) ||
(getUnit() instanceof BattleArmor))) {
return false;
}
int trooper = 0;
if (info.getComponent() instanceof DropTargetCriticalList) {
DropTargetCriticalList<?> list = (DropTargetCriticalList<?>) info.getComponent();
if (getUnit() instanceof BattleArmor){
String[] split = list.getName().split(":");
if (split.length != 2){
return false;
}
location = Integer.parseInt(split[0]);
trooper = Integer.parseInt(split[1]);
} else {
location = Integer.parseInt(list.getName());
}
Transferable t = info.getTransferable();
int slotNumber = list.getDropLocation().getIndex();
try {
Mounted eq = getUnit().getEquipment(Integer.parseInt(
(String) t.getTransferData(DataFlavor.stringFlavor)));
if (getUnit() instanceof BattleArmor){
if ((location == eq.getBaMountLoc())
&& (trooper == eq.getLocation())){
return false;
}
} else {
// If this equipment is already mounted, we need to clear
// the criticals its mounted in
if (eq.getLocation() != Entity.LOC_NONE
|| eq.getSecondLocation() != Entity.LOC_NONE){
UnitUtil.removeCriticals(getUnit(), eq);
changeMountStatus(eq,Entity.LOC_NONE,false);
} else {
eq.setOmniPodMounted(UnitUtil.canPodMount(getUnit(), eq));
}
}
/*if (UnitUtil.isFixedLocationSpreadEquipment(eq.getType())) {
return false;
}*/
if (!UnitUtil.isValidLocation(getUnit(), eq.getType(), location)) {
JOptionPane.showMessageDialog(null, eq.getName() +
" can't be placed in " +
getUnit().getLocationName(location) + "!",
"Invalid Location",
JOptionPane.INFORMATION_MESSAGE);
return false;
}
if (getUnit() instanceof Aero){
return addEquipmentAero((Aero)getUnit(), eq);
} else if (getUnit() instanceof Mech) {
// superheavies can put 2 ammobins or heatsinks in one crit
if ((getUnit() instanceof Mech) && ((Mech)getUnit()).isSuperHeavy()) {
CriticalSlot cs = getUnit().getCritical(location, slotNumber);
if ((cs != null) && (cs.getType() == CriticalSlot.TYPE_EQUIPMENT) && (cs.getMount2() == null)) {
EquipmentType etype = cs.getMount().getType();
EquipmentType etype2 = eq.getType();
if ((etype instanceof AmmoType)) {
if (!(etype2 instanceof AmmoType) || (((AmmoType)etype).getAmmoType() != ((AmmoType)etype2).getAmmoType())) {
return addEquipmentMech((Mech)getUnit(), eq, slotNumber);
}
} else {
if (!(etype.equals(etype2)) || ((etype instanceof MiscType) && (!etype.hasFlag(MiscType.F_HEAT_SINK) && !etype.hasFlag(MiscType.F_DOUBLE_HEAT_SINK ))) || !((etype instanceof MiscType))) {
return addEquipmentMech((Mech)getUnit(), eq, slotNumber);
}
}
cs.setMount2(eq);
changeMountStatus(eq, location, false);
return true;
}
}
return addEquipmentMech((Mech)getUnit(), eq, slotNumber);
} else if (getUnit() instanceof BattleArmor){
return addEquipmentBA((BattleArmor)getUnit(), eq, trooper);
}
} catch (LocationFullException lfe) {
lfe.printStackTrace();
JOptionPane.showMessageDialog(null, lfe.getMessage(),
"Location Full", JOptionPane.INFORMATION_MESSAGE);
return false;
} catch (Exception ex) {
ex.printStackTrace();
}
return true;
}
return false;
}
@Override
public boolean canImport(TransferSupport info) {
// Check for String flavor
if (!info.isDataFlavorSupported(DataFlavor.stringFlavor)) {
return false;
}
// check the target component
if (!(info.getComponent() instanceof DropTargetCriticalList)) {
return false;
}
// check if the dragged mounted should be transferrable
Mounted mounted = null;
try {
mounted = getUnit().getEquipment(Integer
.parseInt((String) info.getTransferable().getTransferData(
DataFlavor.stringFlavor)));
} catch (NumberFormatException e) {
e.printStackTrace();
} catch (UnsupportedFlavorException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// not actually dragged a Mounted? not transferable
if (mounted == null) {
return false;
}
// stuff that has a fixed location is also not transferable
if (UnitUtil.isFixedLocationSpreadEquipment(mounted.getType())) {
return false;
}
// no transfer in the same location
if (getUnit() instanceof BattleArmor){
// Infantry weapons cannot be mounted directly, but must instead
// be mounted in an AP Mount
if (mounted.getType() instanceof InfantryWeapon){
return false;
}
String[] split = info.getComponent().getName().split(":");
if (split.length != 2){
return false;
}
if ((Integer.parseInt(split[0]) == mounted.getBaMountLoc())
&& (Integer.parseInt(split[1]) == mounted.getLocation())) {
return false;
}
}
return true;
}
@Override
protected Transferable createTransferable(JComponent c) {
if (c instanceof JTable) {
JTable table = (JTable) c;
Mounted mount = (Mounted) ((CriticalTableModel) table.getModel()).getValueAt(table.getSelectedRow(), CriticalTableModel.EQUIPMENT);
return new StringSelection(Integer.toString(getUnit().getEquipmentNum(mount)));
} else if (c instanceof DropTargetCriticalList) {
DropTargetCriticalList<?> list = (DropTargetCriticalList<?>)c;
Mounted mount = list.getMounted();
if (mount != null) {
return new StringSelection(Integer.toString(getUnit().getEquipmentNum(mount)));
}
}
return null;
}
@Override
public int getSourceActions(JComponent c) {
return TransferHandler.MOVE;
}
private void changeMountStatus(Mounted eq, int location, boolean rear) {
changeMountStatus(eq, location, -1, rear);
}
private void changeMountStatus(Mounted eq, int location, int secondaryLocation, boolean rear) {
UnitUtil.changeMountStatus(getUnit(), eq, location, secondaryLocation, rear);
// Check linkings after you remove everything.
try {
MechFileParser.postLoadInit(getUnit());
} catch (EntityLoadingException ele) {
// do nothing.
} catch (Exception ex) {
ex.printStackTrace();
}
if (refresh != null) {
refresh.refreshAll();
}
}
public Entity getUnit() {
return eSource.getEntity();
}
}