blob: 2bec50c6e1cb2928b5aab4337fc4e4462ecd7dbc [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011-2018 EclipseSource Muenchen GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Lucas Koehler - initial API and implementation
******************************************************************************/
package org.eclipse.emf.ecp.view.spi.table.nebula.grid;
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 static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.text.MessageFormat;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EcoreFactory;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.ecp.view.internal.table.nebula.grid.GridTestsUtil;
import org.eclipse.emf.ecp.view.spi.context.ViewModelContext;
import org.eclipse.emf.ecp.view.spi.model.VElement;
import org.eclipse.emf.ecp.view.spi.model.VView;
import org.eclipse.emf.ecp.view.spi.model.VViewFactory;
import org.eclipse.emf.ecp.view.spi.renderer.NoPropertyDescriptorFoundExeption;
import org.eclipse.emf.ecp.view.spi.renderer.NoRendererFoundException;
import org.eclipse.emf.ecp.view.spi.table.model.DetailEditing;
import org.eclipse.emf.ecp.view.spi.table.model.VTableControl;
import org.eclipse.emf.ecp.view.spi.util.swt.ImageRegistryService;
import org.eclipse.emf.ecp.view.table.test.common.TableControlHandle;
import org.eclipse.emf.ecp.view.table.test.common.TableTestUtil;
import org.eclipse.emf.ecp.view.template.model.VTViewTemplateProvider;
import org.eclipse.emf.ecp.view.test.common.swt.spi.DatabindingClassRunner;
import org.eclipse.emf.ecp.view.test.common.swt.spi.SWTTestUtil;
import org.eclipse.emf.ecp.view.test.common.swt.spi.SWTViewTestHelper;
import org.eclipse.emf.ecp.view.test.common.swt.spi.SWTViewTestHelper.RendererResult;
import org.eclipse.emfforms.spi.common.converter.EStructuralFeatureValueConverterService;
import org.eclipse.emfforms.spi.common.report.ReportService;
import org.eclipse.emfforms.spi.core.services.databinding.emf.EMFFormsDatabindingEMF;
import org.eclipse.emfforms.spi.core.services.editsupport.EMFFormsEditSupport;
import org.eclipse.emfforms.spi.core.services.label.EMFFormsLabelProvider;
import org.eclipse.emfforms.spi.localization.EMFFormsLocalizationService;
import org.eclipse.emfforms.spi.swt.core.EMFFormsNoRendererException;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.nebula.jface.gridviewer.GridTableViewer;
import org.eclipse.nebula.widgets.grid.Grid;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Shell;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
/**
* Unit tests for the {@link GridControlDetailPanelRenderer}.
*
* @author Lucas Koehler
*
*/
@RunWith(DatabindingClassRunner.class)
public class GridControlDetailPanelRenderer_PTest {
private static String log;
private static PrintStream systemErr;
private Shell shell;
private EObject domainElement;
@BeforeClass
public static void beforeClass() {
systemErr = System.err;
System.setErr(new PrintStreamWrapper(systemErr));
}
@AfterClass
public static void afterClass() {
System.setErr(systemErr);
}
@Before
public void init() {
log = "";
shell = SWTViewTestHelper.createShell();
final EClass eClass = EcoreFactory.eINSTANCE.createEClass();
eClass.getESuperTypes().add(EcorePackage.eINSTANCE.getEClass());
domainElement = eClass;
}
@After
public void after() {
shell.dispose();
if (!log.isEmpty()) {
fail("Unexpected log to System.err: " + log);
}
}
/**
* Tests that a sash form is used in order to allow resizing of the grid and detail panel composites.
*/
@Test
public void testSashForm() throws NoRendererFoundException,
NoPropertyDescriptorFoundExeption, EMFFormsNoRendererException {
// setup model
final TableControlHandle handle = TableTestUtil.createInitializedTableWithoutTableColumns();
handle.getTableControl().setDetailEditing(DetailEditing.WITH_PANEL);
//
final Control render = SWTViewTestHelper.render(handle.getTableControl(), domainElement, shell);
assertTrue(render instanceof Composite);
final Composite border = getChild(getChild(render, Composite.class, 0), Composite.class, 1);
assertEquals("The grid and detail should be surrounded by a common border", SWT.BORDER,
border.getStyle() & SWT.BORDER);
final SashForm sashForm = getChild(border, SashForm.class, 0);
assertEquals("The SashForm should have exactly two child composites: one for the grid and one for the detail.",
2, sashForm.getChildren().length);
final int[] weights = sashForm.getWeights();
assertEquals(2, weights.length);
assertTrue("The table composite should have a lower relative weight in the sash than the detail",
weights[0] < weights[1]);
final Composite gridWrapperComposite = getChild(sashForm, Composite.class, 0);
final Composite gridComposite = getChild(gridWrapperComposite, Composite.class, 0);
getChild(gridComposite, Grid.class, 0);
getChild(sashForm, Composite.class, 1);
}
/**
* Tests that a horizontal and vertical scrollbar appears if the detail is to small.
*/
@Test
public void testScroll() throws NoRendererFoundException,
NoPropertyDescriptorFoundExeption, EMFFormsNoRendererException {
shell.setSize(100, 200);
shell.open();
SWTTestUtil.waitForUIThread();
// setup model
final TableControlHandle handle = TableTestUtil.createInitializedTableWithoutTableColumns();
handle.getTableControl().setDetailEditing(DetailEditing.WITH_PANEL);
//
final RendererResult renderControl = SWTViewTestHelper.renderControl(handle.getTableControl(), domainElement,
shell);
shell.layout();
SWTTestUtil.waitForUIThread();
final GridTableViewer tableViewer = GridTestsUtil.getTableViewerFromRenderer(renderControl.getRenderer());
final Control render = renderControl.getControl().get();
assertTrue(render instanceof Composite);
final Composite border = getChild(getChild(render, Composite.class, 0), Composite.class, 1);
assertEquals("The grid and detail should be surrounded by a common border", SWT.BORDER,
border.getStyle() & SWT.BORDER);
final SashForm sashForm = getChild(border, SashForm.class, 0);
tableViewer.setSelection(new StructuredSelection(tableViewer.getElementAt(0)));
final ScrolledComposite scrolledComposite = getChild(sashForm, ScrolledComposite.class, 1);
assertFalse(scrolledComposite.getAlwaysShowScrollBars());
assertTrue(scrolledComposite.getHorizontalBar().isVisible());
assertTrue(scrolledComposite.getVerticalBar().isVisible());
// modify shell to force no scroll
shell.setSize(1000, 1000);
assertFalse(scrolledComposite.getHorizontalBar().isVisible());
assertFalse(scrolledComposite.getVerticalBar().isVisible());
shell.close();
}
@Test
public void testGetView() {
final GridControlDetailPanelRenderer renderer = new GridControlDetailPanelRenderer(mock(VTableControl.class),
mock(ViewModelContext.class), mock(ReportService.class), mock(EMFFormsDatabindingEMF.class),
mock(EMFFormsLabelProvider.class), mock(VTViewTemplateProvider.class), mock(ImageRegistryService.class),
mock(EMFFormsEditSupport.class), mock(EStructuralFeatureValueConverterService.class),
mock(EMFFormsLocalizationService.class));
final EAttribute eAttribute = EcoreFactory.eINSTANCE.createEAttribute();
final EReference eReference = EcoreFactory.eINSTANCE.createEReference();
final VView viewAttribute1 = renderer.getView(eAttribute);
final VView viewReference = renderer.getView(eReference);
assertFalse(EcoreUtil.equals(viewAttribute1, viewReference));
final VView viewAttribute2 = renderer.getView(eAttribute);
assertTrue(EcoreUtil.equals(viewAttribute1, viewAttribute2));
}
/**
* If the detail view is not configured as readonly, the table sets it to read only when the table is disabled.
* Furthermore, the detail's readonly state is resetted when the table is enabled again.
*/
@Test
public void testEnabledChangeAppliedToDetailView_OriginalReadonlyFalse() {
final VTableControl control = mock(VTableControl.class);
final VView detailView = VViewFactory.eINSTANCE.createView();
detailView.setReadonly(false);
when(control.getDetailView()).thenReturn(detailView);
when(control.isEffectivelyEnabled()).thenReturn(true);
when(control.isEffectivelyReadonly()).thenReturn(false);
final EAttribute eAttribute = EcoreFactory.eINSTANCE.createEAttribute();
final ViewModelContext context = mockViewModelContext(detailView, eAttribute);
final GridControlDetailPanelRenderer renderer = new GridControlDetailPanelRenderer(control, context,
mock(ReportService.class), mock(EMFFormsDatabindingEMF.class), mock(EMFFormsLabelProvider.class),
mock(VTViewTemplateProvider.class), mock(ImageRegistryService.class), mock(EMFFormsEditSupport.class),
mock(EStructuralFeatureValueConverterService.class), mock(EMFFormsLocalizationService.class));
renderer.renderSelectedObject(shell, eAttribute);
assertFalse(detailView.isReadonly());
when(control.isEffectivelyEnabled()).thenReturn(false);
renderer.applyEnable();
assertTrue(detailView.isReadonly());
when(control.isEffectivelyEnabled()).thenReturn(true);
renderer.applyEnable();
assertFalse(detailView.isReadonly());
}
/** If the detail view is configured as readonly, it must always stay readonly. */
@Test
public void testEnabledChangeAppliedToDetailView_OriginalReadonlyTrue() {
final VTableControl control = mock(VTableControl.class);
final VView detailView = VViewFactory.eINSTANCE.createView();
detailView.setReadonly(true);
when(control.getDetailView()).thenReturn(detailView);
when(control.isEffectivelyEnabled()).thenReturn(false);
when(control.isEffectivelyReadonly()).thenReturn(false);
final EAttribute eAttribute = EcoreFactory.eINSTANCE.createEAttribute();
final ViewModelContext context = mockViewModelContext(detailView, eAttribute);
final GridControlDetailPanelRenderer renderer = new GridControlDetailPanelRenderer(control, context,
mock(ReportService.class), mock(EMFFormsDatabindingEMF.class), mock(EMFFormsLabelProvider.class),
mock(VTViewTemplateProvider.class), mock(ImageRegistryService.class), mock(EMFFormsEditSupport.class),
mock(EStructuralFeatureValueConverterService.class), mock(EMFFormsLocalizationService.class));
renderer.renderSelectedObject(shell, eAttribute);
assertTrue(detailView.isReadonly());
when(control.isEffectivelyEnabled()).thenReturn(true);
renderer.applyEnable();
assertTrue(detailView.isReadonly());
}
/**
* If the table is read only, enabling it must not set the detail's readonly flag to false.
*/
@Test
public void testEnabledChangeAppliedToDetailView_DoesNotOverrideReadonlyTrue() {
final VTableControl control = mock(VTableControl.class);
final VView detailView = VViewFactory.eINSTANCE.createView();
detailView.setReadonly(false);
when(control.getDetailView()).thenReturn(detailView);
when(control.isEffectivelyEnabled()).thenReturn(false);
when(control.isEffectivelyReadonly()).thenReturn(true);
final EAttribute eAttribute = EcoreFactory.eINSTANCE.createEAttribute();
final ViewModelContext context = mockViewModelContext(detailView, eAttribute);
final GridControlDetailPanelRenderer renderer = new GridControlDetailPanelRenderer(control, context,
mock(ReportService.class), mock(EMFFormsDatabindingEMF.class), mock(EMFFormsLabelProvider.class),
mock(VTViewTemplateProvider.class), mock(ImageRegistryService.class), mock(EMFFormsEditSupport.class),
mock(EStructuralFeatureValueConverterService.class), mock(EMFFormsLocalizationService.class));
renderer.renderSelectedObject(shell, eAttribute);
assertTrue(detailView.isReadonly());
when(control.isEffectivelyEnabled()).thenReturn(true);
renderer.applyEnable();
assertTrue(detailView.isReadonly());
}
/**
* If the detail view is not configured as readonly, the table sets it to read only when the table is set to
* readonly.
*/
@Test
public void testReadonlyChangeAppliedToDetailView_OriginalReadonlyFalse() {
final VTableControl control = mock(VTableControl.class);
final VView detailView = VViewFactory.eINSTANCE.createView();
detailView.setReadonly(false);
when(control.getDetailView()).thenReturn(detailView);
when(control.isEffectivelyEnabled()).thenReturn(true);
when(control.isEffectivelyReadonly()).thenReturn(false);
final EAttribute eAttribute = EcoreFactory.eINSTANCE.createEAttribute();
final ViewModelContext context = mockViewModelContext(detailView, eAttribute);
final GridControlDetailPanelRenderer renderer = new GridControlDetailPanelRenderer(control, context,
mock(ReportService.class), mock(EMFFormsDatabindingEMF.class), mock(EMFFormsLabelProvider.class),
mock(VTViewTemplateProvider.class), mock(ImageRegistryService.class), mock(EMFFormsEditSupport.class),
mock(EStructuralFeatureValueConverterService.class), mock(EMFFormsLocalizationService.class));
renderer.renderSelectedObject(shell, eAttribute);
assertFalse(detailView.isReadonly());
when(control.isEffectivelyReadonly()).thenReturn(true);
renderer.applyReadOnly();
assertTrue(detailView.isReadonly());
}
/** If the detail view is configured as readonly, it must always stay readonly. */
@Test
public void testReadonlyChangeAppliedToDetailView_OriginalReadonlyTrue() {
final VTableControl control = mock(VTableControl.class);
final VView detailView = VViewFactory.eINSTANCE.createView();
detailView.setReadonly(true);
when(control.getDetailView()).thenReturn(detailView);
when(control.isEffectivelyEnabled()).thenReturn(true);
when(control.isEffectivelyReadonly()).thenReturn(true);
final EAttribute eAttribute = EcoreFactory.eINSTANCE.createEAttribute();
final ViewModelContext context = mockViewModelContext(detailView, eAttribute);
final GridControlDetailPanelRenderer renderer = new GridControlDetailPanelRenderer(control, context,
mock(ReportService.class), mock(EMFFormsDatabindingEMF.class), mock(EMFFormsLabelProvider.class),
mock(VTViewTemplateProvider.class), mock(ImageRegistryService.class), mock(EMFFormsEditSupport.class),
mock(EStructuralFeatureValueConverterService.class), mock(EMFFormsLocalizationService.class));
renderer.renderSelectedObject(shell, eAttribute);
assertTrue(detailView.isReadonly());
when(control.isEffectivelyReadonly()).thenReturn(false);
renderer.applyEnable();
assertTrue(detailView.isReadonly());
}
/**
* If the table is disabled, setting its read only flag to false, must not set the detail's readonly flag to false.
*/
@Test
public void testReadonlyChangeAppliedToDetailView_DoesNotOverrideEnabledFalse() {
final VTableControl control = mock(VTableControl.class);
final VView detailView = VViewFactory.eINSTANCE.createView();
detailView.setReadonly(false);
when(control.getDetailView()).thenReturn(detailView);
when(control.isEffectivelyEnabled()).thenReturn(false);
when(control.isEffectivelyReadonly()).thenReturn(true);
final EAttribute eAttribute = EcoreFactory.eINSTANCE.createEAttribute();
final ViewModelContext context = mockViewModelContext(detailView, eAttribute);
final GridControlDetailPanelRenderer renderer = new GridControlDetailPanelRenderer(control, context,
mock(ReportService.class), mock(EMFFormsDatabindingEMF.class), mock(EMFFormsLabelProvider.class),
mock(VTViewTemplateProvider.class), mock(ImageRegistryService.class), mock(EMFFormsEditSupport.class),
mock(EStructuralFeatureValueConverterService.class), mock(EMFFormsLocalizationService.class));
renderer.renderSelectedObject(shell, eAttribute);
assertTrue(detailView.isReadonly());
when(control.isEffectivelyReadonly()).thenReturn(false);
renderer.applyEnable();
assertTrue(detailView.isReadonly());
}
private ViewModelContext mockViewModelContext(final VView detailView, final EObject domainObject) {
final ViewModelContext context = mock(ViewModelContext.class);
final ViewModelContext childContext = mock(ViewModelContext.class);
when(childContext.getDomainModel()).thenReturn(domainObject);
when(childContext.getViewModel()).thenReturn(detailView);
when(context.getChildContext(any(EObject.class), any(VElement.class), any(VView.class)))
.thenReturn(childContext);
return context;
}
private <T> T getChild(Control parent, Class<T> type, int index) {
assertTrue(MessageFormat.format("The Control {0} is not a composite => No children can be retrieved", parent),
parent instanceof Composite);
final Composite composite = (Composite) parent;
final Control child = composite.getChildren()[index];
assertTrue(MessageFormat.format("Child {0} is not of required type {1}", child, type.getName()),
type.isInstance(child));
return type.cast(child);
}
private static class PrintStreamWrapper extends PrintStream {
private final PrintStream printStream;
PrintStreamWrapper(PrintStream printStream) {
super(new ByteArrayOutputStream());
this.printStream = printStream;
}
@Override
public void print(String s) {
log = log.concat("\n" + s);
printStream.print(s + "\n");
}
}
}