blob: 0a869b82b3e408d2aecd9afb8af98f239d2199da [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011 BSI Business Systems Integration AG.
* 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:
* BSI Business Systems Integration AG - initial API and implementation
*******************************************************************************/
package org.eclipse.scout.rt.ui.rap.form.fields.stringfield;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import org.eclipse.rap.rwt.RWT;
import org.eclipse.scout.commons.beans.IPropertyObserver;
import org.eclipse.scout.commons.dnd.TransferObject;
import org.eclipse.scout.commons.holders.Holder;
import org.eclipse.scout.commons.job.JobEx;
import org.eclipse.scout.rt.client.ui.IDNDSupport;
import org.eclipse.scout.rt.client.ui.action.menu.root.IContextMenu;
import org.eclipse.scout.rt.client.ui.form.fields.IFormField;
import org.eclipse.scout.rt.client.ui.form.fields.stringfield.IStringField;
import org.eclipse.scout.rt.ui.rap.LogicalGridLayout;
import org.eclipse.scout.rt.ui.rap.RwtMenuUtility;
import org.eclipse.scout.rt.ui.rap.action.menu.RwtContextMenuMarkerComposite;
import org.eclipse.scout.rt.ui.rap.action.menu.RwtScoutContextMenu;
import org.eclipse.scout.rt.ui.rap.ext.StatusLabelEx;
import org.eclipse.scout.rt.ui.rap.ext.StyledTextEx;
import org.eclipse.scout.rt.ui.rap.ext.custom.StyledText;
import org.eclipse.scout.rt.ui.rap.extension.UiDecorationExtensionPoint;
import org.eclipse.scout.rt.ui.rap.form.fields.AbstractRwtScoutDndSupport;
import org.eclipse.scout.rt.ui.rap.form.fields.LogicalGridDataBuilder;
import org.eclipse.scout.rt.ui.rap.form.fields.RwtScoutBasicFieldComposite;
import org.eclipse.scout.rt.ui.rap.internal.TextFieldEditableSupport;
import org.eclipse.scout.rt.ui.rap.keystroke.IRwtKeyStroke;
import org.eclipse.scout.rt.ui.rap.keystroke.RwtKeyStroke;
import org.eclipse.scout.rt.ui.rap.util.RwtUtility;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.VerifyEvent;
import org.eclipse.swt.events.VerifyListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Menu;
public class RwtScoutStringField extends RwtScoutBasicFieldComposite<IStringField> implements IRwtScoutStringField {
public static final int DEFAULT_CASE = 0;
public static final int UPPER_CASE = 1;
public static final int LOWER_CASE = 2;
// cache
private int m_characterType = -1;
private MouseListener m_linkTrigger;
// private MouseListener m_linkTrigger;
private boolean m_linkDecoration;
private TextFieldEditableSupport m_editableSupport;
private P_UpperLowerCaseVerifyListener m_upperLowerCaseVerifyListener;
private RwtContextMenuMarkerComposite m_menuMarkerComposite;
private RwtScoutContextMenu m_uiContextMenu;
private P_ContextMenuPropertyListener m_contextMenuPropertyListener;
public RwtScoutStringField() {
}
@Override
protected void initializeUi(Composite parent) {
Composite container = getUiEnvironment().getFormToolkit().createComposite(parent);
StatusLabelEx label = getUiEnvironment().getFormToolkit().createStatusLabel(container, getScoutObject());
m_menuMarkerComposite = new RwtContextMenuMarkerComposite(container, getUiEnvironment());
getUiEnvironment().getFormToolkit().adapt(m_menuMarkerComposite);
m_menuMarkerComposite.setData(RWT.CUSTOM_VARIANT, VARIANT_STRINGFIELD);
m_menuMarkerComposite.addSelectionListener(new SelectionAdapter() {
private static final long serialVersionUID = 1L;
@Override
public void widgetSelected(SelectionEvent e) {
if (getUiContextMenu() != null) {
Menu uiMenu = getUiContextMenu().getUiMenu();
if (e.widget instanceof Control) {
Point loc = ((Control) e.widget).toDisplay(e.x, e.y);
uiMenu.setLocation(RwtMenuUtility.getMenuLocation(getScoutObject().getContextMenu().getChildActions(), uiMenu, loc, getUiEnvironment()));
}
uiMenu.setVisible(true);
}
}
});
int style = SWT.None;// SWT.BORDER;
//Password
if (getScoutObject().isInputMasked()) {
style |= SWT.PASSWORD;
}
//Multi-Line
if (getScoutObject().isMultilineText()) {
style |= SWT.MULTI | SWT.V_SCROLL;
}
//Single-Line
else {
style |= SWT.SINGLE;
}
//Text-Wrap
if (getScoutObject().isWrapText()) {
style |= SWT.WRAP;
}
style |= RwtUtility.getHorizontalAlignment(getScoutObject().getGridData().horizontalAlignment);
StyledText textField = getUiEnvironment().getFormToolkit().createStyledText(m_menuMarkerComposite, style);
setUiContainer(container);
setUiLabel(label);
setUiField(textField);
addDefaultUiListeners(textField);
// layout
LogicalGridLayout layout = new LogicalGridLayout(1, 0);
getUiContainer().setLayout(layout);
m_menuMarkerComposite.setLayoutData(LogicalGridDataBuilder.createField(((IFormField) getScoutObject()).getGridData()));
}
protected void addDefaultUiListeners(StyledText textField) {
textField.addSelectionListener(new P_RwtTextSelectionListener());
attachFocusListener(textField, true);
}
@Override
protected void attachScout() {
super.attachScout();
IStringField f = getScoutObject();
setDecorationLinkFromScout(f.isDecorationLink());
setFormatFromScout(f.getFormat());
setMaxLengthFromScout(f.getMaxLength());
setSelectionFromScout(f.getSelectionStart(), f.getSelectionEnd());
setTextWrapFromScout(f.isWrapText());
attachDndSupport();
// context menu
updateContextMenuVisibilityFromScout();
if (getScoutObject().getContextMenu() != null && m_contextMenuPropertyListener == null) {
m_contextMenuPropertyListener = new P_ContextMenuPropertyListener();
getScoutObject().getContextMenu().addPropertyChangeListener(IContextMenu.PROP_VISIBLE, m_contextMenuPropertyListener);
}
}
protected void attachDndSupport() {
if (UiDecorationExtensionPoint.getLookAndFeel().isDndSupportEnabled()) {
new P_DndSupport(getScoutObject(), getScoutObject(), getUiField());
}
}
@Override
protected void detachScout() {
// context menu listener
if (m_contextMenuPropertyListener != null) {
getScoutObject().getContextMenu().removePropertyChangeListener(IContextMenu.PROP_VISIBLE, m_contextMenuPropertyListener);
m_contextMenuPropertyListener = null;
}
super.detachScout();
}
@Override
public StyledTextEx getUiField() {
return (StyledTextEx) super.getUiField();
}
public RwtScoutContextMenu getUiContextMenu() {
return m_uiContextMenu;
}
@Override
protected void setEnabledFromScout(boolean b) {
super.setEnabledFromScout(b);
if (b) {
m_menuMarkerComposite.setData(RWT.CUSTOM_VARIANT, VARIANT_STRINGFIELD);
}
else {
m_menuMarkerComposite.setData(RWT.CUSTOM_VARIANT, VARIANT_STRINGFIELD_DISABLED);
}
}
@Override
protected void setFieldEnabled(Control swtField, boolean enabled) {
if (m_editableSupport == null) {
m_editableSupport = new TextFieldEditableSupport(getUiField());
}
m_editableSupport.setEditable(enabled);
}
@Override
protected IRwtKeyStroke[] getUiKeyStrokes() {
if (getScoutObject().isMultilineText()) {
//register CR but do not set the RWT.ACTIVE_KEYS property. This would disable typing newlines in the text field
return new IRwtKeyStroke[]{new RwtKeyStroke(SWT.CR, SWT.NONE, false) {
@Override
public void handleUiAction(Event e) {
e.doit = false;
}
}};
}
return super.getUiKeyStrokes();
}
protected void setDecorationLinkFromScout(boolean b) {
if (m_linkDecoration != b) {
m_linkDecoration = b;
if (m_linkDecoration) {
m_linkTrigger = new P_RwtLinkTrigger();
getUiField().addMouseListener(m_linkTrigger);
getUiField().setCursor(getUiField().getDisplay().getSystemCursor(SWT.CURSOR_HAND));
setForegroundFromScout(getScoutObject().getForegroundColor());
}
else {
getUiField().removeMouseListener(m_linkTrigger);
m_linkTrigger = null;
getUiField().setCursor(null);
setForegroundFromScout(getScoutObject().getForegroundColor());
}
}
}
@Override
protected void setForegroundFromScout(String scoutColor) {
if (scoutColor == null && m_linkDecoration) {
scoutColor = "0000FF";
}
super.setForegroundFromScout(scoutColor);
}
protected void setFormatFromScout(String s) {
if (IStringField.FORMAT_UPPER.equals(s)) {
m_characterType = UPPER_CASE;
addUpperLowerCaseVerifyListener();
}
else if (IStringField.FORMAT_LOWER.equals(s)) {
m_characterType = LOWER_CASE;
addUpperLowerCaseVerifyListener();
}
else {
m_characterType = DEFAULT_CASE;
removeUpperLowerCaseVerifyListener();
}
}
protected void addUpperLowerCaseVerifyListener() {
if (m_upperLowerCaseVerifyListener == null) {
m_upperLowerCaseVerifyListener = new P_UpperLowerCaseVerifyListener();
getUiField().addVerifyListener(m_upperLowerCaseVerifyListener);
}
}
protected void removeUpperLowerCaseVerifyListener() {
if (m_upperLowerCaseVerifyListener != null) {
getUiField().removeVerifyListener(m_upperLowerCaseVerifyListener);
m_upperLowerCaseVerifyListener = null;
}
}
protected void setMaxLengthFromScout(int n) {
getUiField().setTextLimit(n);
}
protected void setDoInsertFromScout(String s) {
if (s != null && s.length() > 0) {
StyledText field = getUiField();
int offset = field.getCaretPosition();
int a = field.getSelection().x;
int b = field.getSelection().y;
String uiText = field.getText();
StringBuilder builder = new StringBuilder(uiText);
if (a >= 0 && b > a) {
builder.replace(a, b, s);
}
else if (offset >= 0) {
builder.insert(offset, s);
}
else {
builder = null;
}
if (builder != null) {
field.setText(builder.toString());
}
// reset the cursor after the inserted text
field.setSelection(a + s.length());
}
}
protected void setSelectionFromScout(int startIndex, int endIndex) {
StyledText field = getUiField();
int start = field.getSelection().x;
int end = field.getSelection().y;
if (startIndex < 0) {
startIndex = start;
}
if (endIndex < 0) {
endIndex = end;
}
field.setSelection(startIndex, endIndex);
}
protected void setTextWrapFromScout(boolean booleanValue) {
if (getScoutObject().isMultilineText()) {
//XXX rap getUiField().setWordWrap(booleanValue);
}
}
protected void updateContextMenuVisibilityFromScout() {
m_menuMarkerComposite.setMarkerVisible(getScoutObject().getContextMenu().isVisible());
if (getScoutObject().getContextMenu().isVisible()) {
if (m_uiContextMenu == null) {
m_uiContextMenu = new RwtScoutContextMenu(getUiField().getShell(), getScoutObject().getContextMenu(), getUiEnvironment());
}
}
else {
if (m_uiContextMenu != null) {
m_uiContextMenu.dispose();
}
m_uiContextMenu = null;
}
}
/**
* scout property handler override
*/
@Override
protected void handleScoutPropertyChange(String name, Object newValue) {
super.handleScoutPropertyChange(name, newValue);
if (name.equals(IStringField.PROP_DECORATION_LINK)) {
setDecorationLinkFromScout(((Boolean) newValue).booleanValue());
}
else if (name.equals(IStringField.PROP_MAX_LENGTH)) {
setMaxLengthFromScout(((Number) newValue).intValue());
}
else if (name.equals(IStringField.PROP_INSERT_TEXT)) {
setDoInsertFromScout((String) newValue);
}
else if (name.equals(IStringField.PROP_SELECTION_START)) {
IStringField f = getScoutObject();
setSelectionFromScout(f.getSelectionStart(), f.getSelectionEnd());
}
else if (name.equals(IStringField.PROP_SELECTION_END)) {
IStringField f = getScoutObject();
setSelectionFromScout(f.getSelectionStart(), f.getSelectionEnd());
}
else if (name.equals(IStringField.PROP_WRAP_TEXT)) {
setTextWrapFromScout(((Boolean) newValue).booleanValue());
}
}
protected void handleUiLinkTrigger() {
final String text = getUiField().getText();
// notify Scout
Runnable t = new Runnable() {
@Override
public void run() {
getScoutObject().getUIFacade().fireLinkActionFromUI(text);
}
};
getUiEnvironment().invokeScoutLater(t, 0);
// end notify
}
protected void setSelectionFromUi(final int startIndex, final int endIndex) {
if (getUpdateUiFromScoutLock().isAcquired()) {
return;
}
Runnable t = new Runnable() {
@Override
public void run() {
try {
addIgnoredScoutEvent(PropertyChangeEvent.class, IStringField.PROP_SELECTION_START);
addIgnoredScoutEvent(PropertyChangeEvent.class, IStringField.PROP_SELECTION_END);
//
getScoutObject().getUIFacade().setSelectionFromUI(startIndex, endIndex);
}
finally {
removeIgnoredScoutEvent(PropertyChangeEvent.class, IStringField.PROP_SELECTION_START);
removeIgnoredScoutEvent(PropertyChangeEvent.class, IStringField.PROP_SELECTION_END);
}
}
};
getUiEnvironment().invokeScoutLater(t, 0);
}
@Override
protected boolean isSelectAllOnFocusEnabled() {
return super.isSelectAllOnFocusEnabled() && getScoutObject().isSelectAllOnFocus();
}
private class P_UpperLowerCaseVerifyListener implements VerifyListener {
private static final long serialVersionUID = 1L;
@Override
public void verifyText(VerifyEvent e) {
switch (m_characterType) {
case UPPER_CASE:
e.text = e.text.toUpperCase();
break;
case LOWER_CASE:
e.text = e.text.toLowerCase();
break;
}
}
} // end class P_TextVerifyListener
private class P_RwtLinkTrigger extends MouseAdapter {
private static final long serialVersionUID = 1L;
@Override
public void mouseDoubleClick(MouseEvent e) {
handleUiLinkTrigger();
}
} // end class P_RwtLinkTrigger
private class P_RwtTextSelectionListener extends SelectionAdapter {
private static final long serialVersionUID = 1L;
@Override
public void widgetSelected(SelectionEvent e) {
setSelectionFromUi(e.x, e.y);
}
} // end class P_RwtTextSelectionListener
private class P_DndSupport extends AbstractRwtScoutDndSupport {
public P_DndSupport(IPropertyObserver scoutObject, IDNDSupport scoutDndSupportable, Control control) {
super(scoutObject, scoutDndSupportable, control, RwtScoutStringField.this.getUiEnvironment());
}
@Override
protected TransferObject handleUiDragRequest() {
// will never be called here, since handleDragSetData never calls super.
final Holder<TransferObject> result = new Holder<TransferObject>(TransferObject.class, null);
Runnable t = new Runnable() {
@Override
public void run() {
TransferObject scoutTransferable = RwtScoutStringField.this.getScoutObject().getUIFacade().fireDragRequestFromUI();
result.setValue(scoutTransferable);
}
};
JobEx job = getUiEnvironment().invokeScoutLater(t, 2345);
try {
job.join(2345);
}
catch (InterruptedException e) {
//nop
}
return result.getValue();
}
@Override
protected void handleUiDropAction(DropTargetEvent event, final TransferObject scoutTransferObject) {
Runnable job = new Runnable() {
@Override
public void run() {
if (getScoutObject().isEnabled()) {
getScoutObject().getUIFacade().fireDropActionFromUi(scoutTransferObject);
}
}
};
getUiEnvironment().invokeScoutLater(job, 200);
}
}// end class P_DndSupport
private class P_ContextMenuPropertyListener implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (IContextMenu.PROP_VISIBLE.equals(evt.getPropertyName())) {
// synchronize
getUiEnvironment().invokeUiLater(new Runnable() {
@Override
public void run() {
updateContextMenuVisibilityFromScout();
}
});
}
}
}
}