package net.sf.colossus.guiutil;
import java.lang.reflect.Field;
/**
* 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
*
* @author Clemens Katzer
*/
public class SwingReferenceCleanupHacks
{
public static void cleanupJPopupMenuGlobals(
boolean removeOnlyMenuKeyboardHelpers)
{
try
{
javax.swing.MenuSelectionManager aMenuSelectionManager = javax.swing.MenuSelectionManager
.defaultManager();
Object anObject = safelyGetReflectedField(
"javax.swing.MenuSelectionManager", "listenerList",
aMenuSelectionManager);
if (null != anObject)
{
javax.swing.event.EventListenerList anEventListenerList = (javax.swing.event.EventListenerList)anObject;
Object[] listeners = anEventListenerList.getListenerList();
if (removeOnlyMenuKeyboardHelpers)
{
// This gives us back an Array and the even entries are the
// class type. In this case they are all javax.swing.event.ChangeListeners
// The odd number entries are the instance themselves.
// We were having a problem just blindly removing all of the listeners
// because the next time a popupmenu was show, it wasn't getting dispose (i.e you
// right click and click off to cancel and the menu doesn't go away). We traced
// the memory leak down to this javax.swing.plaf.basic.BasicPopupMenuUI$MenuKeyboardHelper
// holding onto an instance of the JRootPane. Therefore we just remove all of the
// instances of this class and it cleans up fine and seems to work.
Class<?> aClass = Class
.forName("javax.swing.plaf.basic.BasicPopupMenuUI$MenuKeyboardHelper");
for (int i = listeners.length - 1; i >= 0; i -= 2)
{
if (aClass.isInstance(listeners[i]))
{
aMenuSelectionManager
.removeChangeListener((javax.swing.event.ChangeListener)listeners[i]);
}
}
}
else
{
for (int i = listeners.length - 1; i >= 0; i -= 2)
{
aMenuSelectionManager
.removeChangeListener((javax.swing.event.ChangeListener)listeners[i]);
}
}
}
}
catch (Exception e)
{
// e.printStackTrace();
}
try
{
javax.swing.ActionMap anActionMap = (javax.swing.ActionMap)javax.swing.UIManager
.getLookAndFeelDefaults().get("PopupMenu.actionMap");
while (anActionMap != null)
{
Object[] keys = { "press", "release" };
boolean anyFound = false;
for (Object aKey : keys)
{
Object aValue = anActionMap.get(aKey);
anyFound = anyFound || aValue != null;
anActionMap.remove(aKey);
}
if (!anyFound)
{
break;
}
anActionMap = anActionMap.getParent();
}
}
catch (Exception e)
{
// e.printStackTrace();
}
SafelySetReflectedFieldToNull(
"javax.swing.plaf.basic.BasicPopupMenuUI", "menuKeyboardHelper",
null);
Object anObject = safelyGetReflectedField(
"com.sun.java.swing.plaf.windows.WindowsPopupMenuUI",
"mnemonicListener", null);
if (null != anObject)
{
SafelySetReflectedFieldToNull(anObject.getClass(), "repaintRoot",
anObject);
}
}
private static void SafelySetReflectedFieldToNull(Class<?> aClass,
String aFieldName, Object anObject)
{
try
{
java.lang.reflect.Field aField = aClass
.getDeclaredField(aFieldName);
aField.setAccessible(true);
aField.set(anObject, null);
}
catch (Exception e)
{
// ignored...
}
}
private static void SafelySetReflectedFieldToNull(String aClassName,
String aFieldName, Object anObject)
{
try
{
Class<?> aClass = Class.forName(aClassName);
SafelySetReflectedFieldToNull(aClass, aFieldName, anObject);
}
catch (Exception e)
{
return;
}
}
private static Object safelyGetReflectedField(String aClassName,
String aFieldName, Object anObject)
{
try
{
Class<?> aClass = Class.forName(aClassName);
Field aField = aClass.getDeclaredField(aFieldName);
aField.setAccessible(true);
return aField.get(anObject);
}
catch (Exception e)
{
return null;
}
}
public static void cleanupJMenuBarGlobals()
{
SafelySetReflectedFieldToNull(
"com.sun.java.swing.plaf.windows.WindowsRootPaneUI$AltProcessor",
"root", null);
SafelySetReflectedFieldToNull(
"com.sun.java.swing.plaf.windows.WindowsRootPaneUI$AltProcessor",
"winAncestor", null);
}
}