![JAR search and dependency download from the Maven repository](/logo.png)
xdev.ui.XdevDateTextField Maven / Gradle / Ivy
/*
* XDEV Application Framework - XDEV Application Framework
* Copyright © 2003 XDEV Software (https://xdev.software)
*
* This program 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 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
package xdev.ui;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Map;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.DocumentListener;
import javax.swing.text.Document;
import javax.swing.text.JTextComponent;
import xdev.db.Operator;
import xdev.lang.NotNull;
import xdev.ui.text.TextFormat;
import xdev.util.DateFormatException;
import xdev.util.ObjectUtils;
import xdev.util.XdevDate;
import xdev.util.logging.LoggerFactory;
import xdev.util.logging.XdevLogger;
import xdev.vt.VirtualTable;
/**
* The standard date textfield in XDEV. Based on {@link JTextField}.
*
* @see JTextField
* @see ClientProperties
* @see FormattedFormularComponent
* @see XdevFocusCycleComponent
* @see DatePopupOwner
*
* @author XDEV Software
*
* @since 2.0
*/
@BeanSettings(useXdevCustomizer = true)
public class XdevDateTextField extends JTextField implements ClientProperties,
FormattedFormularComponent, DateFormularComponent,
DatePopupOwner, XdevFocusCycleComponent
{
/**
* Logger instance for this class.
*/
private static final XdevLogger log = LoggerFactory
.getLogger(XdevDateTextField.class);
private DatePopup datePopup;
private DatePopupCustomizer datePopupCustomizer;
private TextFormat textFormat;
private XdevDateDropDownButton dropDownButton;
private boolean dropDownButtonVisible = true;
private String savedValue = "";
/**
* tabIndex is used to store the index for {@link XdevFocusCycleComponent}
* functionality.
*/
private int tabIndex = -1;
/**
* @since 3.1
*/
private FocusGainedBehavior focusGainedBehavior = FocusGainedBehavior.SYSTEM_DEFAULT;
/**
* @since 4.0
*/
private TextChangedBehavior textChangedBehavior = TextChangedBehavior.SYSTEM_DEFAULT;
private final TextFormularComponentSupport support = new TextFormularComponentSupport(
this);
/**
* Constructor for creating a new instance of a {@link XdevDateTextField}.
* Initialized with default {@link TextFormat}.
*/
public XdevDateTextField()
{
this(TextFormat.getDateInstance());
}
/**
* Constructor for creating a new instance of a {@link XdevDateTextField}.
* Initialized with the specified textFormat
.
*
* @param textFormat
* the {@link TextFormat} to format the display value,
* null
if none
*/
public XdevDateTextField(TextFormat textFormat)
{
this("",textFormat);
}
/**
* Constructor for creating a new instance of a {@link XdevDateTextField}.
* Initialized with the specified text
, textFormat
* and the default maxSigns
of 100
.
*
* @param text
* the text to be displayed, null
if none
*
* @param textFormat
* the {@link TextFormat} to format the display value,
* null
if none
*
*/
public XdevDateTextField(String text, TextFormat textFormat)
{
this(text,100,textFormat);
}
/**
* Constructor for creating a new instance of a {@link XdevDateTextField}.
* Initialized with the specified maxSigns
and
* textFormat
.
*
*
* @param maxSigns
* a int
to determine the max signs of the
* {@link MaxSignDocument}
*
* @param textFormat
* the {@link TextFormat} to format the display value,
* null
if none
*
* @throws IllegalArgumentException
* if the maxSigns
is <= 0
*/
public XdevDateTextField(int maxSigns, TextFormat textFormat) throws IllegalArgumentException
{
this("",maxSigns,textFormat);
}
/**
* Constructor for creating a new instance of a {@link XdevDateTextField}.
* Initialized with the specified text
, maxSigns
* and textFormat
.
*
* @param text
* the text to be displayed, null
if none
*
* @param maxSigns
* a int
to determine the max signs of the
* {@link MaxSignDocument}
*
* @param textFormat
* the {@link TextFormat} to format the display value,
* null
if none
*
* @throws IllegalArgumentException
* if the maxSigns
is <= 0
*/
public XdevDateTextField(String text, int maxSigns, TextFormat textFormat)
throws IllegalArgumentException
{
super();
setTextFormat(textFormat);
setDocument(new MaxSignDocument(maxSigns));
setText(text);
init();
}
/**
* Constructor for creating a new instance of a {@link XdevDateTextField}.
* Initialized with the specified value
and
* textFormat
.
*
* @param value
* the initial value
*
* @param textFormat
* the {@link TextFormat} to format the display value,
* null
if none
*/
public XdevDateTextField(XdevDate value, TextFormat textFormat)
{
this(value,100,textFormat);
}
/**
* Constructor for creating a new instance of a {@link XdevDateTextField}.
* Initialized with the specified value
, maxSigns
* and textFormat
.
*
* @param value
* the initial value
*
* @param maxSigns
* a int
to determine the max signs of the
* {@link MaxSignDocument}
*
* @param textFormat
* the {@link TextFormat} to format the display value,
* null
if none
*
* @throws IllegalArgumentException
* if the maxSigns
is <= 0
*/
public XdevDateTextField(XdevDate value, int maxSigns, TextFormat textFormat)
throws IllegalArgumentException
{
super();
setTextFormat(textFormat);
setDocument(new MaxSignDocument(maxSigns));
if(value != null)
{
setText(textFormat.format(value));
}
init();
}
private void init()
{
setColumns(20);
addFocusListener(new FocusListener()
{
public void focusGained(FocusEvent e)
{
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
focusGainedBehavior.focusGained(XdevDateTextField.this);
}
});
}
public void focusLost(FocusEvent e)
{
select(0,0);
}
});
dropDownButton = createDropDownButton();
addKeyListener(new KeyAdapter()
{
@Override
public void keyPressed(KeyEvent e)
{
if(e.getKeyCode() == KeyEvent.VK_ESCAPE && datePopup != null)
{
hideDatePopup();
}
}
});
}
/**
* Returns the {@link FocusGainedBehavior} of this TextComponent.
*
* @return the {@link FocusGainedBehavior} of this TextComponent
*
* @since 3.1
*/
public FocusGainedBehavior getFocusGainedBehavior()
{
return focusGainedBehavior;
}
/**
* Sets the new {@link FocusGainedBehavior} for this TextComponent.
*
* @param focusGainedBehavior
* the new {@link FocusGainedBehavior}
* @throws {@link IllegalArgumentException} if
* focusGainedBehavior
is null
*
* @since 3.1
*/
public void setFocusGainedBehavior(@NotNull FocusGainedBehavior focusGainedBehavior)
{
if(focusGainedBehavior == null)
{
throw new IllegalArgumentException("focusGainedBehavior cannot be null");
}
else if(focusGainedBehavior != this.focusGainedBehavior)
{
FocusGainedBehavior old = this.focusGainedBehavior;
this.focusGainedBehavior = focusGainedBehavior;
firePropertyChange(FocusGainedBehavior.PROPERTY_NAME,old,focusGainedBehavior);
}
}
/**
* Return the {@link TextChangedBehavior} of this TextComponent
*
* @return the {@link TextChangedBehavior} of this TextComponent
*
* @since 4.0
*/
public TextChangedBehavior getTextChangedBehavior()
{
return textChangedBehavior;
}
/**
* Sets the new {@link TextChangedBehavior} for this TextComponent.
*
* @param textChangedBehavior
* the new {@link TextChangedBehavior}
* @throws {@link IllegalArgumentException} if
* textChangedBehavior
is null
*
* @since 4.0
*/
public void setTextChangedBehavior(@NotNull TextChangedBehavior textChangedBehavior)
{
if(textChangedBehavior == null)
{
throw new IllegalArgumentException("textChangedBehavior cannot be null");
}
else if(textChangedBehavior != this.textChangedBehavior)
{
TextChangedBehavior old = this.textChangedBehavior;
this.textChangedBehavior = textChangedBehavior;
firePropertyChange(TextChangedBehavior.PROPERTY_NAME,old,textChangedBehavior);
}
}
/**
* {@inheritDoc}
*
* @see UIUtils#scrollToStart(javax.swing.JComponent)
*/
@Override
public void setText(String t)
{
super.setText(t);
textChangedBehavior.textChanged(this);
}
/**
* {@inheritDoc}
*/
@Override
public Dimension getPreferredSize()
{
// Hack because JTextField doesn't honor the set preferred size
if(isPreferredSizeSet())
{
try
{
return UIUtils.getPrefSizeFieldValue(this);
}
catch(Exception e)
{
// Shouldn't happen
log.error(e);
}
}
return super.getPreferredSize();
}
/**
* Creates the drop down button for this text field.
*
* Overwrite this method if you want to use your own drop down button.
*
* @return the drop down button
*/
protected XdevDateDropDownButton createDropDownButton()
{
XdevDateDropDownButton dropDownButton = new XdevDateDropDownButton(this);
dropDownButton.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
dropDownButton.setVisible(isVisible() && dropDownButtonVisible);
return dropDownButton;
}
/**
* Gets the {@link XdevDateDropDownButton} of this {@link XdevDateTextField}
* .
*
* @return the {@link XdevDateDropDownButton} of this
* {@link XdevDateTextField}
*
*/
public XdevDateDropDownButton getDropDownButton()
{
return dropDownButton;
}
/**
* Shows or hides the drop down button.
*
* @param b
* true
if the button should be shown,
* false
if the button should be hidden
*/
public void setDropDownButtonVisible(boolean b)
{
dropDownButtonVisible = b;
if(dropDownButton != null)
{
dropDownButton.setVisible(b);
}
}
/**
* Returns true
if the drop down button is visible,
* false
otherwise
*
* @return the visibility of the drop down button
*/
public boolean isDropDownButtonVisible()
{
return dropDownButtonVisible;
}
/**
* Creates the panel which contains this {@link XdevDateTextField} and the
* drop down button.
* This is a convenience methode to build layout constructs.
*
* @return a panel containing this {@link XdevDateTextField} and the drop
* down button
*/
public XComponent createPanel()
{
XComponent pnl = new XComponent(new BorderLayout());
pnl.add(this,BorderLayout.CENTER);
pnl.add(dropDownButton,BorderLayout.EAST);
return pnl;
}
/**
* Sets the {@link DatePopupCustomizer} of this {@link XdevDateTextField}.
*
* @param datePopupCustomizer
* a {@link DatePopupCustomizer} to be set.
*
*/
public void setDatePopupCustomizer(DatePopupCustomizer datePopupCustomizer)
{
this.datePopupCustomizer = datePopupCustomizer;
}
/**
* Gets the {@link DatePopupCustomizer} of this {@link XdevDateTextField}.
*
* @return the {@link DatePopupCustomizer} of this {@link XdevDateTextField}
*
*/
@Override
public DatePopupCustomizer getDatePopupCustomizer()
{
return datePopupCustomizer;
}
/**
* Registers the given {@link DocumentListener} to begin receiving
* notifications when changes are made to the document.
*
* @param listener
* the {@link DocumentListener} to register
*
* @see Document#addDocumentListener(DocumentListener)
*/
public void addDocumentListener(DocumentListener listener)
{
getDocument().addDocumentListener(listener);
}
/**
* Unregisters the given {@link DocumentListener} from the notification list
* so it will no longer receive change updates.
*
* @param listener
* the observer to register
* @see #addDocumentListener(DocumentListener)
*/
public void removeDocumentListener(DocumentListener listener)
{
getDocument().removeDocumentListener(listener);
}
/**
* Returns the max sign count of this {@link XdevDateTextField}.
*
*
* @return the max sign count of this {@link XdevDateTextField}, -1 if the
* {@link Document} is not an instance of {@link MaxSignDocument}.
*
* @see MaxSignDocument
*/
public int getMaxSignCount()
{
Document doc = getDocument();
if(doc instanceof MaxSignDocument)
{
return ((MaxSignDocument)doc).getMaxSignCount();
}
return -1;
}
/**
* Sets the max sign count of this {@link XdevDateTextField}.
*
* @param maxSignCount
* the max sign count of this {@link XdevDateTextField}
*/
public void setMaxSignCount(int maxSignCount)
{
Document doc = getDocument();
if(doc instanceof MaxSignDocument)
{
MaxSignDocument msDoc = (MaxSignDocument)doc;
int oldValue = msDoc.getMaxSignCount();
if(oldValue != maxSignCount)
{
msDoc.setMaxSignCount(maxSignCount);
firePropertyChange(MaxSignDocument.MAX_SIGNS_PROPERTY,oldValue,maxSignCount);
}
}
}
/**
* {@inheritDoc}
*/
@Override
public String getFormularName()
{
return support.getFormularName();
}
/**
* {@inheritDoc}
*
* @since 3.1
*/
@Override
public void setDataField(String dataField)
{
support.setDataField(dataField);
}
/**
* {@inheritDoc}
*
* @since 3.1
*/
@Override
public String getDataField()
{
return support.getDataField();
}
/**
* {@inheritDoc}
*/
@Override
@Deprecated
public final void setFormularValue(VirtualTable vt, int col, Object value)
{
support.setFormularValue(vt,col,value);
}
/**
* {@inheritDoc}
*
* @since 3.2
*/
@Override
public void setFormularValue(VirtualTable vt, Map record)
{
if(!support.hasDataField())
{
return;
}
Object value = null;
String dataField = getDataField();
String columnName = null;
if(dataField != null && dataField.length() > 0)
{
dataField = support.getFirstDataField(dataField);
columnName = support.getColumnName(dataField);
value = record.get(columnName);
}
String str = value != null ? value.toString() : "";
if(textFormat != null && textFormat.getType() != TextFormat.PLAIN)
{
str = textFormat.format(value);
}
else if(vt != null && columnName != null)
{
str = vt.formatValue(value,columnName);
}
setText(str);
}
/**
* {@inheritDoc}
*/
@Override
public Object getFormularValue()
{
try
{
return getDate();
}
catch(DateFormatException e)
{
return null;
}
}
/**
* {@inheritDoc}
*/
@Override
public void saveState()
{
savedValue = getText();
}
/**
* {@inheritDoc}
*/
@Override
public void restoreState()
{
setText(savedValue);
}
/**
* {@inheritDoc}
*
* @since 3.1
*/
@Override
public boolean hasStateChanged()
{
return !ObjectUtils.equals(savedValue,getText());
}
/**
* {@inheritDoc}
*
* @since 3.1
*/
@Override
public void addValueChangeListener(final ValueChangeListener l)
{
support.addValueChangeListener(l,this);
}
/**
* {@inheritDoc}
*/
@Override
public boolean isMultiSelect()
{
return false;
}
/**
* {@inheritDoc}
*/
@Override
public boolean verify()
{
return support.verify();
}
/**
* {@inheritDoc}
*
* @since 3.1
*/
@Override
public void addValidator(Validator validator)
{
support.addValidator(validator);
}
/**
* {@inheritDoc}
*
* @since 3.1
*/
@Override
public void removeValidator(Validator validator)
{
support.removeValidator(validator);
}
/**
* {@inheritDoc}
*
* @since 3.1
*/
@Override
public Validator[] getValidators()
{
return support.getValidators();
}
/**
* {@inheritDoc}
*
* @since 3.1
*/
@Override
public void validateState() throws ValidationException
{
support.validateState();
}
/**
* {@inheritDoc}
*
* @since 3.1
*/
@Override
public void validateState(Validation validation) throws ValidationException
{
support.validateState(validation);
}
/**
* {@inheritDoc}
*
* @since 3.1
*/
@Override
public void setFilterOperator(Operator filterOperator)
{
support.setFilterOperator(filterOperator);
}
/**
* {@inheritDoc}
*
* @since 3.1
*/
@Override
public Operator getFilterOperator()
{
return support.getFilterOperator();
}
/**
* {@inheritDoc}
*
* @since 3.2
*/
@Override
public void setReadOnly(boolean readOnly)
{
support.setReadOnly(readOnly);
}
/**
* {@inheritDoc}
*
* @since 3.2
*/
@Override
public boolean isReadOnly()
{
return support.isReadOnly();
}
/**
* {@inheritDoc}
*/
@Override
public void setCursor(Cursor cursor)
{
super.setCursor(cursor);
if(dropDownButton != null)
{
dropDownButton.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
}
}
/**
* {@inheritDoc}
*/
@Override
public void setVisible(boolean visible)
{
if(!visible && datePopup != null)
{
hideDatePopup();
}
if(dropDownButton != null)
{
dropDownButton.setVisible(visible);
}
super.setVisible(visible);
}
/**
* {@inheritDoc}
*/
@Override
public void setEnabled(boolean enabled)
{
if(!enabled && datePopup != null)
{
hideDatePopup();
}
if(dropDownButton != null)
{
dropDownButton.setEnabled(enabled);
}
super.setEnabled(enabled);
}
/**
* Shows or hides the date popup.
*
* @param visible
* true
if the popup should be shown,
* false
if the popup should be hidden
*/
@NoBeanProperty
public void setDatePopupVisible(boolean visible)
{
if(visible)
{
requestFocus();
datePopup = DatePopup.getInstance(this);
datePopup.showPopup(this);
}
else
{
hideDatePopup();
}
}
/**
* @return if the date popup is currently showing
*
* @since 4.0
*/
public boolean isDatePopupVisible()
{
return datePopup != null && datePopup.isVisible();
}
/**
* {@inheritDoc}
*/
@Override
public TextFormat getTextFormat()
{
return textFormat;
}
/**
* {@inheritDoc}
*/
@Override
public void setTextFormat(TextFormat textFormat)
{
this.textFormat = textFormat;
}
/**
* Get this {@link XdevDateTextField}.
*
* @return this {@link XdevDateTextField} as {@link Component}
*
*/
@Override
public Component getComponentForDatePopup()
{
return dropDownButton;
}
/**
* {@inheritDoc}
*/
public void hideDatePopup()
{
datePopup.hidePopup();
datePopup = null;
}
/**
* Returns the selected text contained in this {@link XdevDateTextField}. If
* the selection is null
or the document empty, returns a empty
* {@link String}.
*
* @return the selected text, or a empty {@link String}
*
* @throws IllegalArgumentException
* if the selection doesn't have a valid mapping into the
* document for some reason
*
* @see #setText
* @see JTextComponent#getSelectedText()
*/
@Override
public String getSelectedText() throws IllegalArgumentException
{
String st = super.getSelectedText();
if(st == null)
{
st = "";
}
return st;
}
/**
* Inserts a {@link String} into this {@link XdevDateTextField}.
*
* @param text
* the {@link String} to insert
*
* @see Document#insertString(int, String, javax.swing.text.AttributeSet)
*/
public void insertText(String text)
{
try
{
getDocument().insertString(getCaretPosition(),text,null);
}
catch(Exception e)
{
log.error(e);
}
}
/**
* {@inheritDoc}
*/
@NoBeanProperty
@Override
public XdevDate getDate() throws DateFormatException
{
if(textFormat != null)
{
try
{
return new XdevDate(textFormat.parseDate(getText()));
}
catch(Exception e)
{
}
}
throw new DateFormatException(getText());
}
/**
* {@inheritDoc}
*/
@Override
public XdevDate getDate(XdevDate defaultValue)
{
try
{
return getDate();
}
catch(DateFormatException e)
{
return defaultValue;
}
}
/**
* {@inheritDoc}
*/
@NoBeanProperty
@Override
public void setDate(XdevDate date)
{
setValue(date);
}
/**
* Set the value
in this {@link XdevDateTextField} as text. If
* a {@link TextFormat} exist, the value
is formatted.
*
* @param value
* the display value
*
* @see #setText(String)
*/
public void setValue(Object value)
{
if(textFormat != null)
{
setText(textFormat.format(value));
}
else
{
setText(String.valueOf(value));
}
}
/**
* {@inheritDoc}
*/
@Override
public String toString() throws NullPointerException
{
return getText();
}
/**
* {@inheritDoc}
*/
@Override
public int getTabIndex()
{
return tabIndex;
}
/**
* {@inheritDoc}
*/
@Override
public void setTabIndex(int tabIndex)
{
if(this.tabIndex != tabIndex)
{
int oldValue = this.tabIndex;
this.tabIndex = tabIndex;
firePropertyChange(TAB_INDEX_PROPERTY,oldValue,tabIndex);
}
}
}