package games.strategy.triplea.ui; import java.util.concurrent.CountDownLatch; import javax.swing.BoxLayout; import javax.swing.JPanel; import javax.swing.border.EmptyBorder; import games.strategy.engine.data.GameData; import games.strategy.engine.data.PlayerID; /** * Abstract superclass for all action panels. <br> */ public abstract class ActionPanel extends JPanel { private static final long serialVersionUID = -5954576036704958641L; private final GameData m_data; private PlayerID m_currentPlayer; protected final MapPanel m_map; private boolean m_active; private CountDownLatch m_latch; private final Object m_latchLock = new Object(); /** Creates new ActionPanel. */ public ActionPanel(final GameData data, final MapPanel map) { m_data = data; m_map = map; setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); setBorder(new EmptyBorder(5, 5, 0, 0)); } protected final boolean isWW2V2() { return games.strategy.triplea.Properties.getWW2V2(m_data); } protected final boolean isWW2V3TechModel() { return games.strategy.triplea.Properties.getWW2V3TechModel(m_data); } protected final boolean isRestrictedPurchase() { return games.strategy.triplea.Properties.getPlacementRestrictedByFactory(m_data); } protected final boolean isSelectableTechRoll() { return games.strategy.triplea.Properties.getSelectableTechRoll(m_data); } /** * Waitfor another thread to call release. * If the thread is interupted, we will return silently. * * <p> * A memory barrier will be crossed both on entering and before exiting this method. * </p> * * <p> * This method will return in the event of the game shutting down. * </p> */ protected void waitForRelease() { if (Thread.currentThread().isInterrupted()) { release(); return; } synchronized (m_latchLock) { if (m_latch != null) { throw new IllegalStateException("Latch not null"); } m_latch = new CountDownLatch(1); m_map.getUIContext().addShutdownLatch(m_latch); } try { m_latch.await(); } catch (final InterruptedException e) { release(); } // cross a memory barrier synchronized (m_latchLock) { } } /** * Release the latch acquired by waitOnNewLatch() * * <p> * This method will crossed on entering this method. * </p> */ protected void release() { synchronized (m_latchLock) { // not set up yet // this is ok as we set up in one thread // and wait in another // if the release happens too early // the user will be able to press done again if (m_latch == null) { return; } m_map.getUIContext().removeShutdownLatch(m_latch); m_latch.countDown(); m_latch = null; } } protected GameData getData() { return m_data; } public void display(final PlayerID player) { m_currentPlayer = player; setActive(true); } protected PlayerID getCurrentPlayer() { return m_currentPlayer; } protected MapPanel getMap() { return m_map; } /** * Called when the history panel shows used to disable the panel * temporarily. */ public void setActive(final boolean aBool) { m_active = aBool; } public boolean getActive() { return m_active; } /** * Refreshes the action panel. Should be run within the swing event queue. */ protected final Runnable REFRESH = () -> { revalidate(); repaint(); }; }