/******************************************************************************* * Copyright (c) 2007, 2014 compeople AG and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * compeople AG - initial API and implementation *******************************************************************************/ package org.eclipse.riena.navigation.ui.controllers; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.Collection; import java.util.Map; import org.eclipse.core.databinding.BindingException; import org.eclipse.core.databinding.observable.Realm; import org.eclipse.jface.databinding.swt.SWTObservables; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import org.eclipse.riena.core.RienaStatus; import org.eclipse.riena.core.annotationprocessor.AnnotatedOverriddenMethodsGuard; import org.eclipse.riena.core.annotationprocessor.AnnotationProcessor; import org.eclipse.riena.core.annotationprocessor.DisposerList; import org.eclipse.riena.core.annotationprocessor.IAnnotatedMethodHandler; import org.eclipse.riena.core.annotationprocessor.IDisposer; import org.eclipse.riena.core.marker.IMarker; import org.eclipse.riena.core.test.RienaTestCase; import org.eclipse.riena.core.test.collect.UITestCase; import org.eclipse.riena.core.util.Nop; import org.eclipse.riena.core.util.ReflectionUtils; import org.eclipse.riena.internal.core.annotationprocessor.IAnnotatedMethodHandlerExtension; import org.eclipse.riena.internal.ui.ridgets.swt.LabelRidget; import org.eclipse.riena.internal.ui.ridgets.swt.TextRidget; import org.eclipse.riena.navigation.INavigationNodeController; import org.eclipse.riena.navigation.ISubModuleNode; import org.eclipse.riena.navigation.NavigationArgument; import org.eclipse.riena.navigation.NavigationNodeId; import org.eclipse.riena.navigation.model.ModuleNode; import org.eclipse.riena.navigation.model.NavigationProcessor; import org.eclipse.riena.navigation.model.SubModuleNode; import org.eclipse.riena.ui.core.marker.DisabledMarker; import org.eclipse.riena.ui.core.marker.ErrorMarker; import org.eclipse.riena.ui.core.marker.HiddenMarker; import org.eclipse.riena.ui.core.marker.MandatoryMarker; import org.eclipse.riena.ui.core.marker.OutputMarker; import org.eclipse.riena.ui.ridgets.AbstractCompositeRidget; import org.eclipse.riena.ui.ridgets.ComplexRidgetResolver; import org.eclipse.riena.ui.ridgets.IBasicMarkableRidget; import org.eclipse.riena.ui.ridgets.ICompositeRidget; import org.eclipse.riena.ui.ridgets.IMenuItemRidget; import org.eclipse.riena.ui.ridgets.IRidget; import org.eclipse.riena.ui.ridgets.IRidgetContainer; import org.eclipse.riena.ui.ridgets.ITextRidget; import org.eclipse.riena.ui.ridgets.annotation.OnClick; import org.eclipse.riena.ui.ridgets.listener.IFocusListener; import org.eclipse.riena.ui.swt.utils.SwtUtilities; /** * Tests of the class {@link NavigationNodeController}. */ @UITestCase public class NavigationNodeControllerTest extends RienaTestCase { private MyNavigationNodeController controller; private SubModuleNode node; private SubModuleNode node2; private Shell shell; private NavigationProcessor navigationProcessor; private final static String SUBMODULE1_TYPE_ID = "subModule1TypeId"; //$NON-NLS-1$ private final static String SUBMODULE2_TYPE_ID = "subModule2TypeId"; //$NON-NLS-1$ @Override protected void setUp() throws Exception { final Display display = Display.getDefault(); shell = new Shell(display); shell.pack(); shell.setVisible(true); final Realm realm = SWTObservables.getRealm(display); assertNotNull(realm); ReflectionUtils.invokeHidden(realm, "setDefault", realm); //$NON-NLS-1$ node = new SubModuleNode(new NavigationNodeId(SUBMODULE1_TYPE_ID)); node2 = new SubModuleNode(new NavigationNodeId(SUBMODULE2_TYPE_ID)); navigationProcessor = new NavigationProcessor(); node.setNavigationProcessor(navigationProcessor); node2.setNavigationProcessor(navigationProcessor); controller = new MyNavigationNodeController(node); } @Override protected void tearDown() throws Exception { controller = null; node = null; node2 = null; Handler.counter = 0; SwtUtilities.dispose(shell); } public void testUpdateNavigationMarkersUniqueAndDisabled() throws Exception { assertTrue(node.getMarkers().isEmpty()); final TextRidget r1 = new TextRidget(); r1.setUIControl(new Text(shell, SWT.NONE)); final MandatoryMarker m1 = new MandatoryMarker(true); r1.addMarker(m1); controller.addRidget("id1", r1); //$NON-NLS-1$ controller.updateNavigationNodeMarkers(); assertEquals(1, node.getMarkers().size()); assertSame(m1, node.getMarkersOfType(MandatoryMarker.class).iterator().next()); final TextRidget r2 = new TextRidget(); r2.setUIControl(new Text(shell, SWT.NONE)); final MandatoryMarker m2 = new MandatoryMarker(true); r2.addMarker(m2); controller.addRidget("id2", r2); //$NON-NLS-1$ controller.updateNavigationNodeMarkers(); // m2 was not added to the node since m1 is there assertEquals(1, node.getMarkers().size()); assertSame(m1, node.getMarkersOfType(MandatoryMarker.class).iterator().next()); m1.setDisabled(true); // triggers also controller.updateNavigationNodeMarkers(); // m1 was removed since it is disabled, m2 was added to the node instead assertEquals(1, node.getMarkers().size()); assertSame(m2, node.getMarkersOfType(MandatoryMarker.class).iterator().next()); } /** * Tests the method {@code addRidget}. */ public void testAddRidget() { final LabelRidget ridget = new LabelRidget(); controller.addRidget("4711", ridget); //$NON-NLS-1$ assertNotNull(controller.getRidgets()); assertEquals(1, controller.getRidgets().size()); final PropertyChangeSupport support = ReflectionUtils.getHidden(ridget, "propertyChangeSupport"); //$NON-NLS-1$ assertNotNull(support.getPropertyChangeListeners()); assertEquals(4, support.getPropertyChangeListeners().length); } /** * Tests the method {@code updateNavigationNodeMarkers()}. */ public void testUpdateNavigationNodeMarkers() { final TextRidget ridget = new TextRidget(); ridget.setUIControl(new Text(shell, 0)); ridget.addMarker(new ErrorMarker()); controller.addRidget("4711", ridget); //$NON-NLS-1$ controller.updateNavigationNodeMarkers(); assertFalse(node.getMarkers().isEmpty()); assertFalse(node.getMarkersOfType(ErrorMarker.class).isEmpty()); final MandatoryMarker mandatory1 = new MandatoryMarker(); ridget.addMarker(mandatory1); controller.updateNavigationNodeMarkers(); assertFalse(node.getMarkers().isEmpty()); assertFalse(node.getMarkersOfType(ErrorMarker.class).isEmpty()); assertFalse(node.getMarkersOfType(MandatoryMarker.class).isEmpty()); ridget.setText("testtext"); //$NON-NLS-1$ controller.updateNavigationNodeMarkers(); assertFalse(node.getMarkers().isEmpty()); assertFalse(node.getMarkersOfType(ErrorMarker.class).isEmpty()); // the mandatory marker of the ridget is disabled because the text is not empty assertTrue(node.getMarkersOfType(MandatoryMarker.class).isEmpty()); ridget.setText(null); ridget.addMarker(mandatory1); controller.updateNavigationNodeMarkers(); assertFalse(node.getMarkersOfType(MandatoryMarker.class).isEmpty()); mandatory1.setDisabled(true); final MandatoryMarker mandatory2 = new MandatoryMarker(); final TextRidget ridget2 = new TextRidget(); ridget2.setUIControl(new Text(shell, 0)); ridget2.addMarker(mandatory2); controller.addRidget("554", ridget2); //$NON-NLS-1$ controller.updateNavigationNodeMarkers(); assertFalse(node.getMarkersOfType(MandatoryMarker.class).isEmpty()); } /** * Tests the private method {@code getRidgetMarkers()}. */ public void testGetRidgetMarkers() { final TextRidget ridget = new TextRidget(); ridget.setUIControl(new Text(shell, 0)); controller.addRidget("4711", ridget); //$NON-NLS-1$ final TextRidget ridget2 = new TextRidget(); ridget2.setUIControl(new Text(shell, 0)); controller.addRidget("0815", ridget2); //$NON-NLS-1$ Collection<IMarker> markers = ReflectionUtils.invokeHidden(controller, "getRidgetMarkers", (Object[]) null); //$NON-NLS-1$ assertNotNull(markers); final ErrorMarker errorMarker = new ErrorMarker(); ridget.addMarker(errorMarker); final OutputMarker outputMarker = new OutputMarker(); ridget2.addMarker(outputMarker); markers = ReflectionUtils.invokeHidden(controller, "getRidgetMarkers", (Object[]) null); //$NON-NLS-1$ assertNotNull(markers); assertEquals(2, markers.size()); assertTrue(markers.contains(errorMarker)); assertTrue(markers.contains(outputMarker)); final CompositeRidget compositeRidget = new CompositeRidget(); final TextRidget ridget3 = new TextRidget(); ridget3.setUIControl(new Text(shell, 0)); compositeRidget.addRidget("label3", ridget3); //$NON-NLS-1$ controller.addRidget("comp", compositeRidget); //$NON-NLS-1$ final MandatoryMarker mandatoryMarker = new MandatoryMarker(); ridget3.addMarker(mandatoryMarker); markers = ReflectionUtils.invokeHidden(controller, "getRidgetMarkers", (Object[]) null); //$NON-NLS-1$ assertNotNull(markers); assertEquals(3, markers.size()); assertTrue(markers.contains(mandatoryMarker)); } public void testGetRidget() throws Exception { System.getProperties().put(RienaStatus.RIENA_TEST_SYSTEM_PROPERTY, "true"); //$NON-NLS-1$ IRidget ridget = controller.getRidget(MockRidget.class, "myMock"); //$NON-NLS-1$ assertEquals(MockRidget.class, ridget.getClass()); try { ridget = controller.getRidget(IMockRidget.class, "myMockInterface"); //$NON-NLS-1$ fail("BindingException expected"); //$NON-NLS-1$ } catch (final BindingException e) { ok("BindingException expected"); //$NON-NLS-1$ } finally { System.getProperties().put(RienaStatus.RIENA_TEST_SYSTEM_PROPERTY, "false"); //$NON-NLS-1$ } } /** * Tests the <i>private</i> method {@code getChildId(String)}. * * @throws Exception * handled by JUnit */ public void testGetChildId() throws Exception { final ComplexRidgetResolver ridgetResolver = ReflectionUtils.getHidden(controller, "ridgetResolver"); //$NON-NLS-1$ String childId = ReflectionUtils.invokeHidden(ridgetResolver, "getChildId", "aa.bbb.cccc"); //$NON-NLS-1$ //$NON-NLS-2$ assertEquals("cccc", childId); //$NON-NLS-1$ childId = ReflectionUtils.invokeHidden(ridgetResolver, "getChildId", "def"); //$NON-NLS-1$ //$NON-NLS-2$ assertEquals("def", childId); //$NON-NLS-1$ } /** * Tests the <i>private</i> method {@code getContainer(String)}. * * @throws Exception * handled by JUnit */ public void testGetContainer() throws Exception { final ComplexRidgetResolver ridgetResolver = ReflectionUtils.getHidden(controller, "ridgetResolver"); //$NON-NLS-1$ final Map<String, IRidget> ridgets = ReflectionUtils.getHidden(controller, "ridgets"); //$NON-NLS-1$ IRidgetContainer container = ReflectionUtils.invokeHidden(ridgetResolver, "getContainer", "container.child", ridgets); //$NON-NLS-1$ //$NON-NLS-2$ assertNull(container); final ICompositeRidget composite = new org.eclipse.riena.internal.ui.ridgets.swt.CompositeRidget(); controller.addRidget("container", composite); //$NON-NLS-1$ container = ReflectionUtils.invokeHidden(ridgetResolver, "getContainer", "container.child", ridgets); //$NON-NLS-1$ //$NON-NLS-2$ assertSame(composite, container); container = ReflectionUtils.invokeHidden(ridgetResolver, "getContainer", "container", ridgets); //$NON-NLS-1$ //$NON-NLS-2$ assertNull(container); } /** * Test for bug 269131. */ public void testHiddenAndDisabledMarkersBlockAllRidgetMarkers() throws Exception { final TextRidget ridget = new TextRidget(); ridget.setUIControl(new Text(shell, 0)); controller.addRidget("4711", ridget); //$NON-NLS-1$ final TextRidget ridget2 = new TextRidget(); ridget2.setUIControl(new Text(shell, 0)); controller.addRidget("0815", ridget2); //$NON-NLS-1$ final IMarker errorMarker = new ErrorMarker(); final IMarker mandatoryMarker = new MandatoryMarker(); final IMarker hiddenMarker = new HiddenMarker(); final IMarker disabledMarker = new DisabledMarker(); ridget.addMarker(errorMarker); ridget.addMarker(mandatoryMarker); Collection<IMarker> markers = ReflectionUtils.invokeHidden(controller, "getRidgetMarkers", (Object[]) null); //$NON-NLS-1$ assertEquals(2, markers.size()); assertTrue(markers.contains(errorMarker)); assertTrue(markers.contains(mandatoryMarker)); ridget.addMarker(hiddenMarker); markers = ReflectionUtils.invokeHidden(controller, "getRidgetMarkers", (Object[]) null); //$NON-NLS-1$ assertTrue(markers.isEmpty()); ridget2.addMarker(errorMarker); ridget2.addMarker(mandatoryMarker); markers = ReflectionUtils.invokeHidden(controller, "getRidgetMarkers", (Object[]) null); //$NON-NLS-1$ assertEquals(2, markers.size()); assertTrue(markers.contains(errorMarker)); assertTrue(markers.contains(mandatoryMarker)); ridget2.addMarker(disabledMarker); markers = ReflectionUtils.invokeHidden(controller, "getRidgetMarkers", (Object[]) null); //$NON-NLS-1$ assertTrue(markers.isEmpty()); ridget.removeMarker(hiddenMarker); markers = ReflectionUtils.invokeHidden(controller, "getRidgetMarkers", (Object[]) null); //$NON-NLS-1$ assertEquals(2, markers.size()); assertTrue(markers.contains(errorMarker)); assertTrue(markers.contains(mandatoryMarker)); } /** * Tests the method {@link INavigationNodeController#navigationArgumentChanged(NavigationArgument)} */ public void testNavigationArgumentChanged() throws Exception { final ModuleNode module = new ModuleNode(new NavigationNodeId("myModuleNode")); //$NON-NLS-1$ module.setNavigationProcessor(navigationProcessor); module.addChild(node); final SubModuleNode node2 = new SubModuleNode(); module.addChild(node2); node2.activate(); final NavigationArgument arg = new NavigationArgument(new Object()); assertNull(controller.lastArgument); node2.navigate(new NavigationNodeId(SUBMODULE1_TYPE_ID), arg); assertTrue(node.isActivated()); assertSame(arg, controller.lastArgument); } @SuppressWarnings("unchecked") public void testHideShowMarkerFiresEvent() { final ITextRidget ridget = new TextRidget(); final FTPropertyChangeListener listener = new FTPropertyChangeListener(); ridget.addPropertyChangeListener(IBasicMarkableRidget.PROPERTY_MARKER_HIDING, listener); assertEquals(0, listener.count); ridget.hideMarkersOfType(ErrorMarker.class); assertEquals(1, listener.count); ridget.hideMarkersOfType(ErrorMarker.class); assertEquals(1, listener.count); ridget.showMarkersOfType(MandatoryMarker.class); assertEquals(1, listener.count); ridget.showMarkersOfType(ErrorMarker.class); assertEquals(2, listener.count); ridget.showMarkersOfType(ErrorMarker.class); assertEquals(2, listener.count); } @SuppressWarnings({ "restriction" }) public void testDisposeListenerDisposeAnnotations() { final MyAnnotationNavigationNodeController myController = new MyAnnotationNavigationNodeController(node); final TextRidget ridget = new TextRidget(); myController.addRidget("4711", ridget); //$NON-NLS-1$ final TextRidget ridget2 = new TextRidget(); myController.addRidget("0815", ridget2); //$NON-NLS-1$ final Handler onClick = new Handler(); AnnotationProcessor.getInstance().update(new IAnnotatedMethodHandlerExtension[] { create(OnClick.class, onClick) }); final IDisposer disposer = AnnotationProcessor.getInstance().processMethods(myController); myController.addAnnotationDisposer(disposer); assertEquals(1, Handler.counter); node.dispose(); assertEquals(0, Handler.counter); } @SuppressWarnings({ "restriction" }) public void testDisposeListenerDisposeAnnotationsWithChangingController() { final MyAnnotationNavigationNodeController myController = new MyAnnotationNavigationNodeController(node); final MyAnnotationNavigationNodeController myController2 = new MyAnnotationNavigationNodeController(node); final TextRidget ridget = new TextRidget(); myController.addRidget("4711", ridget); //$NON-NLS-1$ final TextRidget ridget2 = new TextRidget(); myController.addRidget("0815", ridget2); //$NON-NLS-1$ final TextRidget ridget3 = new TextRidget(); myController2.addRidget("0815", ridget3); //$NON-NLS-1$ final Handler onClick = new Handler(); AnnotationProcessor.getInstance().update(new IAnnotatedMethodHandlerExtension[] { create(OnClick.class, onClick) }); IDisposer disposer = AnnotationProcessor.getInstance().processMethods(myController); myController.addAnnotationDisposer(disposer); assertEquals(1, Handler.counter); disposer = AnnotationProcessor.getInstance().processMethods(myController2); myController2.addAnnotationDisposer(disposer); assertEquals(2, Handler.counter); myController.setNavigationNode(node2); node.dispose(); assertEquals(1, Handler.counter); } @SuppressWarnings({ "restriction" }) public void testDisposeListenerDisposeAnnotationsWithMoreController() { final MyAnnotationNavigationNodeController myController = new MyAnnotationNavigationNodeController(node); final MyAnnotationNavigationNodeController myController2 = new MyAnnotationNavigationNodeController(node2); final TextRidget ridget = new TextRidget(); myController.addRidget("0815", ridget); //$NON-NLS-1$ final TextRidget ridget2 = new TextRidget(); myController2.addRidget("0815", ridget2); //$NON-NLS-1$ final Handler onClick = new Handler(); AnnotationProcessor.getInstance().update(new IAnnotatedMethodHandlerExtension[] { create(OnClick.class, onClick) }); IDisposer disposer = AnnotationProcessor.getInstance().processMethods(myController); myController.addAnnotationDisposer(disposer); assertEquals(1, Handler.counter); disposer = AnnotationProcessor.getInstance().processMethods(myController2); myController2.addAnnotationDisposer(disposer); assertEquals(2, Handler.counter); node2.dispose(); assertEquals(1, Handler.counter); } // helping classes ////////////////// public static class MyNavigationNodeController extends SubModuleController { private NavigationArgument lastArgument = null; public MyNavigationNodeController(final ISubModuleNode navigationNode) { super(navigationNode); } @Override public void updateNavigationNodeMarkers() { super.updateNavigationNodeMarkers(); } @Override public void navigationArgumentChanged(final NavigationArgument argument) { lastArgument = argument; } } private static class CompositeRidget extends AbstractCompositeRidget { } private interface IMockRidget extends IRidget { } /** * Mock implementation of ridget. */ public static class MockRidget implements IMockRidget { public Object getUIControl() { return null; } public void setUIControl(final Object uiControl) { } public void addPropertyChangeListener(final PropertyChangeListener propertyChangeListener) { } public void addPropertyChangeListener(final String propertyName, final PropertyChangeListener propertyChangeListener) { } public void removePropertyChangeListener(final PropertyChangeListener propertyChangeListener) { } public void removePropertyChangeListener(final String propertyName, final PropertyChangeListener propertyChangeListener) { } public boolean isVisible() { return false; } public void setVisible(final boolean visible) { } public boolean isEnabled() { return false; } public void setEnabled(final boolean enabled) { } public void addFocusListener(final IFocusListener listener) { } public void removeFocusListener(final IFocusListener listener) { } public void updateFromModel() { } public void requestFocus() { } public boolean hasFocus() { return false; } public boolean isFocusable() { return false; } public void setFocusable(final boolean focusable) { } public String getToolTipText() { return null; } public void setToolTipText(final String toolTipText) { } public boolean isBlocked() { return false; } public void setBlocked(final boolean blocked) { } public String getID() { return null; } public IRidgetContainer getController() { return null; } public void setController(final IRidgetContainer controller) { } public void setIgnoreBindingError(final boolean ignore) { } public boolean isIgnoreBindingError() { return false; } public IMenuItemRidget addMenuItem(final String menuItemText) { return null; } public IMenuItemRidget addMenuItem(final String menuItemText, final String iconName) { return null; } public void removeMenuItem(final String menuItemText) { } public void removeMenuItem(final IMenuItemRidget menuItemRidget) { } public IMenuItemRidget getMenuItem(final int index) { return null; } public int getMenuItemCount() { return 0; } public void updateContextMenu() { } } private static final class FTPropertyChangeListener implements PropertyChangeListener { private int count; public void propertyChange(final PropertyChangeEvent evt) { count++; } } private IAnnotatedMethodHandlerExtension create(final Class<? extends Annotation> annotationClass, final IAnnotatedMethodHandler handler) { return new IAnnotatedMethodHandlerExtension() { public Class<? extends Annotation> getAnnotation() { return annotationClass; } public IAnnotatedMethodHandler createHandler() { return handler; } }; } private static class Handler implements IAnnotatedMethodHandler { public static int counter = 0; @Override public void handleAnnotation(final Annotation annotation, final Object object, final Method method, final Map<?, ?> optionalArgs, final AnnotatedOverriddenMethodsGuard guard, final DisposerList disposers) { counter++; disposers.add(new IDisposer() { @Override public void dispose() { counter--; } }); } } private static class MyAnnotationNavigationNodeController extends MyNavigationNodeController { public MyAnnotationNavigationNodeController(final ISubModuleNode navigationNode) { super(navigationNode); } @OnClick(ridgetId = "0815") private void doNothing() { Nop.reason("Empty"); //$NON-NLS-1$ } } }