Skip to content

Package: SWTTable_PTest$PrintStreamWrapper

SWTTable_PTest$PrintStreamWrapper

nameinstructionbranchcomplexitylinemethod
SWTTable_PTest.PrintStreamWrapper(PrintStream)
M: 0 C: 9
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
print(String)
M: 22 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%

Coverage

1: /*******************************************************************************
2: * Copyright (c) 2011-2019 EclipseSource Muenchen GmbH and others.
3: *
4: * All rights reserved. This program and the accompanying materials
5: * are made available under the terms of the Eclipse Public License 2.0
6: * which accompanies this distribution, and is available at
7: * https://www.eclipse.org/legal/epl-2.0/
8: *
9: * SPDX-License-Identifier: EPL-2.0
10: *
11: * Contributors:
12: * Johannes Faltermeier
13: * Christian W. Damus - bugs 527740, 544116, 545686, 527686, 547787, 548592
14: *
15: *******************************************************************************/
16: package org.eclipse.emf.ecp.view.spi.table.swt;
17:
18: import static java.util.Arrays.asList;
19: import static org.hamcrest.CoreMatchers.instanceOf;
20: import static org.hamcrest.CoreMatchers.is;
21: import static org.hamcrest.CoreMatchers.notNullValue;
22: import static org.hamcrest.Matchers.equalTo;
23: import static org.hamcrest.Matchers.greaterThanOrEqualTo;
24: import static org.hamcrest.Matchers.hasItem;
25: import static org.hamcrest.Matchers.lessThan;
26: import static org.junit.Assert.assertEquals;
27: import static org.junit.Assert.assertFalse;
28: import static org.junit.Assert.assertSame;
29: import static org.junit.Assert.assertThat;
30: import static org.junit.Assert.assertTrue;
31: import static org.junit.Assert.fail;
32: import static org.junit.Assume.assumeThat;
33: import static org.mockito.Matchers.any;
34: import static org.mockito.Matchers.anyBoolean;
35: import static org.mockito.Mockito.mock;
36: import static org.mockito.Mockito.verify;
37: import static org.mockito.Mockito.when;
38:
39: import java.io.ByteArrayOutputStream;
40: import java.io.PrintStream;
41: import java.lang.reflect.InvocationTargetException;
42: import java.lang.reflect.Method;
43: import java.util.Arrays;
44: import java.util.HashMap;
45: import java.util.HashSet;
46: import java.util.Hashtable;
47: import java.util.LinkedHashMap;
48: import java.util.Map;
49: import java.util.Set;
50: import java.util.concurrent.TimeUnit;
51:
52: import javax.inject.Inject;
53:
54: import org.eclipse.core.databinding.observable.map.IObservableMap;
55: import org.eclipse.e4.core.contexts.IEclipseContext;
56: import org.eclipse.emf.common.command.BasicCommandStack;
57: import org.eclipse.emf.common.notify.AdapterFactory;
58: import org.eclipse.emf.common.util.BasicDiagnostic;
59: import org.eclipse.emf.common.util.Diagnostic;
60: import org.eclipse.emf.common.util.EList;
61: import org.eclipse.emf.common.util.URI;
62: import org.eclipse.emf.ecore.EAttribute;
63: import org.eclipse.emf.ecore.EClass;
64: import org.eclipse.emf.ecore.EClassifier;
65: import org.eclipse.emf.ecore.EObject;
66: import org.eclipse.emf.ecore.EPackage;
67: import org.eclipse.emf.ecore.EReference;
68: import org.eclipse.emf.ecore.EStructuralFeature;
69: import org.eclipse.emf.ecore.EStructuralFeature.Setting;
70: import org.eclipse.emf.ecore.EcoreFactory;
71: import org.eclipse.emf.ecore.EcorePackage;
72: import org.eclipse.emf.ecore.resource.Resource;
73: import org.eclipse.emf.ecore.resource.ResourceSet;
74: import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
75: import org.eclipse.emf.ecore.util.EcoreUtil;
76: import org.eclipse.emf.ecp.common.spi.UniqueSetting;
77: import org.eclipse.emf.ecp.edit.spi.ReferenceService;
78: import org.eclipse.emf.ecp.edit.spi.swt.table.ECPCellEditorComparator;
79: import org.eclipse.emf.ecp.edit.spi.swt.table.StringCellEditor;
80: import org.eclipse.emf.ecp.view.internal.context.ViewModelContextImpl;
81: import org.eclipse.emf.ecp.view.spi.context.ViewModelContext;
82: import org.eclipse.emf.ecp.view.spi.context.ViewModelContextDisposeListener;
83: import org.eclipse.emf.ecp.view.spi.context.ViewModelContextFactory;
84: import org.eclipse.emf.ecp.view.spi.context.ViewModelService;
85: import org.eclipse.emf.ecp.view.spi.context.ViewModelServiceProvider;
86: import org.eclipse.emf.ecp.view.spi.model.ModelChangeListener;
87: import org.eclipse.emf.ecp.view.spi.model.VControl;
88: import org.eclipse.emf.ecp.view.spi.model.VDiagnostic;
89: import org.eclipse.emf.ecp.view.spi.model.VDomainModelReference;
90: import org.eclipse.emf.ecp.view.spi.model.VElement;
91: import org.eclipse.emf.ecp.view.spi.model.VFeatureDomainModelReferenceSegment;
92: import org.eclipse.emf.ecp.view.spi.model.VFeaturePathDomainModelReference;
93: import org.eclipse.emf.ecp.view.spi.model.VView;
94: import org.eclipse.emf.ecp.view.spi.model.VViewFactory;
95: import org.eclipse.emf.ecp.view.spi.model.VViewPackage;
96: import org.eclipse.emf.ecp.view.spi.renderer.NoPropertyDescriptorFoundExeption;
97: import org.eclipse.emf.ecp.view.spi.renderer.NoRendererFoundException;
98: import org.eclipse.emf.ecp.view.spi.swt.masterdetail.DetailViewCache;
99: import org.eclipse.emf.ecp.view.spi.table.model.DetailEditing;
100: import org.eclipse.emf.ecp.view.spi.table.model.VEnablementConfiguration;
101: import org.eclipse.emf.ecp.view.spi.table.model.VTableControl;
102: import org.eclipse.emf.ecp.view.spi.table.model.VTableDomainModelReference;
103: import org.eclipse.emf.ecp.view.spi.table.model.VTableFactory;
104: import org.eclipse.emf.ecp.view.spi.table.swt.action.AddRowAction;
105: import org.eclipse.emf.ecp.view.spi.table.swt.action.DuplicateRowAction;
106: import org.eclipse.emf.ecp.view.spi.table.swt.action.MoveRowDownAction;
107: import org.eclipse.emf.ecp.view.spi.table.swt.action.MoveRowUpAction;
108: import org.eclipse.emf.ecp.view.spi.table.swt.action.RemoveRowAction;
109: import org.eclipse.emf.ecp.view.spi.util.swt.ImageRegistryService;
110: import org.eclipse.emf.ecp.view.table.test.common.TableControlHandle;
111: import org.eclipse.emf.ecp.view.table.test.common.TableTestUtil;
112: import org.eclipse.emf.ecp.view.template.model.VTViewTemplateProvider;
113: import org.eclipse.emf.ecp.view.template.style.tableValidation.model.VTTableValidationFactory;
114: import org.eclipse.emf.ecp.view.template.style.tableValidation.model.VTTableValidationStyleProperty;
115: import org.eclipse.emf.ecp.view.test.common.swt.spi.DatabindingClassRunner;
116: import org.eclipse.emf.ecp.view.test.common.swt.spi.SWTTestUtil;
117: import org.eclipse.emf.ecp.view.test.common.swt.spi.SWTViewTestHelper;
118: import org.eclipse.emf.ecp.view.test.common.swt.spi.SWTViewTestHelper.RendererResult;
119: import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain;
120: import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
121: import org.eclipse.emf.edit.provider.ReflectiveItemProviderAdapterFactory;
122: import org.eclipse.emfforms.common.Optional;
123: import org.eclipse.emfforms.spi.common.report.ReportService;
124: import org.eclipse.emfforms.spi.core.services.databinding.emf.EMFFormsDatabindingEMF;
125: import org.eclipse.emfforms.spi.core.services.editsupport.EMFFormsEditSupport;
126: import org.eclipse.emfforms.spi.core.services.label.EMFFormsLabelProvider;
127: import org.eclipse.emfforms.spi.core.services.view.EMFFormsContextListener;
128: import org.eclipse.emfforms.spi.core.services.view.RootDomainModelChangeListener;
129: import org.eclipse.emfforms.spi.swt.core.AbstractSWTRenderer;
130: import org.eclipse.emfforms.spi.swt.core.EMFFormsNoRendererException;
131: import org.eclipse.emfforms.spi.swt.core.EMFFormsRendererFactory;
132: import org.eclipse.emfforms.spi.swt.core.SWTDataElementIdHelper;
133: import org.eclipse.emfforms.spi.swt.core.di.EMFFormsContextProvider;
134: import org.eclipse.emfforms.spi.swt.core.di.EMFFormsDIRendererService;
135: import org.eclipse.emfforms.spi.swt.core.layout.SWTGridCell;
136: import org.eclipse.emfforms.spi.swt.core.layout.SWTGridDescription;
137: import org.eclipse.emfforms.view.spi.multisegment.model.VMultiDomainModelReferenceSegment;
138: import org.eclipse.emfforms.view.spi.multisegment.model.VMultisegmentFactory;
139: import org.eclipse.jface.viewers.CellEditor;
140: import org.eclipse.jface.viewers.CellLabelProvider;
141: import org.eclipse.jface.viewers.StructuredSelection;
142: import org.eclipse.jface.viewers.TableViewer;
143: import org.eclipse.swt.SWT;
144: import org.eclipse.swt.custom.ScrolledComposite;
145: import org.eclipse.swt.custom.StackLayout;
146: import org.eclipse.swt.widgets.Button;
147: import org.eclipse.swt.widgets.Composite;
148: import org.eclipse.swt.widgets.Control;
149: import org.eclipse.swt.widgets.Label;
150: import org.eclipse.swt.widgets.Shell;
151: import org.eclipse.swt.widgets.Table;
152: import org.eclipse.swt.widgets.TableColumn;
153: import org.eclipse.swt.widgets.TableItem;
154: import org.junit.After;
155: import org.junit.AfterClass;
156: import org.junit.Before;
157: import org.junit.BeforeClass;
158: import org.junit.Ignore;
159: import org.junit.Test;
160: import org.junit.runner.RunWith;
161: import org.osgi.framework.BundleContext;
162: import org.osgi.framework.FrameworkUtil;
163: import org.osgi.framework.ServiceReference;
164: import org.osgi.framework.ServiceRegistration;
165:
166: @SuppressWarnings({ "restriction", "deprecation" })
167: @RunWith(DatabindingClassRunner.class)
168: public class SWTTable_PTest {
169:         private static String log;
170:         private static ServiceReference<EMFFormsRendererFactory> factoryServiceReference;
171:         private static EMFFormsRendererFactory rendererFactory;
172:         private static PrintStream systemErr;
173:         private Shell shell;
174:         private EObject domainElement;
175:         private ComposedAdapterFactory adapterFactory;
176:
177:         @BeforeClass
178:         public static void beforeClass() {
179:                 systemErr = System.err;
180:                 System.setErr(new PrintStreamWrapper(systemErr));
181:                 final BundleContext bundleContext = FrameworkUtil.getBundle(SWTTable_PTest.class).getBundleContext();
182:                 factoryServiceReference = bundleContext.getServiceReference(EMFFormsRendererFactory.class);
183:                 rendererFactory = bundleContext.getService(factoryServiceReference);
184:         }
185:
186:         @AfterClass
187:         public static void afterClass() {
188:                 System.setErr(systemErr);
189:                 final BundleContext bundleContext = FrameworkUtil.getBundle(SWTTable_PTest.class).getBundleContext();
190:                 bundleContext.ungetService(factoryServiceReference);
191:         }
192:
193:         @Before
194:         public void init() {
195:                 log = "";
196:                 shell = SWTViewTestHelper.createShell();
197:
198:                 final EClass eClass = EcoreFactory.eINSTANCE.createEClass();
199:                 eClass.getESuperTypes().add(EcorePackage.eINSTANCE.getEClass());
200:                 domainElement = eClass;
201:
202:                 // Add domain element to resource with editing domain
203:                 final ResourceSet rs = new ResourceSetImpl();
204:                 adapterFactory = new ComposedAdapterFactory(new AdapterFactory[] {
205:                         new ReflectiveItemProviderAdapterFactory(),
206:                         new ComposedAdapterFactory(ComposedAdapterFactory.Descriptor.Registry.INSTANCE) });
207:                 final AdapterFactoryEditingDomain editingDomain = new AdapterFactoryEditingDomain(
208:                         adapterFactory, new BasicCommandStack(), rs);
209:                 rs.eAdapters().add(new AdapterFactoryEditingDomain.EditingDomainProvider(editingDomain));
210:                 final Resource resource = rs.createResource(URI.createURI("VIRTUAL_URI")); //$NON-NLS-1$
211:                 resource.getContents().add(domainElement);
212:         }
213:
214:         @After
215:         public void after() {
216:                 if (!log.isEmpty()) {
217:                         fail("Unexpected log to System.err: " + log);
218:                 }
219:                 adapterFactory.dispose();
220:                 if (shell != null && !shell.isDisposed()) {
221:                         shell.dispose();
222:                 }
223:         }
224:
225:         @Test
226:         public void testUninitializedTableWithoutColumns() throws NoRendererFoundException,
227:                 NoPropertyDescriptorFoundExeption, EMFFormsNoRendererException {
228:                 // setup model
229:                 final TableControlHandle handle = TableTestUtil.createUninitializedTableWithoutColumns();
230:                 //
231:                 final Control render = SWTViewTestHelper.render(handle.getTableControl(), domainElement, shell);
232:                 assertTrue(Label.class.isInstance(render));// Error label with error text
233:                 assertEquals("The field domainModelEFeature of the given VFeaturePathDomainModelReference must not be null.",
234:                         Label.class.cast(render).getText());
235:         }
236:
237:         @Test
238:         public void testInitializedTableWithoutColumnsAndEmptyReference() throws NoRendererFoundException,
239:                 NoPropertyDescriptorFoundExeption, EMFFormsNoRendererException {
240:                 // setup model
241:                 final EClass createEClass = EcoreFactory.eINSTANCE.createEClass();
242:                 createEClass.eUnset(EcorePackage.eINSTANCE.getEClass_ESuperTypes());
243:                 domainElement = createEClass;
244:                 final TableControlHandle handle = TableTestUtil.createInitializedTableWithoutTableColumns();
245:
246:                 try {
247:                         SWTViewTestHelper.render(handle.getTableControl(), domainElement, shell);
248:                 } catch (final NullPointerException e) {
249:                         fail("Fails without a reference in domain object");
250:                 }
251:
252:         }
253:
254:         @Ignore
255:         @Test
256:         public void testInitializedTableWithoutColumnsSingleReference() throws NoRendererFoundException,
257:                 NoPropertyDescriptorFoundExeption, EMFFormsNoRendererException {
258:                 // setup model
259:                 final VView view = VViewFactory.eINSTANCE.createView();
260:                 view.setRootEClass(VViewPackage.eINSTANCE.getView());
261:                 domainElement = view;
262:                 final TableControlHandle handle = TableTestUtil.createInitializedTableWithoutTableColumns();
263:                 final VFeaturePathDomainModelReference domainModelReference = VViewFactory.eINSTANCE
264:                         .createFeaturePathDomainModelReference();
265:                 domainModelReference.setDomainModelEFeature(VViewPackage.eINSTANCE.getView_RootEClass());
266:                 handle.getTableControl().setDomainModelReference(domainModelReference);
267:
268:                 try {
269:                         SWTViewTestHelper.render(handle.getTableControl(), domainElement, shell);
270:                 } catch (final ClassCastException e) {
271:                         e.printStackTrace();
272:                         fail("Fails with single reference in domain object");
273:                 }
274:
275:         }
276:
277:         @Ignore
278:         @Test
279:         public void testInitializedTableWithoutColumnsEmptySingleReference() throws NoRendererFoundException,
280:                 NoPropertyDescriptorFoundExeption, EMFFormsNoRendererException {
281:                 // setup model
282:                 final VView view = VViewFactory.eINSTANCE.createView();
283:                 domainElement = view;
284:                 final TableControlHandle handle = TableTestUtil.createInitializedTableWithoutTableColumns();
285:                 final VFeaturePathDomainModelReference domainModelReference = VViewFactory.eINSTANCE
286:                         .createFeaturePathDomainModelReference();
287:                 domainModelReference.setDomainModelEFeature(VViewPackage.eINSTANCE.getView_RootEClass());
288:                 handle.getTableControl().setDomainModelReference(domainModelReference);
289:
290:                 try {
291:                         SWTViewTestHelper.render(handle.getTableControl(), domainElement, shell);
292:                 } catch (final NullPointerException e) {
293:                         fail("Fails with empty single reference in domain object");
294:                 }
295:
296:         }
297:
298:         @Test
299:         public void testTableActionControlOrderAndSWTData()
300:                 throws NoRendererFoundException, NoPropertyDescriptorFoundExeption,
301:                 EMFFormsNoRendererException {
302:                 // setup model
303:                 final TableControlHandle handle = TableTestUtil.createInitializedTableWithoutTableColumns();
304:                 handle.getTableControl().setMoveUpDownDisabled(false);
305:                 final Control render = SWTViewTestHelper.render(handle.getTableControl(), domainElement, shell);
306:                 assertEquals("UUID#control", render.getData(SWTDataElementIdHelper.ELEMENT_ID_KEY));
307:                 assertEquals("UUID#table_moveUp", SWTTestUtil.findControl(render, 0, Button.class)
308:                         .getData(SWTDataElementIdHelper.ELEMENT_ID_KEY));
309:                 assertEquals("UUID#table_moveDown", SWTTestUtil.findControl(render, 1, Button.class)
310:                         .getData(SWTDataElementIdHelper.ELEMENT_ID_KEY));
311:                 assertEquals("UUID#table_add", SWTTestUtil.findControl(render, 2, Button.class)
312:                         .getData(SWTDataElementIdHelper.ELEMENT_ID_KEY));
313:                 assertEquals("UUID#table_remove", SWTTestUtil.findControl(render, 3, Button.class)
314:                         .getData(SWTDataElementIdHelper.ELEMENT_ID_KEY));
315:         }
316:
317:         @Test
318:         public void testTableWithoutColumns() throws NoRendererFoundException, NoPropertyDescriptorFoundExeption,
319:                 EMFFormsNoRendererException {
320:                 // setup model
321:                 final TableControlHandle handle = TableTestUtil.createInitializedTableWithoutTableColumns();
322:
323:                 final Control render = SWTViewTestHelper.render(handle.getTableControl(), domainElement, shell);
324:                 assertTrue(render instanceof Composite);
325:
326:                 // see bug #533262, TableColumnGenerator now includes attributes from super types
327:                 // if this is not desired the user has to specify the columns in the view model
328:                 assertEquals(domainElement.eClass().getEAllAttributes().size(),
329:                         VTableDomainModelReference.class.cast(handle.getTableControl().getDomainModelReference())
330:                                 .getColumnDomainModelReferences().size());
331:
332:                 final Control control = getTable(render);
333:                 assertTrue(control instanceof Table);
334:                 final Table table = (Table) control;
335:                 assertEquals(domainElement.eClass().getEAllAttributes().size() + 1, table.getColumnCount());
336:         }
337:
338:         @Test
339:         public void testTableWithoutColumnsWithoutViewServices() throws NoRendererFoundException,
340:                 NoPropertyDescriptorFoundExeption, EMFFormsNoRendererException {
341:                 final TableControlHandle handle = TableTestUtil.createInitializedTableWithoutTableColumns();
342:                 final AbstractSWTRenderer<VElement> tableRenderer = rendererFactory.getRendererInstance(
343:                         handle.getTableControl(),
344:                         new ViewModelContextWithoutServices(handle.getTableControl()));
345:                 tableRenderer.getGridDescription(new SWTGridDescription());
346:                 final Control render = tableRenderer.render(new SWTGridCell(0, 0, tableRenderer), shell);
347:                 if (render == null) {
348:                         fail();
349:                 }
350:                 assertTrue(render instanceof Composite);
351:
352:                 assertEquals(0, VTableDomainModelReference.class.cast(handle.getTableControl().getDomainModelReference())
353:                         .getColumnDomainModelReferences().size());
354:
355:                 final Control control = getTable(render);
356:                 assertTrue(control instanceof Table);
357:                 final Table table = (Table) control;
358:                 assertEquals(1, table.getColumnCount());
359:         }
360:
361:         @Test
362:         public void testTableWithTwoColumns() throws NoRendererFoundException, NoPropertyDescriptorFoundExeption,
363:                 EMFFormsNoRendererException {
364:                 // setup model
365:                 final TableControlHandle handle = createTableWithTwoTableColumns();
366:                 final Control render = SWTViewTestHelper.render(handle.getTableControl(), domainElement, shell);
367:                 assertTrue(render instanceof Composite);
368:
369:                 final Control control = getTable(render);
370:                 assertTrue(control instanceof Table);
371:                 final Table table = (Table) control;
372:                 assertEquals(2 + 1, table.getColumnCount());
373:
374:         }
375:
376:         @Test
377:         public void testTableCustomColumnHeading() throws NoRendererFoundException, NoPropertyDescriptorFoundExeption,
378:                 EMFFormsNoRendererException {
379:
380:                 final TableControlHandle handle = createTableWithTwoTableColumns();
381:
382:                 // The custom label is specified by the Enablement Configuration
383:                 final VEnablementConfiguration config = VTableFactory.eINSTANCE.createEnablementConfiguration();
384:                 config.setColumnDomainReference(handle.getTableColumn2());
385:                 final String customHeading = "Custom Heading";
386:                 config.setName(customHeading);
387:                 config.setLabel(customHeading); // Normally, the view localization service would supply this
388:                 handle.getTableControl().getColumnConfigurations().add(config);
389:
390:                 final Control render = SWTViewTestHelper.render(handle.getTableControl(), domainElement, shell);
391:                 assumeThat("Expected a composite", render, instanceOf(Composite.class));
392:
393:                 final Control control = getTable(render);
394:                 assumeThat("Expected a Table", control, instanceOf(Table.class));
395:                 final Table table = (Table) control;
396:                 assumeThat("Expected three columns (including validation status)",
397:                         table.getColumnCount(), is(1 + 2));
398:
399:                 final TableColumn column = table.getColumn(2);
400:                 assertThat("Wrong column heading", column.getText(), is(customHeading));
401:         }
402:
403:         @Test
404:         public void testTableWithTwoColumnsWithoutViewServices() throws NoRendererFoundException,
405:                 NoPropertyDescriptorFoundExeption, EMFFormsNoRendererException {
406:                 // setup model
407:                 final TableControlHandle handle = createTableWithTwoTableColumns();
408:                 final AbstractSWTRenderer<VElement> tableRenderer = rendererFactory.getRendererInstance(
409:                         handle.getTableControl(),
410:                         new ViewModelContextWithoutServices(handle.getTableControl()));
411:                 tableRenderer.getGridDescription(new SWTGridDescription());
412:                 final Control render = tableRenderer.render(new SWTGridCell(0, 0, tableRenderer), shell);
413:                 if (render == null) {
414:                         fail();
415:                 }
416:                 assertTrue(render instanceof Composite);
417:
418:                 final Control control = getTable(render);
419:                 assertTrue(control instanceof Table);
420:                 final Table table = (Table) control;
421:                 assertEquals(2 + 1, table.getColumnCount());
422:         }
423:
424:         @Test
425:         public void testTableWithTwoColumnsAdd() throws NoRendererFoundException, NoPropertyDescriptorFoundExeption,
426:                 EMFFormsNoRendererException {
427:                 final TableControlHandle handle = createTableWithTwoTableColumns();
428:                 final AbstractSWTRenderer<VElement> tableRenderer = rendererFactory.getRendererInstance(
429:                         handle.getTableControl(),
430:                         new ViewModelContextWithoutServices(handle.getTableControl()));
431:                 tableRenderer.getGridDescription(new SWTGridDescription());
432:                 final Control control = tableRenderer.render(new SWTGridCell(0, 0, tableRenderer), shell);
433:                 if (control == null) {
434:                         fail("No control was rendered");
435:                 }
436:                 final Table table = (Table) getTable(control);
437:                 assertEquals(1, table.getItemCount());
438:                 final EClass eClass = EcoreFactory.eINSTANCE.createEClass();
439:                 ((EClass) domainElement).getESuperTypes().add(eClass);
440:                 assertEquals(2, table.getItemCount());
441:         }
442:
443:         @Test
444:         public void testTableWithTwoColumnsRemove() throws NoRendererFoundException, NoPropertyDescriptorFoundExeption,
445:                 EMFFormsNoRendererException {
446:                 final TableControlHandle handle = createTableWithTwoTableColumns();
447:                 final AbstractSWTRenderer<VElement> tableRenderer = rendererFactory.getRendererInstance(
448:                         handle.getTableControl(),
449:                         new ViewModelContextWithoutServices(handle.getTableControl()));
450:                 tableRenderer.getGridDescription(new SWTGridDescription());
451:                 final Control control = tableRenderer.render(new SWTGridCell(0, 0, tableRenderer), shell);
452:                 if (control == null) {
453:                         fail("No control was rendered");
454:                 }
455:                 final Table table = (Table) getTable(control);
456:                 assertEquals(1, table.getItemCount());
457:                 final EClass eClass = ((EClass) domainElement).getESuperTypes().get(0);
458:                 ((EClass) domainElement).getESuperTypes().remove(eClass);
459:                 assertEquals(0, table.getItemCount());
460:         }
461:
462:         @Test
463:         public void testTableWithTwoColumnsClear() throws NoRendererFoundException, NoPropertyDescriptorFoundExeption,
464:                 EMFFormsNoRendererException {
465:                 final EClass eClass = EcoreFactory.eINSTANCE.createEClass();
466:                 ((EClass) domainElement).getESuperTypes().add(eClass);
467:                 final TableControlHandle handle = createTableWithTwoTableColumns();
468:                 final AbstractSWTRenderer<VElement> tableRenderer = rendererFactory.getRendererInstance(
469:                         handle.getTableControl(),
470:                         new ViewModelContextWithoutServices(handle.getTableControl()));
471:                 tableRenderer.getGridDescription(new SWTGridDescription());
472:                 final Control control = tableRenderer.render(new SWTGridCell(0, 0, tableRenderer), shell);
473:                 if (control == null) {
474:                         fail("No control was rendered");
475:                 }
476:                 final Table table = (Table) getTable(control);
477:                 assertEquals(2, table.getItemCount());
478:                 ((EClass) domainElement).getESuperTypes().clear();
479:                 assertEquals(0, table.getItemCount());
480:         }
481:
482:         @Test
483:         public void testPanelTableWithTwoColumns() throws NoRendererFoundException, NoPropertyDescriptorFoundExeption,
484:                 EMFFormsNoRendererException {
485:                 final EClass eClass = EcoreFactory.eINSTANCE.createEClass();
486:                 ((EClass) domainElement).getESuperTypes().add(eClass);
487:                 final TableControlHandle handle = createTableWithTwoTableColumns();
488:                 handle.getTableControl().setDetailEditing(DetailEditing.WITH_PANEL);
489:                 handle.getTableControl().setDetailView(createDetailView());
490:                 final AbstractSWTRenderer<VElement> tableRenderer = rendererFactory.getRendererInstance(
491:                         handle.getTableControl(),
492:                         new ViewModelContextWithoutServices(handle.getTableControl()));
493:                 tableRenderer.getGridDescription(new SWTGridDescription());
494:                 final Control render = tableRenderer.render(new SWTGridCell(0, 0, tableRenderer), shell);
495:                 final Control control = Composite.class.cast(render).getChildren()[0];
496:                 if (control == null) {
497:                         fail("No control was rendered");
498:                 }
499:                 final Composite controlComposite = (Composite) ((Composite) control).getChildren()[1];
500:                 final Composite tableComposite = (Composite) controlComposite.getChildren()[0];
501:                 final Table table = (Table) tableComposite.getChildren()[0];
502:                 final ScrolledComposite scrolledComposite = (ScrolledComposite) controlComposite.getChildren()[1];
503:                 final Composite parentForECPView = (Composite) scrolledComposite.getChildren()[0];
504:                 assertEquals(2, table.getItemCount());
505:                 final TableViewer tableViewer = getTableViewerFromRenderer(tableRenderer);
506:
507:                 // no initial selection
508:                 assertThat("Composite for no selection not present",
509:                         asList(parentForECPView.getChildren()), hasItem(instanceOf(Composite.class)));
510:                 final Composite stackComposite = (Composite) parentForECPView.getChildren()[0];
511:                 final StackLayout stack = (StackLayout) stackComposite.getLayout();
512:                 Composite labelComposite = (Composite) stack.topControl;
513:                 assertThat("Composite for label not present", labelComposite, notNullValue());
514:                 assertThat("Label for no selection not present",
515:                         asList(labelComposite.getChildren()), hasItem(instanceOf(Label.class)));
516:
517:                 // single selection
518:                 tableViewer.setSelection(new StructuredSelection(table.getItem(0).getData()));
519:                 Composite detailComposite = (Composite) stack.topControl;
520:                 assertEquals(6, detailComposite.getChildren().length);
521:
522:                 // multi selection (it's like no selection)
523:                 tableViewer.setSelection(new StructuredSelection(new Object[] { table.getItem(0).getData(),
524:                         table.getItem(1).getData() }));
525:                 detailComposite = (Composite) stack.topControl;
526:                 assertThat("Label for multi selection not present",
527:                         asList(labelComposite.getChildren()), hasItem(instanceOf(Label.class)));
528:
529:                 // select again
530:                 tableViewer.setSelection(new StructuredSelection(table.getItem(0).getData()));
531:                 detailComposite = (Composite) stack.topControl;
532:                 assertEquals(6, detailComposite.getChildren().length);
533:
534:                 // no selection
535:                 tableViewer.setSelection(new StructuredSelection());
536:                 labelComposite = (Composite) stack.topControl;
537:                 assertThat("Composite for label not present", labelComposite, notNullValue());
538:                 assertThat("Label for no selection not present",
539:                         asList(labelComposite.getChildren()), hasItem(instanceOf(Label.class)));
540:         }
541:
542:         @Test
543:         public void testTableSorting() throws NoRendererFoundException, NoPropertyDescriptorFoundExeption,
544:                 EMFFormsNoRendererException {
545:                 // domain
546:                 ((EClass) domainElement).getEStructuralFeatures().clear();
547:                 final EAttribute attribute1 = createEAttribute("a2", EcorePackage.Literals.ESTRING, 0, 2);
548:                 final EAttribute attribute2 = createEAttribute("a10", EcorePackage.Literals.ESTRING, 0, 11);
549:                 final EAttribute attribute3 = createEAttribute("a10b", EcorePackage.Literals.ESTRING, 0, 1);
550:                 ((EClass) domainElement).getEStructuralFeatures().add(attribute1);
551:                 ((EClass) domainElement).getEStructuralFeatures().add(attribute2);
552:                 ((EClass) domainElement).getEStructuralFeatures().add(attribute3);
553:
554:                 // table control
555:                 final VTableControl tableControl = TableTestUtil.createTableControl();
556:                 final VTableDomainModelReference tableDMR = (VTableDomainModelReference) tableControl.getDomainModelReference();
557:                 tableDMR.setDomainModelEFeature(EcorePackage.eINSTANCE.getEClass_EAttributes());
558:                 tableDMR.getColumnDomainModelReferences().add(createDMR(EcorePackage.eINSTANCE.getENamedElement_Name()));
559:                 tableDMR.getColumnDomainModelReferences().add(
560:                         createDMR(EcorePackage.eINSTANCE.getETypedElement_UpperBound()));
561:
562:                 // render
563:                 final AbstractSWTRenderer<VElement> tableRenderer = rendererFactory.getRendererInstance(tableControl,
564:                         new ViewModelContextWithoutServices(tableControl));
565:                 tableRenderer.getGridDescription(new SWTGridDescription());
566:                 final Control control = tableRenderer.render(new SWTGridCell(0, 0, tableRenderer), shell);
567:                 if (control == null) {
568:                         fail("No control was rendered");
569:                 }
570:                 final Table table = SWTTestUtil.findControl(control, 0, Table.class);
571:                 assertTableItemOrder(table, attribute1, attribute2, attribute3);
572:
573:                 // column 0 is validation column
574:
575:                 // select column 1
576:                 // ascending
577:                 SWTTestUtil.selectWidget(table.getColumns()[1]);
578:                 SWTTestUtil.waitForUIThread();
579:                 assertTableItemOrder(table, attribute1, attribute2, attribute3);
580:                 assertEquals(SWT.DOWN, table.getSortDirection()); // SWT.DOWN := ascending sorting
581:                 // descending
582:                 SWTTestUtil.selectWidget(table.getColumns()[1]);
583:                 SWTTestUtil.waitForUIThread();
584:                 assertTableItemOrder(table, attribute3, attribute2, attribute1);
585:                 assertEquals(SWT.UP, table.getSortDirection()); // SWT.UP := descending sorting
586:                 // none
587:                 SWTTestUtil.selectWidget(table.getColumns()[1]);
588:                 SWTTestUtil.waitForUIThread();
589:                 assertTableItemOrder(table, attribute1, attribute2, attribute3);
590:                 assertEquals(SWT.NONE, table.getSortDirection());
591:
592:                 // select column 2
593:                 // ascending
594:                 SWTTestUtil.selectWidget(table.getColumns()[2]);
595:                 SWTTestUtil.waitForUIThread();
596:                 assertTableItemOrder(table, attribute3, attribute1, attribute2);
597:                 assertEquals(SWT.DOWN, table.getSortDirection()); // SWT.DOWN := ascending sorting
598:                 // descending
599:                 SWTTestUtil.selectWidget(table.getColumns()[2]);
600:                 SWTTestUtil.waitForUIThread();
601:                 assertTableItemOrder(table, attribute2, attribute1, attribute3);
602:                 assertEquals(SWT.UP, table.getSortDirection()); // SWT.UP := descending sorting
603:                 // none
604:                 SWTTestUtil.selectWidget(table.getColumns()[2]);
605:                 SWTTestUtil.waitForUIThread();
606:                 assertTableItemOrder(table, attribute1, attribute2, attribute3);
607:                 assertEquals(SWT.NONE, table.getSortDirection());
608:         }
609:
610:         @Test
611:         public void testTableSortingWithCellEditor() throws NoRendererFoundException, NoPropertyDescriptorFoundExeption,
612:                 EMFFormsNoRendererException {
613:                 // domain
614:                 ((EClass) domainElement).getEStructuralFeatures().clear();
615:                 final EAttribute attribute1 = createEAttribute("a", EcorePackage.Literals.ESTRING, 0, 2);
616:                 final EAttribute attribute2 = createEAttribute("b", EcorePackage.Literals.ESTRING, 0, 11);
617:                 final EAttribute attribute3 = createEAttribute("c", EcorePackage.Literals.ESTRING, 0, 1);
618:                 ((EClass) domainElement).getEStructuralFeatures().add(attribute1);
619:                 ((EClass) domainElement).getEStructuralFeatures().add(attribute2);
620:                 ((EClass) domainElement).getEStructuralFeatures().add(attribute3);
621:
622:                 // table control
623:                 final VTableControl tableControl = TableTestUtil.createTableControl();
624:                 final VTableDomainModelReference tableDMR = (VTableDomainModelReference) tableControl.getDomainModelReference();
625:                 tableDMR.setDomainModelEFeature(EcorePackage.eINSTANCE.getEClass_EAttributes());
626:                 tableDMR.getColumnDomainModelReferences().add(createDMR(EcorePackage.eINSTANCE.getENamedElement_Name()));
627:                 tableDMR.getColumnDomainModelReferences().add(
628:                         createDMR(EcorePackage.eINSTANCE.getETypedElement_UpperBound()));
629:
630:                 // render
631:                 final TableControlSWTRenderer tableRenderer = createRendererInstanceWithCustomCellEditor(tableControl);
632:                 tableRenderer.getGridDescription(new SWTGridDescription());
633:                 final Control control = tableRenderer.render(new SWTGridCell(0, 0, tableRenderer), shell);
634:                 if (control == null) {
635:                         fail("No control was rendered");
636:                 }
637:                 final Table table = SWTTestUtil.findControl(control, 0, Table.class);
638:                 assertTableItemOrder(table, attribute1, attribute2, attribute3);
639:
640:                 // column 0 is validation column
641:
642:                 // select column 1; for this the sort orders are inverted due to the custom cell editor
643:                 // ascending configured -> results in descending sorting
644:                 SWTTestUtil.selectWidget(table.getColumns()[1]);
645:                 SWTTestUtil.waitForUIThread();
646:                 assertTableItemOrder(table, attribute3, attribute2, attribute1);
647:                 assertEquals(SWT.DOWN, table.getSortDirection()); // SWT.DOWN := ascending sorting
648:                 // descending configured -> results in ascending sorting
649:                 SWTTestUtil.selectWidget(table.getColumns()[1]);
650:                 SWTTestUtil.waitForUIThread();
651:                 assertTableItemOrder(table, attribute1, attribute2, attribute3);
652:                 assertEquals(SWT.UP, table.getSortDirection()); // SWT.UP := descending sorting
653:                 // none
654:                 SWTTestUtil.selectWidget(table.getColumns()[1]);
655:                 SWTTestUtil.waitForUIThread();
656:                 assertTableItemOrder(table, attribute1, attribute2, attribute3);
657:                 assertEquals(SWT.NONE, table.getSortDirection());
658:
659:                 // select column 2; no custom cell editor registered => should sort normally
660:                 // ascending
661:                 SWTTestUtil.selectWidget(table.getColumns()[2]);
662:                 SWTTestUtil.waitForUIThread();
663:                 assertTableItemOrder(table, attribute3, attribute1, attribute2);
664:                 assertEquals(SWT.DOWN, table.getSortDirection()); // SWT.DOWN := ascending sorting
665:                 // descending
666:                 SWTTestUtil.selectWidget(table.getColumns()[2]);
667:                 SWTTestUtil.waitForUIThread();
668:                 assertTableItemOrder(table, attribute2, attribute1, attribute3);
669:                 assertEquals(SWT.UP, table.getSortDirection()); // SWT.UP := descending sorting
670:                 // none
671:                 SWTTestUtil.selectWidget(table.getColumns()[2]);
672:                 SWTTestUtil.waitForUIThread();
673:                 assertTableItemOrder(table, attribute1, attribute2, attribute3);
674:                 assertEquals(SWT.NONE, table.getSortDirection());
675:         }
676:
677:         @Test
678:         public void tableSorting_autoSortOnEdit()
679:                 throws EMFFormsNoRendererException, NoRendererFoundException, NoPropertyDescriptorFoundExeption {
680:                 // domain
681:                 ((EClass) domainElement).getEStructuralFeatures().clear();
682:                 final EAttribute attribute1 = createEAttribute("a", EcorePackage.Literals.ESTRING, 0, 2);
683:                 final EAttribute attribute2 = createEAttribute("b", EcorePackage.Literals.ESTRING, 0, 11);
684:                 final EAttribute attribute3 = createEAttribute("c", EcorePackage.Literals.ESTRING, 0, 1);
685:                 ((EClass) domainElement).getEStructuralFeatures().add(attribute1);
686:                 ((EClass) domainElement).getEStructuralFeatures().add(attribute2);
687:                 ((EClass) domainElement).getEStructuralFeatures().add(attribute3);
688:
689:                 // table control
690:                 final VTableControl tableControl = TableTestUtil.createTableControl();
691:                 final VTableDomainModelReference tableDMR = (VTableDomainModelReference) tableControl.getDomainModelReference();
692:                 tableDMR.setDomainModelEFeature(EcorePackage.eINSTANCE.getEClass_EAttributes());
693:                 tableDMR.getColumnDomainModelReferences().add(createDMR(EcorePackage.eINSTANCE.getENamedElement_Name()));
694:                 tableDMR.getColumnDomainModelReferences().add(
695:                         createDMR(EcorePackage.eINSTANCE.getETypedElement_UpperBound()));
696:
697:                 // render
698:                 shell.open();
699:                 // With this shell size, the table will be 77 pixels high and show 2 rows
700:                 shell.setSize(200, 150);
701:                 final Control control = SWTViewTestHelper.render(tableControl, domainElement, shell);
702:                 if (control == null) {
703:                         fail("No control was rendered");
704:                 }
705:                 shell.layout();
706:                 final Table table = SWTTestUtil.findControl(control, 0, Table.class);
707:
708:                 // column 0 is validation column
709:                 // select column 1 (name) and ascending sorting
710:                 SWTTestUtil.selectWidget(table.getColumns()[1]);
711:                 SWTTestUtil.waitForUIThread();
712:                 assertTableItemOrder(table, attribute1, attribute2, attribute3);
713:                 assertEquals(SWT.DOWN, table.getSortDirection()); // SWT.DOWN := ascending sorting
714:
715:                 // Change the attribute the sorting is currently applied on and assert that the table was automatically
716:                 // re-sorted
717:                 attribute1.setName("z");
718:                 SWTTestUtil.waitForUIThread();
719:                 assertTableItemOrder(table, attribute2, attribute3, attribute1);
720:
721:                 final TableItem sortItem = table.getItem(2);
722:                 // Calculate the lower item bound relative to the table. We need to add the header height because the y
723:                 // coordinates of the table items start at the lower end of the header but the header height is included in the
724:                 // table height.
725:                 final int itemLowerEnd = sortItem.getBounds().y + sortItem.getBounds().height + table.getHeaderHeight();
726:                 // Assert that the edited table item was revealed after it had been moved to the end of the table.
727:                 assertThat(
728:                         "The edited table item is not fully visible after the auto sort because the table didn't scroll down.",
729:                         itemLowerEnd, lessThan(table.getBounds().height));
730:                 assertThat(
731:                         "The edited table item is not fully visible after the auto sort because the table is scrolled too far down.",
732:                         sortItem.getBounds().y, greaterThanOrEqualTo(0));
733:         }
734:
735:         @Test
736:         public void testTableReadonlyHidesAddRemoveButtons()
737:                 throws NoRendererFoundException, NoPropertyDescriptorFoundExeption,
738:                 EMFFormsNoRendererException {
739:                 // setup model
740:                 final TableControlHandle handle = createTableWithTwoTableColumns();
741:                 handle.getTableControl().setReadonly(true);
742:                 shell.open();
743:                 final RendererResult result = SWTViewTestHelper.renderControl(handle.getTableControl(), domainElement, shell);
744:                 assertTrue(result.getControl().isPresent() && result.getControl().get() instanceof Composite);
745:
746:                 final TableControlSWTRenderer swtRenderer = TableControlSWTRenderer.class.cast(result.getRenderer());
747:
748:                 final Optional<Control> addRowButton = swtRenderer.getControlForAction(AddRowAction.ACTION_ID);
749:                 final Optional<Control> removeRowButton = swtRenderer.getControlForAction(RemoveRowAction.ACTION_ID);
750:                 final Optional<Control> duplicateRowButton = swtRenderer.getControlForAction(DuplicateRowAction.ACTION_ID);
751:
752:                 assertFalse(addRowButton.isPresent());
753:                 assertFalse(removeRowButton.isPresent());
754:                 assertFalse(duplicateRowButton.isPresent());
755:
756:         }
757:
758:         @Test
759:         public void testTable_unchangeableFeature_doNotRenderButtons()
760:                 throws NoRendererFoundException, NoPropertyDescriptorFoundExeption,
761:                 EMFFormsNoRendererException {
762:                 // setup model, we need a feature that is unchangeable
763:                 final VTableControl tableControl = VTableFactory.eINSTANCE.createTableControl();
764:                 final VTableDomainModelReference tableDmr = VTableFactory.eINSTANCE.createTableDomainModelReference();
765:                 final VFeaturePathDomainModelReference dmr = VViewFactory.eINSTANCE.createFeaturePathDomainModelReference();
766:                 final VMultiDomainModelReferenceSegment segment = VMultisegmentFactory.eINSTANCE
767:                         .createMultiDomainModelReferenceSegment();
768:                 segment.setDomainModelFeature("eReferences");
769:                 dmr.getSegments().add(segment);
770:                 tableDmr.setDomainModelReference(dmr);
771:                 final VFeaturePathDomainModelReference columnDmr = VViewFactory.eINSTANCE
772:                         .createFeaturePathDomainModelReference();
773:                 final VFeatureDomainModelReferenceSegment columnSegment = VViewFactory.eINSTANCE
774:                         .createFeatureDomainModelReferenceSegment();
775:                 columnDmr.getSegments().add(columnSegment);
776:                 segment.getChildDomainModelReferences().add(columnDmr);
777:                 tableControl.setDomainModelReference(tableDmr);
778:                 tableControl.setDuplicateDisabled(false);
779:                 tableControl.setMoveUpDownDisabled(false);
780:                 tableControl.setAddRemoveDisabled(false);
781:
782:                 shell.open();
783:                 final RendererResult result = SWTViewTestHelper.renderControl(tableControl, domainElement, shell);
784:                 assertTrue(result.getControl().isPresent() && result.getControl().get() instanceof Composite);
785:
786:                 final TableControlSWTRenderer swtRenderer = TableControlSWTRenderer.class.cast(result.getRenderer());
787:
788:                 final Optional<Control> addRowButton = swtRenderer.getControlForAction(AddRowAction.ACTION_ID);
789:                 final Optional<Control> removeRowButton = swtRenderer.getControlForAction(RemoveRowAction.ACTION_ID);
790:                 final Optional<Control> duplicateRowButton = swtRenderer.getControlForAction(DuplicateRowAction.ACTION_ID);
791:                 final Optional<Control> moveRowUpButton = swtRenderer.getControlForAction(MoveRowUpAction.ACTION_ID);
792:                 final Optional<Control> moveRowDownButton = swtRenderer.getControlForAction(MoveRowDownAction.ACTION_ID);
793:
794:                 // If the feature is unchangeable, the buttons that allow to change the feature must not be rendered
795:                 assertFalse(addRowButton.isPresent());
796:                 assertFalse(removeRowButton.isPresent());
797:                 assertFalse(duplicateRowButton.isPresent());
798:                 assertFalse(moveRowUpButton.isPresent());
799:                 assertFalse(moveRowDownButton.isPresent());
800:         }
801:
802:         @Test
803:         public void testTable_AddRow_WithTableService() throws NoRendererFoundException, NoPropertyDescriptorFoundExeption,
804:                 EMFFormsNoRendererException {
805:                 // setup model
806:                 final TableControlHandle handle = TableTestUtil.createInitializedTableWithoutTableColumns();
807:
808:                 // mock the TableControlService used to create a new element
809:                 final TableControlService tableService = mock(TableControlService.class);
810:                 final EClass newEClass = EcoreFactory.eINSTANCE.createEClass();
811:                 newEClass.setName("NewlyAddedEClass");
812:                 when(tableService.createNewElement(any(EClass.class), any(EObject.class), any(EStructuralFeature.class)))
813:                         .thenReturn(Optional.of((EObject) newEClass));
814:
815:                 final ViewModelContextWithoutServices context = new ViewModelContextWithoutServices(handle.getTableControl());
816:                 context.addService(tableService, TableControlService.class);
817:
818:                 // Render the table
819:                 final TableControlSWTRenderer tableRenderer = TableControlSWTRenderer.class
820:                         .cast(rendererFactory.getRendererInstance(
821:                                 handle.getTableControl(), context));
822:                 tableRenderer.getGridDescription(new SWTGridDescription());
823:                 final Control render = tableRenderer.render(new SWTGridCell(0, 0, tableRenderer), shell);
824:                 if (render == null) {
825:                         fail();
826:                 }
827:                 final Control control = getTable(render);
828:                 assertTrue(control instanceof Table);
829:                 final Table table = (Table) control;
830:
831:                 // The domain model is initialized with one super type in #init()
832:                 assertEquals(1, table.getItemCount());
833:
834:                 // Add a new row
835:                 tableRenderer.addRow(EcorePackage.eINSTANCE.getEClass(), domainElement,
836:                         EcorePackage.eINSTANCE.getEClass_ESuperTypes());
837:
838:                 // Verify that the new EClass was added to the domain object and the table, and that the TableControlService was
839:                 // used
840:                 assertEquals(2, table.getItemCount());
841:                 assertEquals(2, EClass.class.cast(domainElement).getESuperTypes().size());
842:                 assertEquals(newEClass, EClass.class.cast(domainElement).getESuperTypes().get(1));
843:                 assertEquals(1, table.getSelectionIndex());
844:                 verify(tableService).createNewElement(EcorePackage.eINSTANCE.getEClass(), domainElement,
845:                         EcorePackage.eINSTANCE.getEClass_ESuperTypes());
846:         }
847:
848:         @Test
849:         public void testTable_AddRow_WithTableService_EmptyResult()
850:                 throws NoRendererFoundException, NoPropertyDescriptorFoundExeption,
851:                 EMFFormsNoRendererException {
852:                 // setup model
853:                 final TableControlHandle handle = TableTestUtil.createInitializedTableWithoutTableColumns();
854:
855:                 // mock the TableControlService used to create a new element
856:                 final TableControlService tableService = mock(TableControlService.class);
857:                 when(tableService.createNewElement(any(EClass.class), any(EObject.class), any(EStructuralFeature.class)))
858:                         .thenReturn(Optional.<EObject> empty());
859:
860:                 final ViewModelContextWithoutServices context = new ViewModelContextWithoutServices(handle.getTableControl());
861:                 context.addService(tableService, TableControlService.class);
862:
863:                 // Render the table
864:                 final TableControlSWTRenderer tableRenderer = TableControlSWTRenderer.class
865:                         .cast(rendererFactory.getRendererInstance(
866:                                 handle.getTableControl(), context));
867:                 tableRenderer.getGridDescription(new SWTGridDescription());
868:                 final Control render = tableRenderer.render(new SWTGridCell(0, 0, tableRenderer), shell);
869:                 if (render == null) {
870:                         fail();
871:                 }
872:                 final Control control = getTable(render);
873:                 assertTrue(control instanceof Table);
874:                 final Table table = (Table) control;
875:
876:                 // The domain model is initialized with one super type in #init()
877:                 assertEquals(1, table.getItemCount());
878:
879:                 // Add a new row
880:                 tableRenderer.addRow(EcorePackage.eINSTANCE.getEClass(), domainElement,
881:                         EcorePackage.eINSTANCE.getEClass_ESuperTypes());
882:
883:                 // Verify that the no new EClass was added to the domain object and the table, and that the TableControlService
884:                 // was used
885:                 assertEquals(1, table.getItemCount());
886:                 assertEquals(1, EClass.class.cast(domainElement).getESuperTypes().size());
887:                 verify(tableService).createNewElement(EcorePackage.eINSTANCE.getEClass(), domainElement,
888:                         EcorePackage.eINSTANCE.getEClass_ESuperTypes());
889:         }
890:
891:         @Test
892:         public void testTable_AddRow_WithTableService_NullResult()
893:                 throws NoRendererFoundException, NoPropertyDescriptorFoundExeption,
894:                 EMFFormsNoRendererException {
895:                 // setup model
896:                 final TableControlHandle handle = TableTestUtil.createInitializedTableWithoutTableColumns();
897:
898:                 // mock the TableControlService to return null
899:                 final TableControlService tableService = mock(TableControlService.class);
900:                 when(tableService.createNewElement(any(EClass.class), any(EObject.class), any(EStructuralFeature.class)))
901:                         .thenReturn(null);
902:                 // mock the ReferenceService used to create a new element
903:                 final EClass newEClass = EcoreFactory.eINSTANCE.createEClass();
904:                 newEClass.setName("NewlyAddedEClass");
905:                 final ReferenceService referenceService = mock(ReferenceService.class);
906:                 when(referenceService.addNewModelElements(any(EObject.class), any(EReference.class), anyBoolean()))
907:                         .thenReturn(Optional.of((EObject) newEClass));
908:
909:                 final ViewModelContextWithoutServices context = new ViewModelContextWithoutServices(handle.getTableControl());
910:                 context.addService(tableService, TableControlService.class);
911:                 context.addService(referenceService, ReferenceService.class);
912:
913:                 // Render the table
914:                 final TableControlSWTRenderer tableRenderer = TableControlSWTRenderer.class
915:                         .cast(rendererFactory.getRendererInstance(
916:                                 handle.getTableControl(), context));
917:                 tableRenderer.getGridDescription(new SWTGridDescription());
918:                 final Control render = tableRenderer.render(new SWTGridCell(0, 0, tableRenderer), shell);
919:                 if (render == null) {
920:                         fail();
921:                 }
922:                 final Control control = getTable(render);
923:                 assertTrue(control instanceof Table);
924:                 final Table table = (Table) control;
925:
926:                 // The domain model is initialized with one super type in #init()
927:                 assertEquals(1, table.getItemCount());
928:
929:                 // Add a new row
930:                 tableRenderer.addRow(EcorePackage.eINSTANCE.getEClass(), domainElement,
931:                         EcorePackage.eINSTANCE.getEClass_ESuperTypes());
932:
933:                 // Verify that the new EClass was added although the table service returned null
934:                 assertEquals(2, table.getItemCount());
935:                 assertEquals(2, EClass.class.cast(domainElement).getESuperTypes().size());
936:                 assertEquals(1, table.getSelectionIndex());
937:                 verify(tableService).createNewElement(EcorePackage.eINSTANCE.getEClass(), domainElement,
938:                         EcorePackage.eINSTANCE.getEClass_ESuperTypes());
939:                 verify(referenceService).addNewModelElements(domainElement, EcorePackage.eINSTANCE.getEClass_ESuperTypes(),
940:                         false);
941:         }
942:
943:         @Test
944:         public void testTable_AddRow_WithReferenceService()
945:                 throws NoRendererFoundException, NoPropertyDescriptorFoundExeption,
946:                 EMFFormsNoRendererException {
947:                 // setup model
948:                 final TableControlHandle handle = TableTestUtil.createInitializedTableWithoutTableColumns();
949:
950:                 // mock the ReferenceService used to create a new element
951:                 final EClass newEClass = EcoreFactory.eINSTANCE.createEClass();
952:                 newEClass.setName("NewlyAddedEClass");
953:                 final ReferenceService referenceService = mock(ReferenceService.class);
954:                 when(referenceService.addNewModelElements(any(EObject.class), any(EReference.class), anyBoolean()))
955:                         .thenReturn(Optional.of((EObject) newEClass));
956:
957:                 final ViewModelContextWithoutServices context = new ViewModelContextWithoutServices(handle.getTableControl());
958:                 context.addService(referenceService, ReferenceService.class);
959:
960:                 // Render the table
961:                 final TableControlSWTRenderer tableRenderer = TableControlSWTRenderer.class
962:                         .cast(rendererFactory.getRendererInstance(
963:                                 handle.getTableControl(), context));
964:                 tableRenderer.getGridDescription(new SWTGridDescription());
965:                 final Control render = tableRenderer.render(new SWTGridCell(0, 0, tableRenderer), shell);
966:                 if (render == null) {
967:                         fail();
968:                 }
969:                 final Control control = getTable(render);
970:                 assertTrue(control instanceof Table);
971:                 final Table table = (Table) control;
972:
973:                 // The domain model is initialized with one super type in #init()
974:                 assertEquals(1, table.getItemCount());
975:
976:                 // Add a new row
977:                 tableRenderer.addRow(EcorePackage.eINSTANCE.getEClass(), domainElement,
978:                         EcorePackage.eINSTANCE.getEClass_ESuperTypes());
979:
980:                 // Verify that the new EClass was added to the domain object and the table, and that the reference service was
981:                 // used
982:                 assertEquals(2, table.getItemCount());
983:                 assertEquals(2, EClass.class.cast(domainElement).getESuperTypes().size());
984:                 assertEquals(newEClass, EClass.class.cast(domainElement).getESuperTypes().get(1));
985:                 assertEquals(1, table.getSelectionIndex());
986:                 verify(referenceService).addNewModelElements(domainElement, EcorePackage.eINSTANCE.getEClass_ESuperTypes(),
987:                         false);
988:         }
989:
990:         /**
991:          * Tests that the table's summary validation icon's tooltip shows validation messages related directly to the
992:          * table's reference even if the table style property 'showValidationSummaryTooltip' is false (this is the case by
993:          * default). Furthermore, the test checks that validation messages of objects contained in the table's reference are
994:          * not shown in this case.
995:          *
996:          * @throws EMFFormsNoRendererException
997:          * @throws NoRendererFoundException
998:          * @throws NoPropertyDescriptorFoundExeption
999:          */
1000:         @SuppressWarnings({ "unchecked", "rawtypes" })
1001:         @Test
1002:         public void testTable_summaryToolTip_defaultSettings()
1003:                 throws EMFFormsNoRendererException, NoRendererFoundException, NoPropertyDescriptorFoundExeption {
1004:                 // ----- Create Test Model
1005:                 final EPackage ePackage = EcoreFactory.eINSTANCE.createEPackage();
1006:                 final EClass foo = EcoreFactory.eINSTANCE.createEClass();
1007:                 foo.setName("Foo");
1008:                 final EClass bar = EcoreFactory.eINSTANCE.createEClass();
1009:                 bar.setName("Bar");
1010:                 ePackage.getEClassifiers().add(foo);
1011:                 ePackage.getEClassifiers().add(bar);
1012:
1013:                 final EReference fooToBar = EcoreFactory.eINSTANCE.createEReference();
1014:                 fooToBar.setContainment(true);
1015:                 fooToBar.setEType(bar);
1016:                 fooToBar.setLowerBound(1);
1017:                 fooToBar.setUpperBound(-1);
1018:                 fooToBar.setName("fooToBar");
1019:                 foo.getEStructuralFeatures().add(fooToBar);
1020:
1021:                 final EAttribute barAttribute = EcoreFactory.eINSTANCE.createEAttribute();
1022:                 barAttribute.setEType(EcorePackage.Literals.ESTRING);
1023:                 barAttribute.setName("barAttribute");
1024:                 bar.getEStructuralFeatures().add(barAttribute);
1025:                 barAttribute.setLowerBound(1);
1026:                 barAttribute.setUpperBound(1);
1027:                 // -----
1028:
1029:                 final VTableDomainModelReference tableDmr = VTableFactory.eINSTANCE.createTableDomainModelReference();
1030:                 final VFeaturePathDomainModelReference featureDmr = VViewFactory.eINSTANCE
1031:                         .createFeaturePathDomainModelReference();
1032:                 featureDmr.setDomainModelEFeature(fooToBar);
1033:                 tableDmr.setDomainModelReference(featureDmr);
1034:
1035:                 final VTableControl tableControl = VTableFactory.eINSTANCE.createTableControl();
1036:                 tableControl.setDomainModelReference(tableDmr);
1037:
1038:                 domainElement = EcoreUtil.create(foo);
1039:                 final VView view = VViewFactory.eINSTANCE.createView();
1040:                 view.setRootEClass(bar);
1041:                 view.getChildren().add(tableControl);
1042:                 final ViewModelContext context = new ViewModelContextImpl(view, domainElement);
1043:
1044:                 // Render the table
1045:                 final TableControlSWTRenderer tableRenderer = TableControlSWTRenderer.class
1046:                         .cast(rendererFactory.getRendererInstance(
1047:                                 tableControl, context));
1048:                 tableRenderer.getGridDescription(new SWTGridDescription());
1049:                 final Control render = tableRenderer.render(new SWTGridCell(0, 0, tableRenderer), shell);
1050:                 if (render == null) {
1051:                         fail();
1052:                 }
1053:
1054:                 // Get the validation icon
1055:                 Composite composite = (Composite) render;
1056:                 composite = (Composite) composite.getChildren()[0];
1057:                 composite = (Composite) composite.getChildren()[0];
1058:                 final Label validationIcon = (Label) composite.getChildren()[1];
1059:
1060:                 // Apply validation and wait for Async operation to finish
1061:                 tableRenderer.applyValidation();
1062:                 SWTTestUtil.waitForUIThread();
1063:
1064:                 assertEquals("The tooltip text should contain the multiplicity error.",
1065:                         "The feature 'fooToBar' of 'Foo' with 0 values must have at least 1 values",
1066:                         validationIcon.getToolTipText());
1067:
1068:                 // Add a new Bar object to the foo to bar reference. This removes the validation error from the reference and
1069:                 // adds a validation error on the created Bar object.
1070:                 ((EList) domainElement.eGet(fooToBar)).add(EcoreUtil.create(bar));
1071:
1072:                 // Apply validation and wait for Async operation to finish
1073:                 tableRenderer.applyValidation();
1074:                 SWTTestUtil.waitForUIThread();
1075:
1076:                 assertEquals("The tool tip text should be empty.", "", validationIcon.getToolTipText());
1077:         }
1078:
1079:         /**
1080:          * Test that on validation status changes the table renderer does not update the entire
1081:          * table but only the rows that have validation changes.
1082:          *
1083:          * @see <a href="http://eclip.se/544116">bug 544116</a>
1084:          */
1085:         @Test
1086:         public void testValidationUpdates() throws NoRendererFoundException, NoPropertyDescriptorFoundExeption,
1087:                 EMFFormsNoRendererException {
1088:
1089:                 // domain
1090:                 ((EClass) domainElement).getEStructuralFeatures().clear();
1091:                 final EAttribute attribute1 = createEAttribute("a", EcorePackage.Literals.ESTRING, 0, 2);
1092:                 final EAttribute attribute2 = createEAttribute("b", EcorePackage.Literals.ESTRING, 0, 11);
1093:                 final EAttribute attribute3 = createEAttribute("c", EcorePackage.Literals.ESTRING, 0, 1);
1094:                 final EAttribute attribute4 = createEAttribute("d", EcorePackage.Literals.ESTRING, 0, 1);
1095:                 ((EClass) domainElement).getEStructuralFeatures().add(attribute1);
1096:                 ((EClass) domainElement).getEStructuralFeatures().add(attribute2);
1097:                 ((EClass) domainElement).getEStructuralFeatures().add(attribute3);
1098:                 ((EClass) domainElement).getEStructuralFeatures().add(attribute4);
1099:
1100:                 // table control
1101:                 final VTableControl tableControl = TableTestUtil.createTableControl();
1102:                 final VTableDomainModelReference tableDMR = (VTableDomainModelReference) tableControl.getDomainModelReference();
1103:                 tableDMR.setDomainModelEFeature(EcorePackage.eINSTANCE.getEClass_EAttributes());
1104:                 tableDMR.getColumnDomainModelReferences().add(createDMR(EcorePackage.eINSTANCE.getENamedElement_Name()));
1105:                 tableDMR.getColumnDomainModelReferences().add(
1106:                         createDMR(EcorePackage.eINSTANCE.getETypedElement_UpperBound()));
1107:
1108:                 // render
1109:                 final ViewModelContext context = new ViewModelContextImpl(tableControl, domainElement);
1110:                 final Set<String> requestedCells = new HashSet<>(); // Cell updates are unordered
1111:                 final TableControlSWTRenderer tableRenderer = new TableControlSWTRenderer(tableControl, context,
1112:                         context.getService(ReportService.class),
1113:                         context.getService(EMFFormsDatabindingEMF.class),
1114:                         context.getService(EMFFormsLabelProvider.class),
1115:                         context.getService(VTViewTemplateProvider.class),
1116:                         context.getService(ImageRegistryService.class),
1117:                         context.getService(EMFFormsEditSupport.class)) {
1118:
1119:                         @Override
1120:                         protected CellLabelProvider createCellLabelProvider(EStructuralFeature feature, CellEditor cellEditor,
1121:                                 @SuppressWarnings("rawtypes") IObservableMap attributeMap, VTableControl vTableControl,
1122:                                 VDomainModelReference dmr,
1123:                                 Control table) {
1124:
1125:                                 if (feature == EcorePackage.Literals.ENAMED_ELEMENT__NAME) {
1126:                                         final StringCellEditor editor = new StringCellEditor() {
1127:                                                 @Override
1128:                                                 public String getFormatedString(Object value) {
1129:                                                         requestedCells.add((String) value);
1130:                                                         return super.getFormatedString(value);
1131:                                                 }
1132:                                         };
1133:                                         cellEditor = editor;
1134:                                 }
1135:                                 return super.createCellLabelProvider(feature, cellEditor, attributeMap, vTableControl, dmr, table);
1136:                         }
1137:                 };
1138:                 tableRenderer.init();
1139:                 tableRenderer.getGridDescription(new SWTGridDescription());
1140:                 final Control control = tableRenderer.render(new SWTGridCell(0, 0, tableRenderer), shell);
1141:                 if (control == null) {
1142:                         fail("No control was rendered");
1143:                 }
1144:                 tableRenderer.finalizeRendering(shell);
1145:
1146:                 // Initialize the validation status
1147:                 VDiagnostic vdiag = VViewFactory.eINSTANCE.createDiagnostic();
1148:                 Diagnostic diag = new BasicDiagnostic(Diagnostic.ERROR, "source", 0, "error",
1149:                         new Object[] { attribute2, EcorePackage.Literals.ETYPED_ELEMENT__ETYPE });
1150:                 vdiag.getDiagnostics().add(diag);
1151:                 tableControl.setDiagnostic(vdiag);
1152:
1153:                 SWTTestUtil.waitForUIThread();
1154:
1155:                 // Reset our tracking of accessed cells
1156:                 requestedCells.clear();
1157:
1158:                 // Update the validation results
1159:                 vdiag = VViewFactory.eINSTANCE.createDiagnostic();
1160:                 diag = new BasicDiagnostic(Diagnostic.ERROR, "source", 0, "error",
1161:                         // A different object than the initial validation status
1162:                         new Object[] { attribute3, EcorePackage.Literals.ETYPED_ELEMENT__ETYPE });
1163:                 vdiag.getDiagnostics().add(diag);
1164:                 tableControl.setDiagnostic(vdiag);
1165:
1166:                 waitFor(tableRenderer);
1167:
1168:                 // Notably, we updated these two rows in order and *neither* "a" nor "d"
1169:                 assertThat(requestedCells, equalTo(set("b", "c")));
1170:         }
1171:
1172:         @Test
1173:         public void testTable_validationColumnImage()
1174:                 throws NoRendererFoundException, NoPropertyDescriptorFoundExeption, EMFFormsNoRendererException {
1175:                 // Register test table renderer with configured column image
1176:                 final ColumnImageTableRendererService rendererService = new ColumnImageTableRendererService();
1177:                 final BundleContext bundleContext = FrameworkUtil.getBundle(SWTTable_PTest.class).getBundleContext();
1178:                 @SuppressWarnings("rawtypes")
1179:                 final ServiceRegistration<EMFFormsDIRendererService> registration = bundleContext.registerService(
1180:                         EMFFormsDIRendererService.class, rendererService, new Hashtable<String, Object>());
1181:
1182:                 // setup model and render table
1183:                 final TableControlHandle handle = createTableWithTwoTableColumns();
1184:                 final Control render = SWTViewTestHelper.render(handle.getTableControl(), domainElement, shell);
1185:                 assertTrue(render instanceof Composite);
1186:                 final Control control = getTable(render);
1187:                 assertTrue(control instanceof Table);
1188:                 final Table table = (Table) control;
1189:                 final TableColumn validationColumn = table.getColumn(0);
1190:
1191:                 // If the asserts pass, we know the image was loaded because the default error image is 6x6 pixels
1192:                 assertEquals("The configured valdiation column image is not present", 16,
1193:                         validationColumn.getImage().getImageData().height);
1194:                 assertEquals("The configured valdiation column image is not present", 16,
1195:                         validationColumn.getImage().getImageData().width);
1196:
1197:                 // Unregister test renderer
1198:                 registration.unregister();
1199:         }
1200:
1201:         /**
1202:          * Verify the reuse of detail renderings with caching.
1203:          */
1204:         @Test
1205:         public void testPanelTableDetailReused() throws NoRendererFoundException, NoPropertyDescriptorFoundExeption,
1206:                 EMFFormsNoRendererException {
1207:
1208:                 final EClass eClass = EcoreFactory.eINSTANCE.createEClass();
1209:                 ((EClass) domainElement).getESuperTypes().add(eClass);
1210:                 final TableControlHandle handle = createTableWithTwoTableColumns();
1211:                 handle.getTableControl().setDetailEditing(DetailEditing.WITH_PANEL);
1212:                 handle.getTableControl().setDetailView(createDetailView());
1213:
1214:                 final ViewModelContext context = new ViewModelContextWithoutServices(handle.getTableControl());
1215:                 context.putContextValue(DetailViewCache.DETAIL_VIEW_CACHE_SIZE, 5);
1216:                 final AbstractSWTRenderer<VElement> tableRenderer = rendererFactory.getRendererInstance(
1217:                         handle.getTableControl(), context);
1218:                 tableRenderer.getGridDescription(new SWTGridDescription());
1219:                 final Control render = tableRenderer.render(new SWTGridCell(0, 0, tableRenderer), shell);
1220:                 final Control control = Composite.class.cast(render).getChildren()[0];
1221:                 assertThat("No control was rendered", control, notNullValue());
1222:
1223:                 final Composite controlComposite = (Composite) ((Composite) control).getChildren()[1];
1224:                 final Composite tableComposite = (Composite) controlComposite.getChildren()[0];
1225:                 final Table table = (Table) tableComposite.getChildren()[0];
1226:                 final ScrolledComposite scrolledComposite = (ScrolledComposite) controlComposite.getChildren()[1];
1227:                 final Composite parentForECPView = (Composite) scrolledComposite.getChildren()[0];
1228:                 assumeThat("Not enough rows in the table", table.getItemCount(), greaterThanOrEqualTo(2));
1229:                 final TableViewer tableViewer = getTableViewerFromRenderer(tableRenderer);
1230:
1231:                 // Select an EClass
1232:                 tableViewer.setSelection(new StructuredSelection(table.getItem(0).getData()));
1233:                 assertThat("Composite for selection not present",
1234:                         asList(parentForECPView.getChildren()), hasItem(instanceOf(Composite.class)));
1235:                 final Composite stackComposite = (Composite) parentForECPView.getChildren()[0];
1236:                 final StackLayout stack = (StackLayout) stackComposite.getLayout();
1237:                 Composite detailComposite = (Composite) stack.topControl;
1238:                 assertThat("Composite for details not present", detailComposite, notNullValue());
1239:                 final Control[] detailChildren = detailComposite.getChildren();
1240:                 assertThat("Insufficient number of detail controls", detailChildren.length, greaterThanOrEqualTo(6));
1241:
1242:                 // Select another EClass
1243:                 tableViewer.setSelection(new StructuredSelection(table.getItem(1).getData()));
1244:                 assertThat(parentForECPView.getChildren().length, is(1));
1245:                 detailComposite = (Composite) stack.topControl;
1246:                 assertThat("Detail controls not reused", detailComposite.getChildren(), is(detailChildren));
1247:         }
1248:
1249:         /**
1250:          * Verify the replacement of the parent context root domain model object while a detail
1251:          * is showing, in which the detail must be put away because the table selection is lost.
1252:          */
1253:         @Test
1254:         public void testRootDomainModelChangedWhilePanelTableDetail()
1255:                 throws NoRendererFoundException, NoPropertyDescriptorFoundExeption,
1256:                 EMFFormsNoRendererException {
1257:
1258:                 final EClass eClass = EcoreFactory.eINSTANCE.createEClass();
1259:                 ((EClass) domainElement).getESuperTypes().add(eClass);
1260:                 final TableControlHandle handle = createTableWithTwoTableColumns();
1261:                 handle.getTableControl().setDetailEditing(DetailEditing.WITH_PANEL);
1262:                 handle.getTableControl().setDetailView(createDetailView());
1263:
1264:                 final ViewModelContext context = ViewModelContextFactory.INSTANCE
1265:                         .createViewModelContext(handle.getView(), domainElement);
1266:                 context.putContextValue(DetailViewCache.DETAIL_VIEW_CACHE_SIZE, 5);
1267:                 final AbstractSWTRenderer<VElement> tableRenderer = rendererFactory.getRendererInstance(
1268:                         handle.getTableControl(), context);
1269:                 tableRenderer.getGridDescription(new SWTGridDescription());
1270:                 final Control render = tableRenderer.render(new SWTGridCell(0, 0, tableRenderer), shell);
1271:                 final Control control = Composite.class.cast(render).getChildren()[0];
1272:                 assumeThat("No control was rendered", control, notNullValue());
1273:
1274:                 final Composite controlComposite = (Composite) ((Composite) control).getChildren()[1];
1275:                 final Composite tableComposite = (Composite) controlComposite.getChildren()[0];
1276:                 final Table table = (Table) tableComposite.getChildren()[0];
1277:                 final ScrolledComposite scrolledComposite = (ScrolledComposite) controlComposite.getChildren()[1];
1278:                 final Composite parentForECPView = (Composite) scrolledComposite.getChildren()[0];
1279:                 assumeThat("Not enough rows in the table", table.getItemCount(), greaterThanOrEqualTo(2));
1280:                 final TableViewer tableViewer = getTableViewerFromRenderer(tableRenderer);
1281:
1282:                 // Select an EClass
1283:                 tableViewer.setSelection(new StructuredSelection(table.getItem(0).getData()));
1284:                 assumeThat("Composite for selection not present",
1285:                         asList(parentForECPView.getChildren()), hasItem(instanceOf(Composite.class)));
1286:                 final Composite stackComposite = (Composite) parentForECPView.getChildren()[0];
1287:                 final StackLayout stack = (StackLayout) stackComposite.getLayout();
1288:                 Composite detailComposite = (Composite) stack.topControl;
1289:                 assumeThat("Composite for details not present", detailComposite, notNullValue());
1290:                 Control[] detailChildren = detailComposite.getChildren();
1291:                 assumeThat("Insufficient number of detail controls", detailChildren.length, greaterThanOrEqualTo(6));
1292:
1293:                 // Now, replace the parent context domain model element
1294:                 context.changeDomainModel(eClass);
1295:
1296:                 // Assert that the table is now empty and the detail is the "No selection" label
1297:                 assertThat("Table should be empty", table.getItemCount(), is(0));
1298:                 detailComposite = (Composite) stack.topControl;
1299:                 detailChildren = detailComposite.getChildren();
1300:                 assumeThat("Wrong number of detail controls", detailChildren.length, is(1));
1301:                 assertThat("Detail is not a label", detailChildren[0], instanceOf(Label.class));
1302:         }
1303:
1304:         //
1305:         // Test framework
1306:         //
1307:
1308:         @SafeVarargs
1309:         static <T> Set<T> set(T... elements) {
1310:                 return new HashSet<>(Arrays.asList(elements));
1311:         }
1312:
1313:         /**
1314:          * Wait for any pending updates in a table renderer to be completed.
1315:          *
1316:          * @param tableRenderer a table renderer to wait for
1317:          */
1318:         final void waitFor(TableControlSWTRenderer tableRenderer) {
1319:                 try {
1320:                         if (!tableRenderer.getRunnableManager().waitForIdle(1L, TimeUnit.SECONDS)) {
1321:                                 fail("Timed out waiting for table updates");
1322:                         }
1323:                 } catch (final InterruptedException e) {
1324:                         fail("Interrupted waiting for table updates");
1325:                 }
1326:
1327:         }
1328:
1329:         private static class ColumnImageTableRenderer extends TableControlSWTRenderer {
1330:                 // BEGIN COMPLEX CODE
1331:                 @Inject
1332:                 ColumnImageTableRenderer(VTableControl vElement, ViewModelContext viewContext,
1333:                         ReportService reportService, EMFFormsDatabindingEMF emfFormsDatabinding,
1334:                         EMFFormsLabelProvider emfFormsLabelProvider, VTViewTemplateProvider vtViewTemplateProvider,
1335:                         ImageRegistryService imageRegistryService, EMFFormsEditSupport emfFormsEditSupport) {
1336:                         // END COMPLEX CODE
1337:                         super(vElement, viewContext, reportService, emfFormsDatabinding, emfFormsLabelProvider,
1338:                                 vtViewTemplateProvider,
1339:                                 imageRegistryService, emfFormsEditSupport);
1340:                 }
1341:
1342:                 @Override
1343:                 protected VTTableValidationStyleProperty getTableValidationStyleProperty() {
1344:                         final VTTableValidationStyleProperty property = VTTableValidationFactory.eINSTANCE
1345:                                 .createTableValidationStyleProperty();
1346:                         property.setImagePath("platform:/plugin/org.eclipse.emf.ecp.view.table.ui.swt/icons/cake.png");
1347:                         return property;
1348:                 }
1349:         }
1350:
1351:         private static class ColumnImageTableRendererService implements EMFFormsDIRendererService<VTableControl> {
1352:
1353:                 @Override
1354:                 public double isApplicable(VElement vElement, ViewModelContext viewModelContext) {
1355:                         if (vElement instanceof VTableControl) {
1356:                                 return Double.MAX_VALUE;
1357:                         }
1358:                         return NOT_APPLICABLE;
1359:                 }
1360:
1361:                 @Override
1362:                 public Class<? extends AbstractSWTRenderer<VTableControl>> getRendererClass() {
1363:                         return ColumnImageTableRenderer.class;
1364:                 }
1365:
1366:         }
1367:
1368:         private TableControlSWTRenderer createRendererInstanceWithCustomCellEditor(final VTableControl tableControl)
1369:                 throws EMFFormsNoRendererException {
1370:                 final ViewModelContextWithoutServices viewModelContext = new ViewModelContextWithoutServices(tableControl);
1371:                 final EMFFormsContextProvider contextProvider = viewModelContext.getService(EMFFormsContextProvider.class);
1372:                 final IEclipseContext eclipseContext = contextProvider.getContext();
1373:                 final TableControlSWTRenderer tableControlSWTRenderer = new TableControlSWTRenderer(
1374:                         tableControl,
1375:                         viewModelContext,
1376:                         eclipseContext.get(ReportService.class),
1377:                         eclipseContext.get(EMFFormsDatabindingEMF.class),
1378:                         eclipseContext.get(EMFFormsLabelProvider.class),
1379:                         eclipseContext.get(VTViewTemplateProvider.class),
1380:                         eclipseContext.get(ImageRegistryService.class),
1381:                         eclipseContext.get(EMFFormsEditSupport.class)) {
1382:
1383:                         @Override
1384:                         protected CellEditor createCellEditor(EObject tempInstance, EStructuralFeature feature, Composite table) {
1385:                                 if (feature == EcorePackage.eINSTANCE.getENamedElement_Name()) {
1386:                                         return new CompareCellEditor(table);
1387:                                 }
1388:                                 return super.createCellEditor(tempInstance, feature, table);
1389:                         }
1390:                 };
1391:                 tableControlSWTRenderer.init();
1392:                 return tableControlSWTRenderer;
1393:         }
1394:
1395:         private static void assertTableItemOrder(Table table, Object... objects) {
1396:                 assertEquals(objects.length, table.getItemCount());
1397:                 final TableItem[] items = table.getItems();
1398:                 for (int i = 0; i < items.length; i++) {
1399:                         assertSame(objects[i], items[i].getData());
1400:                 }
1401:         }
1402:
1403:         private static EAttribute createEAttribute(String name, EClassifier classifier, int lowerBound, int upperBound) {
1404:                 final EAttribute attribute = EcoreFactory.eINSTANCE.createEAttribute();
1405:                 attribute.setName(name);
1406:                 attribute.setEType(classifier);
1407:                 attribute.setLowerBound(lowerBound);
1408:                 attribute.setUpperBound(upperBound);
1409:                 return attribute;
1410:         }
1411:
1412:         private static VFeaturePathDomainModelReference createDMR(EAttribute attribute, EReference... refs) {
1413:                 final VFeaturePathDomainModelReference dmr = VViewFactory.eINSTANCE.createFeaturePathDomainModelReference();
1414:                 dmr.setDomainModelEFeature(attribute);
1415:                 dmr.getDomainModelEReferencePath().addAll(Arrays.asList(refs));
1416:                 return dmr;
1417:         }
1418:
1419:         private VView createDetailView() {
1420:                 final VView detailView = VViewFactory.eINSTANCE.createView();
1421:                 final VControl name = VViewFactory.eINSTANCE.createControl();
1422:                 final VFeaturePathDomainModelReference nameRef = VViewFactory.eINSTANCE.createFeaturePathDomainModelReference();
1423:                 nameRef.setDomainModelEFeature(EcorePackage.eINSTANCE.getENamedElement_Name());
1424:                 name.setDomainModelReference(nameRef);
1425:                 detailView.getChildren().add(name);
1426:                 final VControl abstr = VViewFactory.eINSTANCE.createControl();
1427:                 final VFeaturePathDomainModelReference abstractRef = VViewFactory.eINSTANCE
1428:                         .createFeaturePathDomainModelReference();
1429:                 abstractRef.setDomainModelEFeature(EcorePackage.eINSTANCE.getEClass_Abstract());
1430:                 abstr.setDomainModelReference(abstractRef);
1431:                 detailView.getChildren().add(abstr);
1432:                 return detailView;
1433:
1434:         }
1435:
1436:         private Control getTable(Control render) {
1437:                 Composite composite = (Composite) render;
1438:                 composite = (Composite) composite.getChildren()[0];
1439:                 composite = (Composite) composite.getChildren()[1];
1440:                 // composite = (Composite) composite.getChildren()[0];
1441:                 // composite = (Composite) composite.getChildren()[0];
1442:                 // composite = (Composite) composite.getChildren()[0];
1443:                 return composite.getChildren()[0];
1444:         }
1445:
1446:         private static TableControlHandle createTableWithTwoTableColumns() {
1447:                 final TableControlHandle tableControlHandle = TableTestUtil.createInitializedTableWithoutTableColumns();
1448:                 final VDomainModelReference tableColumn1 = TableTestUtil
1449:                         .createTableColumn(EcorePackage.eINSTANCE.getEClass_Abstract());
1450:
1451:                 tableControlHandle.addFirstTableColumn(tableColumn1);
1452:                 final VDomainModelReference tableColumn2 = TableTestUtil
1453:                         .createTableColumn(EcorePackage.eINSTANCE.getEClass_Abstract());
1454:                 tableControlHandle.addSecondTableColumn(tableColumn2);
1455:                 return tableControlHandle;
1456:         }
1457:
1458:         private TableViewer getTableViewerFromRenderer(AbstractSWTRenderer<VElement> renderer) {
1459:                 try {
1460:                         final Method method = TableControlSWTRenderer.class.getDeclaredMethod("getTableViewer");
1461:                         method.setAccessible(true);
1462:                         return (TableViewer) method.invoke(renderer);
1463:                 } catch (final NoSuchMethodException ex) {
1464:                         fail(ex.getMessage());
1465:                 } catch (final SecurityException ex) {
1466:                         fail(ex.getMessage());
1467:                 } catch (final IllegalAccessException ex) {
1468:                         fail(ex.getMessage());
1469:                 } catch (final IllegalArgumentException ex) {
1470:                         fail(ex.getMessage());
1471:                 } catch (final InvocationTargetException ex) {
1472:                         fail(ex.getMessage());
1473:                 }
1474:                 return null;
1475:         }
1476:
1477:         /**
1478:          * Stub implementation without getting services from ex. point.
1479:          *
1480:          * @author jfaltermeier
1481:          *
1482:          */
1483:         private class ViewModelContextWithoutServices implements ViewModelContext {
1484:
1485:                 private final VElement view;
1486:                 private final EMFFormsContextProvider contextProvider;
1487:                 private final Map<Class<?>, Object> services = new LinkedHashMap<>();
1488:                 private final Map<String, Object> contextValues = new HashMap<>();
1489:
1490:                 ViewModelContextWithoutServices(VElement view) {
1491:                         this.view = view;
1492:                         contextProvider = new org.eclipse.emfforms.internal.swt.core.di.EMFFormsContextProviderImpl();
1493:                         contextProvider.instantiate(this);
1494:                 }
1495:
1496:                 /**
1497:                  * {@inheritDoc}
1498:                  *
1499:                  * @see org.eclipse.emf.ecp.view.spi.context.ViewModelContext#getViewModel()
1500:                  */
1501:                 @Override
1502:                 public VElement getViewModel() {
1503:                         return view;
1504:                 }
1505:
1506:                 /**
1507:                  * {@inheritDoc}
1508:                  *
1509:                  * @see org.eclipse.emf.ecp.view.spi.context.ViewModelContext#getDomainModel()
1510:                  */
1511:                 @Override
1512:                 public EObject getDomainModel() {
1513:                         return domainElement;
1514:                 }
1515:
1516:                 /**
1517:                  *
1518:                  * {@inheritDoc}
1519:                  *
1520:                  * @see org.eclipse.emf.ecp.view.spi.context.ViewModelContext#registerViewChangeListener(org.eclipse.emf.ecp.view.spi.model.ModelChangeListener)
1521:                  */
1522:                 @Override
1523:                 public void registerViewChangeListener(ModelChangeListener modelChangeListener) {
1524:                         // not needed
1525:                 }
1526:
1527:                 /**
1528:                  *
1529:                  * {@inheritDoc}
1530:                  *
1531:                  * @see org.eclipse.emf.ecp.view.spi.context.ViewModelContext#unregisterViewChangeListener(org.eclipse.emf.ecp.view.spi.model.ModelChangeListener)
1532:                  */
1533:                 @Override
1534:                 public void unregisterViewChangeListener(ModelChangeListener modelChangeListener) {
1535:                         // not needed
1536:                 }
1537:
1538:                 /**
1539:                  *
1540:                  * {@inheritDoc}
1541:                  *
1542:                  * @see org.eclipse.emf.ecp.view.spi.context.ViewModelContext#registerDomainChangeListener(org.eclipse.emf.ecp.view.spi.model.ModelChangeListener)
1543:                  */
1544:                 @Override
1545:                 public void registerDomainChangeListener(ModelChangeListener modelChangeListener) {
1546:                         // not needed
1547:                 }
1548:
1549:                 /**
1550:                  *
1551:                  * {@inheritDoc}
1552:                  *
1553:                  * @see org.eclipse.emf.ecp.view.spi.context.ViewModelContext#unregisterDomainChangeListener(org.eclipse.emf.ecp.view.spi.model.ModelChangeListener)
1554:                  */
1555:                 @Override
1556:                 public void unregisterDomainChangeListener(ModelChangeListener modelChangeListener) {
1557:                         // not needed
1558:                 }
1559:
1560:                 /**
1561:                  * {@inheritDoc}
1562:                  *
1563:                  * @see org.eclipse.emf.ecp.view.spi.context.ViewModelContext#dispose()
1564:                  */
1565:                 @Override
1566:                 public void dispose() {
1567:                         // not needed
1568:                 }
1569:
1570:                 public <T> void addService(T service, Class<? super T> serviceClass) {
1571:                         services.put(serviceClass, service);
1572:                 }
1573:
1574:                 /**
1575:                  * {@inheritDoc}
1576:                  *
1577:                  * @see org.eclipse.emf.ecp.view.spi.context.ViewModelContext#hasService(java.lang.Class)
1578:                  */
1579:                 @Override
1580:                 public <T> boolean hasService(Class<T> serviceType) {
1581:                         if (EMFFormsContextProvider.class.equals(serviceType)) {
1582:                                 return true;
1583:                         }
1584:                         if (services.containsKey(serviceType)) {
1585:                                 return true;
1586:                         }
1587:                         return false;
1588:                 }
1589:
1590:                 /**
1591:                  * {@inheritDoc}
1592:                  *
1593:                  * @see org.eclipse.emf.ecp.view.spi.context.ViewModelContext#getService(java.lang.Class)
1594:                  */
1595:                 @SuppressWarnings("unchecked")
1596:                 @Override
1597:                 public <T> T getService(Class<T> serviceType) {
1598:                         if (EMFFormsContextProvider.class.equals(serviceType)) {
1599:                                 return (T) contextProvider;
1600:                         }
1601:                         return (T) services.get(serviceType);
1602:                 }
1603:
1604:                 /**
1605:                  * {@inheritDoc}
1606:                  *
1607:                  * @see org.eclipse.emf.ecp.view.spi.context.ViewModelContext#getControlsFor(org.eclipse.emf.ecore.EStructuralFeature.Setting)
1608:                  * @deprecated
1609:                  */
1610:                 @Deprecated
1611:                 @Override
1612:                 public Set<VControl> getControlsFor(Setting setting) {
1613:                         return null;
1614:                 }
1615:
1616:                 /**
1617:                  * {@inheritDoc}
1618:                  *
1619:                  * @see org.eclipse.emf.ecp.view.spi.context.ViewModelContext#getControlsFor(org.eclipse.emf.ecp.common.spi.UniqueSetting)
1620:                  * @deprecated
1621:                  */
1622:                 @Deprecated
1623:                 @Override
1624:                 public Set<VElement> getControlsFor(UniqueSetting setting) {
1625:                         return null;
1626:                 }
1627:
1628:                 @Override
1629:                 public Object getContextValue(String key) {
1630:                         Object result = contextValues.get(key);
1631:                         if (result == null && getParentContext() != null) {
1632:                                 result = getParentContext().getContextValue(key);
1633:                         }
1634:                         return result;
1635:                 }
1636:
1637:                 @Override
1638:                 public void putContextValue(String key, Object value) {
1639:                         contextValues.put(key, value);
1640:                 }
1641:
1642:                 @Override
1643:                 public void registerDisposeListener(ViewModelContextDisposeListener listener) {
1644:                         // do nothing
1645:                 }
1646:
1647:                 @Override
1648:                 public void addContextUser(Object user) {
1649:                         // do nothing
1650:                 }
1651:
1652:                 @Override
1653:                 public void removeContextUser(Object user) {
1654:                         // do nothing
1655:                 }
1656:
1657:                 @Deprecated
1658:                 @Override
1659:                 public ViewModelContext getChildContext(EObject eObject, VElement parent, VView vView,
1660:                         ViewModelService... viewModelServices) {
1661:
1662:                         final ViewModelContextWithoutServices vmcws = new ViewModelContextWithoutServices(vView);
1663:                         return vmcws;
1664:                 }
1665:
1666:                 @Override
1667:                 public ViewModelContext getChildContext(EObject eObject, VElement parent, VView vView,
1668:                         ViewModelServiceProvider viewModelServiceProvider) {
1669:
1670:                         return new ViewModelContextWithoutServices(vView);
1671:                 }
1672:
1673:                 @Override
1674:                 public void registerEMFFormsContextListener(EMFFormsContextListener contextListener) {
1675:                 }
1676:
1677:                 @Override
1678:                 public void unregisterEMFFormsContextListener(EMFFormsContextListener contextListener) {
1679:                 }
1680:
1681:                 @Override
1682:                 public ViewModelContext getParentContext() {
1683:                         return null;
1684:                 }
1685:
1686:                 @Override
1687:                 public void changeDomainModel(EObject newDomainModel) {
1688:                         // do nothing
1689:                 }
1690:
1691:                 @Override
1692:                 public void registerRootDomainModelChangeListener(RootDomainModelChangeListener rootDomainModelChangeListener) {
1693:                         // do nothing
1694:                 }
1695:
1696:                 @Override
1697:                 public void unregisterRootDomainModelChangeListener(
1698:                         RootDomainModelChangeListener rootDomainModelChangeListener) {
1699:                         // do nothing
1700:                 }
1701:
1702:                 @Override
1703:                 public VElement getParentVElement() {
1704:                         return null;
1705:                 }
1706:
1707:                 @Override
1708:                 public void pause() {
1709:                         // do nothing
1710:                 }
1711:
1712:                 @Override
1713:                 public void reactivate() {
1714:                         // do nothing
1715:                 }
1716:
1717:         }
1718:
1719:         private static class PrintStreamWrapper extends PrintStream {
1720:
1721:                 private final PrintStream printStream;
1722:
1723:                 PrintStreamWrapper(PrintStream printStream) {
1724:                         super(new ByteArrayOutputStream());
1725:                         this.printStream = printStream;
1726:                 }
1727:
1728:                 /**
1729:                  * {@inheritDoc}
1730:                  *
1731:                  * @see java.io.PrintStream#print(java.lang.String)
1732:                  */
1733:                 @Override
1734:                 public void print(String s) {
1735:                         log = log.concat("\n" + s);
1736:                         printStream.print(s + "\n");
1737:                 }
1738:         }
1739:
1740:         private static class CompareCellEditor extends StringCellEditor implements ECPCellEditorComparator {
1741:
1742:                 CompareCellEditor(Composite table) {
1743:                         super(table);
1744:                 }
1745:
1746:                 @Override
1747:                 public int compare(Object e1, Object e2, int direction) {
1748:                         final String value1 = String.class.cast(e1);
1749:                         final String value2 = String.class.cast(e2);
1750:                         int result;
1751:                         if (value1 == null) {
1752:                                 result = 1;
1753:                         } else if (value2 == null) {
1754:                                 result = -1;
1755:                         } else {
1756:                                 result = value1.toString().compareTo(value2.toString()) * -1;// we flip the oder in our custom
1757:                                                                                                                                                                 // comparator
1758:                         }
1759:                         // If descending order, flip the direction
1760:                         if (direction == 2) {
1761:                                 result = -result;
1762:                         }
1763:                         return result;
1764:                 }
1765:
1766:         }
1767:
1768: }