94fd56ee757a4e32623c82c2d162cf5052a55c73
[taxeditor.git] / eu.etaxonomy.taxeditor.editor / src / main / java / eu / etaxonomy / taxeditor / editor / name / e4 / container / AbstractGroupedContainerE4.java
1 /**
2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
8 */
9
10 package eu.etaxonomy.taxeditor.editor.name.e4.container;
11
12 import java.util.Iterator;
13 import java.util.List;
14 import java.util.Set;
15
16 import org.apache.commons.lang.StringUtils;
17 import org.eclipse.core.runtime.Assert;
18 import org.eclipse.e4.ui.di.UISynchronize;
19 import org.eclipse.jface.dialogs.Dialog;
20 import org.eclipse.jface.text.IDocument;
21 import org.eclipse.jface.text.Position;
22 import org.eclipse.jface.viewers.ISelectionChangedListener;
23 import org.eclipse.jface.window.DefaultToolTip;
24 import org.eclipse.swt.custom.StyledText;
25 import org.eclipse.swt.dnd.DND;
26 import org.eclipse.swt.dnd.DragSource;
27 import org.eclipse.swt.dnd.Transfer;
28 import org.eclipse.swt.events.ControlAdapter;
29 import org.eclipse.swt.events.ControlEvent;
30 import org.eclipse.swt.events.ControlListener;
31 import org.eclipse.swt.events.FocusAdapter;
32 import org.eclipse.swt.events.FocusEvent;
33 import org.eclipse.swt.events.FocusListener;
34 import org.eclipse.swt.events.ModifyEvent;
35 import org.eclipse.swt.events.ModifyListener;
36 import org.eclipse.swt.events.MouseAdapter;
37 import org.eclipse.swt.events.MouseEvent;
38 import org.eclipse.swt.graphics.Color;
39 import org.eclipse.swt.graphics.Font;
40 import org.eclipse.swt.graphics.Image;
41 import org.eclipse.swt.widgets.Composite;
42 import org.eclipse.swt.widgets.Control;
43 import org.eclipse.swt.widgets.Display;
44 import org.eclipse.swt.widgets.Label;
45 import org.eclipse.ui.forms.IFormPart;
46 import org.eclipse.ui.forms.IManagedForm;
47 import org.eclipse.ui.forms.widgets.TableWrapData;
48 import org.eclipse.ui.forms.widgets.TableWrapLayout;
49
50 import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
51 import eu.etaxonomy.cdm.model.common.CdmBase;
52 import eu.etaxonomy.cdm.model.name.TaxonName;
53 import eu.etaxonomy.cdm.model.taxon.TaxonBase;
54 import eu.etaxonomy.cdm.strategy.parser.ParserProblem;
55 import eu.etaxonomy.taxeditor.editor.CdmDataTransfer;
56 import eu.etaxonomy.taxeditor.editor.l10n.Messages;
57 import eu.etaxonomy.taxeditor.editor.name.container.EditorAnnotation;
58 import eu.etaxonomy.taxeditor.editor.name.container.EditorAnnotation.EditorAnnotationType;
59 import eu.etaxonomy.taxeditor.editor.name.container.IContainerConstants;
60 import eu.etaxonomy.taxeditor.editor.name.container.LineBreakListener;
61 import eu.etaxonomy.taxeditor.editor.name.container.LineWrapSupport;
62 import eu.etaxonomy.taxeditor.editor.name.container.NameViewer;
63 import eu.etaxonomy.taxeditor.editor.name.e4.TaxonNameEditorE4;
64 import eu.etaxonomy.taxeditor.editor.name.e4.dnd.NameEditorDragListenerE4;
65 import eu.etaxonomy.taxeditor.editor.name.e4.dnd.NameEditorDragSourceEffect;
66 import eu.etaxonomy.taxeditor.editor.name.operation.CreateSynonymInNewGroupOperation;
67 import eu.etaxonomy.taxeditor.model.AbstractUtility;
68 import eu.etaxonomy.taxeditor.model.IElementHasDetails;
69 import eu.etaxonomy.taxeditor.model.NameHelper;
70 import eu.etaxonomy.taxeditor.model.TextHelper;
71 import eu.etaxonomy.taxeditor.parser.ParseHandler;
72 import eu.etaxonomy.taxeditor.preference.Resources;
73
74 /**
75 * Formats <code>GroupedComposite</code> with cosmetic and layout properties
76 * specific to the Editor. This should be used to maintain a consistent look and
77 * feel for all Editor freetext area components, such as
78 * DescriptionElementComposite.
79 * <p>
80 * Requires an <code>IManagedForm</code>, whose <code>input</code> is set to the
81 * contents of {@link #getData()} when the <code>GroupedComposite</code> gets
82 * focus, i.e. to populate the property sheet with the data.
83 * </p>
84 * <p>
85 * The <code>IManagedForm</code> is also required to have a <code>Taxon</code>
86 * in its own <code>getData()</code>.
87 * </p>
88 * <p>
89 * The <code>IManagedForm</code> can also used for drawing borders by calling
90 * the method <code>createBorderSupport()</code>.
91 * </p>
92 * @author pplitzner
93 * @date Aug 24, 2017
94 *
95 * @param <T>
96 */
97 abstract public class AbstractGroupedContainerE4<T extends TaxonBase> implements
98 IFormPart, IContainerConstants, IElementHasDetails {
99
100 protected ParseHandler parseHandler;
101
102 private FocusListener nameCompositeFocusListener;
103 private ModifyListener nameCompositeModifyListener;
104
105 protected NameViewer nameViewer;
106
107 private AbstractGroupE4 group;
108
109 private Label nonEditableInfoLabel;
110 private DefaultToolTip nonEditableInfoHover;
111
112 private static AbstractGroupedContainerE4 selection;
113
114 private FocusListener focusListener;
115 private LineBreakListener lineBreakListener;
116
117 private int cursorPosition;
118
119 protected Composite control;
120
121 private Color backgroundColor;
122 private boolean isDirty;
123
124 private ISelectionChangedListener selectionChangedListener;
125
126 public AbstractGroupedContainerE4(AbstractGroupE4 group, T taxonBase) {
127 setData(taxonBase);
128 this.group = group;
129 parseHandler = ParseHandler.NewInstance(taxonBase.getName());
130 }
131
132 public void createContent() {
133 createControl();
134
135 createTextViewer();
136 createLineWrapSupport();
137 createLineBreakListener();
138
139 setMenu();
140
141 setDraggableControl(new Control[] { getControl(),
142 getNameViewer().getRulerControl() });
143
144 createEmptyViewerPrompt(EMPTY_NAME_PROMPT);
145
146 initializeComposite();
147
148 createListener();
149
150 enableFreeText();
151 }
152
153 protected void createListener() {
154 nameCompositeModifyListener = new ModifyListener() {
155
156 @Override
157 public void modifyText(ModifyEvent e) {
158 // mark the composite dirty
159 setDirty(true);
160 // parse the text
161 String text = nameViewer.getTextWidget().getText();
162
163 TaxonName name = (TaxonName)parseHandler.parse(text);
164 getTaxonBase().setName(name);
165 getTaxonBase().setTitleCache((getTaxonBase().generateTitle()));
166
167 // show errors resulting from parsing
168 calculateAnnotations();
169 // store the position of the cursor
170 storeCursor();
171 // notify selection listener
172 setDelayedSelection();
173 }
174 };
175 nameCompositeFocusListener = new FocusAdapter() {
176
177 @Override
178 public void focusLost(FocusEvent e) {
179 super.focusLost(e);
180
181 persistName();
182 }
183 };
184
185 addListener();
186 }
187
188 protected void addListener() {
189 getNameViewer().getTextWidget().addModifyListener(
190 nameCompositeModifyListener);
191 getNameViewer().getTextWidget().addFocusListener(
192 nameCompositeFocusListener);
193 }
194
195 protected void removeListener() {
196 getNameViewer().getTextWidget().removeModifyListener(
197 nameCompositeModifyListener);
198 getNameViewer().getTextWidget().removeFocusListener(
199 nameCompositeFocusListener);
200 }
201
202 /**
203 * Initialize the composite specific code
204 */
205 protected abstract void initializeComposite();
206
207 protected String getEmptyTextPrompt() {
208 return EMPTY_NAME_PROMPT;
209 }
210
211 protected void initTextViewer() {
212
213 updateIndent();
214
215 updateIcon();
216
217 String text = NameHelper.getDisplayNameWithRef(getData());
218
219 if (text.length() == 0) {
220 initEmptyText();
221 } else {
222 getNameViewer().setText(text);
223 placeCursor();
224 }
225 calculateAnnotations();
226 }
227
228 synchronized protected void calculateAnnotations() {
229 getNameViewer().clearAnnotations();
230 showAnnotations();
231 }
232
233 public void showAnnotations() {
234
235 if (getName() != null && getName().hasProblem()) {
236 showParsingProblems();
237 }
238
239 if (!isNameParsable()) {
240 getNameViewer()
241 .addAnnotation(
242 new EditorAnnotation(EditorAnnotationType.WARNING,
243 0,
244 Messages.AbstractGroupedContainer_EDIT_IN_DETAILS_VIEW));
245 }
246
247 if (isNameUsedMultipleTimes()) {
248 getNameViewer().addAnnotation(
249 new EditorAnnotation(EditorAnnotationType.WARNING, 0,
250 Messages.AbstractGroupedContainer_MULTIPLE_USE));
251 }
252
253 }
254
255 private void showParsingProblems() {
256 TaxonName name = getName();
257 if (name == null){
258 return;
259 }
260
261 List<ParserProblem> parsingProblems = name.getParsingProblems();
262
263 for (ParserProblem problem : parsingProblems) {
264 getNameViewer().addAnnotation(new EditorAnnotation(problem),
265 getParsingProblemPosition());
266 }
267 }
268
269 private Position getParsingProblemPosition() {
270 String text = getNameViewer().getTextWidget().getText();
271
272 if (getName() != null && getName().hasProblem() && text.length() > 0) {
273 int start = getName().getProblemStarts();
274 int length = getName().getProblemEnds() - start;
275
276 if (start == -1 || getName().getProblemEnds() == -1) {
277 return null;
278 }
279
280 // Don't let squigglies try to draw beyond the end of the text
281 if (text.length() < start + length) {
282 length = text.length() - start;
283 }
284 if (length<0){
285 return null;
286 }
287 return new Position(start, length);
288 }
289 return null;
290 }
291
292 protected void handleSplitText(String text) {
293 // Create a synonym in a new homotypic group using text as name
294 TaxonName synonymName = TaxonName.castAndDeproxy(
295 ParseHandler.parseReferencedName(text, null));
296
297 AbstractUtility.executeOperation(new CreateSynonymInNewGroupOperation(
298 Messages.AbstractGroupedContainer_NEW_HETERO_SYNONYM, getEditor().getUndoContext(),
299 getEditor().getTaxon(), synonymName, getEditor()), group.getContext().get(UISynchronize.class));
300 }
301
302 /**
303 * Refreshes the display with latest data from the model.
304 *
305 * Note: Will not parse the text and not calculate errors!
306 */
307 @Override
308 public void refresh() {
309 // showNameRelations();
310
311 String text = NameHelper.getDisplayNameWithRef(getTaxonBase());
312
313 if (getNameViewer().getTextWidget() == null) {
314 // we might get here via dnd. Look slike it can be ignored
315 return;
316 }
317
318 if (text.length() == 0) {
319 initEmptyText();
320 } else if (!getNameViewer().getTextWidget().getText().equals(text)) {
321 removeListener();
322 getNameViewer().getTextWidget().setText(text);
323 addListener();
324 }
325
326 updateNonEditableInfo();
327
328 updateIcon();
329 // placeCursor();
330 updateIndent();
331
332 enableFreeText();
333 }
334
335 protected abstract void updateIcon();
336
337 protected abstract void updateIndent();
338
339 protected abstract void updateNonEditableInfo();
340
341 protected void enableFreeText() {
342 setEnabled(isFreetextEditingAllowed());
343
344 }
345
346 /**
347 * Checks whether the freetext should be editable based on specific empty
348 * fields.
349 *
350 * @return
351 */
352 private boolean isFreetextEditingAllowed() {
353 boolean enableFreetext = true;
354
355 enableFreetext |= isNameUsedMultipleTimes();
356 enableFreetext &= isNameParsable();
357
358 return enableFreetext;
359 }
360
361 /**
362 * Checks whether there are more than one, non-orphaned taxon bases
363 * attached to the taxon name
364 *
365 * @return
366 */
367 private boolean isNameUsedMultipleTimes() {
368
369 TaxonName name = getName();
370 if (name != null){
371 Set<TaxonBase> taxonBases = name.getTaxonBases();
372 Iterator<TaxonBase> tbItr = taxonBases.iterator();
373 int nonOrphanedTaxonBaseCount = taxonBases.size();
374
375 while(tbItr.hasNext()) {
376 TaxonBase<?> tb = tbItr.next();
377 if(tb.isOrphaned()) {
378 nonOrphanedTaxonBaseCount--;
379 }
380 }
381 if(nonOrphanedTaxonBaseCount > 1) {
382 return true;
383 }
384 }
385 return false;
386 }
387
388 private boolean isNameParsable() {
389 TaxonName name = getName();
390 if (name == null){
391 return false;
392 }
393
394 boolean isParsable = true;
395 isParsable &= StringUtils.isBlank(name.getAppendedPhrase()); // taxonFieldsEmpty();
396
397 isParsable &= !name.isProtectedAuthorshipCache();
398 isParsable &= !name.isProtectedNameCache();
399
400 return isParsable;
401 }
402
403 /**
404 * Parse the text and calculate errors
405 */
406 public void parseAndCalculateAnnotations() {
407 removeListener();
408 String unparsedNameString = getNameViewer().getTextWidget().getText();
409 parseHandler.parse(unparsedNameString);
410 addListener();
411 calculateAnnotations();
412 }
413
414 public T getTaxonBase() {
415 return getData();
416 }
417
418 public TaxonName getName() {
419 return CdmBase.deproxy(getTaxonBase().getName());
420 }
421
422 public void persistName() {
423 if (isDirty()) {
424 getNameViewer().getTextWidget().setEnabled(false);
425 final String unparsedNameString = getNameViewer().getTextWidget()
426 .getText();
427 final TaxonName name = (TaxonName)parseHandler
428 .parseAndResolveDuplicates(unparsedNameString);
429 getTaxonBase().setName(name);
430 getTaxonBase().setTitleCache((getTaxonBase().generateTitle()));
431 setDirty(false);
432 getNameViewer().getTextWidget().setEnabled(true);
433 }
434 }
435
436 public AbstractGroupE4 getGroup() {
437 if (group == null) {
438 throw new IllegalStateException("Group shall not be null."); //$NON-NLS-1$
439 }
440 return group;
441 }
442
443 public void remove() {
444 getGroup().remove(this);
445 }
446
447 protected void createControl() {
448 control = getEditor().getToolkit().createComposite(
449 getGroup().getControl());
450
451 control.setLayoutData(new TableWrapData(TableWrapData.FILL_GRAB));
452 TableWrapLayout layout = new TableWrapLayout();
453 layout.leftMargin = 0;
454 layout.rightMargin = 0;
455 layout.topMargin = 5;
456 layout.bottomMargin = 5;
457
458 layout.verticalSpacing = 0;
459 layout.horizontalSpacing = 0;
460
461 control.setLayout(layout);
462
463 }
464
465 protected TaxonNameEditorE4 getEditor() {
466 return getGroup().getEditor();
467 }
468
469 public Composite getControl() {
470 return control;
471 }
472
473 protected void createLineWrapSupport() {
474 new LineWrapSupport(getNameViewer(), getEditor().getManagedForm());
475 }
476
477 protected void createTextViewer() {
478 nameViewer = new NameViewer(control);
479
480 focusListener = new FocusAdapter() {
481 @Override
482 public void focusGained(FocusEvent e) {
483 // if(!enabled){
484 // return;
485 // }
486 if (getEditor()
487 .getGroupedContainers().isEmpty()){
488 return;
489 }
490
491 for (AbstractGroupedContainerE4 container : getEditor()
492 .getGroupedContainers()) {
493 container.colorSelected(NOT_SELECTED);
494 }
495 getEditor().getManagedForm().setInput(
496 AbstractGroupedContainerE4.this);
497 placeCursor();
498 colorSelected(SELECTED_FOCUS);
499 }
500 };
501 nameViewer.getTextWidget().addFocusListener(focusListener);
502
503 MouseAdapter mouseListener = new MouseAdapter() {
504 @Override
505 public void mouseDown(MouseEvent e) {
506 storeCursor();
507 }
508 };
509 control.addMouseListener(mouseListener);
510 nameViewer.getRulerControl().addMouseListener(mouseListener);
511 nameViewer.getTextWidget().addMouseListener(mouseListener);
512 }
513
514 public void setIcon(Image icon) {
515 getNameViewer().setIcon(icon);
516 }
517
518 public void setIndent(int indent) {
519 if (control.getLayout() instanceof TableWrapLayout) {
520 TableWrapLayout layout = ((TableWrapLayout) control.getLayout());
521 layout.leftMargin = indent;
522 layout.rightMargin = ACCEPTED_INDENT;
523 control.setLayout(layout);
524 control.layout();
525 } else {
526 throw new RuntimeException(
527 "Couldn't indent - composite's layout must be TableWrapLayout."); //$NON-NLS-1$
528 }
529 }
530
531 public void setSelected() {
532 getNameViewer().getTextWidget().setFocus();
533 }
534
535 public boolean isSelected() {
536 return getEditor().getSelectedContainer() == this;
537 }
538
539 public void colorSelected(int mode) {
540 if (!control.isDisposed()) {
541 String colorString = null;
542
543 switch (mode) {
544 case SELECTED_FOCUS:
545 colorString = Resources.COLOR_CONTROL_SELECTED_FOCUS;
546 break;
547 case SELECTED_NO_FOCUS:
548 colorString = Resources.COLOR_CONTROL_SELECTED;
549 break;
550 default:
551 colorString = Resources.COLOR_COMPOSITE_BACKGROUND;
552 }
553
554 backgroundColor = AbstractUtility.getColor(colorString);
555
556 setBackground(backgroundColor);
557 }
558 }
559
560 protected void setDelayedSelection() {
561 // TODO this might be done better
562 // this is the quickest solution i could come up with and it improves
563 // performance
564 // please reimplement if you know better.
565 selection = this;
566
567 // start timer
568 Display display = Display.getCurrent();
569 Runnable runnable = new Runnable() {
570
571 @Override
572 public void run() {
573 getEditor().getManagedForm().setInput(selection);
574 }
575 };
576 display.timerExec(1000, runnable);
577
578 }
579
580 public void setBackground(Color color) {
581 control.setBackground(color);
582
583 for (Control child : control.getChildren()) {
584 child.setBackground(color);
585 }
586
587 getNameViewer().setBackground(color);
588 }
589
590 public void setFont(Font font) {
591 getNameViewer().getTextWidget().setFont(font);
592 }
593
594 public NameViewer getNameViewer() {
595 if (nameViewer == null) {
596 throw new RuntimeException(
597 "The Name Viewer is corrupt for Name Container: " //$NON-NLS-1$
598 + getTaxonBase().getName().getTitleCache());
599 }
600 return nameViewer;
601 }
602
603 public void createEmptyViewerPrompt(final String prompt) {
604
605 Assert.isNotNull(getNameViewer());
606
607 final StyledText textControl = getNameViewer().getTextWidget();
608 final IDocument document = getNameViewer().getDocument();
609
610 setFocusListener(new FocusListener() {
611
612 @Override
613 public void focusGained(FocusEvent e) {
614 if (document.get().equals(prompt)) {
615 textControl.setFont(getViewerFont());
616 document.set(""); //$NON-NLS-1$
617 }
618 }
619
620 @Override
621 public void focusLost(FocusEvent e) {
622 if (document.getLength() == 0) {
623 initEmptyText();
624 }
625 }
626
627 });
628 textControl.addFocusListener(getFocusListener());
629
630 if (document.getLength() == 0) {
631 textControl.setFont(AbstractUtility
632 .getFont(Resources.FONT_DEFAULT_PROMPT));
633 document.set(prompt);
634 }
635 }
636
637 abstract protected Font getViewerFont();
638
639 protected void initEmptyText() {
640 Font defaultFont = AbstractUtility.getFont(Resources.FONT_DEFAULT_PROMPT);
641 getNameViewer().getTextWidget().setFont(defaultFont);
642
643 getNameViewer().getDocument().set(getEmptyTextPrompt());
644 placeCursor();
645 }
646
647 protected void setFocusListener(FocusListener focusListener) {
648 this.focusListener = focusListener;
649 }
650
651 private FocusListener getFocusListener() {
652 return focusListener;
653 }
654
655 public void setDirty(boolean isDirty) {
656 if (isDirty) {
657 getEditor().getManagedForm().dirtyStateChanged();
658 }
659 this.isDirty = isDirty;
660 }
661
662 @Override
663 public boolean isDirty() {
664 return isDirty;
665 }
666
667 public void setMenu() {
668 getEditor().getMenuService().registerContextMenu(getNameViewer().getTextWidget(), "eu.etaxonomy.taxeditor.editor.popupmenu.nameeditor");
669 }
670
671 private Control[] draggableControls;
672
673 protected void setDraggableControl(Control[] controls) {
674 draggableControls = controls;
675 }
676
677 public void setIsDraggable(boolean draggable) {
678
679 if (draggable) {
680
681 if (draggableControls == null) {
682 throw new NullPointerException(
683 "Draggable controls must be set to add draggability"); //$NON-NLS-1$
684 }
685
686 Transfer[] types = new Transfer[] { CdmDataTransfer.getInstance() };
687 int operations = DND.DROP_MOVE;
688
689 for (Control draggableControl : draggableControls) {
690 DragSource dragSource = new DragSource(draggableControl,
691 operations);
692 dragSource.setTransfer(types);
693
694 dragSource.addDragListener(new NameEditorDragListenerE4(this));
695 dragSource.setDragSourceEffect(new NameEditorDragSourceEffect(
696 control));
697 }
698 }
699 }
700
701 private String nonEditableText;
702
703 ControlListener nonEditableResizeListener = new ControlAdapter() {
704
705 int width = 0;
706
707 @Override
708 public void controlResized(ControlEvent e) {
709 if (nonEditableInfoLabel.getBounds().width == width) {
710 return;
711 }
712 width = nonEditableInfoLabel.getBounds().width;
713 if (nonEditableInfoLabel.getBounds().width > 0) {
714 nonEditableInfoLabel.setText(Dialog.shortenText(
715 nonEditableText.toUpperCase(), nonEditableInfoLabel));
716 }
717 }
718 };
719
720 private String nonEditableHoverText;
721
722 private LabelEllipsisListener nonEditableLabelEllipsisListener;
723
724 private T data;
725
726 private boolean enabled;
727
728 /**
729 * nonEditableInfo is a label displayed underneath a GroupedComposite's
730 * input field. For instance, NameComposites display things like name
731 * relations, sec. references, etc. here.
732 *
733 * @param info
734 * the text to display in the label
735 * @param append
736 * whether the string should be appended to text that is already
737 * shown in the label
738 */
739 public void setNonEditableInfo(String info, boolean append) {
740 // TODO non editable info should only be drawn once, when everything
741 // else is drawn
742 info = info.toUpperCase();
743
744 if (append) {
745 nonEditableText += ", " + info; //$NON-NLS-1$
746 nonEditableHoverText += "\n" + info; //$NON-NLS-1$
747 } else {
748 nonEditableText = info;
749 nonEditableHoverText = info;
750 }
751
752 if (nonEditableInfoLabel == null) {
753 nonEditableInfoLabel = getEditor().getToolkit().createLabel(
754 control, ""); //$NON-NLS-1$
755 TableWrapData layoutData = new TableWrapData(
756 TableWrapData.FILL_GRAB, TableWrapData.TOP);
757 // Set indent to viewer ruler's width
758 if (getNameViewer().getRulerControl() != null) {
759 // TODO right justify
760 layoutData.indent = NameViewer.RULER_WIDTH;
761 }
762 nonEditableInfoLabel.setLayoutData(layoutData);
763
764 nonEditableLabelEllipsisListener = new LabelEllipsisListener(
765 nonEditableInfoLabel) {
766 @Override
767 public String getLabelText() {
768 return nonEditableText.toUpperCase();
769 }
770 };
771 nonEditableInfoLabel
772 .addControlListener(nonEditableLabelEllipsisListener);
773
774 nonEditableInfoHover = new DefaultToolTip(nonEditableInfoLabel);
775 nonEditableInfoHover.setRespectDisplayBounds(true);
776
777 }
778 nonEditableInfoHover.setText(nonEditableHoverText);
779 nonEditableInfoLabel.setText(nonEditableText);
780
781 calculateAnnotations();
782 }
783
784 @Override
785 public T getData() {
786 return data;
787 }
788
789 public void setData(T data) {
790 this.data = HibernateProxyHelper.deproxy(data);
791 }
792
793 /**
794 * If the user hitting carriage return should cause something to happen -
795 * i.e. the creation of a new composite - call this method and override the
796 * method handleSplitText().
797 */
798 protected void createLineBreakListener() {
799 lineBreakListener = new LineBreakListener() {
800 @Override
801 public void handleSplitText(String text) {
802 AbstractGroupedContainerE4.this.handleSplitText(text);
803 }
804
805 };
806
807 getNameViewer().getTextWidget().addVerifyListener(lineBreakListener);
808
809 }
810
811 abstract class LabelEllipsisListener extends ControlAdapter {
812
813 private final Label label;
814 int width = 0;
815
816 LabelEllipsisListener(Label label) {
817 this.label = label;
818 }
819
820 abstract public String getLabelText();
821
822 @Override
823 public void controlResized(ControlEvent e) {
824 if (label.getBounds().width == width) {
825 return;
826 }
827 width = label.getBounds().width;
828 if (label.getBounds().width > 0) {
829 label.setText(TextHelper.shortenText(getLabelText(), label));
830 }
831 }
832 }
833
834 public void storeCursor() {
835 this.cursorPosition = getNameViewer().getCursorPosition();
836 }
837
838 /**
839 * Puts the cursor to the position it was last seen on or to the end of line
840 * if no former position is known.
841 */
842 public void placeCursor() {
843 if (cursorPosition == 0) {
844 getNameViewer().setCursorToEOL();
845 } else {
846 getNameViewer().setCursorPosition(cursorPosition);
847 }
848 }
849
850 public void restoreColor() {
851 setBackground(backgroundColor);
852 }
853
854 @Override
855 public void initialize(IManagedForm form) {
856 // TODO Auto-generated method stub
857
858 }
859
860 @Override
861 public void dispose() {
862 if (getControl() != null) {
863 setMenu();
864 getControl().dispose();
865 }
866 }
867
868 @Override
869 public void commit(boolean onSave) {
870 if (isDirty()) {
871 persistName();
872 }
873 }
874
875 @Override
876 public boolean setFormInput(Object input) {
877 return false;
878 }
879
880 @Override
881 public void setFocus() {
882 getNameViewer().getControl().setFocus();
883 }
884
885 @Override
886 public boolean isStale() {
887 return false;
888 }
889
890 public void setDisabled(boolean disabled) {
891 this.enabled = !disabled;
892 setEnabled(enabled);
893 }
894
895 public void setEnabled(boolean enabled) {
896 this.enabled = enabled;
897 Color color = enabled ? control.getForeground() : AbstractUtility.getColor(Resources.COLOR_DISABLED_EDITOR);
898
899 getNameViewer().getTextWidget().setEditable(enabled);
900 // getNameViewer().getTextWidget().setEnabled(enabled);
901 getNameViewer().getTextWidget().setForeground(color);
902
903
904 }
905
906 public boolean isEnabled(){
907 return enabled;
908 }
909 }