package net.enilink.komma.common.ui.celleditor; import org.eclipse.jface.fieldassist.ContentProposalAdapter; import org.eclipse.jface.fieldassist.IContentProposal; import org.eclipse.jface.fieldassist.IContentProposalListener; import org.eclipse.jface.fieldassist.IContentProposalListener2; import org.eclipse.jface.fieldassist.IContentProposalProvider; import org.eclipse.jface.viewers.TextCellEditor; import org.eclipse.swt.SWT; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Listener; import net.enilink.commons.ui.CommonsUi; import net.enilink.komma.common.ui.assist.ContentProposals; public class TextCellEditorWithContentProposal extends TextCellEditor { private IContentProposalProvider contentProposalProvider; private char[] autoActivationCharacters; private ContentProposalAdapter contentProposalAdapter; private boolean popupOpen = false; // true, iff popup is currently open private boolean proposalAccepted = false; public TextCellEditorWithContentProposal(Composite parent) { this(parent, SWT.SINGLE, null, null); } public TextCellEditorWithContentProposal(Composite parent, int style, IContentProposalProvider contentProposalProvider, char[] autoActivationCharacters) { super(parent, style); this.contentProposalProvider = contentProposalProvider; this.autoActivationCharacters = autoActivationCharacters; } @Override protected Control createControl(Composite parent) { Control text = super.createControl(parent); if (contentProposalProvider == null) { contentProposalProvider = ContentProposals.NULL_PROPOSAL_PROVIDER; } contentProposalAdapter = ContentProposals.enableContentProposal(text, contentProposalProvider, autoActivationCharacters); // Listen for popup open/close events to be able to handle focus events // correctly contentProposalAdapter .addContentProposalListener(new IContentProposalListener2() { public void proposalPopupClosed( ContentProposalAdapter adapter) { popupOpen = false; } public void proposalPopupOpened( ContentProposalAdapter adapter) { proposalAccepted = false; popupOpen = true; } }); contentProposalAdapter .addContentProposalListener(new IContentProposalListener() { public void proposalAccepted(IContentProposal proposal) { proposalAccepted = true; } }); if ((getStyle() & SWT.MULTI) != 0 || CommonsUi.IS_RAP_RUNNING) { text.addListener(SWT.Traverse, new Listener() { public void handleEvent(Event e) { switch (e.character) { case SWT.LF: case SWT.CR: if (e.stateMask == 0 && !(popupOpen || proposalAccepted)) { // apply editor value if enter is pressed e.doit = false; fireApplyEditorValue(); deactivate(); } } proposalAccepted = false; } }); } return text; } @Override protected void keyReleaseOccured(KeyEvent keyEvent) { proposalAccepted = false; if (CommonsUi.IS_RAP_RUNNING && keyEvent.character == '\r') { // correctly handle CTRL+Enter in RAP if (text != null && !text.isDisposed() && (getStyle() & SWT.MULTI) != 0 && (keyEvent.stateMask & SWT.CTRL) != 0) { super.keyReleaseOccured(keyEvent); } return; } super.keyReleaseOccured(keyEvent); } /** * Return the {@link ContentProposalAdapter} of this cell editor. * * @return the {@link ContentProposalAdapter} */ public ContentProposalAdapter getContentProposalAdapter() { return contentProposalAdapter; } @Override protected void focusLost() { if (!popupOpen) { // Focus lost deactivates the cell editor. // This must not happen if focus lost was caused by activating // the completion proposal popup. super.focusLost(); } } @Override protected boolean dependsOnExternalFocusListener() { // Always return false; // Otherwise, the ColumnViewerEditor will install an additional focus // listener // that cancels cell editing on focus lost, even if focus gets lost due // to // activation of the completion proposal popup. See also bug 58777. return false; } }