mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-08-25 21:17:03 +00:00
838 lines
24 KiB
Plaintext
838 lines
24 KiB
Plaintext
/* CPDatePicker.j
|
|
* AppKit
|
|
*
|
|
* Created by Alexandre Wilhelm
|
|
* Copyright 2012 <alexandre.wilhelmfr@gmail.com>
|
|
*
|
|
* This library 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 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This 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
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
@import "CPControl.j"
|
|
@import "CPFont.j"
|
|
@import "CPTextField.j"
|
|
@import "_CPDatePickerTextField.j"
|
|
@import "_CPDatePickerCalendar.j"
|
|
|
|
@import <Foundation/CPArray.j>
|
|
@import <Foundation/CPObject.j>
|
|
@import <Foundation/CPDate.j>
|
|
@import <Foundation/CPLocale.j>
|
|
@import <Foundation/CPTimeZone.j>
|
|
|
|
@class CPStepper
|
|
@class CPApp
|
|
|
|
@global CPLocaleLanguageCode
|
|
@global CPDateFormatterShortStyle
|
|
|
|
var CPDatePicker_validateProposedDateValue_timeInterval = 1 << 1;
|
|
|
|
CPSingleDateMode = 0;
|
|
CPRangeDateMode = 1;
|
|
|
|
CPTextFieldAndStepperDatePickerStyle = 0;
|
|
CPClockAndCalendarDatePickerStyle = 1;
|
|
CPTextFieldDatePickerStyle = 2;
|
|
|
|
CPHourMinuteDatePickerElementFlag = 0x000c;
|
|
CPHourMinuteSecondDatePickerElementFlag = 0x000e;
|
|
CPTimeZoneDatePickerElementFlag = 0x0010;
|
|
CPYearMonthDatePickerElementFlag = 0x00c0;
|
|
CPYearMonthDayDatePickerElementFlag = 0x00e0;
|
|
CPEraDatePickerElementFlag = 0x0100;
|
|
|
|
/*!
|
|
@ingroup appkit
|
|
This control displays a datepicker in a Cappuccino application
|
|
*/
|
|
@implementation CPDatePicker : CPControl
|
|
{
|
|
BOOL _isBordered @accessors(getter=isBordered, setter=setBordered:);
|
|
BOOL _isBezeled @accessors(getter=isBezeled, setter=setBezeled:);
|
|
BOOL _drawsBackground @accessors(property=drawsBackground);
|
|
CPDate _dateValue @accessors(property=dateValue);
|
|
CPDate _minDate @accessors(property=minDate);
|
|
CPDate _maxDate @accessors(property=maxDate);
|
|
CPFont _textFont @accessors(property=textFont);
|
|
CPLocale _locale @accessors(property=locale);
|
|
//CPCalendar _calendar @accessors(property=calendar);
|
|
CPTimeZone _timeZone @accessors(property=timeZone);
|
|
id _delegate @accessors(property=delegate);
|
|
CPInteger _datePickerElements @accessors(property=datePickerElements);
|
|
CPInteger _datePickerMode @accessors(property=datePickerMode);
|
|
CPInteger _datePickerStyle @accessors(property=datePickerStyle);
|
|
CPInteger _timeInterval @accessors(property=timeInterval);
|
|
|
|
BOOL _invokedByUserEvent;
|
|
unsigned _implementedCDatePickerDelegateMethods;
|
|
BOOL _isTextual;
|
|
id _datePickerComponent;
|
|
}
|
|
|
|
|
|
#pragma mark -
|
|
#pragma mark Theme methods
|
|
|
|
+ (CPString)defaultThemeClass
|
|
{
|
|
return @"datePicker";
|
|
}
|
|
|
|
+ (CPDictionary)themeAttributes
|
|
{
|
|
return @{
|
|
@"bezel-color": [CPColor clearColor],
|
|
@"border-width" : 1.0,
|
|
@"border-color": [CPColor clearColor],
|
|
@"content-inset": CGInsetMakeZero(),
|
|
@"bezel-inset": CGInsetMakeZero(),
|
|
@"datepicker-textfield-bezel-color": [CPColor clearColor],
|
|
@"min-size-datepicker-textfield": CGSizeMakeZero(),
|
|
@"content-inset-datepicker-textfield": CGInsetMakeZero(),
|
|
@"content-inset-datepicker-textfield-separator": CGInsetMakeZero(),
|
|
@"separator-content-inset": CGInsetMakeZero(),
|
|
@"date-hour-margin": 5.0,
|
|
@"stepper-margin": 5.0,
|
|
@"bezel-color-calendar": [CPColor clearColor],
|
|
@"title-text-color": [CPColor blackColor],
|
|
@"title-text-shadow-color": [CPColor clearColor],
|
|
@"title-text-shadow-offset": CGSizeMakeZero(),
|
|
@"title-font": [CPNull null],
|
|
@"weekday-text-color": [CPColor blackColor],
|
|
@"weekday-text-shadow-color": [CPColor clearColor],
|
|
@"weekday-text-shadow-offset": CGSizeMakeZero(),
|
|
@"weekday-font": [CPNull null],
|
|
@"arrow-image-left": [CPNull null],
|
|
@"arrow-image-right": [CPNull null],
|
|
@"arrow-image-left-highlighted": [CPNull null],
|
|
@"arrow-image-right-highlighted": [CPNull null],
|
|
@"arrow-inset": CGInsetMakeZero(),
|
|
@"circle-image": [CPNull null],
|
|
@"circle-image-highlighted": [CPNull null],
|
|
@"tile-text-color": [CPColor blackColor],
|
|
@"tile-text-shadow-color": [CPColor clearColor],
|
|
@"tile-text-shadow-offset": CGSizeMakeZero(),
|
|
@"tile-font": [CPNull null],
|
|
@"size-tile": CGSizeMakeZero(),
|
|
@"size-calendar": CGSizeMakeZero(),
|
|
@"size-header": CGSizeMakeZero(),
|
|
@"min-size-calendar": CGSizeMakeZero(),
|
|
@"max-size-calendar": CGSizeMakeZero(),
|
|
@"bezel-color-clock": [CPColor clearColor],
|
|
@"clock-text-color": [CPColor blackColor],
|
|
@"clock-text-shadow-color": [CPColor clearColor],
|
|
@"clock-text-shadow-offset": CGSizeMakeZero(),
|
|
@"clock-font": [CPNull null],
|
|
@"second-hand-image": [CPNull null],
|
|
@"hour-hand-image": [CPNull null],
|
|
@"middle-hand-image": [CPNull null],
|
|
@"minute-hand-image": [CPNull null],
|
|
@"size-clock": CGSizeMakeZero(),
|
|
@"second-hand-size": CGSizeMakeZero(),
|
|
@"hour-hand-size": CGSizeMakeZero(),
|
|
@"middle-hand-size": CGSizeMakeZero(),
|
|
@"minute-hand-size": CGSizeMakeZero(),
|
|
@"previous-button-size": CGSizeMakeZero(),
|
|
@"current-button-size": CGSizeMakeZero(),
|
|
@"next-button-size": CGSizeMakeZero(),
|
|
@"title-inset": [CPNull null],
|
|
@"day-label-inset": [CPNull null],
|
|
@"tile-content-inset": CGInsetMakeZero(),
|
|
@"tile-margin": [CPNull null],
|
|
@"tile-inset": CGInsetMakeZero(),
|
|
@"separator-color": [CPNull null],
|
|
@"separator-margin-width": 0,
|
|
@"separator-height": 0,
|
|
@"bezel-color-calendar-left": [CPNull null],
|
|
@"bezel-color-calendar-middle": [CPNull null],
|
|
@"bezel-color-calendar-right": [CPNull null],
|
|
@"tile-vertical-alignment": CPCenterVerticalTextAlignment,
|
|
@"tile-text-alignment": CPCenterTextAlignment,
|
|
@"hour-ampm-margin": 2,
|
|
@"time-separator-content-inset": CGInsetMakeZero(),
|
|
@"clock-second-hand-over": NO,
|
|
@"clock-draws-hours": NO,
|
|
@"clock-hours-font": [CPNull null],
|
|
@"clock-hours-text-color": [CPColor clearColor],
|
|
@"clock-hours-radius": 0,
|
|
@"calendar-clock-margin": 10,
|
|
@"clock-only-nib2cib-adjustment-frame": CPRectMakeZero(),
|
|
@"uses-focus-ring": NO
|
|
};
|
|
}
|
|
|
|
|
|
#pragma mark -
|
|
#pragma mark Binding methods
|
|
|
|
+ (Class)_binderClassForBinding:(CPString)theBinding
|
|
{
|
|
if (theBinding == CPValueBinding || theBinding == CPMinValueBinding || theBinding == CPMaxValueBinding)
|
|
return [_CPDatePickerValueBinder class];
|
|
|
|
return [super _binderClassForBinding:theBinding];
|
|
}
|
|
|
|
- (CPString)_replacementKeyPathForBinding:(CPString)aBinding
|
|
{
|
|
if (aBinding == CPValueBinding)
|
|
return @"dateValue";
|
|
|
|
if (aBinding == CPMinValueBinding)
|
|
return @"minDate";
|
|
|
|
if (aBinding == CPMaxValueBinding)
|
|
return @"maxDate";
|
|
|
|
return [super _replacementKeyPathForBinding:aBinding];
|
|
}
|
|
|
|
|
|
#pragma mark -
|
|
#pragma mark Init methods
|
|
|
|
- (id)initWithFrame:(CGRect)aFrame
|
|
{
|
|
if (self = [super initWithFrame:aFrame])
|
|
{
|
|
_drawsBackground = YES;
|
|
_datePickerStyle = CPTextFieldAndStepperDatePickerStyle;
|
|
_datePickerMode = CPSingleDateMode;
|
|
_datePickerElements = CPYearMonthDayDatePickerElementFlag | CPHourMinuteSecondDatePickerElementFlag;
|
|
_timeInterval = 0;
|
|
_implementedCDatePickerDelegateMethods = 0;
|
|
|
|
[self setObjectValue:[CPDate date]];
|
|
_minDate = [CPDate distantPast];
|
|
_maxDate = [CPDate distantFuture];
|
|
|
|
[self setBezeled:YES];
|
|
[self setBordered:YES];
|
|
|
|
[self _init];
|
|
}
|
|
|
|
return self
|
|
}
|
|
|
|
- (void)_init
|
|
{
|
|
if (!_locale)
|
|
_locale = [CPLocale currentLocale];
|
|
|
|
_datePickerComponent = nil;
|
|
|
|
[self _createComponents];
|
|
|
|
[self setNeedsDisplay:YES];
|
|
[self setNeedsLayout];
|
|
}
|
|
|
|
- (void)_createComponents
|
|
{
|
|
_isTextual = (_datePickerStyle == CPTextFieldAndStepperDatePickerStyle) || (_datePickerStyle == CPTextFieldDatePickerStyle);
|
|
|
|
if (_datePickerComponent)
|
|
{
|
|
[_datePickerComponent removeFromSuperview];
|
|
|
|
_datePickerComponent = nil;
|
|
}
|
|
|
|
_datePickerComponent = [[(_isTextual ? _CPDatePickerTextField : _CPDatePickerCalendar) alloc] initWithFrame:[self bounds] withDatePicker:self];
|
|
|
|
[_datePickerComponent setDateValue:_dateValue];
|
|
[_datePickerComponent setControlSize:[self controlSize]];
|
|
[_datePickerComponent setDatePickerElements:_datePickerElements];
|
|
|
|
// FIXME: Don't know why but next line will cause theme compilation to fail...
|
|
// Workaround: added "if PLATFORM(DOM)"
|
|
#if PLATFORM(DOM)
|
|
[_datePickerComponent setEnabled:[self isEnabled]];
|
|
#endif
|
|
|
|
if (_isTextual)
|
|
// We need to transmit text color to the text field version (Cocoa doesn't permit adapting the calendar view text color)
|
|
[_datePickerComponent setTextColor:[self textColor]];
|
|
|
|
[self addSubview:_datePickerComponent];
|
|
}
|
|
|
|
|
|
#pragma mark -
|
|
#pragma mark Control Size
|
|
|
|
- (void)setControlSize:(CPControlSize)aControlSize
|
|
{
|
|
[super setControlSize:aControlSize];
|
|
|
|
[_datePickerComponent setControlSize:aControlSize];
|
|
|
|
if (_isTextual)
|
|
[self _sizeToControlSize];
|
|
}
|
|
|
|
|
|
#pragma mark -
|
|
#pragma mark Delegate methods
|
|
|
|
/*! Set the delegate of the datePicker
|
|
@param aDelegate delegate of the datePicker
|
|
*/
|
|
- (void)setDelegate:(id)aDelegate
|
|
{
|
|
_delegate = aDelegate;
|
|
_implementedCDatePickerDelegateMethods = 0;
|
|
|
|
// Look if the delegate implements or not the delegate methods
|
|
if ([_delegate respondsToSelector:@selector(datePicker:validateProposedDateValue:timeInterval:)])
|
|
_implementedCDatePickerDelegateMethods |= CPDatePicker_validateProposedDateValue_timeInterval;
|
|
}
|
|
|
|
|
|
#pragma mark -
|
|
#pragma mark Layout method
|
|
|
|
/*! Layout the subviews
|
|
*/
|
|
- (void)layoutSubviews
|
|
{
|
|
[_datePickerComponent setNeedsLayout];
|
|
[_datePickerComponent setNeedsDisplay:YES];
|
|
}
|
|
|
|
#pragma mark -
|
|
#pragma mark Setter
|
|
|
|
/*! Return the objectValue of the datePicker. The objectValue should take the timeZoneEffect
|
|
*/
|
|
- (id)objectValue
|
|
{
|
|
// TODO : add timeZone effect. How to do it because js ???
|
|
return _dateValue
|
|
}
|
|
|
|
/*! Set the objectValue of the datePicker. It has to be a CPDate
|
|
@param aDateValue the dateValue
|
|
*/
|
|
- (void)setObjectValue:(CPDate)aValue
|
|
{
|
|
if (![aValue isKindOfClass:[CPDate class]])
|
|
return;
|
|
|
|
[self setDateValue:aValue];
|
|
}
|
|
|
|
/* Set the dateValue of the datePicker
|
|
@param aDateValue the dateValue
|
|
*/
|
|
- (void)setDateValue:(CPDate)aDateValue
|
|
{
|
|
if (aDateValue == nil)
|
|
return;
|
|
|
|
_invokedByUserEvent = NO;
|
|
[self _setDateValue:aDateValue timeInterval:_timeInterval];
|
|
}
|
|
|
|
/*! Set the dateValue and the timeInterval. This method checks the min and max date of the datePicker also. It will call the delegate if possible.
|
|
@param aDateValue the dateValue
|
|
@param aTimeInterval the timeInterval
|
|
*/
|
|
- (void)_setDateValue:(CPDate)aDateValue timeInterval:(CPTimeInterval)aTimeInterval
|
|
{
|
|
// Make sure to have a valid date and avoid NaN values
|
|
if (!isFinite(aDateValue))
|
|
{
|
|
[CPException raise:CPInvalidArgumentException
|
|
reason:@"aDateValue is not valid"];
|
|
return;
|
|
}
|
|
|
|
if (_minDate)
|
|
aDateValue = new Date (MAX(aDateValue, _minDate));
|
|
|
|
if (_maxDate)
|
|
aDateValue = new Date (MIN(aDateValue, _maxDate));
|
|
|
|
aTimeInterval = MAX(MIN(aTimeInterval, [_maxDate timeIntervalSinceDate:aDateValue]), [_minDate timeIntervalSinceDate:aDateValue]);
|
|
|
|
if ([aDateValue isEqualToDate:_dateValue] && aTimeInterval == _timeInterval)
|
|
{
|
|
[_datePickerComponent setDateValue:_dateValue];
|
|
|
|
return;
|
|
}
|
|
|
|
if (_implementedCDatePickerDelegateMethods & CPDatePicker_validateProposedDateValue_timeInterval)
|
|
{
|
|
// constrain timeInterval also
|
|
var aStartDateRef = function(x){if (typeof x == 'undefined') return aDateValue; aDateValue = x;};
|
|
var aTimeIntervalRef = function(x){if (typeof x == 'undefined') return aTimeInterval; aTimeInterval = x;};
|
|
|
|
[_delegate datePicker:self validateProposedDateValue:aStartDateRef timeInterval:aTimeIntervalRef];
|
|
}
|
|
|
|
[self willChangeValueForKey:@"objectValue"];
|
|
[self willChangeValueForKey:@"dateValue"];
|
|
_dateValue = aDateValue;
|
|
[super setObjectValue:_dateValue];
|
|
[self didChangeValueForKey:@"objectValue"];
|
|
[self didChangeValueForKey:@"dateValue"];
|
|
|
|
[self willChangeValueForKey:@"timeInterval"];
|
|
_timeInterval = (_datePickerMode == CPSingleDateMode)? 0 : aTimeInterval;
|
|
[self didChangeValueForKey:@"timeInterval"];
|
|
|
|
if (_invokedByUserEvent)
|
|
[self sendAction:[self action] to:[self target]];
|
|
|
|
[_datePickerComponent setDateValue:_dateValue];
|
|
}
|
|
|
|
/*! Set the minDate of the datePicker
|
|
@param aMinDate the minDate
|
|
*/
|
|
- (void)setMinDate:(CPDate)aMinDate
|
|
{
|
|
if (_minDate === aMinDate)
|
|
return;
|
|
|
|
[self willChangeValueForKey:@"minDate"];
|
|
_minDate = aMinDate;
|
|
[self didChangeValueForKey:@"minDate"];
|
|
|
|
[self _setDateValue:_dateValue timeInterval:_timeInterval];
|
|
}
|
|
|
|
/*! Set the maxDate of the datePicker
|
|
@param aMaxDate the maxDate
|
|
*/
|
|
- (void)setMaxDate:(CPDate)aMaxDate
|
|
{
|
|
if (_maxDate === aMaxDate)
|
|
return;
|
|
|
|
[self willChangeValueForKey:@"maxDate"];
|
|
_maxDate = aMaxDate;
|
|
[self didChangeValueForKey:@"maxDate"];
|
|
|
|
[self _setDateValue:_dateValue timeInterval:_timeInterval];
|
|
}
|
|
|
|
/*! Set the syle of the datePicker
|
|
@param aDatePickerStyle the datePicker style
|
|
*/
|
|
- (void)setDatePickerStyle:(CPInteger)aDatePickerStyle
|
|
{
|
|
if (_datePickerStyle === aDatePickerStyle)
|
|
return;
|
|
|
|
_datePickerStyle = aDatePickerStyle;
|
|
|
|
// This is needed in order to specify different theme attributes values for textual / graphical date picker
|
|
if (_datePickerStyle === CPClockAndCalendarDatePickerStyle)
|
|
[self setThemeState:CPThemeStateAlternateState];
|
|
else
|
|
[self unsetThemeState:CPThemeStateAlternateState];
|
|
|
|
// This is needed in order to specify different theme attributes values for with / without stepper textual date picker
|
|
if (_datePickerStyle === CPTextFieldAndStepperDatePickerStyle)
|
|
[self setThemeState:CPThemeStateComposedControl];
|
|
else
|
|
[self unsetThemeState:CPThemeStateComposedControl];
|
|
|
|
[self setControlSize:[self controlSize]];
|
|
|
|
if (_datePickerComponent)
|
|
{
|
|
// We already have a component so we need to update it
|
|
[_datePickerComponent resignFirstResponder];
|
|
[self _createComponents];
|
|
}
|
|
|
|
[self setNeedsDisplay:YES];
|
|
[self setNeedsLayout];
|
|
}
|
|
|
|
/*! Set the elements of the datePicker
|
|
@param aDatePickerElements the datePicker elements
|
|
*/
|
|
- (void)setDatePickerElements:(CPInteger)aDatePickerElements
|
|
{
|
|
if (_datePickerElements === aDatePickerElements)
|
|
return;
|
|
|
|
_datePickerElements = aDatePickerElements;
|
|
|
|
// Notify the component of the new value
|
|
[_datePickerComponent setDatePickerElements:_datePickerElements];
|
|
|
|
[self setNeedsDisplay:YES];
|
|
[self setNeedsLayout];
|
|
}
|
|
|
|
/*! Set the mode of the datePicker
|
|
@param aDatePickerMode the datePicker mode
|
|
*/
|
|
- (void)setDatePickerMode:(CPInteger)aDatePickerMode
|
|
{
|
|
if (_datePickerMode === aDatePickerMode)
|
|
return;
|
|
|
|
_datePickerMode = aDatePickerMode;
|
|
|
|
if (_datePickerMode == CPSingleDateMode)
|
|
[self _setDateValue:[self dateValue] timeInterval:0];
|
|
|
|
[self setNeedsDisplay:YES];
|
|
[self setNeedsLayout];
|
|
}
|
|
|
|
/*! Set the timeInterval of the datePicker
|
|
@param aTimeInterval the timeInterval of the datePicker
|
|
*/
|
|
- (void)setTimeInterval:(CPInteger)aTimeInterval
|
|
{
|
|
if (_datePickerMode == CPSingleDateMode)
|
|
return;
|
|
|
|
[self _setDateValue:[self dateValue] timeInterval:aTimeInterval];
|
|
}
|
|
|
|
/*! Set the locale of the datePicker. This update laso the locale of the formatter.
|
|
@param aLocale the locale
|
|
*/
|
|
- (void)setLocale:(CPLocale)aLocale
|
|
{
|
|
if (_locale === aLocale)
|
|
return;
|
|
|
|
_locale = aLocale;
|
|
|
|
if (_formatter)
|
|
{
|
|
[self willChangeValueForKey:@"locale"];
|
|
[_formatter setLocale:_locale];
|
|
[self didChangeValueForKey:@"locale"];
|
|
}
|
|
|
|
// This will update the textFields (usefull when changing with a date with pm and am)
|
|
if (_isTextual)
|
|
[_datePickerComponent setDateValue:_dateValue];
|
|
|
|
[self setNeedsDisplay:YES];
|
|
[self setNeedsLayout];
|
|
}
|
|
|
|
/*!
|
|
Sets whether the datepicker will have a bezeled border.
|
|
@param shouldBeBezeled \c YES means the datepicker will draw a bezeled border
|
|
*/
|
|
- (void)setBezeled:(BOOL)shouldBeBezeled
|
|
{
|
|
if (_isBezeled === shouldBeBezeled)
|
|
return;
|
|
|
|
_isBezeled = shouldBeBezeled;
|
|
|
|
if (shouldBeBezeled)
|
|
[self setThemeState:CPThemeStateBezeled];
|
|
else
|
|
[self unsetThemeState:CPThemeStateBezeled];
|
|
}
|
|
|
|
/*!
|
|
Sets whether the datepicker will have a border drawn. (actually it does nothing)
|
|
@param shouldBeBordered \c YES makes the datepicker draw a border
|
|
*/
|
|
- (void)setBordered:(BOOL)shouldBeBordered
|
|
{
|
|
if (_isBordered === shouldBeBordered)
|
|
return;
|
|
|
|
_isBordered = shouldBeBordered;
|
|
|
|
if (shouldBeBordered)
|
|
[self setThemeState:CPThemeStateBordered];
|
|
else
|
|
[self unsetThemeState:CPThemeStateBordered];
|
|
}
|
|
|
|
/*!
|
|
Sets the font of the control.
|
|
@param aFont
|
|
*/
|
|
- (void)setTextFont:(CPFont)aFont
|
|
{
|
|
[self setFont:aFont];
|
|
|
|
if (_isTextual)
|
|
[_datePickerComponent setTextFont:aFont];
|
|
}
|
|
|
|
/*!
|
|
Sets the color of the control.
|
|
@param aColor
|
|
*/
|
|
- (void)setTextColor:(CPColor)aColor
|
|
{
|
|
[super setTextColor:aColor];
|
|
|
|
if (_isTextual)
|
|
[_datePickerComponent setTextColor:aColor];
|
|
// REM: in Cocoa, setTextColor has no effect on calendar view
|
|
}
|
|
|
|
/*! Sets the enabled status of the control. Controls that are not enabled can not be used by the user and obtain the CPThemeStateDisabled theme state.
|
|
@param a boolean. YES if the control should be enabled, otherwise NO.
|
|
*/
|
|
- (void)setEnabled:(BOOL)aBoolean
|
|
{
|
|
[super setEnabled:aBoolean];
|
|
|
|
[_datePickerComponent setEnabled:aBoolean];
|
|
|
|
if (!aBoolean)
|
|
[self resignFirstResponder];
|
|
}
|
|
|
|
/*! Set the background color of the datePicker
|
|
@param aColor
|
|
*/
|
|
- (void)setBackgroundColor:(CPColor)aColor
|
|
{
|
|
_backgroundColor = aColor;
|
|
[self setNeedsLayout];
|
|
}
|
|
|
|
/*! Set the boolean drawsBackgroundColor
|
|
@param aBoolean
|
|
*/
|
|
- (void)setDrawsBackground:(BOOL)aBoolean
|
|
{
|
|
if (_drawsBackground === aBoolean)
|
|
return;
|
|
|
|
[self willChangeValueForKey:@"drawsBackground"];
|
|
_drawsBackground = aBoolean;
|
|
[self didChangeValueForKey:@"drawsBackground"];
|
|
|
|
[self setNeedsLayout];
|
|
}
|
|
|
|
/*! Set the timeZone
|
|
@param aTimeZone
|
|
*/
|
|
- (void)setTimeZone:(CPTimeZone)aTimeZone
|
|
{
|
|
if (_timeZone === aTimeZone)
|
|
return;
|
|
|
|
[self willChangeValueForKey:@"timeZone"];
|
|
_timeZone = aTimeZone;
|
|
[self didChangeValueForKey:@"timeZone"];
|
|
|
|
[self setNeedsLayout];
|
|
|
|
[_datePickerComponent setDateValue:_dateValue];
|
|
}
|
|
|
|
|
|
#pragma mark -
|
|
#pragma mark First responder methods
|
|
|
|
/*! Return YES if style is set to CPTextFieldAndStepperDatePickerStyle or CPTextFieldDatePickerStyle
|
|
*/
|
|
- (BOOL)becomeFirstResponder
|
|
{
|
|
if (_isTextual)
|
|
{
|
|
if (![super becomeFirstResponder])
|
|
return NO;
|
|
|
|
[_datePickerComponent _selectTextFieldWithFlags:[[CPApp currentEvent] modifierFlags]];
|
|
|
|
return YES;
|
|
}
|
|
|
|
return NO;
|
|
}
|
|
|
|
/*! Return YES
|
|
*/
|
|
- (BOOL)acceptsFirstResponder
|
|
{
|
|
return YES;
|
|
}
|
|
|
|
/*! Return YES
|
|
*/
|
|
- (BOOL)resignFirstResponder
|
|
{
|
|
if (_isTextual)
|
|
[_datePickerComponent resignFirstResponder];
|
|
|
|
return YES;
|
|
}
|
|
|
|
|
|
#pragma mark -
|
|
#pragma mark getter
|
|
|
|
/*!
|
|
Returns \c YES if the textfield is bezeled.
|
|
*/
|
|
- (BOOL)isBezeled
|
|
{
|
|
return [self hasThemeState:CPThemeStateBezeled];
|
|
}
|
|
|
|
/*!
|
|
Returns \c YES if the textfield has a border.
|
|
*/
|
|
- (BOOL)isBordered
|
|
{
|
|
return [self hasThemeState:CPThemeStateBordered];
|
|
}
|
|
|
|
/*!
|
|
Returns the font of the control.
|
|
*/
|
|
- (CPFont)textFont
|
|
{
|
|
return [self font];
|
|
}
|
|
|
|
/*! Check if we are in the american format or not. Depending on the locale
|
|
*/
|
|
- (BOOL)_isAmericanFormat
|
|
{
|
|
return [[_locale objectForKey:CPLocaleCountryCode] isEqualToString:@"US"];
|
|
}
|
|
|
|
#pragma mark -
|
|
#pragma mark Key event
|
|
|
|
/*! Key down event
|
|
@param anEvent
|
|
*/
|
|
- (void)keyDown:(CPEvent)anEvent
|
|
{
|
|
if (_isTextual)
|
|
[_datePickerComponent keyDown:anEvent];
|
|
}
|
|
|
|
@end
|
|
|
|
var CPDatePickerModeKey = @"CPDatePickerModeKey",
|
|
CPIntervalKey = @"CPIntervalKey",
|
|
CPMinDateKey = @"CPMinDateKey",
|
|
CPMaxDateKey = @"CPMaxDateKey",
|
|
CPBackgroundColorKey = @"CPBackgroundColorKey",
|
|
CPDrawsBackgroundKey = @"CPDrawsBackgroundKey",
|
|
CPTextFontKey = @"CPTextFontKey",
|
|
CPDatePickerElementsKey = @"CPDatePickerElementsKey",
|
|
CPDatePickerStyleKey = @"CPDatePickerStyleKey",
|
|
CPLocaleKey = @"CPLocaleKey",
|
|
CPBorderedKey = @"CPBorderedKey",
|
|
CPDateValueKey = @"CPDateValueKey";
|
|
|
|
@implementation CPDatePicker (CPCoding)
|
|
|
|
- (id)initWithCoder:(CPCoder)aCoder
|
|
{
|
|
self = [super initWithCoder:aCoder];
|
|
|
|
if (self)
|
|
{
|
|
_backgroundColor = [aCoder decodeObjectForKey:CPBackgroundColorKey];
|
|
[self setBordered:[aCoder decodeBoolForKey:CPBorderedKey]];
|
|
[self setDrawsBackground:[aCoder decodeBoolForKey:CPDrawsBackgroundKey]];
|
|
|
|
[self setDatePickerElements:[aCoder decodeIntForKey:CPDatePickerElementsKey]];
|
|
[self setDatePickerMode:[aCoder decodeIntForKey:CPDatePickerModeKey]];
|
|
[self setDatePickerStyle:[aCoder decodeIntForKey:CPDatePickerStyleKey]];
|
|
[self setMinDate:[aCoder decodeObjectForKey:CPMinDateKey] || [CPDate distantPast]];
|
|
[self setMaxDate:[aCoder decodeObjectForKey:CPMaxDateKey] || [CPDate distantFuture]];
|
|
[self setLocale:[aCoder decodeObjectForKey:CPLocaleKey]];
|
|
|
|
[self _init];
|
|
|
|
[self setTextFont:[aCoder decodeObjectForKey:CPTextFontKey]];
|
|
[self setTimeInterval:[aCoder decodeDoubleForKey:CPIntervalKey]];
|
|
[self setDateValue:[aCoder decodeObjectForKey:CPDateValueKey]];
|
|
}
|
|
|
|
return self
|
|
}
|
|
|
|
- (void)encodeWithCoder:(CPCoder)aCoder
|
|
{
|
|
// Before encoding, we remove all subviews as we'll recreate them at loading
|
|
while ([[self subviews] count] > 0)
|
|
[[[self subviews] lastObject] removeFromSuperview];
|
|
|
|
[super encodeWithCoder:aCoder];
|
|
|
|
[aCoder encodeDouble:_timeInterval forKey:CPIntervalKey];
|
|
[aCoder encodeInt:_datePickerMode forKey:CPDatePickerModeKey];
|
|
[aCoder encodeInt:_datePickerStyle forKey:CPDatePickerStyleKey];
|
|
[aCoder encodeInt:_datePickerElements forKey:CPDatePickerElementsKey];
|
|
[aCoder encodeObject:_minDate forKey:CPMinDateKey];
|
|
[aCoder encodeObject:_maxDate forKey:CPMaxDateKey];
|
|
[aCoder encodeObject:_dateValue forKey:CPDateValueKey];
|
|
[aCoder encodeObject:_textFont forKey:CPTextFontKey];
|
|
[aCoder encodeObject:_locale forKey:CPLocaleKey];
|
|
[aCoder encodeObject:_backgroundColor forKey:CPBackgroundColorKey];
|
|
[aCoder encodeObject:_drawsBackground forKey:CPDrawsBackgroundKey];
|
|
[aCoder encodeObject:_isBordered forKey:CPBorderedKey];
|
|
|
|
}
|
|
|
|
@end
|
|
|
|
// FIXME: add support for CPEditorRegistrationProtocol as implemented for CPTextField
|
|
@implementation _CPDatePickerValueBinder : CPBinder
|
|
{
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation CPDate (CPDatePickerAdditions)
|
|
|
|
- (int)_daysInMonth
|
|
{
|
|
return 32 - new Date(self.getFullYear(), self.getMonth(), 32).getDate();
|
|
}
|
|
|
|
- (void)_resetToMidnight
|
|
{
|
|
self.setHours(0);
|
|
self.setMinutes(0);
|
|
self.setSeconds(0);
|
|
self.setMilliseconds(0);
|
|
}
|
|
|
|
- (void)_resetToLastSeconds
|
|
{
|
|
self.setHours(23);
|
|
self.setMinutes(59);
|
|
self.setSeconds(59);
|
|
self.setMilliseconds(99);
|
|
}
|
|
|
|
@end
|