blob: 21d8cf9b70856a23252ab610de93c61074d727e3 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011 Laurent CARON.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation (Snippet 320)
* Laurent CARON (laurent.caron@gmail.com) - Make a widget from the snippet
*******************************************************************************/
package org.mihalis.opal.textAssist;
import java.util.List;
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.events.VerifyListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
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 org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Widget;
/**
* Instances of this class are selectable user interface objects that allow the
* user to enter and modify text. The difference with the Text widget is that
* when the user types something, some propositions are displayed.
*
* @see org.eclipse.swt.widgets.Text
*/
public class TextAssist extends Composite {
/** The Constant SETTEXT_KEY. */
private static final String SETTEXT_KEY = "org.mihalis.opal.textAssist.TextAssist.settext";
/** The text. */
private final Text text;
/** The popup. */
private final Shell popup;
/** The table. */
private final Table table;
/** The content provider. */
private TextAssistContentProvider contentProvider;
/** The number of lines. */
private int numberOfLines;
/**
* Constructs a new instance of this class given its parent and a style
* value describing its behavior and appearance.
* <p>
* The style value is either one of the style constants defined in class
* <code>SWT</code> which is applicable to instances of this class, or must
* be built by <em>bitwise OR</em>'ing together (that is, using the
* <code>int</code> "|" operator) two or more of those <code>SWT</code>
* style constants. The class description lists the style constants that are
* applicable to the class. Style bits are also inherited from superclasses.
* </p>
*
* @param parent a composite control which will be the parent of the new
* instance (cannot be null)
* @param style the style of control to construct
* @param contentProvider the content provider
* @see SWT#SINGLE
* @see SWT#MULTI
* @see SWT#READ_ONLY
* @see SWT#WRAP
* @see SWT#LEFT
* @see SWT#RIGHT
* @see SWT#CENTER
* @see SWT#PASSWORD
* @see SWT#SEARCH
* @see SWT#ICON_SEARCH
* @see SWT#ICON_CANCEL
* @see Widget#checkSubclass
* @see Widget#getStyle
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
* </ul>
* @exception SWTException <ul>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
* thread that created the parent</li>
* <li>ERROR_INVALID_SUBCLASS - if this class is not an
* allowed subclass</li>
* </ul>
*/
public TextAssist(final Composite parent, final int style, final TextAssistContentProvider contentProvider) {
super(parent, SWT.NONE);
this.contentProvider = contentProvider;
this.contentProvider.setTextAssist(this);
setLayout(new FillLayout());
numberOfLines = 10;
text = new Text(this, style);
popup = new Shell(getDisplay(), SWT.ON_TOP);
popup.setLayout(new FillLayout());
table = new Table(popup, SWT.SINGLE);
addTextListener();
addTableLittle();
final int[] events = new int[] { SWT.Move, SWT.FocusOut };
for (final int event : events) {
getShell().addListener(event, new Listener() {
@Override
public void handleEvent(final Event event) {
popup.setVisible(false);
}
});
}
}
/**
* Adds the text listener.
*/
private void addTextListener() {
text.addListener(SWT.KeyDown, createKeyDownListener());
text.addListener(SWT.Modify, createModifyListener());
text.addListener(SWT.FocusOut, createFocusOutListener());
}
/**
* Adds the table little.
*/
private void addTableLittle() {
table.addListener(SWT.DefaultSelection, new Listener() {
@Override
public void handleEvent(final Event event) {
text.setText(table.getSelection()[0].getText());
popup.setVisible(false);
}
});
table.addListener(SWT.KeyDown, new Listener() {
@Override
public void handleEvent(final Event event) {
if (event.keyCode == SWT.ESC) {
popup.setVisible(false);
}
}
});
table.addListener(SWT.FocusOut, createFocusOutListener());
}
/**
* Creates the key down listener.
*
* @return a listener for the keydown event
*/
private Listener createKeyDownListener() {
return new Listener() {
@Override
public void handleEvent(final Event event) {
switch (event.keyCode) {
case SWT.ARROW_DOWN:
int index = (table.getSelectionIndex() + 1) % table.getItemCount();
table.setSelection(index);
event.doit = false;
break;
case SWT.ARROW_UP:
index = table.getSelectionIndex() - 1;
if (index < 0) {
index = table.getItemCount() - 1;
}
table.setSelection(index);
event.doit = false;
break;
case SWT.CR:
case SWT.KEYPAD_CR:
if (popup.isVisible() && table.getSelectionIndex() != -1) {
text.setText(table.getSelection()[0].getText());
popup.setVisible(false);
}
break;
case SWT.ESC:
popup.setVisible(false);
break;
}
}
};
}
/**
* Creates the modify listener.
*
* @return a listener for the modify event
*/
private Listener createModifyListener() {
return new Listener() {
@Override
public void handleEvent(final Event event) {
if (text.getData(SETTEXT_KEY) != null && Boolean.TRUE.equals(text.getData(SETTEXT_KEY))) {
text.setData(SETTEXT_KEY, null);
return;
}
text.setData(SETTEXT_KEY, null);
final String string = text.getText();
if (string.length() == 0) {
popup.setVisible(false);
return;
}
List<String> values = contentProvider.getContent(string);
if (values == null || values.isEmpty()) {
popup.setVisible(false);
return;
}
if (values.size() > numberOfLines) {
values = values.subList(0, numberOfLines);
}
table.removeAll();
final int numberOfRows = Math.min(values.size(), numberOfLines);
for (int i = 0; i < numberOfRows; i++) {
final TableItem tableItem = new TableItem(table, SWT.NONE);
tableItem.setText(values.get(i));
}
final Point point = text.toDisplay(text.getLocation().x, text.getSize().y + text.getBorderWidth() - 3);
int x = point.x;
int y = point.y;
final Rectangle displayRect = getMonitor().getClientArea();
final Rectangle parentRect = getDisplay().map(getParent(), null, getBounds());
popup.pack();
final int width = popup.getBounds().width;
final int height = popup.getBounds().height;
if (y + height > displayRect.y + displayRect.height) {
y = parentRect.y - height;
}
if (x + width > displayRect.x + displayRect.width) {
x = displayRect.x + displayRect.width - width;
}
popup.setLocation(x, y);
popup.setVisible(true);
}
};
}
/**
* Creates the focus out listener.
*
* @return a listener for the FocusOut event
*/
private Listener createFocusOutListener() {
return new Listener() {
@Override
public void handleEvent(final Event event) {
/*
* Async is needed to wait until focus reaches its new Control
*/
TextAssist.this.getDisplay().asyncExec(new Runnable() {
@Override
public void run() {
if (TextAssist.this.isDisposed() || TextAssist.this.getDisplay().isDisposed()) {
return;
}
final Control control = TextAssist.this.getDisplay().getFocusControl();
if (control == null || control != text && control != table) {
popup.setVisible(false);
}
}
});
}
};
}
/**
* Gets the background.
*
* @return the background
* @see org.eclipse.swt.widgets.Control#getBackground()
*/
@Override
public Color getBackground() {
checkWidget();
return text.getBackground();
}
/**
* Gets the content provider.
*
* @return the contentProvider
*/
public TextAssistContentProvider getContentProvider() {
checkWidget();
return contentProvider;
}
/**
* Gets the foreground.
*
* @return the foreground
* @see org.eclipse.swt.widgets.Control#getForeground()
*/
@Override
public Color getForeground() {
checkWidget();
return super.getForeground();
}
/**
* Sets the background.
*
* @param color the new background
* @see org.eclipse.swt.widgets.Text#setBackground(org.eclipse.swt.graphics.Color)
*/
@Override
public void setBackground(final Color color) {
checkWidget();
text.setBackground(color);
}
/**
* Sets the content provider.
*
* @param contentProvider the contentProvider to set
*/
public void setContentProvider(final TextAssistContentProvider contentProvider) {
checkWidget();
this.contentProvider = contentProvider;
}
/**
* Gets the number of lines.
*
* @return the numberOfLines
*/
public int getNumberOfLines() {
checkWidget();
return numberOfLines;
}
/**
* Sets the number of lines.
*
* @param numberOfLines the numberOfLines to set
*/
public void setNumberOfLines(final int numberOfLines) {
checkWidget();
this.numberOfLines = numberOfLines;
}
/**
* Adds the listener.
*
* @param eventType the event type
* @param listener the listener
* @see org.eclipse.swt.widgets.Text#addListener(int,org.eclipse.swt.widgets.Listener)
*/
@Override
public void addListener(final int eventType, final Listener listener) {
checkWidget();
text.addListener(eventType, listener);
}
/**
* Adds the modify listener.
*
* @param listener the listener
* @see org.eclipse.swt.widgets.Text#addModifyListener(org.eclipse.swt.events.ModifyListener)
*/
public void addModifyListener(final ModifyListener listener) {
checkWidget();
text.addModifyListener(listener);
}
/**
* Adds the selection listener.
*
* @param listener the listener
* @see org.eclipse.swt.widgets.Text#addSelectionListener(org.eclipse.swt.events.SelectionListener)
*/
public void addSelectionListener(final SelectionListener listener) {
checkWidget();
text.addSelectionListener(listener);
}
/**
* Adds the verify listener.
*
* @param listener the listener
* @see org.eclipse.swt.widgets.Text#addVerifyListener(org.eclipse.swt.events.VerifyListener)
*/
public void addVerifyListener(final VerifyListener listener) {
checkWidget();
text.addVerifyListener(listener);
}
/**
* Append.
*
* @param string the string
* @see org.eclipse.swt.widgets.Text#append(java.lang.String)
*/
public void append(final String string) {
checkWidget();
text.append(string);
}
/**
* Clear selection.
*
* @see org.eclipse.swt.widgets.Text#clearSelection()
*/
public void clearSelection() {
checkWidget();
text.clearSelection();
}
/**
* Compute size.
*
* @param wHint the w hint
* @param hHint the h hint
* @param changed the changed
* @return the point
* @see org.eclipse.swt.widgets.Text#computeSize(int, int, boolean)
*/
@Override
public Point computeSize(final int wHint, final int hHint, final boolean changed) {
checkWidget();
return text.computeSize(wHint, hHint, changed);
}
/**
* Compute trim.
*
* @param x the x
* @param y the y
* @param width the width
* @param height the height
* @return the rectangle
* @see org.eclipse.swt.widgets.Text#computeTrim(int, int, int, int)
*/
@Override
public Rectangle computeTrim(final int x, final int y, final int width, final int height) {
checkWidget();
return super.computeTrim(x, y, width, height);
}
/**
* Copy.
*
* @see org.eclipse.swt.widgets.Text#copy()
*/
public void copy() {
checkWidget();
text.copy();
}
/**
* Cut.
*
* @see org.eclipse.swt.widgets.Text#cut()
*/
public void cut() {
checkWidget();
text.cut();
}
/**
* Gets the caret line number.
*
* @return the caret line number
* @see org.eclipse.swt.widgets.Text#getCaretLineNumber()
*/
public int getCaretLineNumber() {
checkWidget();
return text.getCaretLineNumber();
}
/**
* Gets the caret location.
*
* @return the caret location
* @see org.eclipse.swt.widgets.Text#getCaretLocation()
*/
public Point getCaretLocation() {
checkWidget();
return text.getCaretLocation();
}
/**
* Gets the caret position.
*
* @return the caret position
* @see org.eclipse.swt.widgets.Text#getCaretPosition()
*/
public int getCaretPosition() {
checkWidget();
return text.getCaretPosition();
}
/**
* Gets the char count.
*
* @return the char count
* @see org.eclipse.swt.widgets.Text#getCharCount()
*/
public int getCharCount() {
checkWidget();
return text.getCharCount();
}
/**
* Gets the double click enabled.
*
* @return the double click enabled
* @see org.eclipse.swt.widgets.Text#getDoubleClickEnabled()
*/
public boolean getDoubleClickEnabled() {
checkWidget();
return text.getDoubleClickEnabled();
}
/**
* Gets the echo char.
*
* @return the echo char
* @see org.eclipse.swt.widgets.Text#getEchoChar()
*/
public char getEchoChar() {
checkWidget();
return text.getEchoChar();
}
/**
* Gets the editable.
*
* @return the editable
* @see org.eclipse.swt.widgets.Text#getEditable()
*/
public boolean getEditable() {
checkWidget();
return text.getEditable();
}
/**
* Gets the enabled.
*
* @return the enabled
* @see org.eclipse.swt.widgets.Control#getEnabled()
*/
@Override
public boolean getEnabled() {
checkWidget();
return super.getEnabled();
}
/**
* Gets the line count.
*
* @return the line count
* @see org.eclipse.swt.widgets.Text#getLineCount()
*/
public int getLineCount() {
checkWidget();
return text.getLineCount();
}
/**
* Gets the line delimiter.
*
* @return the line delimiter
* @see org.eclipse.swt.widgets.Text#getLineDelimiter()
*/
public String getLineDelimiter() {
checkWidget();
return text.getLineDelimiter();
}
/**
* Gets the line height.
*
* @return the line height
* @see org.eclipse.swt.widgets.Text#getLineHeight()
*/
public int getLineHeight() {
checkWidget();
return text.getLineHeight();
}
/**
* Gets the message.
*
* @return the message
* @see org.eclipse.swt.widgets.Text#getMessage()
*/
public String getMessage() {
checkWidget();
return text.getMessage();
}
/**
* Gets the orientation.
*
* @return the orientation
* @see org.eclipse.swt.widgets.Text#getOrientation()
*/
public int getOrientation() {
checkWidget();
return text.getOrientation();
}
/**
* Gets the selection.
*
* @return the selection
* @see org.eclipse.swt.widgets.Text#getSelection()
*/
public Point getSelection() {
checkWidget();
return text.getSelection();
}
/**
* Gets the selection count.
*
* @return the selection count
* @see org.eclipse.swt.widgets.Text#getSelectionCount()
*/
public int getSelectionCount() {
checkWidget();
return text.getSelectionCount();
}
/**
* Gets the selection text.
*
* @return the selection text
* @see org.eclipse.swt.widgets.Text#getSelectionText()
*/
public String getSelectionText() {
checkWidget();
return text.getSelectionText();
}
/**
* Gets the tabs.
*
* @return the tabs
* @see org.eclipse.swt.widgets.Text#getTabs()
*/
public int getTabs() {
checkWidget();
return text.getTabs();
}
/**
* Gets the text.
*
* @return the text
* @see org.eclipse.swt.widgets.Text#getText()
*/
public String getText() {
checkWidget();
return text.getText();
}
/**
* Gets the text.
*
* @param start the start
* @param end the end
* @return the text
* @see org.eclipse.swt.widgets.Text#getText(int, int)
*/
public String getText(final int start, final int end) {
checkWidget();
return text.getText(start, end);
}
/**
* Gets the text limit.
*
* @return the text limit
* @see org.eclipse.swt.widgets.Text#getTextLimit()
*/
public int getTextLimit() {
checkWidget();
return text.getTextLimit();
}
/**
* Gets the top index.
*
* @return the top index
* @see org.eclipse.swt.widgets.Text#getTopIndex()
*/
public int getTopIndex() {
checkWidget();
return text.getTopIndex();
}
/**
* Gets the top pixel.
*
* @return the top pixel
* @see org.eclipse.swt.widgets.Text#getTopPixel()
*/
public int getTopPixel() {
checkWidget();
return text.getTopPixel();
}
/**
* Insert.
*
* @param string the string
* @see org.eclipse.swt.widgets.Text#insert(java.lang.String)
*/
public void insert(final String string) {
checkWidget();
text.insert(string);
}
/**
* Paste.
*
* @see org.eclipse.swt.widgets.Text#paste()
*/
public void paste() {
checkWidget();
text.paste();
}
/**
* Removes the modify listener.
*
* @param listener the listener
* @see org.eclipse.swt.widgets.Text#removeModifyListener(org.eclipse.swt.events.ModifyListener)
*/
public void removeModifyListener(final ModifyListener listener) {
checkWidget();
text.removeModifyListener(listener);
}
/**
* Removes the selection listener.
*
* @param listener the listener
* @see org.eclipse.swt.widgets.Text#removeSelectionListener(org.eclipse.swt.events.SelectionListener)
*/
public void removeSelectionListener(final SelectionListener listener) {
checkWidget();
text.removeSelectionListener(listener);
}
/**
* Removes the verify listener.
*
* @param listener the listener
* @see org.eclipse.swt.widgets.Text#removeVerifyListener(org.eclipse.swt.events.VerifyListener)
*/
public void removeVerifyListener(final VerifyListener listener) {
checkWidget();
text.removeVerifyListener(listener);
}
/**
* Select all.
*
* @see org.eclipse.swt.widgets.Text#selectAll()
*/
public void selectAll() {
checkWidget();
text.selectAll();
}
/**
* Sets the double click enabled.
*
* @param doubleClick the new double click enabled
* @see org.eclipse.swt.widgets.Text#setDoubleClickEnabled(boolean)
*/
public void setDoubleClickEnabled(final boolean doubleClick) {
checkWidget();
text.setDoubleClickEnabled(doubleClick);
}
/**
* Sets the echo char.
*
* @param echo the new echo char
* @see org.eclipse.swt.widgets.Text#setEchoChar(char)
*/
public void setEchoChar(final char echo) {
checkWidget();
text.setEchoChar(echo);
}
/**
* Sets the editable.
*
* @param editable the new editable
* @see org.eclipse.swt.widgets.Text#setEditable(boolean)
*/
public void setEditable(final boolean editable) {
checkWidget();
text.setEditable(editable);
}
/**
* Sets the enabled.
*
* @param value the new enabled
* @see org.eclipse.swt.widgets.Text#setEnabled(boolean)
*/
@Override
public void setEnabled(final boolean value) {
checkWidget();
text.setEnabled(value);
}
/**
* Sets the font.
*
* @param font the new font
* @see org.eclipse.swt.widgets.Text#setFont(org.eclipse.swt.graphics.Font)
*/
@Override
public void setFont(final Font font) {
checkWidget();
text.setFont(font);
table.setFont(font);
}
/**
* Sets the foreground.
*
* @param color the new foreground
* @see org.eclipse.swt.widgets.Text#setForeground(org.eclipse.swt.graphics.Color)
*/
@Override
public void setForeground(final Color color) {
checkWidget();
text.setForeground(color);
}
/**
* Sets the message.
*
* @param string the new message
* @see org.eclipse.swt.widgets.Text#setMessage(java.lang.String)
*/
public void setMessage(final String string) {
checkWidget();
text.setMessage(string);
}
/**
* Sets the orientation.
*
* @param orientation the new orientation
* @see org.eclipse.swt.widgets.Text#setOrientation(int)
*/
public void setOrientation(final int orientation) {
checkWidget();
text.setOrientation(orientation);
}
/**
* Sets the redraw.
*
* @param redraw the new redraw
* @see org.eclipse.swt.widgets.Text#setRedraw(boolean)
*/
@Override
public void setRedraw(final boolean redraw) {
checkWidget();
text.setRedraw(redraw);
}
/**
* Sets the selection.
*
* @param start the start
* @param end the end
* @see org.eclipse.swt.widgets.Text#setSelection(int, int)
*/
public void setSelection(final int start, final int end) {
checkWidget();
text.setSelection(start, end);
}
/**
* Sets the selection.
*
* @param start the new selection
* @see org.eclipse.swt.widgets.Text#setSelection(int)
*/
public void setSelection(final int start) {
checkWidget();
text.setSelection(start);
}
/**
* Sets the selection.
*
* @param selection the new selection
* @see org.eclipse.swt.widgets.Text#setSelection(org.eclipse.swt.graphics.Point)
*/
public void setSelection(final Point selection) {
checkWidget();
text.setSelection(selection);
}
/**
* Sets the tabs.
*
* @param tabs the new tabs
* @see org.eclipse.swt.widgets.Text#setTabs(int)
*/
public void setTabs(final int tabs) {
checkWidget();
text.setTabs(tabs);
}
/**
* Sets the text.
*
* @param text the new text
* @see org.eclipse.swt.widgets.Text#setText(java.lang.String)
*/
public void setText(final String text) {
checkWidget();
this.text.setData(SETTEXT_KEY, Boolean.TRUE);
this.text.setText(text);
}
/**
* Sets the text limit.
*
* @param textLimit the new text limit
* @see org.eclipse.swt.widgets.Text#setTextLimit(int)
*/
public void setTextLimit(final int textLimit) {
checkWidget();
text.setTextLimit(textLimit);
}
/**
* Sets the top index.
*
* @param topIndex the new top index
* @see org.eclipse.swt.widgets.Text#setTopIndex(int)
*/
public void setTopIndex(final int topIndex) {
checkWidget();
text.setTopIndex(topIndex);
}
/**
* Show selection.
*
* @see org.eclipse.swt.widgets.Text#showSelection()
*/
public void showSelection() {
checkWidget();
text.showSelection();
}
}