/* * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.optaplanner.examples.tennis.swingui; import java.awt.BorderLayout; import java.awt.Color; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.swing.AbstractAction; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTabbedPane; import javax.swing.SwingConstants; import org.optaplanner.examples.common.swingui.CommonIcons; import org.optaplanner.examples.common.swingui.SolutionPanel; import org.optaplanner.examples.common.swingui.components.LabeledComboBoxRenderer; import org.optaplanner.examples.common.swingui.timetable.TimeTablePanel; import org.optaplanner.examples.tennis.domain.Day; import org.optaplanner.examples.tennis.domain.Team; import org.optaplanner.examples.tennis.domain.TeamAssignment; import org.optaplanner.examples.tennis.domain.TennisSolution; import org.optaplanner.examples.tennis.domain.UnavailabilityPenalty; import org.optaplanner.swing.impl.SwingUtils; import org.optaplanner.swing.impl.TangoColorFactory; import static org.optaplanner.examples.common.swingui.timetable.TimeTablePanel.HeaderColumnKey.*; import static org.optaplanner.examples.common.swingui.timetable.TimeTablePanel.HeaderRowKey.*; public class TennisPanel extends SolutionPanel<TennisSolution> { public static final String LOGO_PATH = "/org/optaplanner/examples/tennis/swingui/tennisLogo.png"; private final TimeTablePanel<Day, Team> datesPanel; private final TimeTablePanel<Team, Team> confrontationsPanel; public TennisPanel() { setLayout(new BorderLayout()); JTabbedPane tabbedPane = new JTabbedPane(); datesPanel = new TimeTablePanel<>(); tabbedPane.add("Dates", new JScrollPane(datesPanel)); confrontationsPanel = new TimeTablePanel<>(); tabbedPane.add("Confrontations", new JScrollPane(confrontationsPanel)); add(tabbedPane, BorderLayout.CENTER); setPreferredSize(PREFERRED_SCROLLABLE_VIEWPORT_SIZE); } @Override public boolean isWrapInScrollPane() { return false; } @Override public void resetPanel(TennisSolution tennisSolution) { datesPanel.reset(); confrontationsPanel.reset(); defineGrid(tennisSolution); fillCells(tennisSolution); repaint(); // Hack to force a repaint of TimeTableLayout during "refresh screen while solving" } private void defineGrid(TennisSolution tennisSolution) { JButton footprint = SwingUtils.makeSmallButton(new JButton("999999")); int footprintWidth = footprint.getPreferredSize().width; datesPanel.defineColumnHeaderByKey(HEADER_COLUMN); for (Day day : tennisSolution.getDayList()) { datesPanel.defineColumnHeader(day, footprintWidth); } datesPanel.defineColumnHeaderByKey(TRAILING_HEADER_COLUMN); // Assignment count datesPanel.defineRowHeaderByKey(HEADER_ROW); for (Team team : tennisSolution.getTeamList()) { datesPanel.defineRowHeader(team); } datesPanel.defineRowHeader(null); // Unassigned confrontationsPanel.defineColumnHeaderByKey(HEADER_COLUMN); for (Team team : tennisSolution.getTeamList()) { confrontationsPanel.defineColumnHeader(team); } confrontationsPanel.defineRowHeaderByKey(HEADER_ROW); for (Team team : tennisSolution.getTeamList()) { confrontationsPanel.defineRowHeader(team); } } private void fillCells(TennisSolution tennisSolution) { datesPanel.addCornerHeader(HEADER_COLUMN, HEADER_ROW, createTableHeader(new JLabel("Team"))); fillDayCells(tennisSolution); fillTeamCells(tennisSolution); fillUnavailabilityPenaltyCells(tennisSolution); fillTeamAssignmentCells(tennisSolution); fillConfrontationCells(tennisSolution); } private void fillDayCells(TennisSolution tennisSolution) { for (Day day : tennisSolution.getDayList()) { datesPanel.addColumnHeader(day, HEADER_ROW, createTableHeader(new JLabel(day.getLabel(), SwingConstants.CENTER))); } datesPanel.addCornerHeader(TRAILING_HEADER_COLUMN, HEADER_ROW, createTableHeader(new JLabel("Day count"))); } private void fillTeamCells(TennisSolution tennisSolution) { Map<Team, Integer> teamToDayCountMap = extractTeamToDayCountMap(tennisSolution); for (Team team : tennisSolution.getTeamList()) { datesPanel.addRowHeader(HEADER_COLUMN, team, createTableHeader(new JLabel(team.getLabel()))); datesPanel.addRowHeader(TRAILING_HEADER_COLUMN, team, createTableHeader(new JLabel(teamToDayCountMap.get(team) + " days"))); confrontationsPanel.addColumnHeader(team, HEADER_ROW, createTableHeader(new JLabel(team.getLabel()))); confrontationsPanel.addRowHeader(HEADER_COLUMN, team, createTableHeader(new JLabel(team.getLabel()))); } datesPanel.addRowHeader(HEADER_COLUMN, null, createTableHeader(new JLabel("Unassigned"))); } private Map<Team, Integer> extractTeamToDayCountMap(TennisSolution tennisSolution) { Map<Team, Integer> teamToDayCountMap = new HashMap<>(tennisSolution.getTeamList().size()); for (Team team : tennisSolution.getTeamList()) { teamToDayCountMap.put(team, 0); } for (TeamAssignment teamAssignment : tennisSolution.getTeamAssignmentList()) { Team team = teamAssignment.getTeam(); if (team != null) { int count = teamToDayCountMap.get(team); count++; teamToDayCountMap.put(team, count); } } return teamToDayCountMap; } private void fillUnavailabilityPenaltyCells(TennisSolution tennisSolution) { for (UnavailabilityPenalty unavailabilityPenalty : tennisSolution.getUnavailabilityPenaltyList()) { JPanel unavailabilityPanel = new JPanel(); unavailabilityPanel.setBackground(TangoColorFactory.ALUMINIUM_4); datesPanel.addCell(unavailabilityPenalty.getDay(), unavailabilityPenalty.getTeam(), unavailabilityPanel); } } private void fillTeamAssignmentCells(TennisSolution tennisSolution) { TangoColorFactory tangoColorFactory = new TangoColorFactory(); for (Team team : tennisSolution.getTeamList()) { tangoColorFactory.pickColor(team); } for (TeamAssignment teamAssignment : tennisSolution.getTeamAssignmentList()) { Team team = teamAssignment.getTeam(); Color teamColor = team == null ? TangoColorFactory.SCARLET_1 : tangoColorFactory.pickColor(team); datesPanel.addCell(teamAssignment.getDay(), team, createButton(teamAssignment, teamColor)); } } private void fillConfrontationCells(TennisSolution tennisSolution) { List<Team> teamList = tennisSolution.getTeamList(); List<Day> dayList = tennisSolution.getDayList(); Map<Day, List<TeamAssignment>> dayToTeamAssignmentListMap = new HashMap<>( dayList.size()); for (Day day : dayList) { dayToTeamAssignmentListMap.put(day, new ArrayList<>()); } for (TeamAssignment teamAssignment : tennisSolution.getTeamAssignmentList()) { dayToTeamAssignmentListMap.get(teamAssignment.getDay()).add(teamAssignment); } Map<List<Team>, Integer> teamPairToConfrontationCountMap = new HashMap<>(); for (Team left : teamList) { for (Team right : teamList) { if (left != right) { List<Team> teamPair = Arrays.asList(left, right); teamPairToConfrontationCountMap.put(teamPair, 0); } } } for (List<TeamAssignment> teamAssignmentSubList : dayToTeamAssignmentListMap.values()) { for (TeamAssignment left : teamAssignmentSubList) { if (left.getTeam() != null) { for (TeamAssignment right : teamAssignmentSubList) { if (right.getTeam() != null && left.getTeam() != right.getTeam()) { List<Team> teamPair = Arrays.asList(left.getTeam(), right.getTeam()); int confrontationCount = teamPairToConfrontationCountMap.get(teamPair); confrontationCount++; teamPairToConfrontationCountMap.put(teamPair, confrontationCount); } } } } } for (Map.Entry<List<Team>, Integer> teamPairToConfrontationCount : teamPairToConfrontationCountMap.entrySet()) { List<Team> teamPair = teamPairToConfrontationCount.getKey(); int confrontationCount = teamPairToConfrontationCount.getValue(); confrontationsPanel.addCell(teamPair.get(0), teamPair.get(1), createTableHeader(new JLabel(Integer.toString(confrontationCount)))); } } private JPanel createTableHeader(JLabel label) { JPanel headerPanel = new JPanel(new BorderLayout()); headerPanel.add(label, BorderLayout.NORTH); headerPanel.setBorder(BorderFactory.createCompoundBorder( BorderFactory.createLineBorder(TangoColorFactory.ALUMINIUM_5), BorderFactory.createEmptyBorder(2, 2, 2, 2))); return headerPanel; } private JButton createButton(TeamAssignment teamAssignment, Color color) { JButton button = SwingUtils.makeSmallButton(new JButton(new TeamAssignmentAction(teamAssignment))); button.setBackground(color); if (teamAssignment.isLocked()) { button.setIcon(CommonIcons.LOCKED_ICON); } return button; } private class TeamAssignmentAction extends AbstractAction { private TeamAssignment teamAssignment; public TeamAssignmentAction(TeamAssignment teamAssignment) { super("Play"); this.teamAssignment = teamAssignment; } @Override public void actionPerformed(ActionEvent e) { JPanel listFieldsPanel = new JPanel(new GridLayout(2, 2)); listFieldsPanel.add(new JLabel("Team:")); List<Team> teamList = getSolution().getTeamList(); // Add 1 to array size to add null, which makes the entity unassigned JComboBox teamListField = new JComboBox( teamList.toArray(new Object[teamList.size() + 1])); LabeledComboBoxRenderer.applyToComboBox(teamListField); teamListField.setSelectedItem(teamAssignment.getTeam()); listFieldsPanel.add(teamListField); listFieldsPanel.add(new JLabel("Locked:")); JCheckBox lockedField = new JCheckBox("immovable during planning"); lockedField.setSelected(teamAssignment.isLocked()); listFieldsPanel.add(lockedField); int result = JOptionPane.showConfirmDialog(TennisPanel.this.getRootPane(), listFieldsPanel, "Select team", JOptionPane.OK_CANCEL_OPTION); if (result == JOptionPane.OK_OPTION) { Team toTeam = (Team) teamListField.getSelectedItem(); if (teamAssignment.getTeam() != toTeam) { solutionBusiness.doChangeMove(teamAssignment, "team", toTeam); } boolean toLocked = lockedField.isSelected(); if (teamAssignment.isLocked() != toLocked) { if (solutionBusiness.isSolving()) { logger.error("Not doing user change because the solver is solving."); return; } teamAssignment.setLocked(toLocked); } solverAndPersistenceFrame.resetScreen(); } } } }