2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
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.
10 package eu
.etaxonomy
.taxeditor
.editor
.name
.e4
.container
;
12 import java
.util
.Iterator
;
13 import java
.util
.List
;
16 import org
.apache
.commons
.lang3
.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
.window
.DefaultToolTip
;
23 import org
.eclipse
.swt
.custom
.StyledText
;
24 import org
.eclipse
.swt
.dnd
.DND
;
25 import org
.eclipse
.swt
.dnd
.DragSource
;
26 import org
.eclipse
.swt
.dnd
.Transfer
;
27 import org
.eclipse
.swt
.events
.ControlAdapter
;
28 import org
.eclipse
.swt
.events
.ControlEvent
;
29 import org
.eclipse
.swt
.events
.ControlListener
;
30 import org
.eclipse
.swt
.events
.FocusAdapter
;
31 import org
.eclipse
.swt
.events
.FocusEvent
;
32 import org
.eclipse
.swt
.events
.FocusListener
;
33 import org
.eclipse
.swt
.events
.ModifyEvent
;
34 import org
.eclipse
.swt
.events
.ModifyListener
;
35 import org
.eclipse
.swt
.events
.MouseAdapter
;
36 import org
.eclipse
.swt
.events
.MouseEvent
;
37 import org
.eclipse
.swt
.graphics
.Color
;
38 import org
.eclipse
.swt
.graphics
.Font
;
39 import org
.eclipse
.swt
.graphics
.Image
;
40 import org
.eclipse
.swt
.widgets
.Composite
;
41 import org
.eclipse
.swt
.widgets
.Control
;
42 import org
.eclipse
.swt
.widgets
.Display
;
43 import org
.eclipse
.swt
.widgets
.Label
;
44 import org
.eclipse
.ui
.forms
.IFormPart
;
45 import org
.eclipse
.ui
.forms
.IManagedForm
;
46 import org
.eclipse
.ui
.forms
.widgets
.TableWrapData
;
47 import org
.eclipse
.ui
.forms
.widgets
.TableWrapLayout
;
49 import eu
.etaxonomy
.cdm
.hibernate
.HibernateProxyHelper
;
50 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
51 import eu
.etaxonomy
.cdm
.model
.name
.TaxonName
;
52 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonBase
;
53 import eu
.etaxonomy
.cdm
.strategy
.parser
.ParserProblem
;
54 import eu
.etaxonomy
.taxeditor
.editor
.CdmDataTransfer
;
55 import eu
.etaxonomy
.taxeditor
.editor
.l10n
.Messages
;
56 import eu
.etaxonomy
.taxeditor
.editor
.name
.container
.EditorAnnotation
;
57 import eu
.etaxonomy
.taxeditor
.editor
.name
.container
.EditorAnnotation
.EditorAnnotationType
;
58 import eu
.etaxonomy
.taxeditor
.editor
.name
.container
.IContainerConstants
;
59 import eu
.etaxonomy
.taxeditor
.editor
.name
.container
.LineBreakListener
;
60 import eu
.etaxonomy
.taxeditor
.editor
.name
.container
.LineWrapSupport
;
61 import eu
.etaxonomy
.taxeditor
.editor
.name
.e4
.TaxonEditor
;
62 import eu
.etaxonomy
.taxeditor
.editor
.name
.e4
.dnd
.NameEditorDragListenerE4
;
63 import eu
.etaxonomy
.taxeditor
.editor
.name
.e4
.dnd
.NameEditorDragSourceEffect
;
64 import eu
.etaxonomy
.taxeditor
.editor
.name
.operation
.CreateSynonymInNewGroupOperation
;
65 import eu
.etaxonomy
.taxeditor
.event
.EventUtility
;
66 import eu
.etaxonomy
.taxeditor
.event
.WorkbenchEventConstants
;
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
;
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.
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.
85 * The <code>IManagedForm</code> is also required to have a <code>Taxon</code>
86 * in its own <code>getData()</code>.
89 * The <code>IManagedForm</code> can also used for drawing borders by calling
90 * the method <code>createBorderSupport()</code>.
97 abstract public class AbstractGroupedContainer
<T
extends TaxonBase
> implements
98 IFormPart
, IContainerConstants
, IElementHasDetails
{
100 protected ParseHandler parseHandler
;
102 private FocusListener nameCompositeFocusListener
;
103 private ModifyListener nameCompositeModifyListener
;
105 protected NameViewer nameViewer
;
107 private AbstractGroup group
;
109 private Label nonEditableInfoLabel
;
110 private DefaultToolTip nonEditableInfoHover
;
112 private static AbstractGroupedContainer
<?
> selection
;
114 private FocusListener focusListener
;
115 private LineBreakListener lineBreakListener
;
117 private int cursorPosition
;
119 private long lastEventTime
;
121 protected Composite control
;
123 private Color backgroundColor
;
124 private boolean isDirty
;
126 public AbstractGroupedContainer(AbstractGroup group
, T taxonBase
) {
129 parseHandler
= ParseHandler
.NewInstance(taxonBase
.getName());
132 public void createContent() {
136 createLineWrapSupport();
137 createLineBreakListener();
141 setDraggableControl(new Control
[] { getControl(),
142 getNameViewer().getRulerControl() });
144 createEmptyViewerPrompt(EMPTY_NAME_PROMPT
);
146 initializeComposite();
153 protected void createListener() {
154 nameCompositeModifyListener
= (ModifyEvent e
)->{
155 // mark the composite dirty
157 lastEventTime
= System
.currentTimeMillis();
159 String text
= nameViewer
.getTextWidget().getText();
161 TaxonName name
= (TaxonName
)parseHandler
.parse(text
);
162 getTaxonBase().setName(name
);
163 getTaxonBase().setTitleCache((getTaxonBase().generateTitle()));
166 // show errors resulting from parsing
167 calculateAnnotations();
168 // store the position of the cursor
170 // notify selection listener
171 setDelayedSelection();
172 //EventUtility.postAsyncEvent(WorkbenchEventConstants.REFRESH_DETAILS, true);
176 nameCompositeFocusListener
= new FocusAdapter() {
179 public void focusLost(FocusEvent e
) {
182 EventUtility
.postAsyncEvent(WorkbenchEventConstants
.REFRESH_DETAILS
, true);
189 protected void addListener() {
190 getNameViewer().getTextWidget().addModifyListener(
191 nameCompositeModifyListener
);
192 getNameViewer().getTextWidget().addFocusListener(
193 nameCompositeFocusListener
);
196 protected void removeListener() {
197 getNameViewer().getTextWidget().removeModifyListener(
198 nameCompositeModifyListener
);
199 getNameViewer().getTextWidget().removeFocusListener(
200 nameCompositeFocusListener
);
204 * Initialize the composite specific code
206 protected abstract void initializeComposite();
208 protected String
getEmptyTextPrompt() {
209 return EMPTY_NAME_PROMPT
;
212 protected void initTextViewer() {
218 String text
= NameHelper
.getDisplayNameWithRef(getData());
220 if (text
.length() == 0) {
223 getNameViewer().setText(text
);
226 calculateAnnotations();
229 synchronized protected void calculateAnnotations() {
230 getNameViewer().clearAnnotations();
234 public void showAnnotations() {
236 if (getName() != null && getName().hasProblem()) {
237 showParsingProblems();
240 if (!isNameParsable()) {
243 new EditorAnnotation(EditorAnnotationType
.WARNING
,
245 Messages
.AbstractGroupedContainer_EDIT_IN_DETAILS_VIEW
));
248 if (isNameUsedMultipleTimes()) {
249 getNameViewer().addAnnotation(
250 new EditorAnnotation(EditorAnnotationType
.WARNING
, 0,
251 Messages
.AbstractGroupedContainer_MULTIPLE_USE
));
256 private void showParsingProblems() {
257 TaxonName name
= getName();
262 List
<ParserProblem
> parsingProblems
= name
.getParsingProblems();
264 for (ParserProblem problem
: parsingProblems
) {
265 getNameViewer().addAnnotation(new EditorAnnotation(problem
),
266 getParsingProblemPosition());
270 private Position
getParsingProblemPosition() {
271 String text
= getNameViewer().getTextWidget().getText();
273 if (getName() != null && getName().hasProblem() && text
.length() > 0) {
274 int start
= getName().getProblemStarts();
275 int length
= getName().getProblemEnds() - start
;
277 if (start
== -1 || getName().getProblemEnds() == -1) {
281 // Don't let squigglies try to draw beyond the end of the text
282 if (text
.length() < start
+ length
) {
283 length
= text
.length() - start
;
288 return new Position(start
, length
);
293 protected void handleSplitText(String text
) {
294 // Create a synonym in a new homotypic group using text as name
295 TaxonName synonymName
= TaxonName
.castAndDeproxy(
296 ParseHandler
.parseReferencedName(text
, null));
298 AbstractUtility
.executeOperation(new CreateSynonymInNewGroupOperation(
299 Messages
.AbstractGroupedContainer_NEW_HETERO_SYNONYM
, getEditor().getUndoContext(),
300 getEditor().getTaxon(), synonymName
, getEditor()), group
.getContext().get(UISynchronize
.class));
304 * Refreshes the display with latest data from the model.
306 * Note: Will not parse the text and not calculate errors!
309 public void refresh() {
310 // showNameRelations();
312 String text
= NameHelper
.getDisplayNameWithRef(getTaxonBase());
314 if (getNameViewer().getTextWidget() == null) {
315 // we might get here via dnd. Look slike it can be ignored
319 if (text
.length() == 0) {
321 } else if (!getNameViewer().getTextWidget().getText().equals(text
)) {
323 getNameViewer().getTextWidget().setText(text
);
327 updateNonEditableInfo();
332 setDelayedSelection();
336 protected abstract void updateIcon();
338 protected abstract void updateIndent();
340 protected abstract void updateNonEditableInfo();
342 protected void enableFreeText() {
343 setEnabled(isFreetextEditingAllowed());
347 * Checks whether the freetext should be editable based on specific empty
352 private boolean isFreetextEditingAllowed() {
353 boolean enableFreetext
= true;
355 enableFreetext
|= isNameUsedMultipleTimes();
356 enableFreetext
&= isNameParsable();
358 return enableFreetext
;
362 * Checks whether there are more than one, non-orphaned taxon bases
363 * attached to the taxon name
367 private boolean isNameUsedMultipleTimes() {
369 TaxonName name
= getName();
371 Set
<TaxonBase
> taxonBases
= name
.getTaxonBases();
372 Iterator
<TaxonBase
> tbItr
= taxonBases
.iterator();
373 int nonOrphanedTaxonBaseCount
= taxonBases
.size();
375 while(tbItr
.hasNext()) {
376 TaxonBase
<?
> tb
= tbItr
.next();
377 if(tb
.isOrphaned()) {
378 nonOrphanedTaxonBaseCount
--;
381 if(nonOrphanedTaxonBaseCount
> 1) {
388 private boolean isNameParsable() {
389 TaxonName name
= getName();
394 boolean isParsable
= true;
395 isParsable
&= StringUtils
.isBlank(name
.getAppendedPhrase()); // taxonFieldsEmpty();
396 if (name
.isProtectedAuthorshipCache()){
397 isParsable
&= nameAuthorsSet(name
);
399 if (name
.isProtectedNameCache()){
400 isParsable
&= nameEpithetsNotSet(name
) && nameAuthorsSet(name
);
406 private boolean nameAuthorsSet(TaxonName name
) {
407 boolean result
= true;
408 result
&= name
.getBasionymAuthorship() == null && name
.getCombinationAuthorship() == null && name
.getExBasionymAuthorship() == null && name
.getExCombinationAuthorship() == null;
412 private boolean nameEpithetsNotSet(TaxonName name
) {
413 boolean result
= true;
414 result
&= name
.getGenusOrUninomial() == null && name
.getInfraGenericEpithet() == null && name
.getSpecificEpithet() == null && name
.getInfraSpecificEpithet() == null;
420 * Parse the text and calculate errors
422 public void parseAndCalculateAnnotations() {
424 String unparsedNameString
= getNameViewer().getTextWidget().getText();
425 parseHandler
.parse(unparsedNameString
);
427 calculateAnnotations();
430 public T
getTaxonBase() {
434 public TaxonName
getName() {
435 return CdmBase
.deproxy(getTaxonBase().getName());
438 public void persistName() {
440 getNameViewer().getTextWidget().setEnabled(false);
441 final String unparsedNameString
= getNameViewer().getTextWidget()
443 final TaxonName name
= (TaxonName
)parseHandler
444 .parseAndResolveDuplicates(unparsedNameString
);
445 getTaxonBase().setName(name
);
446 getTaxonBase().setTitleCache((getTaxonBase().generateTitle()));
448 getNameViewer().getTextWidget().setEnabled(true);
452 public AbstractGroup
getGroup() {
454 throw new IllegalStateException("Group shall not be null."); //$NON-NLS-1$
459 public void remove() {
460 getGroup().remove(this);
463 protected void createControl() {
464 control
= getEditor().getToolkit().createComposite(
465 getGroup().getControl());
467 control
.setLayoutData(new TableWrapData(TableWrapData
.FILL_GRAB
));
468 TableWrapLayout layout
= new TableWrapLayout();
469 layout
.leftMargin
= 0;
470 layout
.rightMargin
= 0;
471 layout
.topMargin
= 5;
472 layout
.bottomMargin
= 5;
474 layout
.verticalSpacing
= 0;
475 layout
.horizontalSpacing
= 0;
477 control
.setLayout(layout
);
481 protected TaxonEditor
getEditor() {
482 return getGroup().getEditor();
485 public Composite
getControl() {
489 protected void createLineWrapSupport() {
490 new LineWrapSupport(getNameViewer(), getEditor().getManagedForm());
493 protected void createTextViewer() {
494 nameViewer
= new NameViewer(control
);
496 focusListener
= new FocusAdapter() {
498 public void focusGained(FocusEvent e
) {
500 .getGroupedContainers().isEmpty()){
504 for (AbstractGroupedContainer
<?
> container
: getEditor()
505 .getGroupedContainers()) {
506 container
.colorSelected(NOT_SELECTED
);
508 getEditor().getManagedForm().setInput(
509 AbstractGroupedContainer
.this);
511 colorSelected(SELECTED_FOCUS
);
514 nameViewer
.getTextWidget().addFocusListener(focusListener
);
516 MouseAdapter mouseListener
= new MouseAdapter() {
518 public void mouseDown(MouseEvent e
) {
522 control
.addMouseListener(mouseListener
);
523 nameViewer
.getRulerControl().addMouseListener(mouseListener
);
524 nameViewer
.getTextWidget().addMouseListener(mouseListener
);
527 public void setIcon(Image icon
) {
528 getNameViewer().setIcon(icon
);
531 public void setIndent(int indent
) {
532 if (control
.getLayout() instanceof TableWrapLayout
) {
533 TableWrapLayout layout
= ((TableWrapLayout
) control
.getLayout());
534 layout
.leftMargin
= indent
;
535 layout
.rightMargin
= ACCEPTED_INDENT
;
536 control
.setLayout(layout
);
539 throw new RuntimeException(
540 "Couldn't indent - composite's layout must be TableWrapLayout."); //$NON-NLS-1$
544 public void setSelected() {
545 getNameViewer().getTextWidget().setFocus();
548 public boolean isSelected() {
549 return getEditor().getSelectedContainer() == this;
552 public void colorSelected(int mode
) {
553 if (control
!=null && !control
.isDisposed()) {
554 String colorString
= null;
558 colorString
= Resources
.COLOR_CONTROL_SELECTED_FOCUS
;
560 case SELECTED_NO_FOCUS
:
561 colorString
= Resources
.COLOR_CONTROL_SELECTED
;
564 colorString
= Resources
.COLOR_COMPOSITE_BACKGROUND
;
567 backgroundColor
= AbstractUtility
.getColor(colorString
);
569 setBackground(backgroundColor
);
573 private Delay delay
= new Delay(Display
.getCurrent());
575 private class Delay
extends Thread
{
577 private volatile boolean stop
= false;
578 private Display display
;
580 public Delay(Display display
) {
581 this.display
= display
;
591 display
.syncExec(() -> {
592 getEditor().getManagedForm().setInput(selection
);
596 } catch (InterruptedException ex
) {
601 public void requestStop() {
606 protected void setDelayedSelection() {
609 Display display
= Display
.getCurrent();
612 delay
= new Delay(display
);
616 public void setBackground(Color color
) {
617 control
.setBackground(color
);
619 for (Control child
: control
.getChildren()) {
620 child
.setBackground(color
);
623 getNameViewer().setBackground(color
);
626 public void setFont(Font font
) {
627 getNameViewer().getTextWidget().setFont(font
);
630 public NameViewer
getNameViewer() {
631 if (nameViewer
== null) {
632 throw new RuntimeException(
633 "The Name Viewer is corrupt for Name Container: " //$NON-NLS-1$
634 + getTaxonBase().getName().getTitleCache());
639 public void createEmptyViewerPrompt(final String prompt
) {
641 Assert
.isNotNull(getNameViewer());
643 final StyledText textControl
= getNameViewer().getTextWidget();
644 final IDocument document
= getNameViewer().getDocument();
646 setFocusListener(new FocusListener() {
649 public void focusGained(FocusEvent e
) {
650 if (document
.get().equals(prompt
)) {
651 textControl
.setFont(getViewerFont());
652 document
.set(""); //$NON-NLS-1$
657 public void focusLost(FocusEvent e
) {
658 if (document
.getLength() == 0) {
664 textControl
.addFocusListener(getFocusListener());
666 if (document
.getLength() == 0) {
667 textControl
.setFont(AbstractUtility
668 .getFont(Resources
.FONT_DEFAULT_PROMPT
));
669 document
.set(prompt
);
673 abstract protected Font
getViewerFont();
675 protected void initEmptyText() {
676 Font defaultFont
= AbstractUtility
.getFont(Resources
.FONT_DEFAULT_PROMPT
);
677 getNameViewer().getTextWidget().setFont(defaultFont
);
679 getNameViewer().getDocument().set(getEmptyTextPrompt());
682 protected void setFocusListener(FocusListener focusListener
) {
683 this.focusListener
= focusListener
;
686 private FocusListener
getFocusListener() {
687 return focusListener
;
690 public void setDirty(boolean isDirty
) {
692 getEditor().getManagedForm().dirtyStateChanged();
694 this.isDirty
= isDirty
;
698 public boolean isDirty() {
702 public void setMenu() {
703 getEditor().getMenuService().registerContextMenu(getNameViewer().getTextWidget(), "eu.etaxonomy.taxeditor.editor.popupmenu.nameeditor");
706 private Control
[] draggableControls
;
708 protected void setDraggableControl(Control
[] controls
) {
709 draggableControls
= controls
;
712 public void setIsDraggable(boolean draggable
) {
716 if (draggableControls
== null) {
717 throw new NullPointerException(
718 "Draggable controls must be set to add draggability"); //$NON-NLS-1$
721 Transfer
[] types
= new Transfer
[] { CdmDataTransfer
.getInstance() };
722 int operations
= DND
.DROP_MOVE
;
724 for (Control draggableControl
: draggableControls
) {
725 DragSource dragSource
= new DragSource(draggableControl
,
727 dragSource
.setTransfer(types
);
729 dragSource
.addDragListener(new NameEditorDragListenerE4(this));
730 dragSource
.setDragSourceEffect(new NameEditorDragSourceEffect(
736 private String nonEditableText
;
738 ControlListener nonEditableResizeListener
= new ControlAdapter() {
743 public void controlResized(ControlEvent e
) {
744 if (nonEditableInfoLabel
.getBounds().width
== width
) {
747 width
= nonEditableInfoLabel
.getBounds().width
;
748 if (nonEditableInfoLabel
.getBounds().width
> 0) {
749 nonEditableInfoLabel
.setText(Dialog
.shortenText(
750 nonEditableText
.toUpperCase(), nonEditableInfoLabel
));
755 private String nonEditableHoverText
;
757 private LabelEllipsisListener nonEditableLabelEllipsisListener
;
762 * nonEditableInfo is a label displayed underneath a GroupedComposite's
763 * input field. For instance, NameComposites display things like name
764 * relations, sec. references, etc. here.
767 * the text to display in the label
769 * whether the string should be appended to text that is already
772 public void setNonEditableInfo(String info
, boolean append
) {
773 // TODO non editable info should only be drawn once, when everything
775 info
= info
.toUpperCase();
778 nonEditableText
+= ", " + info
; //$NON-NLS-1$
779 nonEditableHoverText
+= "\n" + info
; //$NON-NLS-1$
781 nonEditableText
= info
;
782 nonEditableHoverText
= info
;
785 if (nonEditableInfoLabel
== null) {
786 nonEditableInfoLabel
= getEditor().getToolkit().createLabel(
787 control
, ""); //$NON-NLS-1$
788 TableWrapData layoutData
= new TableWrapData(
789 TableWrapData
.FILL_GRAB
, TableWrapData
.TOP
);
790 // Set indent to viewer ruler's width
791 if (getNameViewer().getRulerControl() != null) {
792 // TODO right justify
793 layoutData
.indent
= NameViewer
.RULER_WIDTH
;
795 nonEditableInfoLabel
.setLayoutData(layoutData
);
797 nonEditableLabelEllipsisListener
= new LabelEllipsisListener(
798 nonEditableInfoLabel
) {
800 public String
getLabelText() {
801 return nonEditableText
.toUpperCase();
805 .addControlListener(nonEditableLabelEllipsisListener
);
807 nonEditableInfoHover
= new DefaultToolTip(nonEditableInfoLabel
);
808 nonEditableInfoHover
.setRespectDisplayBounds(true);
811 nonEditableInfoHover
.setText(nonEditableHoverText
);
812 nonEditableInfoLabel
.setText(nonEditableText
);
814 calculateAnnotations();
822 public void setData(T data
) {
823 this.data
= HibernateProxyHelper
.deproxy(data
);
827 * If the user hitting carriage return should cause something to happen -
828 * i.e. the creation of a new composite - call this method and override the
829 * method handleSplitText().
831 protected void createLineBreakListener() {
832 lineBreakListener
= new LineBreakListener() {
834 public void handleSplitText(String text
) {
835 AbstractGroupedContainer
.this.handleSplitText(text
);
840 getNameViewer().getTextWidget().addVerifyListener(lineBreakListener
);
844 abstract class LabelEllipsisListener
extends ControlAdapter
{
846 private final Label label
;
849 LabelEllipsisListener(Label label
) {
853 abstract public String
getLabelText();
856 public void controlResized(ControlEvent e
) {
857 if (label
.getBounds().width
== width
) {
860 width
= label
.getBounds().width
;
861 if (label
.getBounds().width
> 0) {
862 label
.setText(TextHelper
.shortenText(getLabelText(), label
));
867 public void storeCursor() {
868 this.cursorPosition
= getNameViewer().getCursorPosition();
872 * Puts the cursor to the position it was last seen on or to the end of line
873 * if no former position is known.
875 public void placeCursor() {
876 if (cursorPosition
== 0) {
877 getNameViewer().setCursorToEOL();
879 getNameViewer().setCursorPosition(cursorPosition
);
883 public void restoreColor() {
884 setBackground(backgroundColor
);
888 public void initialize(IManagedForm form
) {
889 // TODO Auto-generated method stub
893 public void dispose() {
894 if (getControl() != null) {
895 getControl().dispose();
900 public void commit(boolean onSave
) {
907 public boolean setFormInput(Object input
) {
912 public void setFocus() {
913 getNameViewer().getControl().setFocus();
917 public boolean isStale() {
921 public void setDisabled(boolean disabled
) {
922 setEnabled(!disabled
);
925 public void setEnabled(boolean enabled
) {
926 Color color
= enabled ? control
.getForeground() : AbstractUtility
.getColor(Resources
.COLOR_DISABLED_EDITOR
);
928 getNameViewer().getTextWidget().setEditable(enabled
);
929 getNameViewer().getTextWidget().setForeground(color
);