Coverage Summary for Class: IslandFieldPanel (it.polimi.ingsw.Client.GUI.Panels)

Class Method, % Branch, % Line, %
IslandFieldPanel 0% (0/8) 0% (0/45) 0% (0/151)
IslandFieldPanel$1 0% (0/1) 0% (0/1)
Total 0% (0/9) 0% (0/45) 0% (0/152)


1 package it.polimi.ingsw.Client.GUI.Panels; 2  3 import it.polimi.ingsw.Client.GUI.ActionType; 4 import it.polimi.ingsw.Client.GUI.CircleLayout; 5 import it.polimi.ingsw.Client.GUI.Components.NoEntryTileComponent; 6 import it.polimi.ingsw.Client.GUI.Components.StudentButton; 7 import it.polimi.ingsw.Client.GUI.Components.TowerComponent; 8 import it.polimi.ingsw.Client.GUI.Listeners.GUISocketListener; 9 import it.polimi.ingsw.Controller.Actions.MoveMotherNature; 10 import it.polimi.ingsw.Controller.Actions.MoveStudent; 11 import it.polimi.ingsw.Controller.Actions.PlayCharacterCard; 12 import it.polimi.ingsw.Controller.MoveDestination; 13 import it.polimi.ingsw.Misc.OptionalValue; 14 import it.polimi.ingsw.Model.Enums.PawnColour; 15 import it.polimi.ingsw.Model.IslandGroup; 16 import it.polimi.ingsw.Model.Model; 17 import it.polimi.ingsw.Network.SocketWrapper; 18 import it.polimi.ingsw.Server.Messages.Events.Requests.PlayerActionRequest; 19  20 import javax.swing.*; 21 import java.awt.*; 22 import java.awt.image.BufferedImage; 23 import java.io.IOException; 24 import java.util.ArrayList; 25 import java.util.Arrays; 26 import java.util.Map; 27  28 import static it.polimi.ingsw.Client.GUI.IconLoader.*; 29  30 /** 31  * Class necessary to print all the islands on GUI and perform all player's action that involve an island or islandGroup 32  */ 33 public class IslandFieldPanel extends JPanel { 34  /** 35  * Contains game's information 36  */ 37  private final Model model; 38  /** 39  * Contains GuiReader's information necessary to record user's requests during his turn 40  */ 41  private final GUISocketListener guiSocketListener; 42  /** 43  * Optional Integer containing student's index inside player's PlayerBoard's entrance (necessary when sending MoveStudentAction to Server) 44  */ 45  private OptionalValue<Integer> entrancePositionToMove = OptionalValue.empty(); 46  /** 47  * Optional Integer containing card's index inside game (0 to 2), it can be empty if no characterCard has been played 48  */ 49  private OptionalValue<Integer> selectedCharacterCard = OptionalValue.empty(); 50  /** 51  * Pawn from character card that player wants to move inside an island 52  */ 53  private OptionalValue<PawnColour> pawnFromCharacterCard = OptionalValue.empty(); 54  /** 55  * Status of islandField 56  */ 57  private ActionType actionType; 58  59  public IslandFieldPanel(Model model, SocketWrapper sw, GUISocketListener guiSocketListener) { 60  //set IslandFieldPanel's actionType basing on previous actions performed by current Player 61  this.setActionType(ActionType.MOVEMOTHERNATURE, OptionalValue.empty()); 62  this.setOpaque(true); 63  this.setBackground(new Color(105, 186, 233)); 64  this.setLayout(new CircleLayout()); 65  this.model = model; 66  this.guiSocketListener = guiSocketListener; 67  ArrayList<IslandGroup> islandGroups = new ArrayList<>(this.model.getMutableIslandField().getMutableGroups()); 68  //list containing islands images 69  ArrayList<ImageIcon> islandIcons = new ArrayList<>(Arrays.asList(Island1, Island2, Island3)); 70  ArrayList<JButton> islandButtons = new ArrayList<>(this.model.getMutableIslandField().getMutableGroups().size()); 71  IslandGroup motherNaturePosition = this.model.getMutableIslandField().getMutableMotherNaturePosition(); 72  //---DYNAMIC SIZING ISLANDS' IMAGES---- 73  int widthIsland = 160 + getDimBoost(islandGroups.size()); 74  int heightIsland = 130 + getDimBoost(islandGroups.size()); 75  int widthStudent = 35 + (getDimBoost(islandGroups.size()) / 5); 76  int heightStudent = 30 + (getDimBoost(islandGroups.size()) / 5); 77  int widthMotherNature = 35 + (getDimBoost(islandGroups.size()) / 5); 78  int heightMotherNature = 45 + (getDimBoost(islandGroups.size()) / 5); 79  int widthTower = 17 + (getDimBoost(islandGroups.size()) / 5); 80  int heightTower = 35 + (getDimBoost(islandGroups.size()) / 5); 81  Map<PawnColour, Integer> pawnCountMap; 82  for (int i = 0; i < islandGroups.size(); i++) { 83  //Map containing students and their count on the islandGroup 84  pawnCountMap = islandGroups.get(i).getStudentCount(); 85  //get and scale an island's image 86  Image img = islandIcons.get(i % 3).getImage(); 87  Image newImg = img.getScaledInstance(widthIsland, heightIsland, java.awt.Image.SCALE_SMOOTH); 88  ImageIcon icon = new ImageIcon(newImg); 89  //create a new button with the scaled images 90  JButton islandButton = new JButton(icon); 91  islandButtons.add(islandButton); 92  int finalI = i; 93  //add on-click action listener to islandGroup 94  islandButton.addActionListener(e -> { 95  // skip execution of the action if a previous action still hasn't been processed by the server 96  if (guiSocketListener.awaitingPlayerActionFeedback()) { 97  JOptionPane.showMessageDialog(null, "Please wait for the server to process your previous" + 98  "request before making a new one"); 99  return; 100  } 101  switch (this.actionType) { 102  case CHARACTERCARD -> { 103  PlayCharacterCard playCharacterCard; 104  //create playCharacterCard action 105  if (pawnFromCharacterCard.isPresent()) { 106  playCharacterCard = new PlayCharacterCard(model.getMutableTurnOrder().getMutableCurrentPlayer().getId(), 107  selectedCharacterCard.get(), OptionalValue.of(islandGroups.get(finalI).getMutableIslands().get(0).getId()) 108  , pawnFromCharacterCard, OptionalValue.empty()); 109  } else { 110  playCharacterCard = new PlayCharacterCard(model.getMutableTurnOrder().getMutableCurrentPlayer().getId(), 111  selectedCharacterCard.get(), OptionalValue.of(islandGroups.get(finalI).getMutableIslands().get(0).getId()) 112  , OptionalValue.empty(), OptionalValue.empty()); 113  } 114  PlayerActionRequest playerActionRequest = new PlayerActionRequest(playCharacterCard); 115  this.guiSocketListener.savePlayerActionRequest(playCharacterCard); 116  try { 117  //send playCharacterCard request to Server 118  sw.sendMessage(playerActionRequest); 119  } catch (IOException ex) { 120  throw new RuntimeException(ex); 121  } 122  } 123  case MOVESTUDENT -> { 124  //create moveStudent action and its playerActionRequest 125  MoveStudent moveStudent = new MoveStudent(this.model.getMutableTurnOrder().getMutableCurrentPlayer().getId(), entrancePositionToMove.get(), MoveDestination.toIsland(islandGroups.get(finalI).getId())); 126  PlayerActionRequest playerAction = new PlayerActionRequest(moveStudent); 127  //save moveStudentAction request inside guiReader 128  this.guiSocketListener.savePlayerActionRequest(moveStudent); 129  try { 130  sw.sendMessage(playerAction); 131  } catch (IOException ex) { 132  throw new RuntimeException(ex); 133  } 134  } 135  case MOVEMOTHERNATURE -> { 136  //create moveMotherNature action and its playerActionRequest 137  MoveMotherNature moveMotherNature = new MoveMotherNature(this.model.getMutableTurnOrder().getMutableCurrentPlayer().getId(), getMotherNatureSteps(islandGroups, islandGroups.get(finalI))); 138  PlayerActionRequest playerAction = new PlayerActionRequest(moveMotherNature); 139  //save moveStudentAction request inside guiReader 140  this.guiSocketListener.savePlayerActionRequest(moveMotherNature); 141  try { 142  sw.sendMessage(playerAction); 143  } catch (IOException ex) { 144  throw new RuntimeException(ex); 145  } 146  } 147  } 148  // reset the action listener to the base action 149  this.setActionType(ActionType.MOVEMOTHERNATURE, OptionalValue.empty()); 150  }); 151  //remove border and filled background from islandGroups' button 152  islandButton.setPreferredSize(new Dimension(widthIsland, heightIsland)); 153  islandButton.setBorderPainted(false); 154  islandButton.setContentAreaFilled(false); 155  islandButton.setFocusPainted(false); 156  islandButton.setOpaque(false); 157  islandButton.setLayout(new GridLayout(3, 1, -45, 0)); 158  for (PawnColour p : pawnCountMap.keySet()) { 159  if (pawnCountMap.get(p) > 0) { 160  //create new StudentButton 161  StudentButton studentButton = new StudentButton(p, pawnCountMap.get(p), true); 162  //scale StudentButton's image 163  newImg = iconToImage(studentButton.getIcon()).getScaledInstance((int) (widthStudent / 1.5), (int) (heightStudent / 1.5), java.awt.Image.SCALE_SMOOTH); 164  icon = new ImageIcon(newImg); 165  studentButton.setIcon(icon); 166  studentButton.setPreferredSize(new Dimension(widthStudent, heightStudent)); 167  islandButton.add(studentButton); 168  //add same IslandGroups' actionListeners to studentButtons 169  studentButton.addActionListener(e -> islandButton.doClick()); 170  } 171  } 172  //Draw motherNature only if it's present in IslandGroup 173  if (islandGroups.get(i).getMutableIslands().stream().anyMatch(island -> island.getId() == motherNaturePosition.getId())) { 174  //load and scale MotherNature's image 175  img = motherNature != null ? motherNature.getImage() : null; 176  assert img != null; 177  newImg = img.getScaledInstance(widthMotherNature, heightMotherNature, java.awt.Image.SCALE_SMOOTH); 178  icon = new ImageIcon(newImg); 179  //create motherNature's label 180  JLabel motherNatureLabel = new JLabel(icon); 181  motherNatureLabel.setPreferredSize(new Dimension(widthMotherNature, heightMotherNature)); 182  //add motherNature to islandGroup's button 183  islandButton.add(motherNatureLabel); 184  } 185  //Drawing eventual tower 186  if (islandGroups.get(i).getTowerColour().isPresent()) { 187  //scale and set tower's image 188  TowerComponent tower = new TowerComponent(islandGroups.get(i).getTowerColour().get(), islandGroups.get(i).getTowerCount()); 189  newImg = iconToImage(tower.getIcon()).getScaledInstance(widthTower, heightTower, java.awt.Image.SCALE_SMOOTH); 190  icon = new ImageIcon(newImg); 191  tower.setIcon(icon); 192  //remove borders and filled background from tower's image 193  tower.setBorderPainted(false); 194  tower.setContentAreaFilled(false); 195  tower.setFocusPainted(false); 196  tower.setPreferredSize(new Dimension(widthTower, heightTower)); 197  tower.addActionListener(e -> islandButton.doClick()); 198  //add tower's image to IslandGroup's button 199  islandButton.add(tower); 200  } 201  //Drawing eventual NoEntryTile 202  if (islandGroups.get(i).getMutableNoEntryTiles().size() > 0) { 203  //scale and set NoEntryTile's image 204  NoEntryTileComponent noEntryTileComponent = new NoEntryTileComponent(islandGroups.get(i).getMutableNoEntryTiles().size()); 205  newImg = iconToImage(noEntryTileComponent.getIcon()).getScaledInstance(40, 35, java.awt.Image.SCALE_SMOOTH); 206  icon = new ImageIcon(newImg); 207  noEntryTileComponent.setIcon(icon); 208  noEntryTileComponent.setPreferredSize(new Dimension(40, 35)); 209  //add NoEntryTile component to island's button 210  islandButton.add(noEntryTileComponent); 211  //add same IslandGroups' actionListeners to noEntryTileComponent 212  noEntryTileComponent.addActionListener(e -> islandButton.doClick()); 213  214  } 215  islandButton.setToolTipText("<html><p width = 100px>ISLAND GROUP #" + islandGroups.get(i).getId() + "<br>" + 216  "STUDENTS:<br>" + 217  "RED:" + pawnCountMap.get(PawnColour.RED) + "<br>" + 218  "BLUE:" + pawnCountMap.get(PawnColour.BLUE) + "<br>" + 219  "YELLOW:" + pawnCountMap.get(PawnColour.YELLOW) + "<br>" + 220  "GREEN:" + pawnCountMap.get(PawnColour.GREEN) + "<br>" + 221  "PINK:" + pawnCountMap.get(PawnColour.PINK) + "</p></html>"); 222  ToolTipManager.sharedInstance().setDismissDelay(Integer.MAX_VALUE); 223  this.add(islandButton); 224  } 225  } 226  227  /** 228  * Method used for setting IslandFieldPanel's actionType from external panels 229  * 230  * @param actionType actionType that IslandFieldPanel will assume 231  * @param toRemove PlayerBoard's entrance's index containing the student to move (Optional.empty if action type is not MOVESTUDENT) 232  */ 233  public void setActionType(ActionType actionType, OptionalValue<Integer> toRemove) { 234  if (actionType == ActionType.MOVESTUDENT) { 235  this.actionType = actionType; 236  this.entrancePositionToMove = toRemove; 237  return; 238  } 239  this.actionType = actionType; 240  } 241  242  /** 243  * Support method used to increase islands' dimensions when the amount of IslandGroups decreases 244  * 245  * @param IslandsNumbers number of IslandGroups to show 246  * @return boost to add to original icons' dimensions 247  */ 248  private int getDimBoost(int IslandsNumbers) { 249  return switch (IslandsNumbers) { 250  case 12 -> 0; 251  case 11 -> 10; 252  case 10 -> 20; 253  case 9 -> 30; 254  case 8 -> 40; 255  case 7 -> 50; 256  case 6 -> 60; 257  case 5, default -> 70; 258  }; 259  } 260  261  /** 262  * Support method used to calculate difference between clicked islandGroup by user and actual motherNature's islandGroup 263  * 264  * @param islandGroups list of islandGroups present in game 265  * @param destinationIsland IslandGroup that has been clicked by player 266  * @return number of steps that motherNature should perform to reach wished IslandGroup 267  */ 268  private int getMotherNatureSteps(ArrayList<IslandGroup> islandGroups, IslandGroup destinationIsland) { 269  //get motherNature's islandGroup's index 270  int motherNatureIndex = islandGroups.indexOf(model.getMutableIslandField().getMutableMotherNaturePosition()); 271  int steps = 1; 272  //repeat until found islandGroup with same id as the one clicked by user 273  while (!islandGroups.get((motherNatureIndex + steps) % islandGroups.size()).equals(destinationIsland)) { 274  steps = steps + 1; 275  } 276  return steps; 277  } 278  279  /** 280  * Support method to extract Image from icon 281  * 282  * @param icon icon to convert 283  * @return image represented by icon 284  */ 285  private Image iconToImage(Icon icon) { 286  if (icon instanceof ImageIcon) { 287  return ((ImageIcon) icon).getImage(); 288  } else { 289  int w = icon.getIconWidth(); 290  int h = icon.getIconHeight(); 291  GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); 292  GraphicsDevice gd = ge.getDefaultScreenDevice(); 293  GraphicsConfiguration gc = gd.getDefaultConfiguration(); 294  BufferedImage image = gc.createCompatibleImage(w, h); 295  Graphics2D g = image.createGraphics(); 296  icon.paintIcon(null, g, 0, 0); 297  g.dispose(); 298  return image; 299  } 300  } 301  302  /** 303  * Basing on CharacterCard that has been activated, this method setup IslandFieldPanel for send the right PlayerActionRequest to Server 304  * 305  * @param actionType ActionType that IslandFieldPanel is going to switch to 306  * @param card card's index inside game 307  * @param toMove possible pawn to move 308  */ 309  public void setCharacterCardAction(ActionType actionType, OptionalValue<Integer> card, OptionalValue<PawnColour> toMove) { 310  this.actionType = actionType; 311  if (card.isEmpty()) return; 312  this.selectedCharacterCard = card; 313  if (toMove.isEmpty()) return; 314  this.pawnFromCharacterCard = toMove; 315  } 316 }