/**
* Warlock, the open-source cross-platform game client
*
* Copyright 2008, Warlock LLC, and individual contributors as indicated
* by the @authors tag.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package cc.warlock.rcp.ui;
import java.text.MessageFormat;
import org.eclipse.core.runtime.Assert;
import org.eclipse.jface.fieldassist.ContentProposalAdapter;
import org.eclipse.jface.fieldassist.IContentProposalProvider;
import org.eclipse.jface.fieldassist.TextContentAdapter;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.FocusAdapter;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.TraverseEvent;
import org.eclipse.swt.events.TraverseListener;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.fieldassist.ContentAssistCommandAdapter;
/**
* A cell editor that manages a content assist field.
* The cell editor's value is the text string itself.
*
* This class may be instantiated; it is not intended to be subclassed.
*
*/
public class ContentAssistCellEditor extends CellEditor
{
protected ContentProposalAdapter adapter;
protected IContentProposalProvider contentProposalProvider;
protected char[] completionProposalAutoActivationCharacters;
private ModifyListener modifyListener;
public ContentAssistCellEditor(char[] completionProposalAutoActivationCharacters, IContentProposalProvider contentProposalProvider)
{
super();
this.completionProposalAutoActivationCharacters = completionProposalAutoActivationCharacters;
this.contentProposalProvider = contentProposalProvider;
createAdapter();
}
/**
* Return the modify listener.
*/
private ModifyListener getModifyListener() {
if (modifyListener == null) {
modifyListener = new ModifyListener() {
public void modifyText(ModifyEvent e) {
editOccured(e);
}
};
}
return modifyListener;
}
public ContentAssistCellEditor(Composite parent, int style, char[] completionProposalAutoActivationCharacters, IContentProposalProvider contentProposalProvider) {
super(parent, style);
this.completionProposalAutoActivationCharacters = completionProposalAutoActivationCharacters;
this.contentProposalProvider = contentProposalProvider;
createAdapter();
}
public ContentAssistCellEditor(Composite parent,char[] completionProposalAutoActivationCharacters, IContentProposalProvider contentProposalProvider)
{
super(parent);
this.completionProposalAutoActivationCharacters = completionProposalAutoActivationCharacters;
this.contentProposalProvider = contentProposalProvider;
createAdapter();
}
private void createAdapter ()
{
adapter = new ContentAssistCommandAdapter(
text,
new TextContentAdapter(),
contentProposalProvider,
// ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS,
null,
completionProposalAutoActivationCharacters, true
);
adapter.setProposalAcceptanceStyle(ContentProposalAdapter.PROPOSAL_REPLACE);
}
/**
* State information for updating action enablement
*/
private boolean isSelection = false;
private boolean isDeleteable = false;
private boolean isSelectable = false;
private Text text;
@Override
protected Control createControl(Composite parent)
{
//SimpleContentProposalProvider proposelProvider = new SimpleContentProposalProvider( new String[] { "a", "b", "c"});
text = new Text(parent, SWT.SINGLE);
// try {
// adapter = new ContentProposalAdapter(text, new TextContentAdapter(), contentProposalProvider, KeyStroke.getInstance(SWTKeyLookup.SPACE_NAME), completionProposalAutoActivationCharacters);
// } catch (ParseException e1) {
// // TODO Auto-generated catch block
// e1.printStackTrace();
// }
text.addSelectionListener(new SelectionAdapter() {
public void widgetDefaultSelected(SelectionEvent e) {
handleDefaultSelection(e);
}
});
text.addKeyListener(new KeyAdapter() {
// hook key pressed - see PR 14201
public void keyPressed(KeyEvent e) {
keyReleaseOccured(e);
// as a result of processing the above call, clients may have
// disposed this cell editor
if ((getControl() == null) || getControl().isDisposed()) {
return;
}
checkSelection(); // see explaination below
checkDeleteable();
checkSelectable();
}
});
text.addTraverseListener(new TraverseListener() {
public void keyTraversed(TraverseEvent e) {
if (e.detail == SWT.TRAVERSE_ESCAPE
|| e.detail == SWT.TRAVERSE_RETURN) {
e.doit = false;
}
}
});
// We really want a selection listener but it is not supported so we
// use a key listener and a mouse listener to know when selection changes
// may have occured
text.addMouseListener(new MouseAdapter() {
public void mouseUp(MouseEvent e) {
checkSelection();
checkDeleteable();
checkSelectable();
}
});
text.addFocusListener(new FocusAdapter() {
public void focusLost(FocusEvent e) {
ContentAssistCellEditor.this.focusLost();
}
});
text.setFont(parent.getFont());
text.setBackground(parent.getBackground());
text.setText("");//$NON-NLS-1$
text.addModifyListener( getModifyListener());
return text;
}
/**
* Checks to see if the "deleteable" state (can delete/
* nothing to delete) has changed and if so fire an
* enablement changed notification.
*/
private void checkDeleteable() {
boolean oldIsDeleteable = isDeleteable;
isDeleteable = isDeleteEnabled();
if (oldIsDeleteable != isDeleteable) {
fireEnablementChanged(DELETE);
}
}
/**
* Checks to see if the "selectable" state (can select)
* has changed and if so fire an enablement changed notification.
*/
private void checkSelectable() {
boolean oldIsSelectable = isSelectable;
isSelectable = isSelectAllEnabled();
if (oldIsSelectable != isSelectable) {
fireEnablementChanged(SELECT_ALL);
}
}
/**
* Checks to see if the selection state (selection /
* no selection) has changed and if so fire an
* enablement changed notification.
*/
private void checkSelection() {
boolean oldIsSelection = isSelection;
isSelection = text.getSelectionCount() > 0;
if (oldIsSelection != isSelection) {
fireEnablementChanged(COPY);
fireEnablementChanged(CUT);
}
}
/**
* Processes a modify event that occurred in this text cell editor.
* This framework method performs validation and sets the error message
* accordingly, and then reports a change via fireEditorValueChanged.
* Subclasses should call this method at appropriate times. Subclasses
* may extend or reimplement.
*
* @param e the SWT modify event
*/
protected void editOccured(ModifyEvent e) {
String value = text.getText();
if (value == null) {
value = "";//$NON-NLS-1$
}
Object typedValue = value;
boolean oldValidState = isValueValid();
boolean newValidState = isCorrect(typedValue);
if (typedValue == null && newValidState) {
Assert.isTrue(false,
"Validator isn't limiting the cell editor's type range");//$NON-NLS-1$
}
if (!newValidState) {
// try to insert the current value into the error message.
setErrorMessage(MessageFormat.format(getErrorMessage(),
new Object[] { value }));
}
valueChanged(oldValidState, newValidState);
}
/**
* Handles a default selection event from the text control by applying the editor
* value and deactivating this cell editor.
*
* @param event the selection event
*/
protected void handleDefaultSelection(SelectionEvent event)
{
// same with enter-key handling code in keyReleaseOccured(e);
fireApplyEditorValue();
deactivate();
}
@Override
protected void doSetFocus()
{
if( adapter!= null) {
text.setFocus();
}
}
@Override
protected Object doGetValue()
{
return text.getText();
}
@Override
protected void doSetValue(Object value)
{
text.setText(value.toString());
}
/**
* The implementation of this
* method copies the
* current selection to the clipboard.
*/
public void performCopy() {
text.copy();
}
/**
* The implementation of this
* method cuts the
* current selection to the clipboard.
*/
public void performCut() {
text.cut();
checkSelection();
checkDeleteable();
checkSelectable();
}
/**
* The implementation of this
* method deletes the
* current selection or, if there is no selection,
* the character next character from the current position.
*/
public void performDelete() {
if (text.getSelectionCount() > 0) {
// remove the contents of the current selection
text.insert(""); //$NON-NLS-1$
} else {
// remove the next character
int pos = text.getCaretPosition();
if (pos < text.getCharCount()) {
text.setSelection(pos, pos + 1);
text.insert(""); //$NON-NLS-1$
}
}
checkSelection();
checkDeleteable();
checkSelectable();
}
/**
* The implementation of this
* method pastes the
* the clipboard contents over the current selection.
*/
public void performPaste() {
text.paste();
checkSelection();
checkDeleteable();
checkSelectable();
}
/**
* The implementation of this
* method selects all of the
* current text.
*/
public void performSelectAll() {
text.selectAll();
checkSelection();
checkDeleteable();
}
/**
* Since a text editor field is scrollable we don't
* set a minimumSize.
*/
public LayoutData getLayoutData() {
return new LayoutData();
}
/**
* Processes a key release event that occurred in this cell editor.
*
* The implementation of this framework method
* ignores when the RETURN key is pressed since this is handled in
* handleDefaultSelection.
* An exception is made for Ctrl+Enter for multi-line texts, since
* a default selection event is not sent in this case.
*
*
* @param keyEvent the key event
*/
protected void keyReleaseOccured(KeyEvent keyEvent) {
if (keyEvent.character == '\r') { // Return key
// Enter is handled in handleDefaultSelection.
// Do not apply the editor value in response to an Enter key event
// since this can be received from the IME when the intent is -not-
// to apply the value.
// See bug 39074 [CellEditors] [DBCS] canna input mode fires bogus event from Text Control
//
// An exception is made for Ctrl+Enter for multi-line texts, since
// a default selection event is not sent in this case.
if (text != null && !text.isDisposed()
&& (text.getStyle() & SWT.MULTI) != 0) {
if ((keyEvent.stateMask & SWT.CTRL) != 0) {
super.keyReleaseOccured(keyEvent);
}
}
return;
}
super.keyReleaseOccured(keyEvent);
}
}