/* * Created on 27.01.2006 * */ package org.jdesktop.swingx.action; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.awt.event.ActionEvent; import java.awt.event.ItemListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.logging.Logger; import javax.swing.AbstractAction; import javax.swing.AbstractButton; import javax.swing.Action; import javax.swing.JCheckBox; import javax.swing.JCheckBoxMenuItem; import javax.swing.JRadioButton; import javax.swing.JRadioButtonMenuItem; import javax.swing.JToggleButton; import org.jdesktop.test.EDTRunner; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @RunWith(EDTRunner.class) @SuppressWarnings("nls") public class AbstractActionExtTest { @SuppressWarnings("all") private static final Logger LOG = Logger.getLogger(AbstractActionExtTest.class.getName()); protected ActionContainerFactory factory; @Before public void setUp() throws Exception { factory = new ActionContainerFactory(null); } /** * Issue #255-swingx: probs in synch selectable button <--> action. * * test that configured button is kept in synch with * action selected state and the other way round. This uses a * custom configure via the ActionContainerFactory.configureSelectableButton. * The direction from button to action is broken. */ @Test public void testButtonSelectedSynchAction() { AbstractActionExt extAction = createStateAction(); boolean actionSelected = true; extAction.setSelected(actionSelected); JToggleButton button = new JToggleButton(); factory.configureSelectableButton(button, extAction, null); // invert action selected and assert that the change is taken up // by the button extAction.setSelected(!actionSelected); assertEquals("button selected must be synched to action", !actionSelected, button.isSelected()); // reset button button.setSelected(actionSelected); // sanity: the button did take the direct selection change assertEquals(actionSelected, button.isSelected()); // assert that changed selected is taken up by action assertEquals("action selected must be synched to button", actionSelected, extAction.isSelected()); } /** * Issue #255-swingx: probs in synch selectable button <--> action. * * test that configured button is kept in synch with * action selected state and the other way round. This uses the * ActionContainerFactory.createButton(). * The direction from button to action is broken. */ @Test public void testCreateButtonSelectedSynchAction() { AbstractActionExt extAction = createStateAction(); boolean actionSelected = true; extAction.setSelected(actionSelected); JToggleButton button = (JToggleButton) factory.createButton(extAction); // invert action selected and assert that the change is taken up // by the button extAction.setSelected(!actionSelected); assertEquals("button selected must be synched to action", !actionSelected, button.isSelected()); // reset button button.setSelected(actionSelected); // sanity: the button did take the direct selection change assertEquals(actionSelected, button.isSelected()); // assert that changed selected is taken up by action assertEquals("action selected must be synched to button", actionSelected, extAction.isSelected()); } /** * Issue #255-swingx: probs in synch selectable button <--> action. * * test that the button always has mostly one * Action registered as itemListener and that * this registered listener is the same as the buttons * action. * */ @Test public void testButtonOneActionAsItemListener() { AbstractActionExt extAction = createStateAction(); JToggleButton button = new JToggleButton(); factory.configureSelectableButton(button, extAction, null); assertCountAsItemListener(button, extAction, 1); factory.configureSelectableButton(button, null, null); // assert that the previous action is removed as itemListener assertCountAsItemListener(button, extAction, 0); } /** * Issue #255-swingx: probs in synch selectable button <--> action. * test that configured button is kept in synch with * maximal one action's selected state */ @Test public void testButtonSelectedNullAction() { AbstractActionExt extAction = createStateAction(); JToggleButton button = new JToggleButton(); factory.configureSelectableButton(button, extAction, null); // we are sure that the button selected is true (has dedicated test) // now configure it with a different action, unselected AbstractActionExt extActionB = createStateAction(); factory.configureSelectableButton(button, extActionB, null); // invert the old action selected and assert that the change // does not effect the taken up by the button extAction.setSelected(!extAction.isSelected()); assertEquals("button selected must be uneffected by old action", extActionB.isSelected(), button.isSelected()); } /** * Issue #255-swingx: probs in synch selectable button <--> action. * test that PCLs related to a previous button are * unregistered from the Action after release. * */ @Test public void testButtonReleaseActionReleasePCL() { AbstractActionExt extAction = createStateAction(); JToggleButton button = new JToggleButton(); factory.configureSelectableButton(button, extAction, null); // sanity: expect it to be 2 - one is the menuitem itself, another // the TogglePCL registered by the ActionContainerFacory assertEquals(2, extAction.getPropertyChangeListeners().length); // set the button's action to null factory.configureSelectableButton(button, null, null); // assert that button related PCLs are removed from the action's listener list assertEquals(0, extAction.getPropertyChangeListeners().length); } /** * Issue #255-swingx: probs in synch selectable button <--> action. * test that configured button is no longer kept in * synch after setting the action to null. */ @Test public void testButtonSelectedReleasedSynchAction() { AbstractActionExt extAction = createStateAction(); JToggleButton button = new JToggleButton(); factory.configureSelectableButton(button, extAction, null); // now we unconfigure it with a null action factory.configureSelectableButton(button, null, null); // invert the old action selected and assert that the change // does not effect the taken up by the button boolean oldSelected = button.isSelected(); extAction.setSelected(!extAction.isSelected()); assertEquals("button selected must be uneffected by old action", oldSelected, button.isSelected()); } /** * Issue #255-swingx: probs in synch selectable button <--> action. * test that configured button is kept in synch with * maximal one action's selected state */ @Test public void testButtonSelectedMaxOneSynchAction() { AbstractActionExt extAction = createStateAction(); boolean actionSelected = true; extAction.setSelected(actionSelected); JToggleButton button = new JToggleButton(); factory.configureSelectableButton(button, extAction, null); // we are sure that the button selected is true (has dedicated test) // now configure it with a different action, unselected AbstractActionExt extActionB = createStateAction(); factory.configureSelectableButton(button, extActionB, null); // sanity: the new action is not effected by the old // currently this may accidentally pass because the back direction isn't // synched!! assertFalse(extActionB.isSelected()); assertEquals("button selected must be initialized to new action", extActionB.isSelected(), button.isSelected()); // invert the old action selected and assert that the change // does not effect the taken up by the button extAction.setSelected(!actionSelected); // need to be done twice, the first toggle produces extAction.setSelected(actionSelected); assertEquals("button selected must be uneffected by old action", extActionB.isSelected(), button.isSelected()); } /** * Issue #255-swingx: probs in synch selectable button <--> action. * test that button is configured with initial action selected state. * */ @Test public void testButtonSelectedInitialSynchAction() { AbstractActionExt extAction = createStateAction(); boolean actionSelected = true; extAction.setSelected(actionSelected); JToggleButton button = new JToggleButton(); boolean buttonSelected = button.isSelected(); // sanity: different selected state assertTrue(actionSelected != buttonSelected); factory.configureSelectableButton(button, extAction, null); assertEquals("action selection must be unchanged", actionSelected, extAction.isSelected()); assertEquals("button selected must be initialized", actionSelected, button.isSelected()); } /** * test method contract: configureSelectable must throw runtime exception * for non-state action. * */ @Test public void testExceptionOnNonStateAction() { AbstractActionExt actionExt = createStateAction(); actionExt.setStateAction(false); JToggleButton button = new JToggleButton(); try { factory.configureSelectableButton(button, actionExt, null); fail("configureSelectable didn't throw IllegalArgument for non-state action "); } catch (IllegalArgumentException e) { // nothing todo - this is what we expect } catch (Exception e) { fail("caught unexpected exception " + e); } } /** * Issue #229-swingx: increasing listener list in column actions. * * sub-issue: ActionContainerFactory doesn't check if the action is * already synchronizing to the same button. */ @Test public void testToggleButtonConfigure() { // this should pass after giving the gc "reasonable" chance to // have collected the unreachable... // assertToggleButtonConfigure(new JToggleButton(), new JToggleButton()); } /** * Issue #229-swingx: increasing listener list in column actions. * * sub-issue: ActionContainerFactory doesn't check if the action is * already synchronizing to the same button. */ @Test public void testToggleButtonConfigureToggleWithSame() { assertToggleButtonConfigureWithSame(new JToggleButton()); assertToggleButtonConfigureWithSame(new JRadioButton()); assertToggleButtonConfigureWithSame(new JCheckBox()); assertToggleButtonConfigureWithSame(new JRadioButtonMenuItem()); assertToggleButtonConfigureWithSame(new JCheckBoxMenuItem()); } private void assertToggleButtonConfigureWithSame(AbstractButton button) { AbstractActionExt extAction = createStateAction(); assertEquals(0, extAction.getPropertyChangeListeners().length); factory.configureSelectableButton(button, extAction, null); // sanity: expect it to be 2 - one is the menuitem itself, another // the TogglePCL registered by the ActionContainerFacory assertEquals(2, extAction.getPropertyChangeListeners().length); factory.configureSelectableButton(button, extAction, null); // JW: wrong assumption!! Valid only if first == second, for // different buttons we actually expect the listener count to be increased! // Note to myself: remove this comment after correcting the method call // sequence here in the test ... assertEquals(2, extAction.getPropertyChangeListeners().length); } /** * Issue #229-swingx: increasing listener list in column actions. * * sub-issue: ActionContainerFactory registers the action multiple times to * the same button as ItemListener */ @Test public void testToggleButtonAddItemListenerToSame() { assertAddItemListenerToSame(new JToggleButton()); assertAddItemListenerToSame(new JRadioButton()); assertAddItemListenerToSame(new JCheckBox()); assertAddItemListenerToSame(new JRadioButtonMenuItem()); assertAddItemListenerToSame(new JCheckBoxMenuItem()); } private void assertAddItemListenerToSame(AbstractButton checkBoxItem) { AbstractActionExt extAction = createStateAction(); factory.configureSelectableButton(checkBoxItem, extAction, null); assertCountAsItemListener(checkBoxItem, extAction, 1 ); factory.configureSelectableButton(checkBoxItem, extAction, null); assertCountAsItemListener(checkBoxItem, extAction, 1 ); } protected AbstractActionExt createStateAction() { AbstractActionExt extAction = new AbstractActionExt("dummy") { public void actionPerformed(ActionEvent e) { } }; extAction.setStateAction(); return extAction; } /** * assert that the given itemListener is registered exactly * expectedCount times to the given button. * @param checkBoxItem * @param extAction * @param expectedCount */ protected void assertCountAsItemListener(AbstractButton checkBoxItem, ItemListener extAction, int expectedCount) { int count = 0; ItemListener[] itemListeners = checkBoxItem.getItemListeners(); for (int j = 0; j < itemListeners.length; j++) { if (extAction == itemListeners[j]) { count++; } } assertEquals("ItemListener registration count", expectedCount, count); } /** * Issue #4-swinglabs: infinite loop when setting long destricption. * */ @Test public void testLongDescriptionLoop() { AbstractActionExt action = createStateAction(); action.setLongDescription("some"); } /** * core issue: * set enabled via putValue leads to inconsistent state. * fixed in jdk6 */ @Test public void testFireEnabled() { Action action = new AbstractAction("dummy") { public void actionPerformed(ActionEvent e) { // nothing to do } }; PropertyChangeListener l = new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent evt) { if ("enabled".equals(evt.getPropertyName())) { assertEquals(evt.getNewValue(), ((Action) evt.getSource()).isEnabled()); } } }; action.addPropertyChangeListener(l); action.putValue("enabled", false); } }