package net.sf.colossus.guiutil;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.AbstractAction;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import net.sf.colossus.util.InstanceTracker;
/**
* Dummy JFrame (KFrame) with menu.
*
* Seems due to some bug, AWT keeps always some reference to the last
* JFrame which has a menu used (or even the last two of those) -
* which will nearly always being some MasterBoard, thus preventing
* MasterBoard and with that very often also the Client (and many other
* related objects) from being properly garbage-collected.
* So, by opening one or two dummy frames, we get the MasterBoards
* free and AWT hold on those dummy frames - which are small and
* don't hurts us much.
* And if the SwingCleanup is done afterwards, we get even rid of
* the dummyFrames.
*
* @author Clemens Katzer
*/
public class DummyFrameWithMenu extends KFrame
{
String id;
private AbstractAction closeBoardAction;
public DummyFrameWithMenu(String nr)
{
super("dummyFrame " + nr);
id = nr;
setupGUI();
}
public static void doOneDummyFrame(String id)
{
DummyFrameWithMenu fdebug = new DummyFrameWithMenu(id);
fdebug.setVisible(false);
fdebug.dispose();
fdebug = null;
}
private void setupGUI()
{
setupActions();
JMenuBar menuBar = new JMenuBar();
this.setJMenuBar(menuBar);
// File menu
JMenu fileMenu = new JMenu("File");
fileMenu.setMnemonic(KeyEvent.VK_F);
menuBar.add(fileMenu);
JMenuItem mi;
mi = fileMenu.add(closeBoardAction);
mi.setMnemonic(KeyEvent.VK_C);
this.pack();
this.setVisible(true);
}
public void setupActions()
{
closeBoardAction = new AbstractAction("Close")
{
public void actionPerformed(ActionEvent e)
{
dispose();
}
};
}
// Special hack to cleanup some static reference to the JFrame
// inside Swing; copied from here:
// http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4907798
// Possibly works only under 1.4.2.
// This is not strictly necessary to ensure proper functioning
// of Colossus; if it does not work, it just means that the last
// displayed JFrame will not be garbage collected, so the GC
// will always be behind with some objects.
// The main reason why I try to ensure this proper cleanup
// is that this way I can use the InstanceTracker in between
// and at program end, to check how well GC cleanup is working
// (would be working )if there weren't this Swing issue.
static public void swingCleanup()
{
SwingReferenceCleanupHacks.cleanupJPopupMenuGlobals(true);
SwingReferenceCleanupHacks.cleanupJMenuBarGlobals();
}
boolean disposed = false;
@Override
public void dispose()
{
if (disposed)
{
return;
}
disposed = true;
super.dispose();
}
/*
* Dummy Main
*
*/
public static void main(String[] args)
{
DummyFrameWithMenu f1 = new DummyFrameWithMenu("1");
DummyFrameWithMenu f2 = new DummyFrameWithMenu("2");
DummyFrameWithMenu f3 = new DummyFrameWithMenu("3");
DebugMethods.waitReturn();
f3.dispose();
f2.dispose();
f1.dispose();
f3 = null;
f1 = null;
f2 = null;
DebugMethods.waitReturn();
InstanceTracker.printStatistics();
Logger LOGGER = Logger.getLogger(DummyFrameWithMenu.class.getName());
LOGGER.log(Level.FINEST,
"\nDummyFrameWithMenu.main() should end now by itself.");
}
}