package games.strategy.triplea.ui; import java.awt.BorderLayout; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTabbedPane; import games.strategy.engine.data.GameData; import games.strategy.engine.data.NamedAttachable; import games.strategy.engine.data.PlayerID; import games.strategy.engine.data.ProductionRule; import games.strategy.engine.data.Resource; import games.strategy.engine.data.UnitType; import games.strategy.engine.data.util.ResourceCollectionUtils; import games.strategy.triplea.attachments.UnitAttachment; import games.strategy.ui.SwingComponents; import games.strategy.util.IntegerMap; import games.strategy.util.Tuple; public class TabbedProductionPanel extends ProductionPanel { private static final long serialVersionUID = 3481282212500641144L; private int m_rows; private int m_columns; protected TabbedProductionPanel(final IUIContext uiContext) { super(uiContext); } public static IntegerMap<ProductionRule> getProduction(final PlayerID id, final JFrame parent, final GameData data, final boolean bid, final IntegerMap<ProductionRule> initialPurchase, final IUIContext uiContext) { return new TabbedProductionPanel(uiContext).show(id, parent, data, bid, initialPurchase); } @Override protected void initLayout() { this.removeAll(); this.setLayout(new GridBagLayout()); add( new JLabel(String.format( "<html>Attack/Defense/Movement.            " + "(Total Resources: %s)</html>", ResourceCollectionUtils.getProductionResources(getResources()))), new GridBagConstraints(0, 0, 1, 1, 1, 1, GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, new Insets(8, 8, 8, 0), 0, 0)); final JTabbedPane tabs = new JTabbedPane(); add(tabs, new GridBagConstraints(0, 1, 1, 1, 100, 100, GridBagConstraints.EAST, GridBagConstraints.BOTH, new Insets(8, 8, 8, 0), 0, 0)); final ProductionTabsProperties properties = ProductionTabsProperties.getInstance(m_id, m_rules); final List<Tuple<String, List<Rule>>> ruleLists = getRuleLists(properties); calculateXY(properties, largestList(ruleLists)); for (final Tuple<String, List<Rule>> ruleList : ruleLists) { if (ruleList.getSecond().size() > 0) { tabs.addTab(ruleList.getFirst(), new JScrollPane(getRulesPanel(ruleList.getSecond()))); } } add(m_left, new GridBagConstraints(0, 2, 1, 1, 1, 1, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(8, 8, 0, 12), 0, 0)); m_done = new JButton(m_done_action); add(m_done, new GridBagConstraints(0, 3, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 0, 8, 0), 0, 0)); tabs.validate(); this.validate(); } private void calculateXY(final ProductionTabsProperties properties, final int largestList) { if (properties == null || properties.getRows() == 0 || properties.getColumns() == 0 || properties.getRows() * properties.getColumns() < largestList) { int m_maxColumns; if (largestList <= 36) { m_maxColumns = Math.max(8, Math.min(12, new BigDecimal(largestList).divide(new BigDecimal(3), BigDecimal.ROUND_UP).intValue())); } else if (largestList <= 64) { m_maxColumns = Math.max(8, Math.min(16, new BigDecimal(largestList).divide(new BigDecimal(4), BigDecimal.ROUND_UP).intValue())); } else { m_maxColumns = Math.max(8, Math.min(16, new BigDecimal(largestList).divide(new BigDecimal(5), BigDecimal.ROUND_UP).intValue())); } m_rows = Math.max(2, new BigDecimal(largestList).divide(new BigDecimal(m_maxColumns), BigDecimal.ROUND_UP).intValue()); m_columns = Math.max(3, new BigDecimal(largestList).divide(new BigDecimal(m_rows), BigDecimal.ROUND_UP).intValue()); } else { m_rows = Math.max(2, properties.getRows()); // There are small display problems if the size is less than 2x3 cells. m_columns = Math.max(3, properties.getColumns()); } } private int largestList(final List<Tuple<String, List<Rule>>> ruleLists) { int largestList = 0; for (final Tuple<String, List<Rule>> tuple : ruleLists) { if (largestList < tuple.getSecond().size()) { largestList = tuple.getSecond().size(); } } return largestList; } private void checkLists(final List<Tuple<String, List<Rule>>> ruleLists) { final List<Rule> rulesCopy = new ArrayList<>(m_rules); for (final Tuple<String, List<Rule>> tuple : ruleLists) { for (final Rule rule : tuple.getSecond()) { rulesCopy.remove(rule); } } if (rulesCopy.size() > 0) { throw new IllegalStateException("production_tabs: must include all player production rules/units"); } } private List<Tuple<String, List<Rule>>> getRuleLists(final ProductionTabsProperties properties) { if (properties != null && !properties.useDefaultTabs()) { final List<Tuple<String, List<Rule>>> ruleLists = properties.getRuleLists(); checkLists(ruleLists); return ruleLists; } else { return getDefaultRuleLists(); } } private List<Tuple<String, List<Rule>>> getDefaultRuleLists() { final List<Tuple<String, List<Rule>>> ruleLists = new ArrayList<>(); final ArrayList<Rule> allRules = new ArrayList<>(); final ArrayList<Rule> landRules = new ArrayList<>(); final ArrayList<Rule> airRules = new ArrayList<>(); final ArrayList<Rule> seaRules = new ArrayList<>(); final ArrayList<Rule> constructRules = new ArrayList<>(); final ArrayList<Rule> upgradeConsumesRules = new ArrayList<>(); final ArrayList<Rule> resourceRules = new ArrayList<>(); for (final Rule rule : m_rules) { allRules.add(rule); final NamedAttachable resourceOrUnit = rule.getProductionRule().getResults().keySet().iterator().next(); if (resourceOrUnit instanceof UnitType) { final UnitType type = (UnitType) resourceOrUnit; final UnitAttachment attach = UnitAttachment.get(type); if (attach.getConsumesUnits() != null && attach.getConsumesUnits().totalValues() >= 1) { upgradeConsumesRules.add(rule); } // canproduceUnits isn't checked on purpose, since this category is for units that can be placed // anywhere (placed without needing a factory). if (attach.getIsConstruction()) { constructRules.add(rule); } else if (attach.getIsSea()) { seaRules.add(rule); } else if (attach.getIsAir()) { airRules.add(rule); } else { landRules.add(rule); } } else if (resourceOrUnit instanceof Resource) { resourceRules.add(rule); } } ruleLists.add(Tuple.of("All", (List<Rule>) allRules)); ruleLists.add(Tuple.of("Land", (List<Rule>) landRules)); ruleLists.add(Tuple.of("Air", (List<Rule>) airRules)); ruleLists.add(Tuple.of("Sea", (List<Rule>) seaRules)); ruleLists.add(Tuple.of("Construction", (List<Rule>) constructRules)); ruleLists.add(Tuple.of("Upgrades/Consumes", (List<Rule>) upgradeConsumesRules)); ruleLists.add(Tuple.of("Resources", (List<Rule>) resourceRules)); return ruleLists; } private JPanel getRulesPanel(final List<Rule> rules) { final JPanel panel = SwingComponents.gridPanel(m_rows, m_columns); final JPanel[][] panelHolder = new JPanel[m_rows][m_columns]; for (int m = 0; m < m_rows; m++) { for (int n = 0; n < m_columns; n++) { panelHolder[m][n] = new JPanel(new BorderLayout()); panel.add(panelHolder[m][n]); } } for (int x = 0; x < m_columns * m_rows; x++) { if (x < rules.size()) { panelHolder[(x % m_rows)][(x / m_rows)].add(rules.get(x).getPanelComponent()); } } return panel; } }