/*
This file belongs to the Servoy development and deployment environment, Copyright (C) 1997-2010 Servoy BV
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Affero General Public License as published by the Free
Software Foundation; either version 3 of the License, or (at your option) any
later version.
This program 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License along
with this program; if not, see http://www.gnu.org/licenses or write to the Free
Software Foundation,Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
*/
package com.servoy.j2db.smart.dataui;
import java.awt.AWTEvent;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.KeyboardFocusManager;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.dnd.DropTarget;
import java.awt.event.ActionEvent;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.JTextArea;
import javax.swing.KeyStroke;
import javax.swing.ScrollPaneConstants;
import javax.swing.TransferHandler;
import javax.swing.plaf.ComponentUI;
import javax.swing.text.Caret;
import javax.swing.text.Document;
import javax.swing.text.Keymap;
import org.jdesktop.xswingx.PromptSupport;
import com.servoy.base.util.ITagResolver;
import com.servoy.j2db.IApplication;
import com.servoy.j2db.IModeManager;
import com.servoy.j2db.IScriptExecuter;
import com.servoy.j2db.IServiceProvider;
import com.servoy.j2db.ISmartClientApplication;
import com.servoy.j2db.dataprocessing.IDisplayData;
import com.servoy.j2db.dataprocessing.IEditListener;
import com.servoy.j2db.dataprocessing.TagResolver;
import com.servoy.j2db.dnd.FormDataTransferHandler;
import com.servoy.j2db.dnd.ISupportDragNDropTextTransfer;
import com.servoy.j2db.printing.IFixedPreferredWidth;
import com.servoy.j2db.ui.IDataRenderer;
import com.servoy.j2db.ui.IEditProvider;
import com.servoy.j2db.ui.IEventExecutor;
import com.servoy.j2db.ui.IFieldComponent;
import com.servoy.j2db.ui.ILabel;
import com.servoy.j2db.ui.IScrollPane;
import com.servoy.j2db.ui.ISupportCachedLocationAndSize;
import com.servoy.j2db.ui.ISupportEditProvider;
import com.servoy.j2db.ui.ISupportOnRender;
import com.servoy.j2db.ui.ISupportPlaceholderText;
import com.servoy.j2db.ui.scripting.RuntimeTextArea;
import com.servoy.j2db.util.Debug;
import com.servoy.j2db.util.EnableScrollPanel;
import com.servoy.j2db.util.HtmlUtils;
import com.servoy.j2db.util.ISkinnable;
import com.servoy.j2db.util.ISupplyFocusChildren;
import com.servoy.j2db.util.ScopesUtils;
import com.servoy.j2db.util.Text;
import com.servoy.j2db.util.Utils;
import com.servoy.j2db.util.docvalidator.LengthDocumentValidator;
import com.servoy.j2db.util.docvalidator.ValidatingDocument;
/**
* Runtime swing component which makes a text area
* @author jblok
*/
public class DataTextArea extends EnableScrollPanel implements IDisplayData, IFieldComponent, IScrollPane, IFixedPreferredWidth,
ISupplyFocusChildren<Component>, ISupportCachedLocationAndSize, ISupportDragNDropTextTransfer, ISupportEditProvider, ISupportPlaceholderText,
ISupportOnRender
{
private final JTextArea enclosedComponent;
private String dataProviderID;
private final Document plainDocument;
private Document editorDocument;
private final EventExecutor eventExecutor;
private final IApplication application;
private MouseAdapter rightclickMouseAdapter = null;
private final RuntimeTextArea scriptable;
public DataTextArea(IApplication app, RuntimeTextArea scriptable)
{
super();
application = app;
getViewport().setView(new MyTextArea());
enclosedComponent = (JTextArea)getViewport().getView();
eventExecutor = new EventExecutor(this, enclosedComponent)
{
@Override
public void fireLeaveCommands(Object display, boolean focusEvent, int modifiers)
{
if (hasLeaveCmds())
{
editProvider.focusLost(new FocusEvent(DataTextArea.this, FocusEvent.FOCUS_LOST));
}
super.fireLeaveCommands(display, focusEvent, modifiers);
}
};
enclosedComponent.addKeyListener(eventExecutor);
plainDocument = editorDocument = enclosedComponent.getDocument();
enclosedComponent.setBorder(BorderFactory.createEmptyBorder());
enclosedComponent.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
Collections.singleton(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, InputEvent.SHIFT_DOWN_MASK)));
enclosedComponent.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, Collections.singleton(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0)));
Keymap keymap = enclosedComponent.getKeymap();
keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, InputEvent.CTRL_DOWN_MASK), new AbstractAction()
{
private static final long serialVersionUID = 1L;
public void actionPerformed(ActionEvent e)
{
((JTextArea)e.getSource()).replaceSelection("\t"); //$NON-NLS-1$
}
});
enclosedComponent.addKeyListener(new KeyAdapter()
{
@Override
public void keyPressed(KeyEvent e)
{
if (e.getKeyCode() == KeyEvent.VK_ESCAPE)
{
JTextArea ta = (JTextArea)e.getSource();
if (ta.hasFocus() && ta.isEditable() && ta.isEnabled() && !Utils.equalObjects(previousValue, ta.getText()))
{
e.consume();
}
}
}
@Override
public void keyReleased(KeyEvent e)
{
if (e.getKeyCode() == KeyEvent.VK_ESCAPE)
{
JTextArea ta = (JTextArea)e.getSource();
if (ta.hasFocus() && ta.isEditable() && ta.isEnabled() && !Utils.equalObjects(previousValue, ta.getText()))
{
ta.setText(previousValue);
e.consume();
}
}
}
});
this.scriptable = scriptable;
scriptable.setTextComponent(enclosedComponent);
}
public final RuntimeTextArea getScriptObject()
{
return scriptable;
}
/*
* _____________________________________________________________ Methods for event handling
*/
public void addScriptExecuter(IScriptExecuter el)
{
eventExecutor.setScriptExecuter(el);
}
public IEventExecutor getEventExecutor()
{
return eventExecutor;
}
public void setEnterCmds(String[] ids, Object[][] args)
{
eventExecutor.setEnterCmds(ids, args);
}
public void setLeaveCmds(String[] ids, Object[][] args)
{
eventExecutor.setLeaveCmds(ids, args);
}
public boolean isValueValid()
{
return isValueValid;
}
private boolean isValueValid = true;
private Object previousValidValue;
public void setValueValid(boolean valid, Object oldVal)
{
application.getRuntimeProperties().put(IServiceProvider.RT_LASTFIELDVALIDATIONFAILED_FLAG, Boolean.valueOf(!valid));
isValueValid = valid;
if (!isValueValid)
{
previousValidValue = oldVal;
application.invokeLater(new Runnable()
{
public void run()
{
requestFocus();
}
});
}
else
{
previousValidValue = null;
}
}
public void notifyLastNewValueWasChange(Object oldVal, Object newVal)
{
if (previousValidValue != null)
{
oldVal = previousValidValue;
}
previousValue = (newVal == null ? null : newVal.toString());
eventExecutor.fireChangeCommand(oldVal, newVal, false, this);
// if change cmd is not succeeded also don't call action cmd?
if (isValueValid)
{
eventExecutor.fireActionCommand(false, this);
}
}
public void setChangeCmd(String id, Object[] args)
{
eventExecutor.setChangeCmd(id, args);
}
public void setActionCmd(String id, Object[] args)
{
eventExecutor.setActionCmd(id, args);
}
public void setRightClickCommand(String rightClickCmd, Object[] args)
{
eventExecutor.setRightClickCmd(rightClickCmd, args);
if (rightClickCmd != null && rightclickMouseAdapter == null)
{
rightclickMouseAdapter = new MouseAdapter()
{
@Override
public void mousePressed(MouseEvent e)
{
if (e.isPopupTrigger()) handle(e);
}
@Override
public void mouseReleased(MouseEvent e)
{
if (e.isPopupTrigger()) handle(e);
}
private void handle(MouseEvent e)
{
if (isEnabled())
{
eventExecutor.fireRightclickCommand(true, DataTextArea.this, e.getModifiers(), e.getPoint());
}
}
};
enclosedComponent.addMouseListener(rightclickMouseAdapter);
addMouseListener(rightclickMouseAdapter);
}
}
private boolean wasEditable;
public void setValidationEnabled(boolean b)
{
if (eventExecutor.getValidationEnabled() == b) return;
if (dataProviderID != null && ScopesUtils.isVariableScope(dataProviderID)) return;
eventExecutor.setValidationEnabled(b);
boolean prevEditState = editState;
if (b)
{
setEditable(wasEditable);
enclosedComponent.setDocument(editorDocument);
previousValue = enclosedComponent.getText();
// Commented out this part because, when executing search with a button action - with the mouse
// it would not show any contents in the field afterwards (it doesn't show the content of the found records).
// try
// {
// plainDocument.remove(0, plainDocument.getLength());
// }
// catch (BadLocationException e)
// {
// Debug.error(e);
// }
}
else
{
wasEditable = enclosedComponent.isEditable();
if (!Boolean.TRUE.equals(application.getClientProperty(IApplication.LEAVE_FIELDS_READONLY_IN_FIND_MODE)))
{
setEditable(true);
}
// keep the old text
String text = enclosedComponent.getText();
enclosedComponent.setDocument(plainDocument);
enclosedComponent.setText(text);
}
editState = prevEditState;
}
public void setSelectOnEnter(boolean b)
{
eventExecutor.setSelectOnEnter(b);
}
//_____________________________________________________________
@Override
public void setName(String name)
{
super.setName(name);
enclosedComponent.setName(name);
}
public void setMaxLength(int i)
{
enclosedComponent.setDocument(editorDocument = new ValidatingDocument(new LengthDocumentValidator(i)));
}
public Document getDocument()
{
return enclosedComponent.getDocument();
}
public void setMargin(Insets m)
{
// enclosedComponent.setMargin(i); seems to have no effect
enclosedComponent.setBorder(BorderFactory.createCompoundBorder(enclosedComponent.getBorder(),
BorderFactory.createEmptyBorder(m.top, m.left, m.bottom, m.right)));
}
public Insets getMargin()
{
return null;
}
@Override
public void setFont(Font f)
{
super.setFont(f);
if (enclosedComponent != null) enclosedComponent.setFont(f);
}
@Override
public Font getFont()
{
if (enclosedComponent != null)
{
return enclosedComponent.getFont();
}
return super.getFont();
}
@Override
public void setHorizontalScrollBarPolicy(int policy)
{
if (enclosedComponent != null)
{
if (policy == ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS || policy == ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED)
{
enclosedComponent.setLineWrap(false);
enclosedComponent.setWrapStyleWord(false);
}
else
{
enclosedComponent.setLineWrap(true);
enclosedComponent.setWrapStyleWord(true);
}
}
super.setHorizontalScrollBarPolicy(policy);
}
public void setHorizontalAlignment(int a)
{
//not supported by textarea
}
private boolean isInsertMode;
public boolean getOverwriteMode()
{
return !isInsertMode;
}
public class MyTextArea extends JTextArea implements ISkinnable, ISupportDragNDropTextTransfer
{
private final Caret defaultCaret;
private final Caret overtypeCaret;
MyTextArea()
{
super();
setDragEnabledEx(true);
defaultCaret = getCaret();
overtypeCaret = new OvertypeCaret();
overtypeCaret.setBlinkRate(defaultCaret.getBlinkRate());
setInsertMode(true);
}
/*
* Return the insert/overtype mode
*/
public boolean isInsertMode()
{
return isInsertMode;
}
/*
* Set the caret to use depending on insert/overtype mode
*/
public void setInsertMode(boolean isInsertMode)
{
DataTextArea.this.isInsertMode = isInsertMode;
int pos = getCaretPosition();
if (isInsertMode())
{
setCaret(defaultCaret);
}
else
{
setCaret(overtypeCaret);
}
setCaretPosition(pos);
}
/*
* Override method from JComponent
*/
@Override
public void replaceSelection(String text)
{
// Implement overtype mode by selecting the character at the current
// caret position
if (!isInsertMode())
{
int pos = getCaretPosition();
if (getSelectedText() == null && pos < getDocument().getLength())
{
moveCaretPosition(pos + 1);
}
}
super.replaceSelection(text);
}
/*
* Override method from JComponent
*/
@Override
protected void processKeyEvent(KeyEvent e)
{
super.processKeyEvent(e);
// Handle release of Insert key to toggle insert/overtype mode
if (e.getID() == KeyEvent.KEY_RELEASED && e.getKeyCode() == KeyEvent.VK_INSERT)
{
setInsertMode(!isInsertMode());
((ISmartClientApplication)application).updateInsertModeIcon(DataTextArea.this);
}
}
// MAC FIX
@Override
public Insets getInsets()
{
Insets insets = super.getInsets();
if (insets == null)
{
insets = new Insets(0, 0, 0, 0);
}
return insets;
}
// MAC FIX
@Override
public Insets getMargin()
{
Insets insets = super.getMargin();
if (insets == null)
{
insets = new Insets(0, 0, 0, 0);
}
return insets;
}
private void setDragEnabledEx(boolean b)
{
try
{
Method m = getClass().getMethod("setDragEnabled", new Class[] { boolean.class }); //$NON-NLS-1$
m.invoke(this, new Object[] { new Boolean(b) });
}
catch (Exception e)
{
// Debug.trace(e);//is intenionaly trace, becouse fails before 1.4
}
}
@Override
public void setUI(ComponentUI ui)
{
super.setUI(ui);
}
@Override
public void setText(String t)
{
super.setText(t);
setCaretPosition(0);
}
//fix for incorrect clipping
@Override
public void print(Graphics g)
{
Shape saveClip = g.getClip();
try
{
int w = DataTextArea.this.getWidth();
w -= DataTextArea.this.getInsets().left + DataTextArea.this.getInsets().right;
int h = DataTextArea.this.getHeight();
h -= DataTextArea.this.getInsets().top + DataTextArea.this.getInsets().bottom;
if (saveClip != null)
{
g.setClip(saveClip.getBounds().intersection(new Rectangle(0, 0, w, h)));
}
else
{
g.setClip(0, 0, w, h);
}
super.print(g);
}
finally
{
g.setClip(saveClip);
}
}
@Override
public void copy()
{
if (textTransferHandler != null)
{
Action copyAction = FormDataTransferHandler.getCopyFormDataAction();
copyAction.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, (String)copyAction.getValue(Action.NAME),
EventQueue.getMostRecentEventTime(), getCurrentEventModifiers()));
}
else super.copy();
}
@Override
public void cut()
{
if (textTransferHandler != null && isEditable() && isEnabled())
{
Action cutAction = FormDataTransferHandler.getCutFormDataAction();
cutAction.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, (String)cutAction.getValue(Action.NAME),
EventQueue.getMostRecentEventTime(), getCurrentEventModifiers()));
}
else super.cut();
}
@Override
public void paste()
{
if (textTransferHandler != null && isEditable() && isEnabled())
{
Action pasteAction = FormDataTransferHandler.getPasteFormDataAction();
pasteAction.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, (String)pasteAction.getValue(Action.NAME),
EventQueue.getMostRecentEventTime(), getCurrentEventModifiers()));
}
else super.paste();
}
private int getCurrentEventModifiers()
{
int modifiers = 0;
AWTEvent currentEvent = EventQueue.getCurrentEvent();
if (currentEvent instanceof InputEvent)
{
modifiers = ((InputEvent)currentEvent).getModifiers();
}
else if (currentEvent instanceof ActionEvent)
{
modifiers = ((ActionEvent)currentEvent).getModifiers();
}
return modifiers;
}
private TransferHandler textTransferHandler;
/*
* @see com.servoy.j2db.dnd.ISupportDragNDropTextTransfer#clearTransferHandler()
*/
public void clearTransferHandler()
{
textTransferHandler = getTransferHandler();
setTransferHandler(null);
}
/*
* @see com.servoy.j2db.dnd.ISupportDragNDropTextTransfer#getTextTransferHandler()
*/
public TransferHandler getTextTransferHandler()
{
return textTransferHandler;
}
}
/*
* @see IDisplayData#getValue()
*/
public Object getValueObject()
{
previousValue = enclosedComponent.getText();
return previousValue;
}
@Override
public void addFocusListener(FocusListener fl)
{
if (enclosedComponent != null) enclosedComponent.addFocusListener(fl);
}
@Override
public void removeFocusListener(FocusListener fl)
{
if (enclosedComponent != null) enclosedComponent.removeFocusListener(fl);
}
public boolean needEntireState()
{
return needEntireState;
}
private boolean needEntireState;
public void setNeedEntireState(boolean b)
{
needEntireState = b;
}
private String previousValue;
private void setValueEx(String txt)
{
if (!Utils.equalObjects(previousValue, txt))
{
previousValue = txt;
enclosedComponent.setText(txt);
// if ((enclosedComponent.getWidth() == 0 || enclosedComponent.getHeight() == 0) && !"".equals(txt))
// {
// Dimension thisSize = getSize();
// enclosedComponent.setSize(thisSize);
// Dimension d = enclosedComponent.getPreferredSize();
// enclosedComponent.setSize(d);
// enclosedComponent.invalidate();
// validate();
// doLayout();
// }
}
}
protected ITagResolver resolver;
public void setTagResolver(ITagResolver resolver)
{
this.resolver = resolver;
}
/*
* @see IDisplayData#setValue(Object)
*/
public void setValueObject(Object obj)
{
try
{
if (editProvider != null) editProvider.setAdjusting(true);
if (needEntireState)
{
if (resolver != null)
{
setValueEx(Text.processTags(TagResolver.formatObject(obj != null ? obj : "", application.getLocale(), application.getSettings()), resolver)); //$NON-NLS-1$
if (tooltip != null)
{
enclosedComponent.setToolTipText(Text.processTags(tooltip, resolver));
}
}
else
{
setValueEx(""); //$NON-NLS-1$
if (tooltip != null)
{
enclosedComponent.setToolTipText(null);
}
}
}
else
{
if (obj == null)
{
setValueEx(""); //$NON-NLS-1$
}
else
{
setValueEx(TagResolver.formatObject(obj, application.getLocale(), application.getSettings()));
}
if (tooltip != null)
{
enclosedComponent.setToolTipText(tooltip);
}
}
}
finally
{
if (editProvider != null) editProvider.setAdjusting(false);
}
fireOnRender(false);
}
public void fireOnRender(boolean force)
{
if (scriptable != null)
{
if (force) scriptable.getRenderEventExecutor().setRenderStateChanged();
scriptable.getRenderEventExecutor().fireOnRender(enclosedComponent.hasFocus());
}
}
/*
* @see IDisplayData#needFocusListner()
*/
public boolean needEditListener()
{
return true;
}
private EditProvider editProvider = null;
public IEditProvider getEditProvider()
{
return editProvider;
}
private ArrayList<ILabel> labels;
public void addEditListener(IEditListener l)
{
if (editProvider == null)
{
editProvider = new EditProvider(this, true);
addFocusListener(editProvider);
plainDocument.addDocumentListener(editProvider);
editorDocument.addDocumentListener(editProvider);
editProvider.addEditListener(l);
editProvider.setEditable(enclosedComponent.isEditable());
try
{
DropTarget dt = enclosedComponent.getDropTarget();
if (dt != null) dt.addDropTargetListener(editProvider);
}
catch (Exception e)
{
Debug.error(e);
}
}
}
/*
* @see IDisplayData#getDataProviderID()
*/
public String getDataProviderID()
{
return dataProviderID;
}
public void setDataProviderID(String dataProviderID)
{
this.dataProviderID = dataProviderID;
}
@Override
public void setBackground(Color bg)
{
if (enclosedComponent != null) enclosedComponent.setBackground(bg);
super.setBackground(bg);
}
@Override
public Color getBackground()
{
if (enclosedComponent != null)
{
return enclosedComponent.getBackground();
}
return super.getBackground();
}
@Override
public Color getForeground()
{
if (enclosedComponent != null)
{
return enclosedComponent.getForeground();
}
return super.getForeground();
}
@Override
public void setForeground(Color fg)
{
if (enclosedComponent != null) enclosedComponent.setForeground(fg);
super.setForeground(fg);
}
public void setComponentVisible(boolean b_visible)
{
if (viewable || !b_visible)
{
setVisible(b_visible);
}
}
@Override
public void setVisible(boolean flag)
{
super.setVisible(flag);
if (labels != null)
{
for (int i = 0; i < labels.size(); i++)
{
ILabel label = labels.get(i);
label.setComponentVisible(flag);
}
}
}
public void addLabelFor(ILabel label)
{
if (labels == null) labels = new ArrayList<ILabel>(3);
labels.add(label);
}
public List<ILabel> getLabelsFor()
{
return labels;
}
@Override
public void setOpaque(boolean b)
{
if (enclosedComponent != null) enclosedComponent.setOpaque(b);
getViewport().setOpaque(b);
super.setOpaque(b);
}
public void setComponentEnabled(final boolean b)
{
if (accessible || !b)
{
super.setEnabled(b);
if (labels != null)
{
for (int i = 0; i < labels.size(); i++)
{
ILabel label = labels.get(i);
label.setComponentEnabled(b);
}
}
}
}
private boolean accessible = true;
public void setAccessible(boolean b)
{
if (!b) setComponentEnabled(b);
accessible = b;
}
private boolean viewable = true;
public void setViewable(boolean b)
{
if (!b) setComponentVisible(b);
this.viewable = b;
}
public boolean isViewable()
{
return viewable;
}
public void setEditable(boolean b)
{
editState = b;
enclosedComponent.setEditable(b);
if (editProvider != null) editProvider.setEditable(b);
if (b)
{
enclosedComponent.removeMouseListener(eventExecutor);
}
else
{
enclosedComponent.addMouseListener(eventExecutor);//listen when not editable
}
}
public boolean isEditable()
{
return enclosedComponent.isEditable();
}
private boolean editState;
public void setReadOnly(boolean b)
{
if (b && !enclosedComponent.isEditable()) return;
if (b)
{
setEditable(false);
editState = true;
}
else
{
setEditable(editState);
}
}
public boolean isReadOnly()
{
return !enclosedComponent.isEditable();
}
/*
* titleText---------------------------------------------------
*/
private String titleText = null;
public void setTitleText(String title)
{
this.titleText = title;
}
public String getTitleText()
{
return Text.processTags(titleText, resolver);
}
private String tooltip;
@Override
public void setToolTipText(String tip)
{
if (tip != null && tip.indexOf("%%") != -1) //$NON-NLS-1$
{
tooltip = tip;
}
else if (!Utils.stringIsEmpty(tip))
{
if (!Utils.stringContainsIgnoreCase(tip, "<html")) //$NON-NLS-1$
{
enclosedComponent.setToolTipText(tip);
}
else if (HtmlUtils.hasUsefulHtmlContent(tip))
{
enclosedComponent.setToolTipText(tip);
}
}
else
{
enclosedComponent.setToolTipText(null);
}
}
/*
* (non-Javadoc)
*
* @see javax.swing.JComponent#getToolTipText(java.awt.event.MouseEvent)
*/
@Override
public String getToolTipText(MouseEvent event)
{
String txt = super.getToolTipText(event);
if (txt == null || txt.length() == 0)
{
return enclosedComponent.getToolTipText(event);
}
return null;
}
public int getAbsoluteFormLocationY()
{
Container parent = getParent();
while ((parent != null) && !(parent instanceof IDataRenderer))
{
parent = parent.getParent();
}
if (parent != null)
{
return ((IDataRenderer)parent).getYOffset() + getLocation().y;
}
return getLocation().y;
}
private Point cachedLocation;
public Point getCachedLocation()
{
return cachedLocation;
}
public void setCachedLocation(Point location)
{
this.cachedLocation = location;
}
public void setCachedSize(Dimension size)
{
this.cachedSize = size;
}
private Dimension cachedSize;
public Dimension getCachedSize()
{
return cachedSize;
}
// If component not shown or not added yet
// and request focus is called it should wait for the component
// to be created.
boolean wantFocus = false;
@Override
public void addNotify()
{
super.addNotify();
if (wantFocus)
{
wantFocus = false;
enclosedComponent.requestFocus();
}
}
public void requestFocusToComponent()
{
// if (!enclosedComponent.hasFocus()) Don't test on hasFocus (it can have focus,but other component already did requestFocus)
{
if (isDisplayable())
{
// Must do it in a runnable or else others after a script can get focus first again..
application.invokeLater(new Runnable()
{
public void run()
{
enclosedComponent.requestFocus();
}
});
}
else
{
wantFocus = true;
}
}
}
@Override
public String toString()
{
return scriptable.toString();
}
public boolean stopUIEditing(boolean looseFocus)
{
if (editProvider != null) editProvider.forceCommit();
if (!isValueValid)
{
application.invokeLater(new Runnable()
{
public void run()
{
requestFocus();
}
});
return false;
}
if (looseFocus && eventExecutor.mustFireFocusLostCommand())
{
eventExecutor.skipNextFocusLost();
eventExecutor.fireLeaveCommands(this, false, IEventExecutor.MODIFIERS_UNSPECIFIED);
}
return true;
}
public String getId()
{
return (String)getClientProperty("Id"); //$NON-NLS-1$
}
@Override
protected void printChildren(Graphics g)
{
super.printChildren(g);
super.printBorder(g); // print border after children print, to prevent child backgrounds ontop of border
}
@Override
protected void printBorder(Graphics g)
{
//intentionally empty to have the border drawn after the content
}
private int preferredWidth = -1;
public void setPreferredWidth(int preferredWidth)
{
this.preferredWidth = preferredWidth;
}
@Override
public Dimension getPreferredSize()
{
if (preferredWidth < 0)
{
// normal behavior (used when not in print preview... and normally in print preview)
// preview and printing should behave the same
if (application.getModeManager().getMode() == IModeManager.PREVIEW_MODE || Utils.getAsBoolean(application.getRuntimeProperties().get("isPrinting")))
{
// in print preview, the preferred size of the text area must calculate it's width as well;
// this happens only if line wrap is false
boolean lineWrap = enclosedComponent.getLineWrap();
int height = 0;
if (lineWrap)
{
height = super.getPreferredSize().height;
enclosedComponent.setLineWrap(false);
}
Dimension d = super.getPreferredSize();
if (lineWrap)
{
d.height = height;
enclosedComponent.setLineWrap(true);
}
return d;
}
return super.getPreferredSize();
}
else
{
// in print preview, with grow horizontal + shrink or grow vertical, this is what happens
Dimension preferredSize = new Dimension();
preferredSize.width = preferredWidth;
// compute preferred height for the given width (preferredWidth)
Insets insets = getInsets();
Dimension oldSize = enclosedComponent.getSize();
enclosedComponent.setSize(preferredWidth - insets.left - insets.right, getHeight() - insets.top - insets.bottom);
boolean lineWrap = enclosedComponent.getLineWrap(); // if line wrap is true, the preferred size reported
// by a JTextArea only calculates the height and uses the current component width
if (!lineWrap) enclosedComponent.setLineWrap(true);
preferredSize.height = super.getPreferredSize().height;
if (!lineWrap) enclosedComponent.setLineWrap(false);
enclosedComponent.setSize(oldSize);
return preferredSize;
}
}
public Component[] getFocusChildren()
{
return new Component[] { enclosedComponent };
}
/*
* @see com.servoy.j2db.dnd.ISupportTextTransfer#clearTransferHandler()
*/
public void clearTransferHandler()
{
setTransferHandler(null);
if (enclosedComponent instanceof ISupportDragNDropTextTransfer) ((ISupportDragNDropTextTransfer)enclosedComponent).clearTransferHandler();
}
/*
* @see com.servoy.j2db.dnd.ISupportTextTransfer#getTextTransferHandler()
*/
public TransferHandler getTextTransferHandler()
{
return enclosedComponent instanceof ISupportDragNDropTextTransfer ? ((ISupportDragNDropTextTransfer)enclosedComponent).getTextTransferHandler() : null;
}
@Override
public void setPlaceholderText(String text)
{
PromptSupport.uninstall(enclosedComponent);
PromptSupport.setPrompt(application.getI18NMessageIfPrefixed(text), enclosedComponent);
repaint();
}
}