Java tutorial
/* * EventManager * Copyright (c) 2008-2017 James Watmuff & Leonard Hall * * 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 3 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package au.com.jwatmuff.eventmanager.gui.wizard; import au.com.jwatmuff.eventmanager.db.PlayerPoolDAO; import au.com.jwatmuff.eventmanager.gui.wizard.DrawWizardWindow.Context; import au.com.jwatmuff.eventmanager.model.config.ConfigurationFile; import au.com.jwatmuff.eventmanager.model.info.PlayerPoolInfo; import au.com.jwatmuff.eventmanager.model.misc.*; import au.com.jwatmuff.eventmanager.model.misc.CSVImporter.TooFewPlayersException; import au.com.jwatmuff.eventmanager.model.vo.CompetitionInfo; import au.com.jwatmuff.eventmanager.model.vo.Player; import au.com.jwatmuff.eventmanager.model.vo.PlayerPool; import au.com.jwatmuff.eventmanager.model.vo.Pool; import au.com.jwatmuff.eventmanager.util.GUIUtils; import au.com.jwatmuff.genericdb.transaction.Transaction; import au.com.jwatmuff.genericdb.transaction.TransactionalDatabase; import java.awt.Cursor; import java.io.File; import java.io.IOException; import java.util.*; import javax.swing.DefaultCellEditor; import javax.swing.JComboBox; import javax.swing.table.DefaultTableModel; import javax.swing.table.TableCellEditor; import org.apache.commons.lang.mutable.MutableInt; import org.apache.log4j.Logger; /** * * @author James */ public class SeedingPanel extends javax.swing.JPanel implements DrawWizardWindow.Panel { private static final Logger log = Logger.getLogger(SeedingPanel.class); private DefaultTableModel model; private TransactionalDatabase database; private Pool pool; private Context context; private static final Comparator<Player> PLAYERS_COMPARATOR_POSITION = new Comparator<Player>() { @Override public int compare(Player p1, Player p2) { String n1 = p1.getLastName() + p1.getFirstName(); String n2 = p2.getLastName() + p2.getFirstName(); return n1.compareTo(n2); } }; /** Creates new form SeedingPanel */ public SeedingPanel(TransactionalDatabase database, Context context) { this.database = database; this.context = context; initComponents(); model = new DefaultTableModel(); model.addColumn("Player"); model.addColumn("Team"); model.addColumn("Seed"); model.setColumnIdentifiers(new Object[] { "Player", "Team", "Seed" }); seedingTable.setModel(model); } private TableCellEditor getSeedingCellEditor(int numPlayers) { Object[] values = new Object[numPlayers + 1]; values[0] = "None"; for (int i = 1; i <= numPlayers; i++) values[i] = "" + i; return new DefaultCellEditor(new JComboBox<>(values)); } private Object[] getRowData(Player player) { int playerID = player.getID(); Integer seed = context.seeds.get(playerID); return new Object[] { player.getLastName() + ", " + player.getFirstName(), player.getTeam(), seed == null || seed <= 0 ? "None" : "" + seed }; } /** This method is called from within the constructor to * initialize the form. * WARNING: Do NOT modify this code. The content of this method is * always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { jScrollPane1 = new javax.swing.JScrollPane(); seedingTable = new javax.swing.JTable(); divisionNameLabel = new javax.swing.JLabel(); seedingTable .setModel(new javax.swing.table.DefaultTableModel( new Object[][] { { null, null, null, null }, { null, null, null, null }, { null, null, null, null }, { null, null, null, null } }, new String[] { "Title 1", "Title 2", "Title 3", "Title 4" })); seedingTable.setGridColor(new java.awt.Color(237, 237, 237)); seedingTable.setRowHeight(19); jScrollPane1.setViewportView(seedingTable); divisionNameLabel.setFont(new java.awt.Font("Tahoma", 1, 24)); divisionNameLabel.setText("Division Name"); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addGroup( javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup().addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) .addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 549, Short.MAX_VALUE) .addComponent(divisionNameLabel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 549, Short.MAX_VALUE)) .addContainerGap())); layout.setVerticalGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup().addContainerGap().addComponent(divisionNameLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 353, Short.MAX_VALUE) .addContainerGap())); }// </editor-fold>//GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JLabel divisionNameLabel; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JTable seedingTable; // End of variables declaration//GEN-END:variables private void lockDivisionPlayers() throws DatabaseStateException { Map<Integer, PlayerPool> playerPoolMap = new HashMap<>(); for (PlayerPool pp : database.findAll(PlayerPool.class, PlayerPoolDAO.FOR_POOL, pool.getID())) { // Save player seeds as chosen by user - requires updateSeeds() to be called first. if (context.seeds.containsKey(pp.getPlayerID())) { pp.setSeed(context.seeds.get(pp.getPlayerID())); } playerPoolMap.put(pp.getPlayerID(), pp); } for (Player p : context.unapprovedPlayers) { PlayerPool pp = playerPoolMap.remove(p.getID()); if (pp == null) { pp = new PlayerPool(); pp.setID(new PlayerPool.Key(p.getID(), pool.getID())); } pp.setApproved(false); database.update(pp); } for (Player p : context.players) { PlayerPool pp = playerPoolMap.remove(p.getID()); if (pp == null) { pp = new PlayerPool(); pp.setID(new PlayerPool.Key(p.getID(), pool.getID())); } pp.setApproved(true); database.update(pp); } for (PlayerPool pp : playerPoolMap.values()) { database.delete(pp); } pool = PoolLocker.lockPoolPlayers(database, pool); } private boolean commitChanges() { updateSeeds(); try { lockDivisionPlayers(); } catch (DatabaseStateException e) { GUIUtils.displayError(this, "Unable to lock players in pool " + pool.getDescription()); return false; } CompetitionInfo ci = database.get(CompetitionInfo.class, null); ConfigurationFile configurationFile = ConfigurationFile.getConfiguration(ci.getDrawConfiguration()); if (configurationFile == null) { GUIUtils.displayError(this, "Unable to load draw configuration."); return false; } String drawName = configurationFile.getDrawName(context.players.size()); if (drawName == null) { GUIUtils.displayError(this, "The current draw configuration does not support divisions with " + context.players.size() + " players"); return false; } File csvFile = new File("resources/draw/" + drawName + ".csv"); try { CSVImporter.importFightDraw(csvFile, database, pool, context.players.size()); } catch (IOException | DatabaseStateException | TooFewPlayersException e) { GUIUtils.displayError(this, "Failed to import fight draw (" + drawName + ")"); log.error("Error importing fight draw", e); return false; } try { PoolDraw poolDraw = PoolDraw.getInstance(database, pool.getID(), context.seeds); List<PlayerPoolInfo> orderedPlayers = poolDraw.getOrderedPlayers(); PoolPlayerSequencer.savePlayerSequence(database, pool.getID(), orderedPlayers); pool = PoolLocker.lockPoolFights(database, pool); } catch (Exception e) { GUIUtils.displayError(this, "Failed to generate and lock fights"); log.error("Error generating and locking fights", e); return false; } context.pool = pool; return true; } @Override public boolean nextButtonPressed() { if (!GUIUtils.confirmLock(null, "all players and fights in division " + pool.getDescription())) return false; // TODO: I would like this to be wrapped in a transaction, so that it can't fail halfway (e.g. players // locked, but fights not), but I couldn't get this working easily. boolean result = false; try { context.detectExternalChanges = false; context.wizardWindow.disableNavigation(); seedingTable.setEnabled(false); context.wizardWindow.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); result = commitChanges(); } finally { context.wizardWindow.enableNavigation(); seedingTable.setEnabled(true); context.wizardWindow.setCursor(Cursor.getDefaultCursor()); if (!result) context.detectExternalChanges = true; } return result; } @Override public boolean backButtonPressed() { updateSeeds(); return true; } @Override public boolean closedButtonPressed() { return true; } // Updates context.seeds from selection made by the user in the seedingTable private void updateSeeds() { int index = 0; for (Player player : context.players) { if (player != null) { String seed = (String) seedingTable.getModel().getValueAt(index, 2); try { context.seeds.put(player.getID(), Integer.parseInt(seed)); } catch (NumberFormatException e) { // do nothing, just means no seed specified } index++; } } } @Override public void beforeShow() { pool = context.pool; divisionNameLabel.setText(pool.getDescription() + ": Seeding"); Collections.sort(context.players, PLAYERS_COMPARATOR_POSITION); seedingTable.getColumn("Seed").setCellEditor(getSeedingCellEditor(context.players.size())); // clear table while (model.getRowCount() > 0) model.removeRow(0); for (Player player : context.players) { model.addRow(getRowData(player)); } } @Override public void afterHide() { } }