From 8652e97bb63f18d24c6f76ed6efd6bbb056b13eb Mon Sep 17 00:00:00 2001 From: Windchild292 Date: Mon, 9 Nov 2020 00:01:53 -0500 Subject: [PATCH 1/4] Fixing null issues with ImageIcon creation --- megamek/src/megamek/common/icons/AbstractIcon.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/megamek/src/megamek/common/icons/AbstractIcon.java b/megamek/src/megamek/common/icons/AbstractIcon.java index ff6389faa20..f601919101c 100644 --- a/megamek/src/megamek/common/icons/AbstractIcon.java +++ b/megamek/src/megamek/common/icons/AbstractIcon.java @@ -94,11 +94,13 @@ protected boolean isScaled(int width, int height) { * @return the ImageIcon for the Image stored by the AbstractIcon */ public ImageIcon getImageIcon() { - return new ImageIcon(getImage()); + Image image = getImage(); + return (image == null) ? null : new ImageIcon(image); } public ImageIcon getImageIcon(int size) { - return new ImageIcon(getImage(size)); + Image image = getImage(size); + return (image == null) ? null : new ImageIcon(image); } public Image getImage() { @@ -109,14 +111,16 @@ public Image getImage(int size) { return getImage(size, -1); } + public Image getImage(int width, int height) { + return getImage(getBaseImage(), width, height); + } + /** * This is used to create the proper image and scale it if required. It also handles null protection * by creating a blank image if required. * @return the created image */ - public Image getImage(int width, int height) { - Image image = getBaseImage(); - + protected Image getImage(Image image, int width, int height) { if (image == null) { return ImageUtil.failStandardImage(); } else if (isScaled(width, height)) { From 8c5014a68c2b9423e7a1a86c5a20460971bb2fce Mon Sep 17 00:00:00 2001 From: Windchild292 Date: Tue, 10 Nov 2020 15:46:11 -0500 Subject: [PATCH 2/4] Dividing between dialogs and choosers as part of implementing LayeredForceIconDialog --- .../megamek/client/ui/swing/ChatLounge.java | 14 +- .../client/ui/swing/CustomPilotView.java | 6 +- .../client/ui/swing/ScenarioDialog.java | 4 +- .../imageChooser/AbstractIconChooser.java | 194 +++--------- .../AbstractIconChooserDialog.java | 156 ++++++++++ .../dialog/imageChooser/CamoChooser.java | 281 ++++++++---------- .../imageChooser/CamoChooserDialog.java | 98 ++++++ .../dialog/imageChooser/PortraitChooser.java | 164 +++++----- .../imageChooser/PortraitChooserDialog.java | 55 ++++ 9 files changed, 560 insertions(+), 412 deletions(-) create mode 100644 megamek/src/megamek/client/ui/swing/dialog/imageChooser/AbstractIconChooserDialog.java create mode 100644 megamek/src/megamek/client/ui/swing/dialog/imageChooser/CamoChooserDialog.java create mode 100644 megamek/src/megamek/client/ui/swing/dialog/imageChooser/PortraitChooserDialog.java diff --git a/megamek/src/megamek/client/ui/swing/ChatLounge.java b/megamek/src/megamek/client/ui/swing/ChatLounge.java index b2f4d4491a7..9670c9e8dad 100644 --- a/megamek/src/megamek/client/ui/swing/ChatLounge.java +++ b/megamek/src/megamek/client/ui/swing/ChatLounge.java @@ -68,7 +68,7 @@ import megamek.client.generator.RandomCallsignGenerator; import megamek.client.ui.Messages; import megamek.client.ui.swing.boardview.BoardView1; -import megamek.client.ui.swing.dialog.imageChooser.CamoChooser; +import megamek.client.ui.swing.dialog.imageChooser.CamoChooserDialog; import megamek.client.ui.swing.util.MenuScroller; import megamek.client.ui.swing.util.PlayerColors; import megamek.client.ui.swing.widget.SkinSpecification; @@ -177,7 +177,7 @@ public void doneLoading() { } }; - private CamoChooser camoDialog; + private CamoChooserDialog camoDialog; //region Action Commands private static final String NAME_COMMAND = "NAME"; @@ -458,7 +458,7 @@ public String getToolTipText(MouseEvent e) { butCamo.setPreferredSize(new Dimension(84, 72)); butCamo.setActionCommand("camo"); butCamo.addActionListener(e -> { - // Show the CamoChooser for the selected player + // Show the CamoChooserDialog for the selected player IPlayer player = getPlayerSelected().getLocalPlayer(); int result = camoDialog.showDialog(player); @@ -477,7 +477,7 @@ public String getToolTipText(MouseEvent e) { butCamo.setIcon(player.getCamouflage().getImageIcon()); getPlayerSelected().sendPlayerInfo(); }); - camoDialog = new CamoChooser(clientgui.getFrame()); + camoDialog = new CamoChooserDialog(clientgui.getFrame()); refreshCamos(); butChangeStart = new JButton(Messages.getString("ChatLounge.butChangeStart")); @@ -2341,7 +2341,7 @@ public void customizeMech(Entity entity) { } /** - * Displays a CamoChooser to choose an individual camo for + * Displays a CamoChooserDialog to choose an individual camo for * the given vector of entities. The camo will only be applied * to units configurable by the local player, i.e. his own units * or those of his bots. @@ -2351,9 +2351,9 @@ public void mechCamo(Vector entities) { return; } - // Display the CamoChooser and await the result + // Display the CamoChooserDialog and await the result // The dialog is preset to the first selected unit's settings - CamoChooser mcd = new CamoChooser(clientgui.getFrame()); + CamoChooserDialog mcd = new CamoChooserDialog(clientgui.getFrame()); int result = mcd.showDialog(entities.get(0)); // If the dialog was canceled or nothing was selected, do nothing diff --git a/megamek/src/megamek/client/ui/swing/CustomPilotView.java b/megamek/src/megamek/client/ui/swing/CustomPilotView.java index ed0ffbdc5c6..c61d7d87930 100644 --- a/megamek/src/megamek/client/ui/swing/CustomPilotView.java +++ b/megamek/src/megamek/client/ui/swing/CustomPilotView.java @@ -36,8 +36,8 @@ import megamek.client.generator.RandomCallsignGenerator; import megamek.client.ui.GBC; import megamek.client.ui.Messages; -import megamek.client.ui.swing.dialog.imageChooser.AbstractIconChooser; -import megamek.client.ui.swing.dialog.imageChooser.PortraitChooser; +import megamek.client.ui.swing.dialog.imageChooser.AbstractIconChooserDialog; +import megamek.client.ui.swing.dialog.imageChooser.PortraitChooserDialog; import megamek.common.Entity; import megamek.common.EntitySelector; import megamek.common.Infantry; @@ -102,7 +102,7 @@ public CustomPilotView(CustomMechDialog parent, Entity entity, int slot, boolean portraitButton.setPreferredSize(new Dimension(72, 72)); portraitButton.setName("portrait"); portraitButton.addActionListener(e -> { - AbstractIconChooser portraitDialog = new PortraitChooser(parent, + AbstractIconChooserDialog portraitDialog = new PortraitChooserDialog(parent, entity.getCrew().getPortrait(slot)); int result = portraitDialog.showDialog(); if (result == JOptionPane.OK_OPTION) { diff --git a/megamek/src/megamek/client/ui/swing/ScenarioDialog.java b/megamek/src/megamek/client/ui/swing/ScenarioDialog.java index e2751b093f8..dc4cd4e5b52 100644 --- a/megamek/src/megamek/client/ui/swing/ScenarioDialog.java +++ b/megamek/src/megamek/client/ui/swing/ScenarioDialog.java @@ -30,7 +30,7 @@ import javax.swing.SwingConstants; import megamek.client.ui.Messages; -import megamek.client.ui.swing.dialog.imageChooser.CamoChooser; +import megamek.client.ui.swing.dialog.imageChooser.CamoChooserDialog; import megamek.common.IPlayer; import megamek.common.Player; import megamek.common.icons.AbstractIcon; @@ -79,7 +79,7 @@ public ScenarioDialog(final JFrame frame, Player[] pa) { curButton.setText(Messages.getString("MegaMek.NoCamoBtn")); curButton.setPreferredSize(new Dimension(84, 72)); - CamoChooser camoDialog = new CamoChooser(frame); + CamoChooserDialog camoDialog = new CamoChooserDialog(frame); curButton.addActionListener(e -> { int result = camoDialog.showDialog(curPlayer); diff --git a/megamek/src/megamek/client/ui/swing/dialog/imageChooser/AbstractIconChooser.java b/megamek/src/megamek/client/ui/swing/dialog/imageChooser/AbstractIconChooser.java index 4ddd187cf9b..a346a3580f0 100644 --- a/megamek/src/megamek/client/ui/swing/dialog/imageChooser/AbstractIconChooser.java +++ b/megamek/src/megamek/client/ui/swing/dialog/imageChooser/AbstractIconChooser.java @@ -18,61 +18,28 @@ */ package megamek.client.ui.swing.dialog.imageChooser; -import java.awt.BorderLayout; -import java.awt.Dimension; -import java.awt.FlowLayout; -import java.awt.Window; -import java.awt.event.MouseEvent; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.Iterator; -import java.util.List; -import java.util.regex.Pattern; +import megamek.client.ui.swing.GUIPreferences; +import megamek.common.annotations.Nullable; +import megamek.common.icons.AbstractIcon; +import megamek.common.util.fileUtils.DirectoryItems; -import javax.swing.JButton; -import javax.swing.JDialog; -import javax.swing.JLabel; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.JSplitPane; -import javax.swing.JTextField; -import javax.swing.JTree; -import javax.swing.ListCellRenderer; -import javax.swing.ScrollPaneConstants; -import javax.swing.UIManager; +import javax.swing.*; import javax.swing.border.EmptyBorder; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; -import javax.swing.event.MouseInputAdapter; import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.TreePath; +import java.awt.*; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; +import java.util.regex.Pattern; -import megamek.client.ui.Messages; -import megamek.client.ui.swing.GUIPreferences; -import megamek.common.annotations.Nullable; -import megamek.common.icons.AbstractIcon; -import megamek.common.util.fileUtils.DirectoryItems; - -/** - * Creates a dialog that allows players to select a directory from - * a directory tree and choose an image from the images in that directory. - * Subclasses must provide the getItems() method that translates - * a given category (directory) selected in the tree to a list - * of items (images) to show in the list. - * Subclasses can provide getSearchedItems() that translates a given search - * String to the list of "found" items. If this is provided, showSearch(true) - * should be called in the constructor to show the search panel. - */ -public abstract class AbstractIconChooser extends JDialog implements TreeSelectionListener { +public abstract class AbstractIconChooser extends JPanel implements TreeSelectionListener { //region Variable Declarations - private static final long serialVersionUID = -7836502700465322620L; - protected static final GUIPreferences GUIP = GUIPreferences.getInstance(); - // display frames private JSplitPane splitPane; @@ -85,28 +52,13 @@ public abstract class AbstractIconChooser extends JDialog implements TreeSelecti // image selection list protected ImageList imageList; - /** True when the user canceled. */ - private boolean wasCanceled = false; - /** When true, icons from all subdirectories of the current selection are shown. */ protected boolean includeSubDirs = true; //endregion Variable Declarations //region Constructors - /** - * Creates a dialog that allows players to choose a directory from - * a directory tree and an image from the images in that directory. - * - * @param parent The Window (dialog or frame) hosting this dialog - * @param title the dialog title - * @param renderer A ListCellRenderer to show the images - * @param tree the JTree with the directories - */ - public AbstractIconChooser(Window parent, AbstractIcon icon, String title, - ListCellRenderer renderer, JTree tree) { - super(parent, title, ModalityType.APPLICATION_MODAL); - - initialize(renderer, tree); + public AbstractIconChooser(JTree tree, AbstractIcon icon) { + initialize(tree); if (icon != null) { setSelection(icon); @@ -115,17 +67,9 @@ public AbstractIconChooser(Window parent, AbstractIcon icon, String title, //endregion Constructors //region Initialization - private void initialize(ListCellRenderer renderer, JTree tree) { + private void initialize(JTree tree) { // Set up the image list (right panel) - imageList = new ImageList(renderer); - imageList.addMouseListener(new MouseInputAdapter() { - @Override - public void mouseClicked(MouseEvent e) { - if (e.getClickCount() == 2) { - select(); - } - } - }); + imageList = new ImageList(new AbstractIconRenderer()); JScrollPane scrpImages = new JScrollPane(imageList); scrpImages.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); scrpImages.setMinimumSize(new Dimension(500, 240)); @@ -139,42 +83,11 @@ public void mouseClicked(MouseEvent e) { splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, scrpTree, scrpImages); splitPane.setResizeWeight(0.5); + splitPane.setDividerLocation(GUIPreferences.getInstance().getInt(GUIPreferences.IMAGE_CHOOSER_SPLIT_POS)); + setLayout(new BorderLayout()); - JPanel searchPanel = searchPanel(); - add(searchPanel, BorderLayout.PAGE_START); + add(searchPanel(), BorderLayout.PAGE_START); add(splitPane, BorderLayout.CENTER); - add(buttonPanel(), BorderLayout.PAGE_END); - - // Size and position of the dialog - setMinimumSize(new Dimension(480, 240)); - splitPane.setDividerLocation(GUIP.getInt(GUIPreferences.IMAGE_CHOOSER_SPLIT_POS)); - setSize(GUIP.getImageChoiceSizeWidth(), GUIP.getImageChoiceSizeHeight()); - setLocation(GUIP.getImageChoicePosX(), GUIP.getImageChoicePosY()); - - // Make the close "X" cancel the dialog - setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); - addWindowListener(new WindowAdapter() { - @Override - public void windowClosing(WindowEvent e) { - cancel(); - } - }); - } - - /** Constructs the bottom panel with the Okay and Cancel buttons. */ - private JPanel buttonPanel() { - JPanel panel = new JPanel(new FlowLayout(FlowLayout.CENTER, 20, 2)); - - JButton btnCancel = new JButton(Messages.getString("Cancel")); - btnCancel.addActionListener(evt -> cancel()); - - JButton btnOkay = new JButton(Messages.getString("Okay")); - btnOkay.addActionListener(evt -> select()); - - panel.add(btnOkay); - panel.add(btnCancel); - panel.setBorder(new EmptyBorder(5, 5, 5, 5)); - return panel; } /** Constructs a functions panel containing the search bar. */ @@ -252,7 +165,8 @@ private void updateSearch(String contents) { } /** Returns the selected AbstractIcon. May be null. */ - public @Nullable AbstractIcon getSelectedItem() { + public @Nullable + AbstractIcon getSelectedItem() { return imageList.getSelectedValue(); } @@ -261,33 +175,23 @@ public int getSelectedIndex() { return imageList.getSelectedIndex(); } - /** Activates the dialog and returns if the user cancelled. */ - public int showDialog() { - wasCanceled = false; - setVisible(true); - // After returning from the modal dialog, save settings the return whether it was cancelled or not... - saveWindowSettings(); - return wasCanceled ? JOptionPane.CANCEL_OPTION : JOptionPane.OK_OPTION; - } - - /** Called when the Okay button is pressed or an image is double-clicked. */ - protected void select() { - wasCanceled = false; - setVisible(false); - } - - private void cancel() { - wasCanceled = true; - setVisible(false); - } + /** + * This is used to refresh the contents of the directory + */ + protected abstract void refreshDirectory(); - /** Saves the position, size and split of the dialog. */ - private void saveWindowSettings() { - GUIP.setValue(GUIPreferences.IMAGE_CHOOSER_POS_X, getLocation().x); - GUIP.setValue(GUIPreferences.IMAGE_CHOOSER_POS_Y, getLocation().y); - GUIP.setValue(GUIPreferences.IMAGE_CHOOSER_SIZE_WIDTH, getSize().width); - GUIP.setValue(GUIPreferences.IMAGE_CHOOSER_SIZE_HEIGHT, getSize().height); - GUIP.setValue(GUIPreferences.IMAGE_CHOOSER_SPLIT_POS, splitPane.getDividerLocation()); + /** + * This method is to ONLY be called by those methods overwriting the abstract refreshDirectory + * above + * @param newTree the new directory tree + */ + protected void refreshDirectory(JTree newTree) { + treeCategories.removeTreeSelectionListener(this); + treeCategories = newTree; + treeCategories.addTreeSelectionListener(this); + scrpTree = new JScrollPane(treeCategories); + splitPane.setLeftComponent(scrpTree); + splitPane.setDividerLocation(GUIPreferences.getInstance().getInt(GUIPreferences.IMAGE_CHOOSER_SPLIT_POS)); } /** @@ -295,7 +199,7 @@ private void saveWindowSettings() { * Returns a list of items that should be shown for the category which * is given as a Treepath. */ - protected abstract List getItems(String category); + protected abstract java.util.List getItems(String category); /** * Called when at least 3 characters are entered into the search bar. @@ -303,7 +207,7 @@ private void saveWindowSettings() { * @param searchString the string to search for * @return a list of icons that fit the provided search string */ - protected List getSearchedItems(String searchString) { + protected java.util.List getSearchedItems(String searchString) { // For a category that contains the search string, all its items // are added to the list. Additionally, all items that contain // the search string are added. @@ -361,23 +265,9 @@ protected void setSelection(AbstractIcon icon) { } } - /** - * This is used to refresh the contents of the directory - */ - protected abstract void refreshDirectory(); - - /** - * This method is to ONLY be called by those methods overwriting the abstract refreshDirectory - * above - * @param newTree the new directory tree - */ - protected void refreshDirectory(JTree newTree) { - treeCategories.removeTreeSelectionListener(this); - treeCategories = newTree; - treeCategories.addTreeSelectionListener(this); - scrpTree = new JScrollPane(treeCategories); - splitPane.setLeftComponent(scrpTree); - splitPane.setDividerLocation(GUIP.getInt(GUIPreferences.IMAGE_CHOOSER_SPLIT_POS)); + public void saveWindowSettings() { + GUIPreferences.getInstance().setValue(GUIPreferences.IMAGE_CHOOSER_SPLIT_POS, + splitPane.getDividerLocation()); } @Override diff --git a/megamek/src/megamek/client/ui/swing/dialog/imageChooser/AbstractIconChooserDialog.java b/megamek/src/megamek/client/ui/swing/dialog/imageChooser/AbstractIconChooserDialog.java new file mode 100644 index 00000000000..7c553d3fbfd --- /dev/null +++ b/megamek/src/megamek/client/ui/swing/dialog/imageChooser/AbstractIconChooserDialog.java @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2020 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MegaMek. + * + * MegaMek 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. + * + * MegaMek 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 MegaMek. If not, see . + */ +package megamek.client.ui.swing.dialog.imageChooser; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Window; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; + +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.border.EmptyBorder; + +import megamek.client.ui.Messages; +import megamek.client.ui.swing.GUIPreferences; +import megamek.common.icons.AbstractIcon; + +/** + * Creates a dialog that allows players to select a directory from + * a directory tree and choose an image from the images in that directory. + * Subclasses must provide the getItems() method that translates + * a given category (directory) selected in the tree to a list + * of items (images) to show in the list. + * Subclasses can provide getSearchedItems() that translates a given search + * String to the list of "found" items. If this is provided, showSearch(true) + * should be called in the constructor to show the search panel. + */ +public abstract class AbstractIconChooserDialog extends JDialog { + //region Variable Declarations + private static final long serialVersionUID = -7836502700465322620L; + protected static final GUIPreferences GUIP = GUIPreferences.getInstance(); + + private AbstractIconChooser chooser; + + /** True when the user canceled. */ + private boolean wasCanceled = false; + //endregion Variable Declarations + + //region Constructors + /** + * Creates a dialog that allows players to choose a directory from + * a directory tree and an image from the images in that directory. + * + * @param parent The Window (dialog or frame) hosting this dialog + * @param title the dialog title + * @param chooser the icon chooser display panel + */ + public AbstractIconChooserDialog(Window parent, String title, AbstractIconChooser chooser) { + super(parent, title, ModalityType.APPLICATION_MODAL); + this.chooser = chooser; + + initialize(); + } + //endregion Constructors + + //region Initialization + private void initialize() { + setLayout(new BorderLayout()); + add(getChooser(), BorderLayout.CENTER); + add(buttonPanel(), BorderLayout.PAGE_END); + + // Size and position of the dialog + setMinimumSize(new Dimension(480, 240)); + setSize(GUIP.getImageChoiceSizeWidth(), GUIP.getImageChoiceSizeHeight()); + setLocation(GUIP.getImageChoicePosX(), GUIP.getImageChoicePosY()); + + // Make the close "X" cancel the dialog + setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); + addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + cancel(); + } + }); + } + + /** Constructs the bottom panel with the Okay and Cancel buttons. */ + private JPanel buttonPanel() { + JPanel panel = new JPanel(new FlowLayout(FlowLayout.CENTER, 20, 2)); + + JButton btnCancel = new JButton(Messages.getString("Cancel")); + btnCancel.addActionListener(evt -> cancel()); + + JButton btnOkay = new JButton(Messages.getString("Okay")); + btnOkay.addActionListener(evt -> select()); + + panel.add(btnOkay); + panel.add(btnCancel); + panel.setBorder(new EmptyBorder(5, 5, 5, 5)); + return panel; + } + //endregion Initialization + + //region Getters/Setters + protected AbstractIconChooser getChooser() { + return chooser; + } + + public AbstractIcon getSelectedItem() { + return getChooser().getSelectedItem(); + } + + public int getSelectedIndex() { + return getChooser().getSelectedIndex(); + } + //endregion Getters/Setters + + /** Activates the dialog and returns if the user cancelled. */ + public int showDialog() { + wasCanceled = false; + setVisible(true); + // After returning from the modal dialog, save settings the return whether it was cancelled or not... + saveWindowSettings(); + return wasCanceled ? JOptionPane.CANCEL_OPTION : JOptionPane.OK_OPTION; + } + + /** Called when the Okay button is pressed or an image is double-clicked. */ + protected void select() { + wasCanceled = false; + setVisible(false); + } + + private void cancel() { + wasCanceled = true; + setVisible(false); + } + + /** Saves the position, size and split of the dialog. */ + private void saveWindowSettings() { + GUIP.setValue(GUIPreferences.IMAGE_CHOOSER_POS_X, getLocation().x); + GUIP.setValue(GUIPreferences.IMAGE_CHOOSER_POS_Y, getLocation().y); + GUIP.setValue(GUIPreferences.IMAGE_CHOOSER_SIZE_WIDTH, getSize().width); + GUIP.setValue(GUIPreferences.IMAGE_CHOOSER_SIZE_HEIGHT, getSize().height); + getChooser().saveWindowSettings(); + } +} diff --git a/megamek/src/megamek/client/ui/swing/dialog/imageChooser/CamoChooser.java b/megamek/src/megamek/client/ui/swing/dialog/imageChooser/CamoChooser.java index 4cddca790f1..62a92dff981 100644 --- a/megamek/src/megamek/client/ui/swing/dialog/imageChooser/CamoChooser.java +++ b/megamek/src/megamek/client/ui/swing/dialog/imageChooser/CamoChooser.java @@ -1,161 +1,120 @@ -/* - * MegaMek - Copyright (C) 2004 Ben Mazur (bmazur@sev.org) - * Copyright © 2013 Edward Cullen (eddy@obsessedcomputers.co.uk) - * MegaMek - Copyright (C) 2020 - The MegaMek Team - * - * 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 megamek.client.ui.swing.dialog.imageChooser; - -import java.awt.Window; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import megamek.client.ui.Messages; -import megamek.client.ui.swing.tileset.MMStaticDirectoryManager; -import megamek.common.Configuration; -import megamek.common.Entity; -import megamek.common.IPlayer; -import megamek.common.icons.Camouflage; -import megamek.common.icons.AbstractIcon; -import megamek.common.util.fileUtils.DirectoryItems; - -/** - * This dialog allows players to select the camo pattern (or color) used by - * their units during the game. It automatically fills itself with all the color - * choices in IPlayer and all the camo patterns in the - * {@link Configuration#camoDir()} directory tree. - * Should be shown by using showDialog(IPlayer) or showDialog(Entity). These - * methods return either JOptionPane.OK_OPTION or .CANCEL_OPTION. - * - * @see AbstractIconChooser - */ -public class CamoChooser extends AbstractIconChooser { - //region Variable Declarations - private static final long serialVersionUID = -8060324139099113292L; - - /** True when an individual camo is being selected for an entity. */ - private boolean individualCamo = false; - - /** When an individual camo is being selected, the player's camo is displayed as a reset option. */ - private AbstractIcon entityOwnerCamo; - //endregion Variable Declarations - - //region Constructors - /** Creates a dialog that allows players to choose a camo pattern. */ - public CamoChooser(Window parent) { - super(parent, null, Messages.getString("CamoChoiceDialog.select_camo_pattern"), - new AbstractIconRenderer(), new CamoChooserTree()); - } - //endregion Constructors - - @Override - protected DirectoryItems getDirectory() { - return MMStaticDirectoryManager.getCamouflage(); - } - - @Override - protected AbstractIcon createIcon(String category, String filename) { - return new Camouflage(category, filename); - } - - /** - * Show the camo choice dialog and pre-select the camo or color - * of the given player. The dialog will allow choosing camos - * and colors. Also refreshes the camos from disk. - */ - public int showDialog(IPlayer player) { - refreshDirectory(); - individualCamo = false; - setSelection(player.getCamouflage()); - return showDialog(); - } - - /** - * Show the camo choice dialog and pre-select the camo or color - * of the given entity. The dialog will allow choosing camos - * and the single color of the player owning the entity. - * Also refreshes the camos from disk. - */ - public int showDialog(Entity entity) { - refreshDirectory(); - individualCamo = true; - setEntity(entity); - return showDialog(); - } - - @Override - protected List getItems(String category) { - List result = new ArrayList<>(); - - // If a player camo is being selected, the items presented in the - // NO_CAMO section are the available player colors. - // If an individual camo is being selected, then the only item presented - // in the NO_CAMO section is the owner's camo. This can be chosen - // to remove the individual camo. - if (category.startsWith(Camouflage.NO_CAMOUFLAGE)) { - if (individualCamo) { - result.add(entityOwnerCamo); - } else { - for (String color: IPlayer.colorNames) { - result.add(createIcon(Camouflage.NO_CAMOUFLAGE, color)); - } - } - return result; - } - - // In any other camo section, the camos of the selected category are - // presented. When the includeSubDirs flag is true, all categories - // below the selected one are also presented. - if (includeSubDirs) { - for (Iterator catNames = getDirectory().getCategoryNames(); catNames.hasNext(); ) { - String tcat = catNames.next(); - if (tcat.startsWith(category)) { - addCategoryItems(tcat, result); - } - } - } else { - addCategoryItems(category, result); - } - return result; - } - - /** Reloads the camo directory from disk. */ - @Override - protected void refreshDirectory() { - MMStaticDirectoryManager.refreshCamouflageDirectory(); - refreshDirectory(new CamoChooserTree()); - } - - /** - * Preselects the Tree and the Images with the given entity's camo - * or the owner's, if the entity has no individual camo. Also stores - * the owner's camo to present a "revert to no individual" camo option. - */ - private void setEntity(Entity entity) { - // Store the owner's camo to display as the only "No Camo" option - // This may be a color - String item = entity.getOwner().getCamouflage().getFilename(); - if (entity.getOwner().getCamouflage().getCategory().equals(Camouflage.NO_CAMOUFLAGE)) { - item = IPlayer.colorNames[entity.getOwner().getColorIndex()]; - } - entityOwnerCamo = createIcon(entity.getOwner().getCamouflage().getCategory(), item); - - // Set the camo category and filename to the entity's if it has one, - // otherwise to the corresponding player's camo category - if (entity.getCamouflage().isDefault()) { - setSelection(entity.getOwner().getCamouflage()); - } else { - setSelection(entity.getCamouflage()); - } - } -} +/* + * Copyright (c) 2020 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MegaMek. + * + * MegaMek 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. + * + * MegaMek 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 MegaMek. If not, see . + */ +package megamek.client.ui.swing.dialog.imageChooser; + +import megamek.client.ui.swing.tileset.MMStaticDirectoryManager; +import megamek.common.IPlayer; +import megamek.common.icons.AbstractIcon; +import megamek.common.icons.Camouflage; +import megamek.common.util.fileUtils.DirectoryItems; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class CamoChooser extends AbstractIconChooser { + //region Variable Declarations + /** True when an individual camo is being selected for an entity. */ + private boolean individualCamo = false; + + /** When an individual camo is being selected, the player's camo is displayed as a reset option. */ + private AbstractIcon entityOwnerCamo; + //endregion Variable Declarations + + //region Constructors + public CamoChooser() { + this(null); + } + + public CamoChooser(AbstractIcon icon) { + super(new CamoChooserTree(), icon); + } + //endregion Constructors + + //region Getters/Setters + public boolean isIndividualCamo() { + return individualCamo; + } + + public void setIndividualCamo(boolean individualCamo) { + this.individualCamo = individualCamo; + } + + public AbstractIcon getEntityOwnerCamo() { + return entityOwnerCamo; + } + + public void setEntityOwnerCamo(AbstractIcon entityOwnerCamo) { + this.entityOwnerCamo = entityOwnerCamo; + } + //endregion Getters/Setters + + @Override + protected DirectoryItems getDirectory() { + return MMStaticDirectoryManager.getCamouflage(); + } + + @Override + protected AbstractIcon createIcon(String category, String filename) { + return new Camouflage(category, filename); + } + + @Override + protected List getItems(String category) { + List result = new ArrayList<>(); + + // If a player camo is being selected, the items presented in the + // NO_CAMO section are the available player colors. + // If an individual camo is being selected, then the only item presented + // in the NO_CAMO section is the owner's camo. This can be chosen + // to remove the individual camo. + if (category.startsWith(Camouflage.NO_CAMOUFLAGE)) { + if (individualCamo) { + result.add(entityOwnerCamo); + } else { + for (String color: IPlayer.colorNames) { + result.add(createIcon(Camouflage.NO_CAMOUFLAGE, color)); + } + } + return result; + } + + // In any other camo section, the camos of the selected category are + // presented. When the includeSubDirs flag is true, all categories + // below the selected one are also presented. + if (includeSubDirs) { + for (Iterator catNames = getDirectory().getCategoryNames(); catNames.hasNext(); ) { + String tcat = catNames.next(); + if (tcat.startsWith(category)) { + addCategoryItems(tcat, result); + } + } + } else { + addCategoryItems(category, result); + } + return result; + } + + /** Reloads the camo directory from disk. */ + @Override + protected void refreshDirectory() { + MMStaticDirectoryManager.refreshCamouflageDirectory(); + refreshDirectory(new CamoChooserTree()); + } +} diff --git a/megamek/src/megamek/client/ui/swing/dialog/imageChooser/CamoChooserDialog.java b/megamek/src/megamek/client/ui/swing/dialog/imageChooser/CamoChooserDialog.java new file mode 100644 index 00000000000..d7b898a5c74 --- /dev/null +++ b/megamek/src/megamek/client/ui/swing/dialog/imageChooser/CamoChooserDialog.java @@ -0,0 +1,98 @@ +/* + * MegaMek - Copyright (C) 2004 Ben Mazur (bmazur@sev.org) + * Copyright © 2013 Edward Cullen (eddy@obsessedcomputers.co.uk) + * MegaMek - Copyright (C) 2020 - The MegaMek Team + * + * 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 megamek.client.ui.swing.dialog.imageChooser; + +import java.awt.Window; + +import megamek.client.ui.Messages; +import megamek.common.Configuration; +import megamek.common.Entity; +import megamek.common.IPlayer; +import megamek.common.icons.Camouflage; + +/** + * This dialog allows players to select the camo pattern (or color) used by + * their units during the game. It automatically fills itself with all the color + * choices in IPlayer and all the camo patterns in the + * {@link Configuration#camoDir()} directory tree. + * Should be shown by using showDialog(IPlayer) or showDialog(Entity). These + * methods return either JOptionPane.OK_OPTION or .CANCEL_OPTION. + * + * @see AbstractIconChooserDialog + */ +public class CamoChooserDialog extends AbstractIconChooserDialog { + //region Variable Declarations + private static final long serialVersionUID = -8060324139099113292L; + //endregion Variable Declarations + + //region Constructors + /** Creates a dialog that allows players to choose a camo pattern. */ + public CamoChooserDialog(Window parent) { + super(parent, Messages.getString("CamoChoiceDialog.select_camo_pattern"), new CamoChooser()); + } + //endregion Constructors + + @Override + protected CamoChooser getChooser() { + return (CamoChooser) super.getChooser(); + } + + /** + * Show the camo choice dialog and pre-select the camo or color + * of the given player. The dialog will allow choosing camos + * and colors. Also refreshes the camos from disk. + */ + public int showDialog(IPlayer player) { + getChooser().refreshDirectory(); + getChooser().setIndividualCamo(false); + getChooser().setSelection(player.getCamouflage()); + return showDialog(); + } + + /** + * Show the camo choice dialog and pre-select the camo or color + * of the given entity. The dialog will allow choosing camos + * and the single color of the player owning the entity. + * Also refreshes the camos from disk. + */ + public int showDialog(Entity entity) { + getChooser().refreshDirectory(); + getChooser().setIndividualCamo(true); + setEntity(entity); + return showDialog(); + } + + /** + * Preselects the Tree and the Images with the given entity's camo + * or the owner's, if the entity has no individual camo. Also stores + * the owner's camo to present a "revert to no individual" camo option. + */ + private void setEntity(Entity entity) { + // Store the owner's camo to display as the only "No Camo" option + // This may be a color + String item = entity.getOwner().getCamouflage().getFilename(); + if (entity.getOwner().getCamouflage().getCategory().equals(Camouflage.NO_CAMOUFLAGE)) { + item = IPlayer.colorNames[entity.getOwner().getColorIndex()]; + } + getChooser().setEntityOwnerCamo(getChooser() + .createIcon(entity.getOwner().getCamouflage().getCategory(), item)); + + // Set the camo category and filename to the entity's if it has one, + // otherwise to the corresponding player's camo category + getChooser().setSelection((entity.getCamouflage()).isDefault() + ? entity.getOwner().getCamouflage(): entity.getCamouflage()); + } +} diff --git a/megamek/src/megamek/client/ui/swing/dialog/imageChooser/PortraitChooser.java b/megamek/src/megamek/client/ui/swing/dialog/imageChooser/PortraitChooser.java index 9f661a1c763..6ee18c1bc4f 100644 --- a/megamek/src/megamek/client/ui/swing/dialog/imageChooser/PortraitChooser.java +++ b/megamek/src/megamek/client/ui/swing/dialog/imageChooser/PortraitChooser.java @@ -1,87 +1,77 @@ -/* - * Copyright (c) 2020 - The MegaMek Team. All Rights Reserved. - * - * This file is part of MegaMek. - * - * MegaMek 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. - * - * MegaMek 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 MegaMek. If not, see . - */ -package megamek.client.ui.swing.dialog.imageChooser; - -import java.awt.Window; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import megamek.client.ui.Messages; -import megamek.client.ui.swing.tileset.MMStaticDirectoryManager; -import megamek.common.Configuration; -import megamek.common.icons.AbstractIcon; -import megamek.common.icons.Portrait; -import megamek.common.util.fileUtils.DirectoryItems; - -/** - * This dialog allows players to select a portrait - * It automatically fills itself with the portraits - * in the {@link Configuration#portraitImagesDir()} directory tree. - * Should be shown by using showDialog(). This method - * returns either JOptionPane.OK_OPTION or .CANCEL_OPTION. - * - * @see AbstractIconChooser - */ -public class PortraitChooser extends AbstractIconChooser { - private static final long serialVersionUID = 6487684461690549139L; - - /** Creates a dialog that allows players to choose a portrait. */ - public PortraitChooser(Window parent, AbstractIcon icon) { - super(parent, icon, Messages.getString("PortraitChoiceDialog.select_portrait"), - new AbstractIconRenderer(), new PortraitChooserTree()); - } - - @Override - protected DirectoryItems getDirectory() { - return MMStaticDirectoryManager.getPortraits(); - } - - @Override - protected AbstractIcon createIcon(String category, String filename) { - return new Portrait(category, filename); - } - - @Override - protected List getItems(String category) { - List result = new ArrayList<>(); - - // The portraits of the selected category are presented. - // When the includeSubDirs flag is true, all categories - // below the selected one are also presented. - if (includeSubDirs) { - for (Iterator catNames = getDirectory().getCategoryNames(); catNames.hasNext(); ) { - String tcat = catNames.next(); - if (tcat.startsWith(category)) { - addCategoryItems(tcat, result); - } - } - } else { - addCategoryItems(category, result); - } - return result; - } - - /** Reloads the portrait directory from disk. */ - @Override - protected void refreshDirectory() { - MMStaticDirectoryManager.refreshPortraitDirectory(); - refreshDirectory(new PortraitChooserTree()); - } -} +/* + * Copyright (c) 2020 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MegaMek. + * + * MegaMek 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. + * + * MegaMek 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 MegaMek. If not, see . + */ +package megamek.client.ui.swing.dialog.imageChooser; + +import megamek.client.ui.swing.tileset.MMStaticDirectoryManager; +import megamek.common.icons.AbstractIcon; +import megamek.common.icons.Portrait; +import megamek.common.util.fileUtils.DirectoryItems; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class PortraitChooser extends AbstractIconChooser { + //region Constructors + public PortraitChooser() { + this(null); + } + + public PortraitChooser(AbstractIcon icon) { + super(new PortraitChooserTree(), icon); + } + //endregion Constructors + + @Override + protected DirectoryItems getDirectory() { + return MMStaticDirectoryManager.getPortraits(); + } + + @Override + protected AbstractIcon createIcon(String category, String filename) { + return new Portrait(category, filename); + } + + @Override + protected List getItems(String category) { + List result = new ArrayList<>(); + + // The portraits of the selected category are presented. + // When the includeSubDirs flag is true, all categories + // below the selected one are also presented. + if (includeSubDirs) { + for (Iterator catNames = getDirectory().getCategoryNames(); catNames.hasNext(); ) { + String tcat = catNames.next(); + if (tcat.startsWith(category)) { + addCategoryItems(tcat, result); + } + } + } else { + addCategoryItems(category, result); + } + return result; + } + + /** Reloads the portrait directory from disk. */ + @Override + protected void refreshDirectory() { + MMStaticDirectoryManager.refreshPortraitDirectory(); + refreshDirectory(new PortraitChooserTree()); + } +} diff --git a/megamek/src/megamek/client/ui/swing/dialog/imageChooser/PortraitChooserDialog.java b/megamek/src/megamek/client/ui/swing/dialog/imageChooser/PortraitChooserDialog.java new file mode 100644 index 00000000000..6e3dfddcb86 --- /dev/null +++ b/megamek/src/megamek/client/ui/swing/dialog/imageChooser/PortraitChooserDialog.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2020 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MegaMek. + * + * MegaMek 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. + * + * MegaMek 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 MegaMek. If not, see . + */ +package megamek.client.ui.swing.dialog.imageChooser; + +import java.awt.Window; + +import megamek.client.ui.Messages; +import megamek.common.Configuration; +import megamek.common.icons.AbstractIcon; + +/** + * This dialog allows players to select a portrait + * It automatically fills itself with the portraits + * in the {@link Configuration#portraitImagesDir()} directory tree. + * Should be shown by using showDialog(). This method + * returns either JOptionPane.OK_OPTION or .CANCEL_OPTION. + * + * @see AbstractIconChooserDialog + */ +public class PortraitChooserDialog extends AbstractIconChooserDialog { + //region Variable Declarations + private static final long serialVersionUID = 6487684461690549139L; + //endregion Variable Declarations + + //region Constructors + /** Creates a dialog that allows players to choose a portrait. */ + public PortraitChooserDialog(Window parent, AbstractIcon icon) { + super(parent, Messages.getString("PortraitChoiceDialog.select_portrait"), + new PortraitChooser(icon)); + } + //endregion Constructors + + //region Getters + @Override + protected PortraitChooser getChooser() { + return (PortraitChooser) super.getChooser(); + } + //endregion Getters +} From 2e32833117c81ba232fcbb6a77e7ac4e91199ea1 Mon Sep 17 00:00:00 2001 From: Windchild292 Date: Sun, 13 Dec 2020 18:39:28 -0500 Subject: [PATCH 3/4] Fixing issues found during personal review --- .../ui/swing/dialog/imageChooser/AbstractIconChooser.java | 4 ++-- .../swing/dialog/imageChooser/AbstractIconChooserDialog.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/megamek/src/megamek/client/ui/swing/dialog/imageChooser/AbstractIconChooser.java b/megamek/src/megamek/client/ui/swing/dialog/imageChooser/AbstractIconChooser.java index a346a3580f0..e07ed3e3cc1 100644 --- a/megamek/src/megamek/client/ui/swing/dialog/imageChooser/AbstractIconChooser.java +++ b/megamek/src/megamek/client/ui/swing/dialog/imageChooser/AbstractIconChooser.java @@ -199,7 +199,7 @@ protected void refreshDirectory(JTree newTree) { * Returns a list of items that should be shown for the category which * is given as a Treepath. */ - protected abstract java.util.List getItems(String category); + protected abstract List getItems(String category); /** * Called when at least 3 characters are entered into the search bar. @@ -207,7 +207,7 @@ protected void refreshDirectory(JTree newTree) { * @param searchString the string to search for * @return a list of icons that fit the provided search string */ - protected java.util.List getSearchedItems(String searchString) { + protected List getSearchedItems(String searchString) { // For a category that contains the search string, all its items // are added to the list. Additionally, all items that contain // the search string are added. diff --git a/megamek/src/megamek/client/ui/swing/dialog/imageChooser/AbstractIconChooserDialog.java b/megamek/src/megamek/client/ui/swing/dialog/imageChooser/AbstractIconChooserDialog.java index 7c553d3fbfd..16984a34f31 100644 --- a/megamek/src/megamek/client/ui/swing/dialog/imageChooser/AbstractIconChooserDialog.java +++ b/megamek/src/megamek/client/ui/swing/dialog/imageChooser/AbstractIconChooserDialog.java @@ -134,7 +134,7 @@ public int showDialog() { return wasCanceled ? JOptionPane.CANCEL_OPTION : JOptionPane.OK_OPTION; } - /** Called when the Okay button is pressed or an image is double-clicked. */ + /** Called when the Okay button is pressed */ protected void select() { wasCanceled = false; setVisible(false); From 3db606e0ad636c9372cdde63aa7595be4b7eabf4 Mon Sep 17 00:00:00 2001 From: Windchild292 Date: Mon, 14 Dec 2020 14:27:03 -0500 Subject: [PATCH 4/4] Applying changes as per review --- .../dialog/imageChooser/AbstractIconChooser.java | 3 +-- megamek/src/megamek/common/icons/AbstractIcon.java | 13 +++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/megamek/src/megamek/client/ui/swing/dialog/imageChooser/AbstractIconChooser.java b/megamek/src/megamek/client/ui/swing/dialog/imageChooser/AbstractIconChooser.java index e07ed3e3cc1..7aba3e735ea 100644 --- a/megamek/src/megamek/client/ui/swing/dialog/imageChooser/AbstractIconChooser.java +++ b/megamek/src/megamek/client/ui/swing/dialog/imageChooser/AbstractIconChooser.java @@ -165,8 +165,7 @@ private void updateSearch(String contents) { } /** Returns the selected AbstractIcon. May be null. */ - public @Nullable - AbstractIcon getSelectedItem() { + public @Nullable AbstractIcon getSelectedItem() { return imageList.getSelectedValue(); } diff --git a/megamek/src/megamek/common/icons/AbstractIcon.java b/megamek/src/megamek/common/icons/AbstractIcon.java index f601919101c..bf434c81ab0 100644 --- a/megamek/src/megamek/common/icons/AbstractIcon.java +++ b/megamek/src/megamek/common/icons/AbstractIcon.java @@ -91,27 +91,28 @@ protected boolean isScaled(int width, int height) { } /** - * @return the ImageIcon for the Image stored by the AbstractIcon + * @return the ImageIcon for the Image stored by the AbstractIcon. May be null for non-existent + * files */ - public ImageIcon getImageIcon() { + public @Nullable ImageIcon getImageIcon() { Image image = getImage(); return (image == null) ? null : new ImageIcon(image); } - public ImageIcon getImageIcon(int size) { + public @Nullable ImageIcon getImageIcon(int size) { Image image = getImage(size); return (image == null) ? null : new ImageIcon(image); } - public Image getImage() { + public @Nullable Image getImage() { return getImage(0, 0); } - public Image getImage(int size) { + public @Nullable Image getImage(int size) { return getImage(size, -1); } - public Image getImage(int width, int height) { + public @Nullable Image getImage(int width, int height) { return getImage(getBaseImage(), width, height); }