Skip to content

Package: RichTextControlSWTRenderer$3

RichTextControlSWTRenderer$3

nameinstructionbranchcomplexitylinemethod
focusGained(FocusEvent)
M: 1 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
focusLost(FocusEvent)
M: 13 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
{...}
M: 9 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%

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: * Jonas Helming - initial API and implementation
13: ******************************************************************************/
14: package org.eclipse.emfforms.spi.swt.control.text.richtext.renderer;
15:
16: import javax.inject.Inject;
17:
18: import org.eclipse.core.databinding.Binding;
19: import org.eclipse.core.databinding.DataBindingContext;
20: import org.eclipse.core.databinding.UpdateValueStrategy;
21: import org.eclipse.core.databinding.observable.value.IObservableValue;
22: import org.eclipse.emf.ecp.view.spi.context.ViewModelContext;
23: import org.eclipse.emf.ecp.view.spi.core.swt.renderer.TextControlSWTRenderer;
24: import org.eclipse.emf.ecp.view.spi.model.VControl;
25: import org.eclipse.emf.ecp.view.template.model.VTViewTemplateProvider;
26: import org.eclipse.emfforms.spi.common.report.ReportService;
27: import org.eclipse.emfforms.spi.core.services.databinding.EMFFormsDatabinding;
28: import org.eclipse.emfforms.spi.core.services.editsupport.EMFFormsEditSupport;
29: import org.eclipse.emfforms.spi.core.services.label.EMFFormsLabelProvider;
30: import org.eclipse.emfforms.spi.swt.core.layout.EMFFormsSWTLayoutUtil;
31: import org.eclipse.emfforms.spi.swt.core.util.PopupWindow;
32: import org.eclipse.jface.databinding.swt.typed.WidgetProperties;
33: import org.eclipse.jface.layout.GridDataFactory;
34: import org.eclipse.jface.layout.GridLayoutFactory;
35: import org.eclipse.swt.SWT;
36: import org.eclipse.swt.custom.StyledText;
37: import org.eclipse.swt.events.DisposeEvent;
38: import org.eclipse.swt.events.DisposeListener;
39: import org.eclipse.swt.events.FocusEvent;
40: import org.eclipse.swt.events.FocusListener;
41: import org.eclipse.swt.events.KeyAdapter;
42: import org.eclipse.swt.events.KeyEvent;
43: import org.eclipse.swt.events.KeyListener;
44: import org.eclipse.swt.events.ModifyEvent;
45: import org.eclipse.swt.events.ModifyListener;
46: import org.eclipse.swt.events.MouseEvent;
47: import org.eclipse.swt.events.MouseListener;
48: import org.eclipse.swt.events.TraverseEvent;
49: import org.eclipse.swt.events.TraverseListener;
50: import org.eclipse.swt.events.VerifyEvent;
51: import org.eclipse.swt.events.VerifyListener;
52: import org.eclipse.swt.layout.GridData;
53: import org.eclipse.swt.widgets.Composite;
54: import org.eclipse.swt.widgets.Control;
55: import org.eclipse.swt.widgets.Text;
56:
57: /**
58: * The multi line text control renderer displays the text in a read only fashion. Once the user starts editing (pressing
59: * any key except tab), a
60: * popupcontrol is displayed allowing the user to edit the contents.
61: *
62: * @author Jonas Helming
63: *
64: */
65: public class RichTextControlSWTRenderer extends TextControlSWTRenderer {
66:         private GridData textGridData;
67:         private StyledText text;
68:
69:         private static final String RETURN_PATTERN = "[\n]"; //$NON-NLS-1$
70:         private static final String CARRIAGE_PATTERN = "[\r]"; //$NON-NLS-1$
71:         private PopupWindow popupWindow;
72:         private Text innerText;
73:         private Binding binding;
74:
75:         /**
76:          * @author Jonas Helming
77:          *
78:          */
79:         private final class OpenPopupHandler implements MouseListener {
80:                 private final StyledText text;
81:
82:                 private OpenPopupHandler(StyledText text) {
83:                         this.text = text;
84:                 }
85:
86:                 @Override
87:                 public void mouseUp(MouseEvent e) {
88:                         openPopUp(text, false);
89:                 }
90:
91:                 @Override
92:                 public void mouseDown(MouseEvent e) {
93:
94:                 }
95:
96:                 @Override
97:                 public void mouseDoubleClick(MouseEvent e) {
98:                 }
99:         }
100:
101:         private void openPopUp(final StyledText text, boolean selectAll) {
102:                 popupWindow = createPopupWindow();
103:
104:                 innerText = new Text(popupWindow.getContent(),
105:                         SWT.MULTI | SWT.WRAP | SWT.V_SCROLL | SWT.H_SCROLL);
106:                 final GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true);
107:                 layoutData.heightHint = getPreferrredPopupHeight();
108:                 innerText.setLayoutData(layoutData);
109:                 innerText.setSize(300, getPreferrredPopupHeight());
110:                 popupWindow.getContent().pack();
111:                 popupWindow.open();
112:
113:                 innerText.setFocus();
114:                 innerText.setText(text.getText());
115:
116:                 if (selectAll) {
117:                         innerText.selectAll();
118:                 } else {
119:                         innerText.setSelection(text.getSelectionRange().x, text.getSelectionRange().x + text.getSelectionCount());
120:                 }
121:
122:                 innerText.addVerifyListener(new VerifyListener() {
123:
124:                         @Override
125:                         public void verifyText(VerifyEvent e) {
126:                                 if (e.text != null) {
127:                                         e.text = e.text.replaceAll(CARRIAGE_PATTERN, "").replaceAll(RETURN_PATTERN, Text.DELIMITER); //$NON-NLS-1$
128:                                 }
129:                         }
130:                 });
131:
132:                 innerText.addKeyListener(new KeyAdapter() {
133:                         @Override
134:                         public void keyPressed(KeyEvent e) {
135:                                 if (e.keyCode == 'a' && (isCtrlKeyPressed(e) || isCommandKeyPressed(e))) {
136:                                         innerText.selectAll();
137:                                 }
138:                         }
139:                 });
140:
141:                 innerText.addFocusListener(new FocusListener() {
142:                         @Override
143:                         public void focusLost(FocusEvent e) {
144:                                 storePopUpInOriginalText(text, innerText);
145:                                 popupWindow.close();
146:                         }
147:
148:                         @Override
149:                         public void focusGained(FocusEvent e) {
150:                                 // do nothing
151:                         }
152:                 });
153:
154:                 innerText.addDisposeListener(new DisposeListener() {
155:
156:                         @Override
157:                         public void widgetDisposed(DisposeEvent e) {
158:                                 storePopUpInOriginalText(text, innerText);
159:                                 text.setCaretOffset(innerText.getCaretPosition());
160:
161:                         }
162:
163:                 });
164:
165:         }
166:
167:         private void storePopUpInOriginalText(final StyledText originalText, Text popUpText) {
168:                 originalText.setText(popUpText.getText());
169:                 originalText.setSelection(popUpText.getCaretPosition());
170:                 binding.updateTargetToModel();
171:         }
172:
173:         private static boolean isCtrlKeyPressed(KeyEvent e) {
174:                 return (e.stateMask & SWT.MODIFIER_MASK) == SWT.CTRL;
175:         }
176:
177:         private static boolean isCommandKeyPressed(KeyEvent e) {
178:                 return (e.stateMask & SWT.MODIFIER_MASK) == SWT.COMMAND;
179:         }
180:
181:         /**
182:          * Specifies the preferred size of the popup window.
183:          *
184:          * @return the size in pixel
185:          */
186:         protected int getPreferrredPopupHeight() {
187:                 return 450;
188:         }
189:
190:         /**
191:          * creates the popup window.
192:          *
193:          * @return a new {@link PopupWindow}
194:          */
195:         protected PopupWindow createPopupWindow() {
196:                 return new PopupWindow(text, getPreferrredPopupHeight(), SWT.RESIZE, true);
197:         }
198:
199:         /**
200:          * Constructs a new {@link RichTextControlSWTRenderer}.
201:          *
202:          * @param vElement the view model element to be rendered
203:          * @param viewContext the view context
204:          * @param reportService The {@link ReportService}
205:          * @param emfFormsDatabinding The {@link EMFFormsDatabinding}
206:          * @param emfFormsLabelProvider The {@link EMFFormsLabelProvider}
207:          * @param vtViewTemplateProvider The {@link VTViewTemplateProvider}
208:          * @param emfFormsEditSupport The {@link EMFFormsEditSupport}
209:          */
210:         @Inject
211:         public RichTextControlSWTRenderer(
212:                 VControl vElement,
213:                 ViewModelContext viewContext,
214:                 ReportService reportService,
215:                 EMFFormsDatabinding emfFormsDatabinding,
216:                 EMFFormsLabelProvider emfFormsLabelProvider,
217:                 VTViewTemplateProvider vtViewTemplateProvider, EMFFormsEditSupport emfFormsEditSupport) {
218:                 super(vElement, viewContext, reportService, emfFormsDatabinding, emfFormsLabelProvider, vtViewTemplateProvider,
219:                         emfFormsEditSupport);
220:         }
221:
222:         /**
223:          * {@inheritDoc}
224:          *
225:          * Databinding is set to SWT.Modify, because we cannot guarantee that the focus of the text field is lost after the
226:          * popup windows is closed.
227:          *
228:          * @see org.eclipse.emf.ecp.view.spi.core.swt.renderer.TextControlSWTRenderer#bindValue(org.eclipse.swt.widgets.Control,
229:          * org.eclipse.core.databinding.observable.value.IObservableValue,
230:          * org.eclipse.core.databinding.DataBindingContext, org.eclipse.core.databinding.UpdateValueStrategy,
231:          * org.eclipse.core.databinding.UpdateValueStrategy)
232:          */
233:         @Override
234:         protected Binding bindValue(Control text, IObservableValue modelValue, DataBindingContext dataBindingContext,
235:                 UpdateValueStrategy targetToModel, UpdateValueStrategy modelToTarget) {
236:                 final IObservableValue value = WidgetProperties.text(SWT.NONE).observe(this.text);
237:                 binding = dataBindingContext.bindValue(value, modelValue, targetToModel, modelToTarget);
238:                 return binding;
239:         }
240:
241:         @Override
242:         protected Control createSWTControl(Composite parent) {
243:                 final Composite composite = new Composite(parent, SWT.NONE);
244:                 GridLayoutFactory.fillDefaults().numColumns(1).equalWidth(true).applyTo(composite);
245:                 text = new StyledText(composite, getTextWidgetStyle());
246:                 text.setData(CUSTOM_VARIANT, getTextVariantID());
247:                 text.setEditable(true);
248:                 text.setToolTipText(getTextMessage());
249:                 final GridDataFactory gdf = GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER)
250:                         .grab(true, true).span(1, 1);
251:                 final EMFFormsEditSupport editSupport = getEMFFormsEditSupport();
252:                 if (editSupport.isMultiLine(getVElement().getDomainModelReference(), getViewModelContext().getDomainModel())) {
253:                         gdf.hint(0, getTextHeightHint());// set x hint to enable wrapping
254:                 }
255:                 textGridData = gdf.create();
256:                 text.setLayoutData(textGridData);
257:                 text.addMouseListener(new OpenPopupHandler(text));
258:                 text.addTraverseListener(new TraverseListener() {
259:
260:                         @Override
261:                         public void keyTraversed(TraverseEvent e) {
262:                                 e.doit = true;
263:
264:                         }
265:                 });
266:                 text.addKeyListener(new KeyListener() {
267:
268:                         @Override
269:                         public void keyReleased(KeyEvent e) {
270:
271:                         }
272:
273:                         @Override
274:                         public void keyPressed(KeyEvent e) {
275:
276:                                 if (isOpenKey(e)) {
277:                                         boolean selectAll = false;
278:                                         if ((isCommandKeyPressed(e) || isCtrlKeyPressed(e)) && e.keyCode == 'a') {
279:                                                 selectAll = true;
280:                                         }
281:                                         openPopUp(text, selectAll);
282:                                 }
283:
284:                         }
285:                 });
286:
287:                 text.addModifyListener(new ModifyListener() {
288:
289:                         @Override
290:                         public void modifyText(ModifyEvent e) {
291:                                 textGridData.heightHint = getTextHeightHint();
292:                                 text.setLayoutData(textGridData);
293:                                 EMFFormsSWTLayoutUtil.adjustParentSize(text);
294:                         }
295:
296:                 });
297:                 return composite;
298:         }
299:
300:         /**
301:          * Determines, whether the popup shall be opened on a specific KeyEvent on the regular Text Control. By default the
302:          * popup opens on any key except SHIFT and ALT, but additional keys can be added by overriding the method.
303:          *
304:          * @param e the {@link KeyEvent} on the regular {@link Text}
305:          * @return whether the popup should open
306:          * @since 1.14
307:          */
308:         protected boolean isOpenKey(KeyEvent e) {
309:                 if (e.keyCode == SWT.SHIFT) {
310:                         return false;
311:                 }
312:                 if (e.keyCode == SWT.ALT) {
313:                         return false;
314:                 }
315:                 if (e.keyCode == SWT.CTRL) {
316:                         return false;
317:                 }
318:                 if (e.keyCode == SWT.COMMAND) {
319:                         return false;
320:                 }
321:
322:                 return true;
323:         }
324:
325:         /**
326:          * {@inheritDoc}
327:          *
328:          * @see org.eclipse.emf.ecp.view.spi.core.swt.AbstractControlSWTRenderer#postInit()
329:          */
330:         @Override
331:         protected void postInit() {
332:                 super.postInit();
333:         }
334:
335:         /**
336:          * The preferred height in pixels for the text control.
337:          *
338:          * @return the height hint
339:          * @see GridData#heightHint
340:          */
341:         protected int getTextHeightHint() {
342:                 if (text == null || text.isDisposed()) {
343:                         return -1;
344:                 }
345:                 final int lineCount = text.getLineCount();
346:                 int height = lineCount * text.getLineHeight();
347:
348:                 final int maxHeight = getMaxTextHeight();
349:                 final int minHeight = getMinTextHeight();
350:                 if (height > maxHeight) {
351:                         height = maxHeight;
352:                 } else if (height < minHeight) {
353:                         height = minHeight;
354:                 }
355:                 return height;
356:         }
357:
358:         /**
359:          * The maximum height in pixels for the text control.
360:          *
361:          * @return the maximum height
362:          */
363:         protected int getMaxTextHeight() {
364:                 if (text == null || text.isDisposed()) {
365:                         return -1;
366:                 }
367:
368:                 return getMaxVisibleLines() * text.getLineHeight();
369:         }
370:
371:         /**
372:          * The minimum height in pixels for the text control.
373:          *
374:          * @return the minimum height
375:          */
376:         protected int getMinTextHeight() {
377:                 if (text == null || text.isDisposed()) {
378:                         return -1;
379:                 }
380:                 return getMinVisibleLines() * text.getLineHeight();
381:         }
382:
383:         /**
384:          * The minimum number of visible lines in the text control.
385:          *
386:          * @return the minimum visible lines
387:          */
388:         protected int getMinVisibleLines() {
389:                 return 2;
390:         }
391:
392:         /**
393:          * The maximum number of visible lines in the text control.
394:          *
395:          * @return the maximum visible lines
396:          */
397:         protected int getMaxVisibleLines() {
398:                 return 10;
399:         }
400:
401: }