blob: 41e6c9ec633dca6556a733ab084a53b9910eae97 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011-2019 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:
* Johannes Faltermeier - initial API and implementation
* Mat Hansen - modifications for Nebula Grid
* Christian W. Damus - bugs 527686, 548592
*******************************************************************************/
package org.eclipse.emf.ecp.view.internal.table.nebula.grid;
import static java.util.Arrays.asList;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.lessThan;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.util.Arrays;
import java.util.Set;
import org.eclipse.e4.core.contexts.IEclipseContext;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.EStructuralFeature.Setting;
import org.eclipse.emf.ecore.EcoreFactory;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecp.common.spi.UniqueSetting;
import org.eclipse.emf.ecp.edit.spi.swt.table.ECPCellEditorComparator;
import org.eclipse.emf.ecp.edit.spi.swt.table.StringCellEditor;
import org.eclipse.emf.ecp.view.spi.context.ViewModelContext;
import org.eclipse.emf.ecp.view.spi.context.ViewModelContextDisposeListener;
import org.eclipse.emf.ecp.view.spi.context.ViewModelService;
import org.eclipse.emf.ecp.view.spi.context.ViewModelServiceProvider;
import org.eclipse.emf.ecp.view.spi.model.ModelChangeListener;
import org.eclipse.emf.ecp.view.spi.model.VControl;
import org.eclipse.emf.ecp.view.spi.model.VDomainModelReference;
import org.eclipse.emf.ecp.view.spi.model.VElement;
import org.eclipse.emf.ecp.view.spi.model.VFeaturePathDomainModelReference;
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.model.VViewPackage;
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.table.model.VTableDomainModelReference;
import org.eclipse.emf.ecp.view.spi.table.nebula.grid.GridControlSWTRenderer;
import org.eclipse.emf.ecp.view.spi.table.swt.TableControlSWTRenderer;
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.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.core.services.view.EMFFormsContextListener;
import org.eclipse.emfforms.spi.core.services.view.RootDomainModelChangeListener;
import org.eclipse.emfforms.spi.localization.EMFFormsLocalizationService;
import org.eclipse.emfforms.spi.swt.core.AbstractSWTRenderer;
import org.eclipse.emfforms.spi.swt.core.EMFFormsNoRendererException;
import org.eclipse.emfforms.spi.swt.core.EMFFormsRendererFactory;
import org.eclipse.emfforms.spi.swt.core.di.EMFFormsContextProvider;
import org.eclipse.emfforms.spi.swt.core.layout.SWTGridCell;
import org.eclipse.emfforms.spi.swt.core.layout.SWTGridDescription;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.nebula.jface.gridviewer.GridTableViewer;
import org.eclipse.nebula.widgets.grid.Grid;
import org.eclipse.nebula.widgets.grid.GridItem;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.custom.StackLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
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.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.ServiceReference;
/**
* This is a basically a copy of the SWTTable_PTest for the sake of completeness.
*
* @author Mat Hansen <mhansen@eclipsesource.com>
*
*/
@RunWith(DatabindingClassRunner.class)
public class GridTable_PTest {
private static String log;
private static ServiceReference<EMFFormsRendererFactory> factoryServiceReference;
private static EMFFormsRendererFactory rendererFactory;
private static PrintStream systemErr;
private Shell shell;
private EObject domainElement;
@BeforeClass
public static void beforeClass() {
systemErr = System.err;
System.setErr(new PrintStreamWrapper(systemErr));
final BundleContext bundleContext = FrameworkUtil.getBundle(GridTable_PTest.class).getBundleContext();
factoryServiceReference = bundleContext.getServiceReference(EMFFormsRendererFactory.class);
rendererFactory = bundleContext.getService(factoryServiceReference);
}
@AfterClass
public static void afterClass() {
System.setErr(systemErr);
final BundleContext bundleContext = FrameworkUtil.getBundle(GridTable_PTest.class).getBundleContext();
bundleContext.ungetService(factoryServiceReference);
}
@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() {
if (!log.isEmpty()) {
fail("Unexpected log to System.err: " + log);
}
}
@Test
public void testUninitializedTableWithoutColumns() throws NoRendererFoundException,
NoPropertyDescriptorFoundExeption, EMFFormsNoRendererException {
// setup model
final TableControlHandle handle = TableTestUtil.createUninitializedTableWithoutColumns();
//
final Control render = SWTViewTestHelper.render(handle.getTableControl(), domainElement, shell);
assertTrue(Label.class.isInstance(render));// Error label with error text
assertEquals("The field domainModelEFeature of the given VFeaturePathDomainModelReference must not be null.",
Label.class.cast(render).getText());
}
@Test
public void testInitializedTableWithoutColumnsAndEmptyReference() throws NoRendererFoundException,
NoPropertyDescriptorFoundExeption, EMFFormsNoRendererException {
// setup model
final EClass createEClass = EcoreFactory.eINSTANCE.createEClass();
createEClass.eUnset(EcorePackage.eINSTANCE.getEClass_ESuperTypes());
domainElement = createEClass;
final TableControlHandle handle = TableTestUtil.createInitializedTableWithoutTableColumns();
try {
SWTViewTestHelper.render(handle.getTableControl(), domainElement, shell);
} catch (final NullPointerException e) {
fail("Fails without a reference in domain object");
}
}
@Ignore
@Test
public void testInitializedTableWithoutColumnsSingleReference() throws NoRendererFoundException,
NoPropertyDescriptorFoundExeption, EMFFormsNoRendererException {
// setup model
final VView view = VViewFactory.eINSTANCE.createView();
view.setRootEClass(VViewPackage.eINSTANCE.getView());
domainElement = view;
final TableControlHandle handle = TableTestUtil.createInitializedTableWithoutTableColumns();
final VFeaturePathDomainModelReference domainModelReference = VViewFactory.eINSTANCE
.createFeaturePathDomainModelReference();
domainModelReference.setDomainModelEFeature(VViewPackage.eINSTANCE.getView_RootEClass());
handle.getTableControl().setDomainModelReference(domainModelReference);
try {
SWTViewTestHelper.render(handle.getTableControl(), domainElement, shell);
} catch (final ClassCastException e) {
e.printStackTrace();
fail("Fails with single reference in domain object");
}
}
@Ignore
@Test
public void testInitializedTableWithoutColumnsEmptySingleReference() throws NoRendererFoundException,
NoPropertyDescriptorFoundExeption, EMFFormsNoRendererException {
// setup model
final VView view = VViewFactory.eINSTANCE.createView();
domainElement = view;
final TableControlHandle handle = TableTestUtil.createInitializedTableWithoutTableColumns();
final VFeaturePathDomainModelReference domainModelReference = VViewFactory.eINSTANCE
.createFeaturePathDomainModelReference();
domainModelReference.setDomainModelEFeature(VViewPackage.eINSTANCE.getView_RootEClass());
handle.getTableControl().setDomainModelReference(domainModelReference);
try {
SWTViewTestHelper.render(handle.getTableControl(), domainElement, shell);
} catch (final NullPointerException e) {
fail("Fails with empty single reference in domain object");
}
}
@Test
public void testTableWithoutColumns() throws NoRendererFoundException, NoPropertyDescriptorFoundExeption,
EMFFormsNoRendererException {
// setup model
final TableControlHandle handle = TableTestUtil.createInitializedTableWithoutTableColumns();
final Control render = SWTViewTestHelper.render(handle.getTableControl(), domainElement, shell);
assertTrue(render instanceof Composite);
// see bug #533262, TableColumnGenerator now includes attributes from super types
// if this is not desired the user has to specify the columns in the view model
assertEquals(domainElement.eClass().getEAllAttributes().size(),
VTableDomainModelReference.class.cast(handle.getTableControl().getDomainModelReference())
.getColumnDomainModelReferences().size());
final Control control = getTable(render);
assertTrue(control instanceof Grid);
final Grid table = (Grid) control;
assertEquals(domainElement.eClass().getEAllAttributes().size() + 1, table.getColumnCount());
}
@Test
public void testTableWithoutColumnsWithoutViewServices() throws NoRendererFoundException,
NoPropertyDescriptorFoundExeption, EMFFormsNoRendererException {
final TableControlHandle handle = TableTestUtil.createInitializedTableWithoutTableColumns();
final AbstractSWTRenderer<VElement> tableRenderer = rendererFactory.getRendererInstance(
handle.getTableControl(),
new ViewModelContextWithoutServices(handle.getTableControl()));
tableRenderer.getGridDescription(new SWTGridDescription());
final Control render = tableRenderer.render(new SWTGridCell(0, 0, tableRenderer), shell);
if (render == null) {
fail();
}
assertTrue(render instanceof Composite);
assertEquals(0, VTableDomainModelReference.class.cast(handle.getTableControl().getDomainModelReference())
.getColumnDomainModelReferences().size());
final Control control = getTable(render);
assertTrue(control instanceof Grid);
final Grid table = (Grid) control;
assertEquals(1, table.getColumnCount());
}
@Test
public void testTableWithTwoColumns() throws NoRendererFoundException, NoPropertyDescriptorFoundExeption,
EMFFormsNoRendererException {
// setup model
final TableControlHandle handle = createTableWithTwoTableColumns();
final Control render = SWTViewTestHelper.render(handle.getTableControl(), domainElement, shell);
assertTrue(render instanceof Composite);
final Control control = getTable(render);
assertTrue(control instanceof Grid);
final Grid table = (Grid) control;
assertEquals(2 + 1, table.getColumnCount());
}
@Test
public void testTableWithTwoColumnsWithoutViewServices() throws NoRendererFoundException,
NoPropertyDescriptorFoundExeption, EMFFormsNoRendererException {
// setup model
final TableControlHandle handle = createTableWithTwoTableColumns();
final AbstractSWTRenderer<VElement> tableRenderer = rendererFactory.getRendererInstance(
handle.getTableControl(),
new ViewModelContextWithoutServices(handle.getTableControl()));
tableRenderer.getGridDescription(new SWTGridDescription());
final Control render = tableRenderer.render(new SWTGridCell(0, 0, tableRenderer), shell);
if (render == null) {
fail();
}
assertTrue(render instanceof Composite);
final Control control = getTable(render);
assertTrue(control instanceof Grid);
final Grid table = (Grid) control;
assertEquals(2 + 1, table.getColumnCount());
}
@Test
public void testTableWithTwoColumnsAdd() throws NoRendererFoundException, NoPropertyDescriptorFoundExeption,
EMFFormsNoRendererException {
final TableControlHandle handle = createTableWithTwoTableColumns();
final AbstractSWTRenderer<VElement> tableRenderer = rendererFactory.getRendererInstance(
handle.getTableControl(),
new ViewModelContextWithoutServices(handle.getTableControl()));
tableRenderer.getGridDescription(new SWTGridDescription());
final Control control = tableRenderer.render(new SWTGridCell(0, 0, tableRenderer), shell);
if (control == null) {
fail("No control was rendered");
}
final Grid table = (Grid) getTable(control);
assertEquals(1, table.getItemCount());
final EClass eClass = EcoreFactory.eINSTANCE.createEClass();
((EClass) domainElement).getESuperTypes().add(eClass);
assertEquals(2, table.getItemCount());
}
@Test
public void testTableWithTwoColumnsRemove() throws NoRendererFoundException, NoPropertyDescriptorFoundExeption,
EMFFormsNoRendererException {
final TableControlHandle handle = createTableWithTwoTableColumns();
final AbstractSWTRenderer<VElement> tableRenderer = rendererFactory.getRendererInstance(
handle.getTableControl(),
new ViewModelContextWithoutServices(handle.getTableControl()));
tableRenderer.getGridDescription(new SWTGridDescription());
final Control control = tableRenderer.render(new SWTGridCell(0, 0, tableRenderer), shell);
if (control == null) {
fail("No control was rendered");
}
final Grid table = (Grid) getTable(control);
assertEquals(1, table.getItemCount());
final EClass eClass = ((EClass) domainElement).getESuperTypes().get(0);
((EClass) domainElement).getESuperTypes().remove(eClass);
assertEquals(0, table.getItemCount());
}
@Test
public void testTableWithTwoColumnsClear() throws NoRendererFoundException, NoPropertyDescriptorFoundExeption,
EMFFormsNoRendererException {
final EClass eClass = EcoreFactory.eINSTANCE.createEClass();
((EClass) domainElement).getESuperTypes().add(eClass);
final TableControlHandle handle = createTableWithTwoTableColumns();
final AbstractSWTRenderer<VElement> tableRenderer = rendererFactory.getRendererInstance(
handle.getTableControl(),
new ViewModelContextWithoutServices(handle.getTableControl()));
tableRenderer.getGridDescription(new SWTGridDescription());
final Control control = tableRenderer.render(new SWTGridCell(0, 0, tableRenderer), shell);
if (control == null) {
fail("No control was rendered");
}
final Grid table = (Grid) getTable(control);
assertEquals(2, table.getItemCount());
((EClass) domainElement).getESuperTypes().clear();
assertEquals(0, table.getItemCount());
}
@Test
public void testPanelTableWithTwoColumns() throws NoRendererFoundException, NoPropertyDescriptorFoundExeption,
EMFFormsNoRendererException {
final EClass eClass = EcoreFactory.eINSTANCE.createEClass();
((EClass) domainElement).getESuperTypes().add(eClass);
final TableControlHandle handle = createTableWithTwoTableColumns();
handle.getTableControl().setDetailEditing(DetailEditing.WITH_PANEL);
handle.getTableControl().setDetailView(createDetailView());
final AbstractSWTRenderer<VElement> tableRenderer = rendererFactory.getRendererInstance(
handle.getTableControl(),
new ViewModelContextWithoutServices(handle.getTableControl()));
tableRenderer.getGridDescription(new SWTGridDescription());
final Control render = tableRenderer.render(new SWTGridCell(0, 0, tableRenderer), shell);
final Control control = Composite.class.cast(render).getChildren()[0];
if (control == null) {
fail("No control was rendered");
}
final Composite controlComposite = (Composite) ((Composite) control).getChildren()[1];
final SashForm sash = (SashForm) controlComposite.getChildren()[0];
final Composite tableWrapperComposite = (Composite) sash.getChildren()[0];
final Composite tableComposite = (Composite) tableWrapperComposite.getChildren()[0];
final Grid table = (Grid) tableComposite.getChildren()[0];
final ScrolledComposite scrolledComposite = (ScrolledComposite) sash.getChildren()[1];
final Composite parentForECPView = (Composite) scrolledComposite.getChildren()[0];
assertEquals(2, table.getItemCount());
final GridTableViewer tableViewer = GridTestsUtil.getTableViewerFromRenderer(tableRenderer);
// no initial selection
assertThat("Composite for no selection not present",
asList(parentForECPView.getChildren()), hasItem(instanceOf(Composite.class)));
final Composite stackComposite = (Composite) parentForECPView.getChildren()[0];
final StackLayout stack = (StackLayout) stackComposite.getLayout();
Composite labelComposite = (Composite) stack.topControl;
assertThat("Composite for label not present", labelComposite, notNullValue());
assertThat("Label for no selection not present",
asList(labelComposite.getChildren()), hasItem(instanceOf(Label.class)));
// single selection
tableViewer.setSelection(new StructuredSelection(table.getItem(0).getData()));
Composite detailComposite = (Composite) stack.topControl;
assertEquals(6, detailComposite.getChildren().length);
// multi selection (it's like no selection)
tableViewer.setSelection(new StructuredSelection(new Object[] { table.getItem(0).getData(),
table.getItem(1).getData() }));
detailComposite = (Composite) stack.topControl;
assertThat("Label for multi selection not present",
asList(labelComposite.getChildren()), hasItem(instanceOf(Label.class)));
// select again
tableViewer.setSelection(new StructuredSelection(table.getItem(0).getData()));
detailComposite = (Composite) stack.topControl;
assertEquals(6, detailComposite.getChildren().length);
// no selection
tableViewer.setSelection(new StructuredSelection());
labelComposite = (Composite) stack.topControl;
assertThat("Composite for label not present", labelComposite, notNullValue());
assertThat("Label for no selection not present",
asList(labelComposite.getChildren()), hasItem(instanceOf(Label.class)));
}
@Test
public void testTableSorting() throws NoRendererFoundException, NoPropertyDescriptorFoundExeption,
EMFFormsNoRendererException {
// domain
((EClass) domainElement).getESuperTypes().clear();
final EClass class1 = createEClass("a", "b");
final EClass class2 = createEClass("b", "c");
final EClass class3 = createEClass("c", "a");
((EClass) domainElement).getESuperTypes().add(class1);
((EClass) domainElement).getESuperTypes().add(class2);
((EClass) domainElement).getESuperTypes().add(class3);
// table control
final VTableControl tableControl = TableTestUtil.createTableControl();
final VTableDomainModelReference tableDMR = (VTableDomainModelReference) tableControl.getDomainModelReference();
tableDMR.setDomainModelEFeature(EcorePackage.eINSTANCE.getEClass_ESuperTypes());
tableDMR.getColumnDomainModelReferences().add(createDMR(EcorePackage.eINSTANCE.getENamedElement_Name()));
tableDMR.getColumnDomainModelReferences().add(
createDMR(EcorePackage.eINSTANCE.getEClassifier_InstanceClassName()));
// render
final AbstractSWTRenderer<VElement> tableRenderer = rendererFactory.getRendererInstance(tableControl,
new ViewModelContextWithoutServices(tableControl));
tableRenderer.getGridDescription(new SWTGridDescription());
final Control control = tableRenderer.render(new SWTGridCell(0, 0, tableRenderer), shell);
if (control == null) {
fail("No control was rendered");
}
final Grid table = SWTTestUtil.findControl(control, 0, Grid.class);
assertGridItemOrder(table, class1, class2, class3);
// column 0 is validation column
// select column 1
// up
SWTTestUtil.selectWidget(table.getColumns()[1]);
SWTTestUtil.waitForUIThread();
assertGridItemOrder(table, class1, class2, class3);
// down
SWTTestUtil.selectWidget(table.getColumns()[1]);
SWTTestUtil.waitForUIThread();
assertGridItemOrder(table, class3, class2, class1);
// none
SWTTestUtil.selectWidget(table.getColumns()[1]);
SWTTestUtil.waitForUIThread();
assertGridItemOrder(table, class1, class2, class3);
// select column 2
// up
SWTTestUtil.selectWidget(table.getColumns()[2]);
SWTTestUtil.waitForUIThread();
assertGridItemOrder(table, class3, class1, class2);
// down
SWTTestUtil.selectWidget(table.getColumns()[2]);
SWTTestUtil.waitForUIThread();
assertGridItemOrder(table, class2, class1, class3);
// none
SWTTestUtil.selectWidget(table.getColumns()[2]);
SWTTestUtil.waitForUIThread();
assertGridItemOrder(table, class1, class2, class3);
}
@Test
public void testTableSortingWithCellEditor() throws NoRendererFoundException, NoPropertyDescriptorFoundExeption,
EMFFormsNoRendererException {
// domain
((EClass) domainElement).getESuperTypes().clear();
final EClass class1 = createEClass("a", "b");
final EClass class2 = createEClass("b", "c");
final EClass class3 = createEClass("c", "a");
((EClass) domainElement).getESuperTypes().add(class1);
((EClass) domainElement).getESuperTypes().add(class2);
((EClass) domainElement).getESuperTypes().add(class3);
// table control
final VTableControl tableControl = TableTestUtil.createTableControl();
final VTableDomainModelReference tableDMR = (VTableDomainModelReference) tableControl.getDomainModelReference();
tableDMR.setDomainModelEFeature(EcorePackage.eINSTANCE.getEClass_ESuperTypes());
tableDMR.getColumnDomainModelReferences().add(createDMR(EcorePackage.eINSTANCE.getENamedElement_Name()));
tableDMR.getColumnDomainModelReferences().add(
createDMR(EcorePackage.eINSTANCE.getEClassifier_InstanceClassName()));
// render
final TableControlSWTRenderer tableRenderer = createRendererInstanceWithCustomCellEditor(tableControl);
tableRenderer.getGridDescription(new SWTGridDescription());
final Control control = tableRenderer.render(new SWTGridCell(0, 0, tableRenderer), shell);
if (control == null) {
fail("No control was rendered");
}
final Grid table = SWTTestUtil.findControl(control, 0, Grid.class);
assertGridItemOrder(table, class1, class2, class3);
// column 0 is validation column
// select column 1
// up
SWTTestUtil.selectWidget(table.getColumns()[1]);
SWTTestUtil.waitForUIThread();
assertGridItemOrder(table, class3, class2, class1);
// down
SWTTestUtil.selectWidget(table.getColumns()[1]);
SWTTestUtil.waitForUIThread();
assertGridItemOrder(table, class1, class2, class3);
// none
SWTTestUtil.selectWidget(table.getColumns()[1]);
SWTTestUtil.waitForUIThread();
assertGridItemOrder(table, class1, class2, class3);
// select column 2
// up
SWTTestUtil.selectWidget(table.getColumns()[2]);
SWTTestUtil.waitForUIThread();
assertGridItemOrder(table, class3, class1, class2);
// down
SWTTestUtil.selectWidget(table.getColumns()[2]);
SWTTestUtil.waitForUIThread();
assertGridItemOrder(table, class2, class1, class3);
// none
SWTTestUtil.selectWidget(table.getColumns()[2]);
SWTTestUtil.waitForUIThread();
assertGridItemOrder(table, class1, class2, class3);
}
@Test
public void gridSorting_autoSortOnEdit()
throws EMFFormsNoRendererException, NoRendererFoundException, NoPropertyDescriptorFoundExeption {
// domain
((EClass) domainElement).getEStructuralFeatures().clear();
final EAttribute attribute1 = createEAttribute("a", EcorePackage.Literals.ESTRING, 0, 2);
final EAttribute attribute2 = createEAttribute("b", EcorePackage.Literals.ESTRING, 0, 11);
final EAttribute attribute3 = createEAttribute("c", EcorePackage.Literals.ESTRING, 0, 1);
((EClass) domainElement).getEStructuralFeatures().add(attribute1);
((EClass) domainElement).getEStructuralFeatures().add(attribute2);
((EClass) domainElement).getEStructuralFeatures().add(attribute3);
// table control
final VTableControl tableControl = TableTestUtil.createTableControl();
final VTableDomainModelReference tableDMR = (VTableDomainModelReference) tableControl.getDomainModelReference();
tableDMR.setDomainModelEFeature(EcorePackage.eINSTANCE.getEClass_EAttributes());
tableDMR.getColumnDomainModelReferences().add(createDMR(EcorePackage.eINSTANCE.getENamedElement_Name()));
tableDMR.getColumnDomainModelReferences().add(
createDMR(EcorePackage.eINSTANCE.getETypedElement_UpperBound()));
// render
shell.open();
// With this shell size, the table will be 77 pixels high and show 2 rows
shell.setSize(200, 150);
final Control control = SWTViewTestHelper.render(tableControl, domainElement, shell);
if (control == null) {
fail("No control was rendered");
}
shell.layout();
final Grid grid = SWTTestUtil.findControl(control, 0, Grid.class);
// column 0 is validation column
// select column 1 (name) and ascending sorting
SWTTestUtil.selectWidget(grid.getColumns()[1]);
SWTTestUtil.waitForUIThread();
assertGridItemOrder(grid, attribute1, attribute2, attribute3);
// Change the attribute the sorting is currently applied on and assert that the table was automatically
// re-sorted
attribute1.setName("z");
SWTTestUtil.waitForUIThread();
assertGridItemOrder(grid, attribute2, attribute3, attribute1);
final GridItem sortItem = grid.getItem(2);
final int itemLowerEnd = sortItem.getBounds(1).y + sortItem.getBounds(1).height;
// Assert that the edited grid item was revealed after it had been moved to the end of the grid.
assertThat(
"The edited grid item is not fully visible after the auto sort because the grid didn't scroll down.",
itemLowerEnd, lessThan(grid.getBounds().height));
assertThat(
"The edited grid item is not fully visible after the auto sort because the grid is scrolled too far down.",
sortItem.getBounds(1).y, greaterThan(grid.getHeaderHeight()));
shell.close();
}
/** Tests that the sort indicator of a column is removed when another column is used for sorting. */
@Test
public void gridSorting_sortIndicatorReset()
throws EMFFormsNoRendererException, NoRendererFoundException, NoPropertyDescriptorFoundExeption {
// domain
((EClass) domainElement).getESuperTypes().clear();
final EClass class1 = createEClass("a", "b");
final EClass class2 = createEClass("b", "c");
((EClass) domainElement).getESuperTypes().add(class1);
((EClass) domainElement).getESuperTypes().add(class2);
// table control
final VTableControl tableControl = TableTestUtil.createTableControl();
final VTableDomainModelReference tableDMR = (VTableDomainModelReference) tableControl.getDomainModelReference();
tableDMR.setDomainModelEFeature(EcorePackage.eINSTANCE.getEClass_ESuperTypes());
tableDMR.getColumnDomainModelReferences().add(createDMR(EcorePackage.eINSTANCE.getENamedElement_Name()));
tableDMR.getColumnDomainModelReferences().add(
createDMR(EcorePackage.eINSTANCE.getEClassifier_InstanceClassName()));
// render
final AbstractSWTRenderer<VElement> tableRenderer = rendererFactory.getRendererInstance(tableControl,
new ViewModelContextWithoutServices(tableControl));
tableRenderer.getGridDescription(new SWTGridDescription());
final Control control = tableRenderer.render(new SWTGridCell(0, 0, tableRenderer), shell);
if (control == null) {
fail("No control was rendered");
}
final Grid table = SWTTestUtil.findControl(control, 0, Grid.class);
assertEquals(SWT.NONE, table.getColumn(1).getSort());
assertEquals(SWT.NONE, table.getColumn(2).getSort());
// column 0 is validation column
// select column 1
SWTTestUtil.selectWidget(table.getColumns()[1]);
SWTTestUtil.waitForUIThread();
assertEquals(SWT.DOWN, table.getColumn(1).getSort());
assertEquals(SWT.NONE, table.getColumn(2).getSort());
// select column 2 -> column 1 indicator should be reset
SWTTestUtil.selectWidget(table.getColumn(2));
SWTTestUtil.waitForUIThread();
assertEquals(SWT.NONE, table.getColumn(1).getSort());
assertEquals(SWT.DOWN, table.getColumn(2).getSort());
}
private GridControlSWTRenderer createRendererInstanceWithCustomCellEditor(final VTableControl tableControl)
throws EMFFormsNoRendererException {
final ViewModelContextWithoutServices viewModelContext = new ViewModelContextWithoutServices(tableControl);
final EMFFormsContextProvider contextProvider = viewModelContext.getService(EMFFormsContextProvider.class);
final IEclipseContext eclipseContext = contextProvider.getContext();
final GridControlSWTRenderer tableControlSWTRenderer = new GridControlSWTRenderer(
tableControl,
viewModelContext,
eclipseContext.get(ReportService.class),
eclipseContext.get(EMFFormsDatabindingEMF.class),
eclipseContext.get(EMFFormsLabelProvider.class),
eclipseContext.get(VTViewTemplateProvider.class),
eclipseContext.get(ImageRegistryService.class),
eclipseContext.get(EMFFormsEditSupport.class),
eclipseContext.get(EStructuralFeatureValueConverterService.class),
eclipseContext.get(EMFFormsLocalizationService.class)) {
@Override
protected CellEditor createCellEditor(EObject tempInstance, EStructuralFeature feature, Composite table) {
if (feature == EcorePackage.eINSTANCE.getENamedElement_Name()) {
return new CompareCellEditor(table);
}
return super.createCellEditor(tempInstance, feature, table);
}
};
tableControlSWTRenderer.init();
return tableControlSWTRenderer;
}
private static void assertGridItemOrder(Grid table, Object... objects) {
assertEquals(objects.length, table.getItemCount());
final GridItem[] items = table.getItems();
for (int i = 0; i < items.length; i++) {
assertSame(objects[i], items[i].getData());
}
}
private static EClass createEClass(String name, String instanceClassName) {
final EClass clazz = EcoreFactory.eINSTANCE.createEClass();
clazz.setName(name);
clazz.setInstanceClassName(instanceClassName);
return clazz;
}
private static EAttribute createEAttribute(String name, EClassifier classifier, int lowerBound, int upperBound) {
final EAttribute attribute = EcoreFactory.eINSTANCE.createEAttribute();
attribute.setName(name);
attribute.setEType(classifier);
attribute.setLowerBound(lowerBound);
attribute.setUpperBound(upperBound);
return attribute;
}
private static VFeaturePathDomainModelReference createDMR(EAttribute attribute, EReference... refs) {
final VFeaturePathDomainModelReference dmr = VViewFactory.eINSTANCE.createFeaturePathDomainModelReference();
dmr.setDomainModelEFeature(attribute);
dmr.getDomainModelEReferencePath().addAll(Arrays.asList(refs));
return dmr;
}
private VView createDetailView() {
final VView detailView = VViewFactory.eINSTANCE.createView();
final VControl name = VViewFactory.eINSTANCE.createControl();
final VFeaturePathDomainModelReference nameRef = VViewFactory.eINSTANCE.createFeaturePathDomainModelReference();
nameRef.setDomainModelEFeature(EcorePackage.eINSTANCE.getENamedElement_Name());
name.setDomainModelReference(nameRef);
detailView.getChildren().add(name);
final VControl abstr = VViewFactory.eINSTANCE.createControl();
final VFeaturePathDomainModelReference abstractRef = VViewFactory.eINSTANCE
.createFeaturePathDomainModelReference();
abstractRef.setDomainModelEFeature(EcorePackage.eINSTANCE.getEClass_Abstract());
abstr.setDomainModelReference(abstractRef);
detailView.getChildren().add(abstr);
return detailView;
}
private Control getTable(Control render) {
Composite composite = (Composite) render;
composite = (Composite) composite.getChildren()[0];
composite = (Composite) composite.getChildren()[1];
// composite = (Composite) composite.getChildren()[0];
// composite = (Composite) composite.getChildren()[0];
// composite = (Composite) composite.getChildren()[0];
return composite.getChildren()[0];
}
private static TableControlHandle createTableWithTwoTableColumns() {
final TableControlHandle tableControlHandle = TableTestUtil.createInitializedTableWithoutTableColumns();
final VDomainModelReference tableColumn1 = TableTestUtil
.createTableColumn(EcorePackage.eINSTANCE.getEClass_Abstract());
tableControlHandle.addFirstTableColumn(tableColumn1);
final VDomainModelReference tableColumn2 = TableTestUtil
.createTableColumn(EcorePackage.eINSTANCE.getEClass_Abstract());
tableControlHandle.addSecondTableColumn(tableColumn2);
return tableControlHandle;
}
/**
* Stub implementation without getting services from ex. point.
*
* @author jfaltermeier
*
*/
private class ViewModelContextWithoutServices implements ViewModelContext {
private final VElement view;
private final EMFFormsContextProvider contextProvider;
@SuppressWarnings("restriction")
ViewModelContextWithoutServices(VElement view) {
this.view = view;
contextProvider = new org.eclipse.emfforms.internal.swt.core.di.EMFFormsContextProviderImpl();
contextProvider.instantiate(this);
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.ecp.view.spi.context.ViewModelContext#getViewModel()
*/
@Override
public VElement getViewModel() {
return view;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.ecp.view.spi.context.ViewModelContext#getDomainModel()
*/
@Override
public EObject getDomainModel() {
return domainElement;
}
/**
*
* {@inheritDoc}
*
* @see org.eclipse.emf.ecp.view.spi.context.ViewModelContext#registerViewChangeListener(org.eclipse.emf.ecp.view.spi.model.ModelChangeListener)
*/
@Override
public void registerViewChangeListener(ModelChangeListener modelChangeListener) {
// not needed
}
/**
*
* {@inheritDoc}
*
* @see org.eclipse.emf.ecp.view.spi.context.ViewModelContext#unregisterViewChangeListener(org.eclipse.emf.ecp.view.spi.model.ModelChangeListener)
*/
@Override
public void unregisterViewChangeListener(ModelChangeListener modelChangeListener) {
// not needed
}
/**
*
* {@inheritDoc}
*
* @see org.eclipse.emf.ecp.view.spi.context.ViewModelContext#registerDomainChangeListener(org.eclipse.emf.ecp.view.spi.model.ModelChangeListener)
*/
@Override
public void registerDomainChangeListener(ModelChangeListener modelChangeListener) {
// not needed
}
/**
*
* {@inheritDoc}
*
* @see org.eclipse.emf.ecp.view.spi.context.ViewModelContext#unregisterDomainChangeListener(org.eclipse.emf.ecp.view.spi.model.ModelChangeListener)
*/
@Override
public void unregisterDomainChangeListener(ModelChangeListener modelChangeListener) {
// not needed
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.ecp.view.spi.context.ViewModelContext#dispose()
*/
@Override
public void dispose() {
// not needed
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.ecp.view.spi.context.ViewModelContext#hasService(java.lang.Class)
*/
@Override
public <T> boolean hasService(Class<T> serviceType) {
if (EMFFormsContextProvider.class.equals(serviceType)) {
return true;
}
return false;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.ecp.view.spi.context.ViewModelContext#getService(java.lang.Class)
*/
@SuppressWarnings("unchecked")
@Override
public <T> T getService(Class<T> serviceType) {
if (EMFFormsContextProvider.class.equals(serviceType)) {
return (T) contextProvider;
}
return null;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.ecp.view.spi.context.ViewModelContext#getControlsFor(org.eclipse.emf.ecore.EStructuralFeature.Setting)
* @deprecated
*/
@Deprecated
@Override
public Set<VControl> getControlsFor(Setting setting) {
return null;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.ecp.view.spi.context.ViewModelContext#getControlsFor(org.eclipse.emf.ecp.common.spi.UniqueSetting)
* @deprecated
*/
@Deprecated
@Override
public Set<VElement> getControlsFor(UniqueSetting setting) {
return null;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.ecp.view.spi.context.ViewModelContext#getContextValue(java.lang.String)
*/
@Override
public Object getContextValue(String key) {
return null;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.ecp.view.spi.context.ViewModelContext#putContextValue(java.lang.String,
* java.lang.Object)
*/
@Override
public void putContextValue(String key, Object value) {
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.ecp.view.spi.context.ViewModelContext#registerDisposeListener(org.eclipse.emf.ecp.view.spi.context.ViewModelContextDisposeListener)
*/
@Override
public void registerDisposeListener(ViewModelContextDisposeListener listener) {
// TODO Auto-generated method stub
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.ecp.view.spi.context.ViewModelContext#addContextUser(java.lang.Object)
*/
@Override
public void addContextUser(Object user) {
// TODO Auto-generated method stub
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.ecp.view.spi.context.ViewModelContext#removeContextUser(java.lang.Object)
*/
@Override
public void removeContextUser(Object user) {
// TODO Auto-generated method stub
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.ecp.view.spi.context.ViewModelContext#getChildContext(org.eclipse.emf.ecore.EObject,
* org.eclipse.emf.ecp.view.spi.model.VElement, org.eclipse.emf.ecp.view.spi.model.VView,
* org.eclipse.emf.ecp.view.spi.context.ViewModelService[])
*/
@Override
public ViewModelContext getChildContext(EObject eObject, VElement parent, VView vView,
ViewModelService... viewModelServices) {
// TODO Auto-generated method stub
final ViewModelContextWithoutServices vmcws = new ViewModelContextWithoutServices(vView);
return vmcws;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emfforms.spi.core.services.view.EMFFormsViewContext#registerEMFFormsContextListener(org.eclipse.emfforms.spi.core.services.view.EMFFormsContextListener)
*/
@Override
public void registerEMFFormsContextListener(EMFFormsContextListener contextListener) {
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emfforms.spi.core.services.view.EMFFormsViewContext#unregisterEMFFormsContextListener(org.eclipse.emfforms.spi.core.services.view.EMFFormsContextListener)
*/
@Override
public void unregisterEMFFormsContextListener(EMFFormsContextListener contextListener) {
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.ecp.view.spi.context.ViewModelContext#getParentContext()
*/
@Override
public ViewModelContext getParentContext() {
// TODO Auto-generated method stub
return null;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emfforms.spi.core.services.view.EMFFormsViewContext#changeDomainModel(org.eclipse.emf.ecore.EObject)
*/
@Override
public void changeDomainModel(EObject newDomainModel) {
// TODO Auto-generated method stub
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emfforms.spi.core.services.view.EMFFormsViewContext#registerRootDomainModelChangeListener(org.eclipse.emfforms.spi.core.services.view.RootDomainModelChangeListener)
*/
@Override
public void registerRootDomainModelChangeListener(RootDomainModelChangeListener rootDomainModelChangeListener) {
// TODO Auto-generated method stub
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emfforms.spi.core.services.view.EMFFormsViewContext#unregisterRootDomainModelChangeListener(org.eclipse.emfforms.spi.core.services.view.RootDomainModelChangeListener)
*/
@Override
public void unregisterRootDomainModelChangeListener(
RootDomainModelChangeListener rootDomainModelChangeListener) {
// TODO Auto-generated method stub
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.ecp.view.spi.context.ViewModelContext#getParentVElement()
*/
@Override
public VElement getParentVElement() {
// TODO Auto-generated method stub
return null;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.ecp.view.spi.context.ViewModelContext#getChildContext(org.eclipse.emf.ecore.EObject,
* org.eclipse.emf.ecp.view.spi.model.VElement, org.eclipse.emf.ecp.view.spi.model.VView,
* org.eclipse.emf.ecp.view.spi.context.ViewModelServiceProvider)
*/
@Override
public ViewModelContext getChildContext(EObject eObject, VElement parent, VView vView,
ViewModelServiceProvider viewModelServiceProvider) {
// TODO Auto-generated method stub
return null;
}
@Override
public void pause() {
// do nothing
}
@Override
public void reactivate() {
// do nothing
}
}
private static class PrintStreamWrapper extends PrintStream {
private final PrintStream printStream;
PrintStreamWrapper(PrintStream printStream) {
super(new ByteArrayOutputStream());
this.printStream = printStream;
}
/**
* {@inheritDoc}
*
* @see java.io.PrintStream#print(java.lang.String)
*/
@Override
public void print(String s) {
log = log.concat("\n" + s);
printStream.print(s + "\n");
}
}
private static class CompareCellEditor extends StringCellEditor implements ECPCellEditorComparator {
CompareCellEditor(Composite table) {
super(table);
}
@Override
public int compare(Object e1, Object e2, int direction) {
final String value1 = String.class.cast(e1);
final String value2 = String.class.cast(e2);
int result;
if (value1 == null) {
result = 1;
} else if (value2 == null) {
result = -1;
} else {
result = value1.toString().compareTo(value2.toString()) * -1;// we flip the oder in our custom
// comparator
}
// If descending order, flip the direction
if (direction == 2) {
result = -result;
}
return result;
}
}
}