com.alee.extended.date.WebDateField Maven / Gradle / Ivy
/*
* This file is part of WebLookAndFeel library.
*
* WebLookAndFeel library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* WebLookAndFeel library 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with WebLookAndFeel library. If not, see .
*/
package com.alee.extended.date;
import com.alee.global.StyleConstants;
import com.alee.laf.WebLookAndFeel;
import com.alee.laf.button.WebButton;
import com.alee.laf.rootpane.WebWindow;
import com.alee.laf.text.WebFormattedTextField;
import com.alee.managers.hotkey.Hotkey;
import com.alee.managers.settings.SettingsMethods;
import com.alee.utils.CollectionUtils;
import com.alee.utils.CompareUtils;
import com.alee.utils.SizeUtils;
import com.alee.utils.SwingUtils;
import com.alee.utils.laf.ShapeProvider;
import com.alee.utils.swing.SizeMethods;
import javax.swing.*;
import javax.swing.event.AncestorEvent;
import javax.swing.event.AncestorListener;
import java.awt.*;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* This is a custom component that allows date selection.
*
* @author Mikle Garin
* @see com.alee.extended.date.WebCalendar
*/
public class WebDateField extends WebFormattedTextField implements ShapeProvider, SettingsMethods, SizeMethods
{
/**
* todo 1. Change JWindow to WebHeavyWeightPopup
*/
/**
* Used icons.
*/
public static final ImageIcon selectDateIcon = new ImageIcon ( WebDateField.class.getResource ( "icons/date.png" ) );
/**
* Date selection listeners.
*/
protected List dateSelectionListeners = new ArrayList ( 1 );
/**
* Date display format.
*/
protected SimpleDateFormat dateFormat = new SimpleDateFormat ( "dd.MM.yyyy" );
/**
* Currently selected date.
*/
protected Date date = null;
/**
* UI components.
*/
protected WebButton popupButton;
protected WebWindow popup;
protected WebCalendar calendar;
protected DateSelectionListener dateSelectionListener;
/**
* Constructs new date field.
*/
public WebDateField ()
{
this ( null );
}
/**
* Constructs new date field.
*
* @param drawBorder whether should draw border or not
*/
public WebDateField ( final boolean drawBorder )
{
this ( null, drawBorder );
}
/**
* Constructs new date field with the specified selected date.
*
* @param date selected date
*/
public WebDateField ( final Date date )
{
this ( date, WebDateFieldStyle.drawBorder );
}
/**
* Constructs new date field with the specified selected date.
*
* @param drawBorder whether should draw border or not
* @param date selected date
*/
public WebDateField ( final Date date, final boolean drawBorder )
{
super ();
this.date = date;
// Basic field settings
setOpaque ( false );
setWebColored ( WebDateFieldStyle.webColored );
setDrawBackground ( WebDateFieldStyle.drawBackground );
setBackground ( WebDateFieldStyle.backgroundColor );
setWebColored ( WebDateFieldStyle.webColored );
setDrawFocus ( WebDateFieldStyle.drawFocus );
// Popup button
popupButton = WebButton.createIconWebButton ( selectDateIcon, WebDateFieldStyle.round );
popupButton.setFocusable ( false );
popupButton.setShadeWidth ( 0 );
popupButton.setMoveIconOnPress ( false );
popupButton.setRolloverDecoratedOnly ( true );
popupButton.setCursor ( Cursor.getDefaultCursor () );
popupButton.addActionListener ( new ActionListener ()
{
@Override
public void actionPerformed ( final ActionEvent e )
{
showCalendarPopup ();
}
} );
setTrailingComponent ( popupButton );
// Actions
addActionListener ( new ActionListener ()
{
@Override
public void actionPerformed ( final ActionEvent e )
{
setDateFromField ();
}
} );
addMouseListener ( new MouseAdapter ()
{
@Override
public void mousePressed ( final MouseEvent e )
{
if ( isEnabled () && SwingUtilities.isRightMouseButton ( e ) )
{
showCalendarPopup ();
}
}
} );
addFocusListener ( new FocusAdapter ()
{
@Override
public void focusLost ( final FocusEvent e )
{
if ( !SwingUtils.isEqualOrChild ( popup, e.getOppositeComponent () ) )
{
setDateFromField ();
}
}
} );
addKeyListener ( new KeyAdapter ()
{
@Override
public void keyReleased ( final KeyEvent e )
{
if ( isEnabled () )
{
if ( Hotkey.ESCAPE.isTriggered ( e ) )
{
updateFieldFromDate ();
}
else if ( Hotkey.DOWN.isTriggered ( e ) )
{
showCalendarPopup ();
}
}
}
} );
addAncestorListener ( new AncestorListener ()
{
@Override
public void ancestorAdded ( final AncestorEvent event )
{
hideCalendarPopup ();
}
@Override
public void ancestorRemoved ( final AncestorEvent event )
{
hideCalendarPopup ();
}
@Override
public void ancestorMoved ( final AncestorEvent event )
{
hideCalendarPopup ();
}
} );
addComponentListener ( new ComponentAdapter ()
{
@Override
public void componentHidden ( final ComponentEvent e )
{
hideCalendarPopup ();
}
} );
// Initial field date
updateFieldFromDate ();
// Initial styling settings
setDrawBorder ( drawBorder );
setRound ( WebDateFieldStyle.round );
setShadeWidth ( WebDateFieldStyle.shadeWidth );
}
/**
* {@inheritDoc}
*/
@Override
public void setRound ( final int round )
{
super.setRound ( round );
popupButton.setRound ( round );
}
/**
* {@inheritDoc}
*/
@Override
public void setDrawBorder ( final boolean drawBorder )
{
super.setDrawBorder ( drawBorder );
updateMargin ();
}
/**
* Updates field margin.
*/
protected void updateMargin ()
{
setMargin ( isDrawBorder () ? WebDateFieldStyle.margin : WebDateFieldStyle.undecoratedMargin );
}
/**
* Displays calendar popup.
*/
protected void showCalendarPopup ()
{
// Checking that component is eligable for focus request
if ( !requestFocusInWindow () && !isFocusOwner () )
{
// Cancel operation if component is not eligable for focus yet
// This might occur if some other component input verifier holds the focus or in some other rare cases
return;
}
// Updating date from field
setDateFromField ();
// Create popup if it doesn't exist
if ( popup == null || calendar == null )
{
final Window ancestor = SwingUtils.getWindowAncestor ( this );
// Calendar
calendar = new WebCalendar ( date );
calendar.setPaintFocus ( false );
calendar.setRound ( StyleConstants.smallRound );
calendar.setShadeWidth ( 0 );
// Popup window
popup = new WebWindow ( ancestor );
popup.setLayout ( new BorderLayout () );
popup.setCloseOnFocusLoss ( true );
popup.setWindowOpaque ( false );
popup.add ( calendar );
customizePopup ( popup );
popup.pack ();
// Correct popup positioning
updatePopupLocation ();
ancestor.addPropertyChangeListener ( WebLookAndFeel.ORIENTATION_PROPERTY, new PropertyChangeListener ()
{
@Override
public void propertyChange ( final PropertyChangeEvent evt )
{
if ( popup.isShowing () )
{
updatePopupLocation ();
}
}
} );
// Selection listener
dateSelectionListener = new DateSelectionListener ()
{
@Override
public void dateSelected ( final Date date )
{
hideCalendarPopup ();
setDateFromCalendar ();
requestFocusInWindow ();
}
};
calendar.addDateSelectionListener ( dateSelectionListener );
}
else
{
// Updating window location
updatePopupLocation ();
}
// Applying orientation to popup
SwingUtils.copyOrientation ( WebDateField.this, popup );
// Showing popup and changing focus
popup.setVisible ( true );
calendar.transferFocus ();
}
@SuppressWarnings ("UnusedParameters")
protected void customizePopup ( final WebWindow popup )
{
// You can customize date field popup window here
}
/**
* Hides calendar popup.
*/
protected void hideCalendarPopup ()
{
if ( popup != null )
{
popup.setVisible ( false );
}
}
/**
* Updates calendar popup location.
*/
protected void updatePopupLocation ()
{
final Point los = WebDateField.this.getLocationOnScreen ();
final Rectangle gb = popup.getGraphicsConfiguration ().getBounds ();
final int shadeWidth = isDrawBorder () ? getShadeWidth () : 0;
final boolean ltr = WebDateField.this.getComponentOrientation ().isLeftToRight ();
final int w = WebDateField.this.getWidth ();
final int h = WebDateField.this.getHeight ();
final int x;
if ( ltr )
{
if ( los.x + shadeWidth + popup.getWidth () <= gb.x + gb.width )
{
x = los.x + shadeWidth;
}
else
{
x = los.x + w - shadeWidth - popup.getWidth ();
}
}
else
{
if ( los.x + w - shadeWidth - popup.getWidth () >= gb.x )
{
x = los.x + w - shadeWidth - popup.getWidth ();
}
else
{
x = los.x + shadeWidth;
}
}
final int y;
if ( los.y + h + popup.getHeight () <= gb.y + gb.height )
{
y = los.y + h + ( isDrawBorder () ? 0 : 1 );
}
else
{
y = los.y - popup.getHeight () - ( isDrawBorder () ? 0 : 1 );
}
popup.setLocation ( x, y );
}
/**
* Returns date specified in text field.
*
* @return date specified in text field
*/
protected Date getDateFromField ()
{
try
{
final String text = getText ();
if ( text != null && !text.trim ().equals ( "" ) )
{
return dateFormat.parse ( text );
}
else
{
return null;
}
}
catch ( final Throwable ex )
{
return date;
}
}
/**
* Returns text date representation according to date format.
*
* @return text date representation according to date format
*/
protected String getTextDate ()
{
return date != null ? dateFormat.format ( date ) : "";
}
/**
* Returns currently selected date.
*
* @return currently selected date
*/
public Date getDate ()
{
return date;
}
/**
* Sets currently selected date.
*
* @param date new selected date
*/
public void setDate ( final Date date )
{
setDateImpl ( date, UpdateSource.other );
}
/**
* Updates date using the value from field.
*/
protected void setDateFromField ()
{
setDateImpl ( getDateFromField (), UpdateSource.field );
}
/**
* Updates date using the value from calendar.
*/
protected void setDateFromCalendar ()
{
setDateImpl ( calendar.getDate (), UpdateSource.calendar );
}
/**
* Sets currently selected date and updates component depending on update source.
*
* @param date new selected date
*/
protected void setDateImpl ( final Date date, final UpdateSource source )
{
final boolean changed = !CompareUtils.equals ( this.date, date );
this.date = date;
// Updating field text even if there is no changes
// Text still might change due to formatting pattern
updateFieldFromDate ();
if ( changed )
{
// Updating calendar date
if ( source != UpdateSource.calendar && calendar != null )
{
updateCalendarFromDate ( date );
}
// Informing about date selection changes
fireDateSelected ( date );
}
}
/**
* Updates text field with currently selected date.
*/
protected void updateFieldFromDate ()
{
setText ( getTextDate () );
}
/**
* Updates date displayed in calendar.
*
* @param date new displayed date
*/
protected void updateCalendarFromDate ( final Date date )
{
calendar.removeDateSelectionListener ( dateSelectionListener );
calendar.setDate ( date, false );
calendar.addDateSelectionListener ( dateSelectionListener );
}
/**
* Returns date format.
*
* @return date format
*/
public SimpleDateFormat getDateFormat ()
{
return dateFormat;
}
/**
* Sets date format.
*
* @param dateFormat date format
*/
public void setDateFormat ( final SimpleDateFormat dateFormat )
{
this.dateFormat = dateFormat;
updateFieldFromDate ();
}
/**
* {@inheritDoc}
*/
@Override
public void setEnabled ( final boolean enabled )
{
super.setEnabled ( enabled );
popupButton.setEnabled ( enabled );
}
/**
* Adds date selection listener.
*
* @param listener date selection listener to add
*/
public void addDateSelectionListener ( final DateSelectionListener listener )
{
dateSelectionListeners.add ( listener );
}
/**
* Removes date selection listener.
*
* @param listener date selection listener to remove
*/
public void removeDateSelectionListener ( final DateSelectionListener listener )
{
dateSelectionListeners.remove ( listener );
}
/**
* Notifies about date selection change.
*
* @param date new selected date
*/
public void fireDateSelected ( final Date date )
{
for ( final DateSelectionListener listener : CollectionUtils.copy ( dateSelectionListeners ) )
{
listener.dateSelected ( date );
}
}
/**
* {@inheritDoc}
*/
@Override
public int getPreferredWidth ()
{
return SizeUtils.getPreferredWidth ( this );
}
/**
* {@inheritDoc}
*/
@Override
public WebDateField setPreferredWidth ( final int preferredWidth )
{
return SizeUtils.setPreferredWidth ( this, preferredWidth );
}
/**
* {@inheritDoc}
*/
@Override
public int getPreferredHeight ()
{
return SizeUtils.getPreferredHeight ( this );
}
/**
* {@inheritDoc}
*/
@Override
public WebDateField setPreferredHeight ( final int preferredHeight )
{
return SizeUtils.setPreferredHeight ( this, preferredHeight );
}
/**
* {@inheritDoc}
*/
@Override
public int getMinimumWidth ()
{
return SizeUtils.getMinimumWidth ( this );
}
/**
* {@inheritDoc}
*/
@Override
public WebDateField setMinimumWidth ( final int minimumWidth )
{
return SizeUtils.setMinimumWidth ( this, minimumWidth );
}
/**
* {@inheritDoc}
*/
@Override
public int getMinimumHeight ()
{
return SizeUtils.getMinimumHeight ( this );
}
/**
* {@inheritDoc}
*/
@Override
public WebDateField setMinimumHeight ( final int minimumHeight )
{
return SizeUtils.setMinimumHeight ( this, minimumHeight );
}
/**
* {@inheritDoc}
*/
@Override
public Dimension getPreferredSize ()
{
return SizeUtils.getPreferredSize ( this, super.getPreferredSize () );
}
/**
* This enumeration represents the type of source that caused view update.
*/
protected enum UpdateSource
{
/**
* Text field source.
*/
field,
/**
* Calendar source.
*/
calendar,
/**
* Other source.
*/
other
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy