Skip to content

Package: ControlGridSWTRenderer

ControlGridSWTRenderer

nameinstructionbranchcomplexitylinemethod
ControlGridSWTRenderer(VControlGrid, ViewModelContext, ReportService, EMFFormsRendererFactory)
M: 0 C: 14
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 4
100%
M: 0 C: 1
100%
applyLayout(Composite, int, SWTGridDescription, int, int, int, int)
M: 17 C: 159
90%
M: 5 C: 25
83%
M: 5 C: 11
69%
M: 6 C: 41
87%
M: 0 C: 1
100%
computeColumnCountSoThatAllRowsCanBeRendered(Collection)
M: 0 C: 24
100%
M: 0 C: 4
100%
M: 0 C: 3
100%
M: 0 C: 6
100%
M: 0 C: 1
100%
computeColumnsForSWTLayout(int, int)
M: 0 C: 6
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
computePreferredWidthBasedOnPixelGridSize(double, int)
M: 0 C: 13
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
createControlGridComposite(Composite, int)
M: 0 C: 15
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
createEmptySingleCellGridDescription()
M: 0 C: 22
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 4
100%
M: 0 C: 1
100%
createGridDataForControlWithHorizontalGrab(SWTGridDescription, SWTGridCell, Control, int)
M: 0 C: 27
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 10
100%
M: 0 C: 1
100%
createGridDataForControlWithoutHorizontalGrab(SWTGridDescription, SWTGridCell, Control)
M: 0 C: 24
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 9
100%
M: 0 C: 1
100%
createGridDescriptionForEmptyCells(Collection)
M: 5 C: 188
97%
M: 2 C: 22
92%
M: 2 C: 11
85%
M: 1 C: 39
98%
M: 0 C: 1
100%
gcd(int, int)
M: 0 C: 10
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
getChildRenderers()
M: 0 C: 59
100%
M: 0 C: 6
100%
M: 0 C: 4
100%
M: 0 C: 12
100%
M: 0 C: 1
100%
getColumnCountsFromRows()
M: 0 C: 27
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 4
100%
M: 0 C: 1
100%
getColumnsPerRenderer(Collection)
M: 0 C: 20
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 4
100%
M: 0 C: 1
100%
getGridDescription(SWTGridDescription)
M: 0 C: 21
100%
M: 1 C: 1
50%
M: 1 C: 1
50%
M: 0 C: 4
100%
M: 0 C: 1
100%
getGridDescriptions(Collection)
M: 0 C: 27
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 6
100%
M: 0 C: 1
100%
getHorizontalSpacing()
M: 0 C: 2
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
getPixelGridSize()
M: 0 C: 2
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
getRendererFactory()
M: 0 C: 3
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
getRequiredColumnSizesOfRenderers(Collection)
M: 0 C: 26
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 4
100%
M: 0 C: 1
100%
lcm(int, int)
M: 0 C: 9
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
renderControl(SWTGridCell, Composite)
M: 16 C: 217
93%
M: 3 C: 19
86%
M: 2 C: 10
83%
M: 1 C: 52
98%
M: 0 C: 1
100%

Coverage

1: /*******************************************************************************
2: * Copyright (c) 2011-2015 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 - initial API and implementation
13: ******************************************************************************/
14: package org.eclipse.emfforms.spi.swt.controlgrid.renderer;
15:
16: import java.util.ArrayList;
17: import java.util.Collection;
18: import java.util.Iterator;
19: import java.util.LinkedHashMap;
20: import java.util.LinkedHashSet;
21: import java.util.List;
22: import java.util.Map;
23: import java.util.Map.Entry;
24: import java.util.Set;
25:
26: import javax.inject.Inject;
27:
28: import org.eclipse.emf.ecp.view.spi.context.ViewModelContext;
29: import org.eclipse.emf.ecp.view.spi.model.VControl;
30: import org.eclipse.emf.ecp.view.spi.model.VElement;
31: import org.eclipse.emf.ecp.view.spi.renderer.NoPropertyDescriptorFoundExeption;
32: import org.eclipse.emf.ecp.view.spi.renderer.NoRendererFoundException;
33: import org.eclipse.emf.emfforms.spi.view.controlgrid.model.VControlGrid;
34: import org.eclipse.emf.emfforms.spi.view.controlgrid.model.VControlGridCell;
35: import org.eclipse.emf.emfforms.spi.view.controlgrid.model.VControlGridRow;
36: import org.eclipse.emfforms.common.Optional;
37: import org.eclipse.emfforms.spi.common.report.AbstractReport;
38: import org.eclipse.emfforms.spi.common.report.ReportService;
39: import org.eclipse.emfforms.spi.swt.core.AbstractSWTRenderer;
40: import org.eclipse.emfforms.spi.swt.core.EMFFormsNoRendererException;
41: import org.eclipse.emfforms.spi.swt.core.EMFFormsRendererFactory;
42: import org.eclipse.emfforms.spi.swt.core.layout.GridDescriptionFactory;
43: import org.eclipse.emfforms.spi.swt.core.layout.SWTGridCell;
44: import org.eclipse.emfforms.spi.swt.core.layout.SWTGridDescription;
45: import org.eclipse.jface.layout.GridDataFactory;
46: import org.eclipse.jface.layout.GridLayoutFactory;
47: import org.eclipse.swt.SWT;
48: import org.eclipse.swt.events.ControlEvent;
49: import org.eclipse.swt.events.ControlListener;
50: import org.eclipse.swt.graphics.Point;
51: import org.eclipse.swt.layout.GridData;
52: import org.eclipse.swt.widgets.Composite;
53: import org.eclipse.swt.widgets.Control;
54: import org.eclipse.swt.widgets.Label;
55:
56: /**
57: * SWT Renderer for {@link VControlGrid}.
58: *
59: * @author Johannes Faltermeier
60: *
61: */
62: public class ControlGridSWTRenderer extends AbstractSWTRenderer<VControlGrid> {
63:
64:         private static final int SPACING = 20;
65:
66:         private final Map<Control, Integer> controlsToAlign = new LinkedHashMap<Control, Integer>();
67:
68:         private SWTGridDescription rendererGridDescription;
69:
70:         private final EMFFormsRendererFactory rendererFactory;
71:
72:         private SWTGridDescription emptyGridDescription;
73:
74:         /**
75:          * Default Constructor.
76:          *
77:          * @param vElement the view element to be rendered
78:          * @param viewContext The view model context
79:          * @param reportService the ReportService to use
80:          * @param rendererFactory the {@link EMFFormsRendererFactory renderer factory}
81:          */
82:         @Inject
83:         public ControlGridSWTRenderer(
84:                 VControlGrid vElement,
85:                 ViewModelContext viewContext,
86:                 ReportService reportService,
87:                 EMFFormsRendererFactory rendererFactory) {
88:                 super(vElement, viewContext, reportService);
89:                 this.rendererFactory = rendererFactory;
90:         }
91:
92:         /**
93:          * Returns the {@link EMFFormsRendererFactory}.
94:          *
95:          * @return the renderer factory
96:          */
97:         protected EMFFormsRendererFactory getRendererFactory() {
98:                 return rendererFactory;
99:         }
100:
101:         @Override
102:         public SWTGridDescription getGridDescription(SWTGridDescription gridDescription) {
103:•                if (rendererGridDescription == null) {
104:                         rendererGridDescription = GridDescriptionFactory.INSTANCE.createSimpleGrid(1, 1, this);
105:                         rendererGridDescription.getGrid().get(0).setVerticalGrab(false);
106:                 }
107:                 return rendererGridDescription;
108:         }
109:
110:         @Override
111:         protected Control renderControl(SWTGridCell cell, Composite parent)
112:                 throws NoRendererFoundException, NoPropertyDescriptorFoundExeption {
113:                 final Map<VControlGridCell, AbstractSWTRenderer<VElement>> renderers = getChildRenderers();
114:
115:                 final Map<AbstractSWTRenderer<VElement>, SWTGridDescription> gridDescriptions = getGridDescriptions(
116:                         renderers.values());
117:
118:                 emptyGridDescription = createGridDescriptionForEmptyCells(gridDescriptions.values());
119:
120:                 final Map<SWTGridDescription, Integer> gridDescriptionToRequiredRendererColumnsMap = getRequiredColumnSizesOfRenderers(
121:                         gridDescriptions.values());
122:
123:                 final int actualSWTColumnCountAvailableForEachRenderer = getColumnsPerRenderer(
124:                         gridDescriptionToRequiredRendererColumnsMap.values());
125:
126:                 final Set<Integer> columnsAsPerControlGrid = getColumnCountsFromRows();
127:
128:                 final int swtColumnsAsPerControlGrid = computeColumnCountSoThatAllRowsCanBeRendered(columnsAsPerControlGrid);
129:
130:                 final int layoutColumns = computeColumnsForSWTLayout(actualSWTColumnCountAvailableForEachRenderer,
131:                         swtColumnsAsPerControlGrid);
132:
133:                 /* create composite with columns */
134:                 final Composite composite = createControlGridComposite(parent, layoutColumns);
135:
136:                 /* render the rows */
137:•                for (final VControlGridRow row : getVElement().getRows()) {
138:•                        if (row.getCells().size() == 0) {
139:                                 final Label label = new Label(composite, SWT.NONE);
140:                                 GridDataFactory.fillDefaults().span(layoutColumns, 1).grab(false, false)
141:                                         .applyTo(label);
142:                                 continue;
143:                         }
144:                         /* -1 because of spacing label */
145:                         final int swtColumnsAvailableForRowElement = layoutColumns / row.getCells().size() - 1;
146:•                        for (final VControlGridCell vCell : row.getCells()) {
147:                                 /* render */
148:                                 final AbstractSWTRenderer<VElement> renderer = renderers.get(vCell);
149:•                                final SWTGridDescription swtGridDescription = renderer != null
150:                                         ? gridDescriptions.get(renderer)
151:                                         : emptyGridDescription;
152:
153:                                 /* analyze grid cells */
154:                                 int cellsWithoutHorizontalGrab = 0;
155:                                 int cellsWithHorizontalGrab = 0;
156:•                                for (final SWTGridCell swtGridCell : swtGridDescription.getGrid()) {
157:•                                        if (!swtGridCell.isHorizontalGrab()) {
158:                                                 cellsWithoutHorizontalGrab++;
159:                                         } else {
160:                                                 cellsWithHorizontalGrab++;
161:                                         }
162:                                 }
163:
164:                                 /* distribute space between grabing cells as equal as possible. */
165:                                 final int swtColumnsAvailableForGrabingCells = swtColumnsAvailableForRowElement
166:                                         - cellsWithoutHorizontalGrab;
167:                                 int spanForSpanningCells = 0;
168:                                 int spanForLastSpanningCell = 0;
169:•                                if (cellsWithHorizontalGrab > 0) {
170:                                         spanForSpanningCells = swtColumnsAvailableForGrabingCells / cellsWithHorizontalGrab;
171:                                         spanForLastSpanningCell = swtColumnsAvailableForGrabingCells
172:                                                 - (cellsWithHorizontalGrab - 1) * spanForSpanningCells;
173:                                 }
174:
175:                                 /* apply layout */
176:                                 applyLayout(composite, swtColumnsAvailableForRowElement, swtGridDescription,
177:                                         cellsWithoutHorizontalGrab, cellsWithHorizontalGrab, spanForSpanningCells,
178:                                         spanForLastSpanningCell);
179:
180:                                 /* render spacing label */
181:                                 final Label spacing = new Label(composite, SWT.NONE);
182:•                                final int xHint = row.getCells().get(row.getCells().size() - 1) != vCell ? getHorizontalSpacing() : 1;
183:                                 GridDataFactory.fillDefaults().hint(xHint, SWT.DEFAULT).applyTo(spacing);
184:
185:                         }
186:                 }
187:
188:                 /* finalize */
189:•                for (final AbstractSWTRenderer<VElement> renderer : renderers.values()) {
190:                         renderer.finalizeRendering(composite);
191:                 }
192:
193:                 /* listen for layout changes */
194:                 final Optional<Integer> pixelGridSize = getPixelGridSize();
195:•                if (pixelGridSize.isPresent() && !controlsToAlign.isEmpty()) {
196:                         composite.addControlListener(new AlignNonGrabbingControlsListener(composite, pixelGridSize.get()));
197:                 }
198:
199:                 composite.layout(true, true);
200:
201:                 return composite;
202:         }
203:
204:         /**
205:          * When this returns a non-empty optional all non-spanning/grabbing controls in a spanning/grabbing parent will have
206:          * a width which is a multiple of this pixel grid size. To be more specific, the preferred size of the control will
207:          * be rounded up to match this criteria.
208:          *
209:          * @return the grid size in pixels
210:          * @since 1.16
211:          */
212:         protected Optional<Integer> getPixelGridSize() {
213:                 return Optional.empty();
214:         }
215:
216:         /**
217:          * Multiplies the two column counts giving a required number for columns to use in the SWT composite.
218:          *
219:          * @param actualSWTColumnCountAvailableForEachRenderer count1
220:          * @param swtColumnsAsPerControlGrid count2
221:          * @return the column count
222:          */
223:         int computeColumnsForSWTLayout(final int actualSWTColumnCountAvailableForEachRenderer,
224:                 final int swtColumnsAsPerControlGrid) {
225:                 final int layoutColumns = swtColumnsAsPerControlGrid * actualSWTColumnCountAvailableForEachRenderer;
226:                 return layoutColumns;
227:         }
228:
229:         /**
230:          * Creates a composite with the given number of columns.
231:          *
232:          * @param parent the parent
233:          * @param layoutColumns the columns
234:          * @return the new composite
235:          */
236:         Composite createControlGridComposite(Composite parent, final int layoutColumns) {
237:                 final Composite composite = new Composite(parent, SWT.NONE);
238:                 GridLayoutFactory.fillDefaults().numColumns(layoutColumns).equalWidth(false).applyTo(composite);
239:                 return composite;
240:         }
241:
242:         /**
243:          * Returns the hint for the horizontal spacing.
244:          *
245:          * @return the spacing
246:          * @since 1.8
247:          */
248:         protected int getHorizontalSpacing() {
249:                 return SPACING;
250:         }
251:
252:         // BEGIN COMPLEX CODE
253:         private void applyLayout(final Composite composite, final int swtColumnsAvailableForRowElement,
254:                 final SWTGridDescription swtGridDescription, int cellsWithoutHorizontalGrab, int cellsWithHorizontalGrab,
255:                 int spanForSpanningCells, int spanForLastSpanningCell)
256:                 throws NoRendererFoundException, NoPropertyDescriptorFoundExeption {
257:                 int withHorizontalGrabLeft = cellsWithHorizontalGrab;
258:                 int withoutHorizontalGrabLeft = cellsWithoutHorizontalGrab;
259:•                for (final SWTGridCell swtGridCell : swtGridDescription.getGrid()) {
260:                         /*
261:                          * Create a wrapper composite, so that the child renderer may take as little space as it wants inside the
262:                          * wrapper
263:                          */
264:                         final Composite wrapperComposite = new Composite(composite, SWT.NONE);
265:                         GridLayoutFactory.fillDefaults().numColumns(1).equalWidth(true).applyTo(wrapperComposite);
266:                         final Control control;
267:•                        if (swtGridCell.getRenderer() != null) {
268:                                 control = swtGridCell.getRenderer().render(swtGridCell, wrapperComposite);
269:                         } else {
270:                                 control = new Label(wrapperComposite, SWT.NONE);
271:                         }
272:
273:                         boolean withHorizontalGrab = true;
274:                         GridData gridData;
275:•                        if (swtGridCell.isHorizontalGrab()) {
276:•                                final int hSpan = withHorizontalGrabLeft == 1 ? spanForLastSpanningCell
277:                                         : spanForSpanningCells;
278:                                 withHorizontalGrabLeft--;
279:                                 gridData = createGridDataForControlWithHorizontalGrab(swtGridDescription, swtGridCell, control,
280:                                         hSpan);
281:•                        } else if (cellsWithHorizontalGrab == 0 && withoutHorizontalGrabLeft == 1) {
282:                                 /*
283:                                  * if we have no spanning cells: renderer the last non spanning cell with span to take up the
284:                                  * remaining columns available for the rowelement
285:                                  */
286:                                 withoutHorizontalGrabLeft--;
287:                                 final int hSpan = swtColumnsAvailableForRowElement - cellsWithoutHorizontalGrab + 1;
288:                                 gridData = createGridDataForControlWithHorizontalGrab(swtGridDescription, swtGridCell, control,
289:                                         hSpan);
290:                         } else {
291:                                 withHorizontalGrab = false;
292:                                 withoutHorizontalGrabLeft--;
293:                                 // XXX minSize is not working... preferred way of solving this would be the next line only
294:                                 // GridDataFactory.fillDefaults().span(1, 1).grab(false, false).align(SWT.BEGINNING,
295:                                 // SWT.CENTER).minSize(16,SWT.DEFAULT).applyTo(control);
296:                                 gridData = createGridDataForControlWithoutHorizontalGrab(swtGridDescription, swtGridCell,
297:                                         control);
298:                         }
299:
300:                         final GridData controlGriddata = GridDataFactory.createFrom(gridData).span(1, 1).create();
301:
302:•                        if (!gridData.grabExcessHorizontalSpace && withHorizontalGrab) {
303:                                 /* if the width of a child is limited, we should still span on the wrapper */
304:                                 gridData.grabExcessHorizontalSpace = true;
305:                         }
306:•                        if (gridData.grabExcessHorizontalSpace) {
307:                                 /* set a minimal width hint as this will act as weight for spanning */
308:                                 /* if a width hint was set beforehand, the control will still have the set value */
309:                                 gridData.widthHint = 1;
310:                         }
311:•                        if (!swtGridCell.isHorizontalGrab() && controlGriddata.grabExcessHorizontalSpace) {
312:                                 /*
313:                                  * if we force a control to span because of layout-reasons (e.g. when only spanning cells, last cell
314:                                  * will span) we have to make sure that the inner control does not span
315:                                  */
316:                                 controlGriddata.grabExcessHorizontalSpace = false;
317:                         }
318:
319:•                        if (gridData.grabExcessHorizontalSpace && !controlGriddata.grabExcessHorizontalSpace) {
320:                                 /* child placed in grabbing parent. Store in map to align in a nice manner */
321:                                 int widthHint;
322:•                                if (controlGriddata.widthHint == SWT.DEFAULT) {
323:                                         /* if no pref size was specified via layout data use the natural width of the control */
324:                                         widthHint = control.computeSize(SWT.DEFAULT, SWT.DEFAULT).x;
325:                                 } else {
326:                                         widthHint = controlGriddata.widthHint;
327:                                 }
328:                                 controlsToAlign.put(control, widthHint);
329:                                 final Optional<Integer> pixelGridSize = getPixelGridSize();
330:•                                if (pixelGridSize.isPresent()) {
331:                                         controlGriddata.widthHint = computePreferredWidthBasedOnPixelGridSize(
332:                                                 widthHint,
333:                                                 pixelGridSize.get());
334:                                 }
335:                         }
336:
337:                         wrapperComposite.setLayoutData(gridData);
338:                         control.setLayoutData(controlGriddata);
339:                 }
340:         }
341:         // END COMPLEX CODE
342:
343:         /**
344:          * Creates the {@link GridData} which will be set on control which will take a span of 1 column an have no
345:          * horizontal grab.
346:          *
347:          * @param swtGridDescription the {@link SWTGridDescription}
348:          * @param swtGridCell the current {@link SWTGridCell} of the description
349:          * @param control the {@link Control}
350:          * @return the layout data
351:          * @since 1.8
352:          */
353:         protected GridData createGridDataForControlWithoutHorizontalGrab(final SWTGridDescription swtGridDescription,
354:                 final SWTGridCell swtGridCell, final Control control) {
355:                 GridData gridData;
356:                 final GridDataFactory gridDataFactory = GridDataFactory
357:                         .fillDefaults()
358:                         .span(1, 1)
359:                         .grab(false, false)
360:                         .align(SWT.FILL, SWT.CENTER);
361:
362:•                if (swtGridCell.getPreferredSize() != null) {
363:                         gridDataFactory.hint(swtGridCell.getPreferredSize());
364:                 }
365:
366:                 gridData = gridDataFactory.create();
367:                 return gridData;
368:         }
369:
370:         /**
371:          * Creates the {@link GridData} which will be set on control which will take up horizontal space an will span over
372:          * the given amount of columns.
373:          *
374:          * @param swtGridDescription the {@link SWTGridDescription}
375:          * @param swtGridCell the current {@link SWTGridCell} of the description
376:          * @param control the {@link Control}
377:          * @param hSpan the horizontal span
378:          * @return the layout data
379:          * @since 1.8
380:          */
381:         protected GridData createGridDataForControlWithHorizontalGrab(final SWTGridDescription swtGridDescription,
382:                 final SWTGridCell swtGridCell, final Control control, final int hSpan) {
383:                 GridData gridData;
384:                 gridData = GridDataFactory
385:                         .fillDefaults()
386:                         .span(hSpan, 1)
387:                         .grab(true, false)
388:                         .align(SWT.FILL, SWT.CENTER)
389:                         .create();
390:•                if (swtGridCell.getPreferredSize() != null) {
391:                         gridData.widthHint = swtGridCell.getPreferredSize().x;
392:                         gridData.heightHint = swtGridCell.getPreferredSize().y;
393:                 }
394:                 return gridData;
395:         }
396:
397:         /**
398:          * Computes the lcm of all column counts.
399:          *
400:          * @param columnsAsPerControlGrid the counts
401:          * @return the lcm
402:          */
403:         /* package */ int computeColumnCountSoThatAllRowsCanBeRendered(final Collection<Integer> columnsAsPerControlGrid) {
404:                 int swtColumnsAsPerControlGrid = 1;
405:•                for (final Integer integer : columnsAsPerControlGrid) {
406:•                        if (integer == 0) {
407:                                 continue;
408:                         }
409:                         swtColumnsAsPerControlGrid = lcm(swtColumnsAsPerControlGrid, integer);
410:                 }
411:                 return swtColumnsAsPerControlGrid;
412:         }
413:
414:         /**
415:          * Counts the columns as requested by the control grid.
416:          *
417:          * @return a set of all wanted columns
418:          */
419:         /* package */ Set<Integer> getColumnCountsFromRows() {
420:                 final Set<Integer> columnsAsPerControlGrid = new LinkedHashSet<Integer>();
421:•                for (final VControlGridRow row : getVElement().getRows()) {
422:                         columnsAsPerControlGrid.add(row.getCells().size());
423:                 }
424:                 return columnsAsPerControlGrid;
425:         }
426:
427:         /**
428:          * Will compute the lcm of the given integers.
429:          *
430:          * @param collection the ints
431:          * @return the lcm
432:          */
433:         /* package */ int getColumnsPerRenderer(final Collection<Integer> collection) {
434:                 int columnsPerRenderer = 1;
435:•                for (final Integer integer : collection) {
436:                         columnsPerRenderer = lcm(columnsPerRenderer, integer);
437:                 }
438:                 return columnsPerRenderer;
439:         }
440:
441:         /**
442:          * Returns a map from griddescription to required column size. This will be 1 more than specified by the description
443:          * itself, since we will render an additional label after each control to allow adding spacing.
444:          *
445:          * @param collection the descriptions
446:          * @return the map
447:          */
448:         /* package */ Map<SWTGridDescription, Integer> getRequiredColumnSizesOfRenderers(
449:                 final Collection<SWTGridDescription> collection) {
450:                 final Map<SWTGridDescription, Integer> requiredColumnSizesOfRenderers = new LinkedHashMap<SWTGridDescription, Integer>();
451:•                for (final SWTGridDescription description : collection) {
452:                         // +1 because we will renderer an empty spacing label after each control
453:                         requiredColumnSizesOfRenderers.put(description, description.getColumns() + 1);
454:                 }
455:                 return requiredColumnSizesOfRenderers;
456:
457:         }
458:
459:         /**
460:          * Returns a Map from cell to renderer. If a cell is empty or a renderer could not be created, there will be no
461:          * entry.
462:          *
463:          * @return the map
464:          */
465:         /* package */ Map<VControlGridCell, AbstractSWTRenderer<VElement>> getChildRenderers() {
466:                 final Map<VControlGridCell, AbstractSWTRenderer<VElement>> renderers = new LinkedHashMap<VControlGridCell, AbstractSWTRenderer<VElement>>();
467:•                for (final VControlGridRow row : getVElement().getRows()) {
468:•                        for (final VControlGridCell cell : row.getCells()) {
469:                                 final VControl control = cell.getControl();
470:•                                if (control == null) {
471:                                         /* render empty */
472:                                         continue;
473:                                 }
474:                                 try {
475:                                         final AbstractSWTRenderer<VElement> renderer = getRendererFactory()
476:                                                 .getRendererInstance(control, getViewModelContext());
477:                                         renderers.put(cell, renderer);
478:                                 } catch (final EMFFormsNoRendererException ex) {
479:                                         getReportService().report(new AbstractReport(ex));
480:                                 }
481:
482:                         }
483:                 }
484:                 return renderers;
485:         }
486:
487:         /**
488:          * Returns a map from renderer to its grid description.
489:          *
490:          * @param renderers the renderers
491:          * @return the map
492:          */
493:         /* package */ Map<AbstractSWTRenderer<VElement>, SWTGridDescription> getGridDescriptions(
494:                 final Collection<AbstractSWTRenderer<VElement>> renderers) {
495:                 final Map<AbstractSWTRenderer<VElement>, SWTGridDescription> gridDescriptions = new LinkedHashMap<AbstractSWTRenderer<VElement>, SWTGridDescription>();
496:•                for (final AbstractSWTRenderer<VElement> renderer : renderers) {
497:                         final SWTGridDescription gridDescription = renderer
498:                                 .getGridDescription(GridDescriptionFactory.INSTANCE.createEmptyGridDescription());
499:                         gridDescriptions.put(renderer, gridDescription);
500:                 }
501:                 return gridDescriptions;
502:         }
503:
504:         /**
505:          * @param values the collected grid description of the renderers
506:          * @return a {@link SWTGridDescription} which will be used to create empty cells. Please note that the
507:          * {@link SWTGridCell#getRenderer() renderer} of this description will be ignored, so it is fine to pass
508:          * <code>null</code> as a renderer
509:          * @since 1.16
510:          */
511:         // BEGIN COMPLEX CODE
512:         protected SWTGridDescription createGridDescriptionForEmptyCells(Collection<SWTGridDescription> values) {
513:                 final Iterator<SWTGridDescription> iterator = values.iterator();
514:
515:                 /* in case of no reference description, use on cell */
516:•                if (!iterator.hasNext()) {
517:                         return createEmptySingleCellGridDescription();
518:                 }
519:
520:                 final SWTGridDescription first = iterator.next();
521:
522:                 final int rows = first.getRows();
523:                 final int columns = first.getColumns();
524:                 final List<Boolean> grabHorizontal = new ArrayList<Boolean>();
525:                 final List<Point> sizes = new ArrayList<Point>();
526:
527:•                for (final SWTGridCell swtGridCell : first.getGrid()) {
528:                         grabHorizontal.add(swtGridCell.isHorizontalGrab());
529:                         final Point size = swtGridCell.getPreferredSize();
530:•                        if (size == null) {
531:                                 sizes.add(new Point(-1, -1));
532:                         } else {
533:                                 sizes.add(new Point(size.x, size.y));
534:                         }
535:                 }
536:
537:•                while (iterator.hasNext()) {
538:                         final SWTGridDescription next = iterator.next();
539:
540:•                        if (rows != next.getRows()) {
541:                                 return createEmptySingleCellGridDescription();
542:                         }
543:
544:•                        if (columns != next.getColumns()) {
545:                                 return createEmptySingleCellGridDescription();
546:                         }
547:
548:•                        for (int i = 0; i < next.getGrid().size(); i++) {
549:                                 final SWTGridCell swtGridCell = next.getGrid().get(i);
550:•                                if (!swtGridCell.isHorizontalGrab()) {
551:                                         grabHorizontal.set(i, false);
552:                                 }
553:                                 final Point sizeToCheck = swtGridCell.getPreferredSize();
554:•                                if (sizeToCheck == null) {
555:                                         continue;
556:                                 }
557:                                 final Point curSize = sizes.get(i);
558:                                 sizes.set(i, new Point(
559:•                                        sizeToCheck.x > curSize.x ? sizeToCheck.x : curSize.x,
560:•                                        sizeToCheck.y > curSize.y ? sizeToCheck.y : curSize.y));
561:                         }
562:                 }
563:
564:                 final SWTGridDescription swtGridDescription = GridDescriptionFactory.INSTANCE.createSimpleGrid(rows, columns,
565:                         null);
566:•                for (int j = 0; j < swtGridDescription.getGrid().size(); j++) {
567:                         final SWTGridCell swtGridCell = swtGridDescription.getGrid().get(j);
568:                         swtGridCell.setHorizontalGrab(grabHorizontal.get(j));
569:                         swtGridCell.setHorizontalFill(grabHorizontal.get(j));
570:                         swtGridCell.setPreferredSize(sizes.get(j));
571:                 }
572:
573:                 return swtGridDescription;
574:         }
575:         // END COMPLEX CODE
576:
577:         private static SWTGridDescription createEmptySingleCellGridDescription() {
578:                 final SWTGridDescription swtGridDescription = GridDescriptionFactory.INSTANCE.createSimpleGrid(1, 1, null);
579:                 swtGridDescription.getGrid().get(0).setHorizontalGrab(false);
580:                 swtGridDescription.getGrid().get(0).setHorizontalFill(false);
581:                 return swtGridDescription;
582:         }
583:
584:         /**
585:          * Rounds up the given width based on the given grid size.
586:          *
587:          * @param prefWidth the width to round up
588:          * @param pixelGridSize grid size
589:          * @return the new width
590:          */
591:         /* package */ int computePreferredWidthBasedOnPixelGridSize(final double prefWidth, int pixelGridSize) {
592:                 return Double.class.cast(Math.ceil(prefWidth / pixelGridSize)).intValue() * pixelGridSize;
593:         }
594:
595:         private static int gcd(int a, int b) {
596:•                if (b == 0) {
597:                         return a;
598:                 }
599:                 return gcd(b, a % b);
600:         }
601:
602:         private static int lcm(int a, int b) {
603:                 return Math.abs(a * b) / gcd(a, b);
604:         }
605:
606:         /**
607:          * {@link ControlListener} which makes non-grabbing controls slightly bigger so that they get aligned in a more
608:          * structured way.
609:          *
610:          * @author Johannes Faltermeier
611:          *
612:          */
613:         private final class AlignNonGrabbingControlsListener implements ControlListener {
614:                 private final Composite composite;
615:                 private final int pixelGridSize;
616:
617:                 private AlignNonGrabbingControlsListener(Composite composite, int pixelGridSize) {
618:                         this.composite = composite;
619:                         this.pixelGridSize = pixelGridSize;
620:                 }
621:
622:                 @Override
623:                 public void controlMoved(ControlEvent e) {
624:                         /* empty */
625:                 }
626:
627:                 @Override
628:                 public void controlResized(ControlEvent e) {
629:                         for (final Entry<Control, Integer> entry : controlsToAlign.entrySet()) {
630:                                 final int availableWidth = entry.getKey().getParent().getSize().x;
631:                                 if (availableWidth == 0) {
632:                                         continue;
633:                                 }
634:                                 final int prefWidth = entry.getValue();
635:
636:                                 int widthHint = computePreferredWidthBasedOnPixelGridSize(prefWidth, pixelGridSize);
637:                                 if (widthHint > availableWidth) {
638:                                         widthHint = prefWidth > availableWidth ? prefWidth : availableWidth;
639:                                 }
640:                                 GridData.class.cast(entry.getKey().getLayoutData()).widthHint = widthHint;
641:                         }
642:                         composite.layout(true, true);
643:                 }
644:         }
645: }