OceanusDateConfig.java
/*******************************************************************************
* Oceanus: Java Utilities
* Copyright 2012,2025 Tony Washer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package net.sourceforge.joceanus.oceanus.date;
import java.time.LocalDate;
import java.util.Locale;
import java.util.function.Predicate;
import net.sourceforge.joceanus.oceanus.event.OceanusEventManager;
import net.sourceforge.joceanus.oceanus.event.OceanusEventRegistrar;
import net.sourceforge.joceanus.oceanus.event.OceanusEventRegistrar.OceanusEventProvider;
/**
* Date Configuration.
*/
public class OceanusDateConfig
implements OceanusEventProvider<OceanusDateEvent> {
/**
* The Event Manager.
*/
private final OceanusEventManager<OceanusDateEvent> theEventManager;
/**
* The formatter.
*/
private final OceanusDateFormatter theFormatter;
/**
* The Locale.
*/
private Locale theLocale;
/**
* Show Narrow days.
*/
private boolean doShowNarrowDays;
/**
* Allow null date selection.
*/
private boolean allowNullDateSelection;
/**
* The selected date.
*/
private OceanusDate theSelected;
/**
* The earliest select-able date (or null if no lower bound).
*/
private OceanusDate theEarliest;
/**
* The latest select-able date (or null if no upper bound).
*/
private OceanusDate theLatest;
/**
* The list of disallowed dates.
*/
private Predicate<OceanusDate> theAllowed;
/**
* The active display month.
*/
private OceanusDate theMonth;
/**
* Constructor.
* @param pFormatter the date formatter
*/
public OceanusDateConfig(final OceanusDateFormatter pFormatter) {
/* Create resources */
theFormatter = pFormatter;
theEventManager = new OceanusEventManager<>();
setLocale(pFormatter.getLocale());
/* Initialise the allowed predicate */
theAllowed = d -> true;
/* Listen to locale changes */
theFormatter.getEventRegistrar().addEventListener(e -> setLocale(theFormatter.getLocale()));
}
@Override
public OceanusEventRegistrar<OceanusDateEvent> getEventRegistrar() {
return theEventManager.getEventRegistrar();
}
/**
* Get the locale.
* @return the locale
*/
public Locale getLocale() {
return theLocale;
}
/**
* Get the selected date.
* @return the Selected date
*/
public OceanusDate getSelectedDate() {
return theSelected;
}
/**
* Get the earliest select-able date.
* @return the Earliest date
*/
public OceanusDate getEarliestDate() {
return theEarliest;
}
/**
* Get the latest select-able date.
* @return the Latest date
*/
public OceanusDate getLatestDate() {
return theLatest;
}
/**
* Get the current month.
* @return the current month
*/
public OceanusDate getCurrentMonth() {
return theMonth;
}
/**
* Allow Null Date selection.
* @return true/false
*/
public boolean allowNullDateSelection() {
return allowNullDateSelection;
}
/**
* Show Narrow Days.
* @return true/false
*/
public boolean showNarrowDays() {
return doShowNarrowDays;
}
/**
* Set the Allowed predicate.
* @param pAllowed the predicate
*/
public void setAllowed(final Predicate<OceanusDate> pAllowed) {
theAllowed = pAllowed;
}
/**
* Determine whether the day in the month is allowed.
* @param pDay the day of the current month
* @return true/false
*/
public boolean isAllowed(final int pDay) {
final OceanusDate myDate = new OceanusDate(theMonth);
myDate.adjustDay(pDay - 1);
return theAllowed.test(myDate);
}
/**
* Set the Locale.
* @param pLocale the Locale
*/
public final void setLocale(final Locale pLocale) {
/* Store locale */
theLocale = pLocale;
/* Request rebuild of names */
rebuildNames();
}
/**
* Allow null date selection. If this flag is set an additional button will be displayed
* allowing the user to explicitly select no date, thus setting the SelectedDate to null.
* @param pAllowNullDateSelection true/false
*/
public void setAllowNullDateSelection(final boolean pAllowNullDateSelection) {
allowNullDateSelection = pAllowNullDateSelection;
}
/**
* Show Narrow Days. If this flag is set Days are show in narrow rather than short form.
* @param pShowNarrowDays true/false
*/
public void setShowNarrowDays(final boolean pShowNarrowDays) {
/* Set options */
doShowNarrowDays = pShowNarrowDays;
/* Request rebuild of names */
rebuildNames();
}
/**
* Rebuild names.
*/
protected final void rebuildNames() {
/* Fire event */
theEventManager.fireEvent(OceanusDateEvent.FORMATCHANGED);
}
/**
* Set the earliest date. This is the earliest date that may be selected. If the configured
* latest date is earlier than this date, it will be set to this date to ensure a valid range.
* @param pEarliest the Earliest select-able date (or null if unlimited)
*/
public final void setEarliestDate(final OceanusDate pEarliest) {
/* Default the field to null */
theEarliest = null;
/* If we have an earliest */
if (pEarliest != null) {
/* Store the date */
theEarliest = pEarliest;
/* If we have a latest date, reset if necessary */
if (theLatest != null
&& theLatest.compareTo(theEarliest) < 0) {
theLatest = theEarliest;
}
}
}
/**
* Set the latest date. This is the latest date that may be selected. If the configured earliest
* date is later than this date, it will be set to this date to ensure a valid range.
* @param pLatest the Latest select-able date (or null if unlimited)
*/
public final void setLatestDate(final OceanusDate pLatest) {
/* Null the field */
theLatest = null;
/* If we have an earliest */
if (pLatest != null) {
/* Store the date */
theLatest = pLatest;
/* If we have an earliest date, reset if necessary */
if (theEarliest != null
&& theLatest.compareTo(theEarliest) < 0) {
theEarliest = theLatest;
}
}
}
/**
* Format a date according to configured rules.
* @param pDate the date to format
* @return the formatted date
*/
public String formatDate(final LocalDate pDate) {
/* Handle null */
if (pDate == null) {
return null;
}
/* Format the date */
return theFormatter.formatLocalDate(pDate);
}
/**
* Capitalise first letter of string.
* @param pValue the string to capitalise the first letter of
* @return the capitalised string
*/
public String capitaliseString(final String pValue) {
String myValue = pValue;
/* If the first UniCode item is lowerCase */
if (Character.isLowerCase(pValue.codePointAt(0))) {
/* Locate the length of the first character */
final int iCharLen = pValue.offsetByCodePoints(0, 1);
/* UpperCase the first iCharLen letters */
myValue = pValue.substring(0, iCharLen).toUpperCase(theLocale)
+ pValue.substring(iCharLen);
}
/* Return the capitalised value */
return myValue;
}
/**
* Obtain current date.
* @return the current date
*/
public OceanusDate currentDate() {
return new OceanusDate();
}
/**
* Obtain current day of month or zero if not current month.
* @return the current month day
*/
public int getCurrentDay() {
final OceanusDate myDate = currentDate();
return isSameMonth(myDate, theMonth)
? myDate.getDay()
: 0;
}
/**
* Obtain Selected day of month or zero if not current month.
* @return the selected month day
*/
public int getSelectedDay() {
final OceanusDate myDate = getSelectedDate();
return isSameMonth(myDate, theMonth)
? myDate.getDay()
: 0;
}
/**
* Obtain Earliest day of month or zero if not current month.
* @return the earliest month day
*/
public int getEarliestDay() {
return isSameMonth(theEarliest, theMonth)
? theEarliest.getDay()
: 0;
}
/**
* Obtain Latest day of month or zero if not current month.
* @return the latest month day
*/
public int getLatestDay() {
return isSameMonth(theLatest, theMonth)
? theLatest.getDay()
: 0;
}
/**
* Adjust current month to previous month.
*/
public void previousMonth() {
theMonth.adjustMonth(-1);
}
/**
* Adjust current month to next month.
*/
public void nextMonth() {
theMonth.adjustMonth(1);
}
/**
* Adjust current month to previous year.
*/
public void previousYear() {
theMonth.adjustYear(-1);
if (theEarliest != null
&& theMonth.compareTo(theEarliest) < 0) {
theMonth = new OceanusDate(theEarliest);
theMonth.startCalendarMonth();
}
}
/**
* Adjust current month to next year.
*/
public void nextYear() {
theMonth.adjustYear(1);
if (theLatest != null
&& theMonth.compareTo(theLatest) > 0) {
theMonth = new OceanusDate(theLatest);
theMonth.startCalendarMonth();
}
}
/**
* Set the selected date.
* @param pDate the Selected date
*/
public final void setSelectedDate(final OceanusDate pDate) {
/* Store the date */
theSelected = pDate;
}
/**
* Set selected day in current month (called from dialog).
* @param pDay the selected day
*/
public void setSelectedDay(final int pDay) {
final OceanusDate myOld = getSelectedDate();
OceanusDate myNew = null;
/* If we are selecting a proper date */
if (pDay > 0) {
/* Build the new selected date */
myNew = new OceanusDate(theMonth);
myNew.adjustDay(pDay - 1);
}
/* Ignore if there is no change */
if (!isDateChanged(myOld, myNew)) {
return;
}
/* Store the explicitly selected date */
theSelected = myNew;
}
/**
* Initialise the current month.
*/
public void initialiseCurrent() {
/* Access Selected Date */
OceanusDate myDate = theSelected;
if (myDate == null) {
myDate = currentDate();
}
/* Move to start date if we are earlier */
if (theEarliest != null
&& myDate.compareTo(theEarliest) < 0) {
myDate = theEarliest;
}
/* Move to end date if we are later */
if (theLatest != null
&& myDate.compareTo(theLatest) > 0) {
myDate = theLatest;
}
/* Set to 1st of month and record it */
theMonth = new OceanusDate(myDate);
theMonth.startCalendarMonth();
}
/**
* Has the date changed?
* @param pFirst the first date
* @param pSecond the second date
* @return <code>true/false</code>
*/
public static boolean isDateChanged(final OceanusDate pFirst,
final OceanusDate pSecond) {
if (pFirst == null) {
return pSecond != null;
} else {
return !pFirst.equals(pSecond);
}
}
/**
* Are the dates in the same month.
* @param pFirst the first date (maybe null)
* @param pSecond the second date
* @return true/false
*/
public static boolean isSameMonth(final OceanusDate pFirst,
final OceanusDate pSecond) {
if (!isSameYear(pFirst, pSecond)) {
return false;
} else {
return pFirst.getMonth() == pSecond.getMonth();
}
}
/**
* Are the dates in the same year.
* @param pFirst the first date (maybe null)
* @param pSecond the second date
* @return true/false
*/
public static boolean isSameYear(final OceanusDate pFirst,
final OceanusDate pSecond) {
if (pFirst == null) {
return false;
}
return pFirst.getYear() == pSecond.getYear();
}
}