--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.1
+import com.nokia.meego 1.0
+import "constants.js" as C
+import "TumblerIndexHelper.js" as TH
+
+/*
+ Class: DatePickerDialog
+ Dialog that shows a date picker.
+*/
+
+Dialog {
+ id: root
+
+ /*
+ * Property: titleText
+ * [string] If not null, it will be used as the title text for the dialog.
+ * If further customization is needed, use property title instead
+ */
+ property alias titleText: title.text
+
+ /*
+ * Property: year
+ * [int] The displayed year.
+ */
+ property int year: dateTime.currentYear()
+
+ /*
+ * Property: month
+ * [int] The displayed month.
+ */
+ property int month: 1
+
+ /*
+ * Property: day
+ * [int] The displayed day.
+ */
+ property int day: 1
+
+ /*
+ * Property: minimumYear
+ * [int] Optional, the minimum year shown on the tumbler. This property should
+ * only be set once during construction. If the value is not specified,
+ * it is default to current year - 1.
+ */
+ property int minimumYear: dateTime.currentYear() - 1
+
+ /*
+ * Property: maximumYear
+ * [int] Optional, the maximum year shown on the tumbler. This property should
+ * only be set once during construction. If the value is not specified,
+ * it is default to current year + 20.
+ */
+ property int maximumYear: dateTime.currentYear() + 20
+
+ /*
+ * Property: acceptButtonText
+ * [string] Optional, the button text for the accept button.
+ */
+ property alias acceptButtonText: confirmButton.text
+
+ /*
+ * Property: rejectButtonText
+ * [string] Optional, the button text for the reject button.
+ */
+ property alias rejectButtonText: rejectButton.text
+
+ // TODO do not dismiss the dialog when empty area is clicked
+ style: DialogStyle {
+ titleBarHeight: 48
+ leftMargin: screen.currentOrientation == Screen.Portrait || screen.currentOrientation == Screen.PortraitInverted ? 16 : 215
+ rightMargin: screen.currentOrientation == Screen.Portrait || screen.currentOrientation == Screen.PortraitInverted ? 16 : 215
+ centered: true
+ }
+ title: Text {
+ id: title
+ objectName: "title"
+ visible: text.length > 0
+ color: theme.selectionColor
+ font { pixelSize: 32; family: C.FONT_FAMILY_BOLD }
+ elide: Text.ElideRight
+ }
+ content: Item {
+ id: dialogContent
+ height: 300
+ width: parent.width
+
+ Tumbler {
+ id: tumbler
+
+ function _handleTumblerChanges(index) {
+ if (index == 1 || index == 2) {
+ var curYear = yearColumn.selectedIndex + yearList.get(0).value;
+ var curMonth = monthColumn.selectedIndex + 1;
+
+ var d = dateTime.daysInMonth(curYear, curMonth);
+ if (dayColumn.selectedIndex >= d)
+ dayColumn.selectedIndex = d - 1
+ while (dayList.count > d)
+ dayList.remove(dayList.count - 1)
+ while (dayList.count < d)
+ dayList.append({"value" : dayList.count + 1})
+ }
+ }
+
+ columns: [dayColumn, monthColumn, yearColumn]
+ onChanged: {
+ _handleTumblerChanges(index);
+ }
+ height: 300
+ privateDelayInit: true
+
+ TumblerColumn {
+ id: dayColumn
+ items: ListModel {
+ id: dayList
+ }
+ label: "DAY"
+ selectedIndex: root.day - (root.day > 0 ? 1 : 0)
+ }
+
+ TumblerColumn {
+ id: monthColumn
+ items: ListModel {
+ id: monthList
+ }
+ label: "MONTH"
+ selectedIndex: root.month - (root.month > 0 ? 1 : 0)
+ }
+
+ TumblerColumn {
+ id: yearColumn
+ items: ListModel {
+ id: yearList
+ }
+ label: "YEAR"
+ selectedIndex: yearList.length > 0 ? internal.year - yearList.get(0).value : 0
+ }
+ }
+ }
+ buttons: Row {
+ height: 56
+ anchors.horizontalCenter: parent.horizontalCenter
+ spacing: 6
+ Button {
+ id: confirmButton
+ text: "CONFIRM"
+ onClicked: accept()
+ width: (root.width / 2) - 3
+ style: ButtonStyle { inverted: true }
+ }
+ Button {
+ id: rejectButton
+ text: "CANCEL"
+ onClicked: reject()
+ width: (root.width / 2) - 3
+ platformStyle: ButtonStyle { inverted: true }
+ }
+ }
+ onMinimumYearChanged: {
+ if (!internal.surpassUpdate) {
+ internal.year = root.year
+ internal.minYear = root.minimumYear
+
+ if (internal.minYear < 0)
+ internal.minYear = dateTime.currentYear() - 1;
+ else if (internal.minYear > root.maximumYear)
+ internal.minYear = root.maximumYear;
+
+ internal.updateYearList()
+ internal.validateDate()
+ internal.year = internal.year < internal.minYear ? internal.minYear :
+ (internal.year > root.maximumYear ? root.maximumYear :internal.year)
+ }
+ }
+ onMaximumYearChanged: {
+ internal.minYear = root.minimumYear
+
+ if (root.maximumYear < 0)
+ root.maximumYear = dateTime.currentYear() + 20;
+ else if (root.maximumYear < internal.minYear)
+ root.maximumYear = internal.minYear;
+
+ internal.updateYearList()
+ internal.validateDate()
+ internal.year = internal.year > root.maximumYear ? root.maximumYear :
+ (internal.year < internal.minYear ? internal.minYear : internal.year)
+ if (internal.minYear < 0)
+ root.minimumYear = dateTime.currentYear() - 1
+ }
+ onStatusChanged: {
+ if (status == DialogStatus.Opening) {
+ TH.saveIndex(tumbler);
+ if (!internal.initialized)
+ internal.initializeDataModels();
+ if (internal.year > 0)
+ yearColumn.selectedIndex = internal.year - yearList.get(0).value;
+ tumbler._handleTumblerChanges(2);
+ dayColumn.selectedIndex = root.day - 1;
+ }
+ if (status == DialogStatus.Closing) {
+ internal.surpassUpdate = true
+ if (internal.surpassUpdate) {
+ root.year = internal.year
+ root.minimumYear = internal.minYear
+ }
+ internal.surpassUpdate = false
+ }
+ }
+ onDayChanged: {
+ internal.validateDate()
+ if (dayColumn.items.length > root.day - 1)
+ dayColumn.selectedIndex = root.day - 1
+ }
+ onMonthChanged: {
+ internal.validateDate()
+ monthColumn.selectedIndex = root.month - 1
+ }
+ onYearChanged: {
+ if (!internal.surpassUpdate) {
+ internal.year = root.year
+ internal.validateDate()
+ internal.year = internal.year < internal.minYear ? internal.minYear :
+ (internal.year > root.maximumYear ? root.maximumYear : internal.year)
+
+ if (internal.initialized)
+ yearColumn.selectedIndex = internal.year - yearList.get(0).value
+ }
+ }
+ onAccepted: {
+ tumbler.privateForceUpdate();
+ root.year = yearColumn.selectedIndex + yearList.get(0).value;
+ root.month = monthColumn.selectedIndex + 1;
+ root.day = dayColumn.selectedIndex + 1;
+ }
+ onRejected: {
+ TH.restoreIndex(tumbler);
+ }
+
+ QtObject {
+ id: internal
+
+ property variant initialized: false
+ property int year
+ property int minYear
+ property bool surpassUpdate: false
+
+ function initializeDataModels() {
+ var currentYear = new Date().getFullYear();
+ minimumYear = minimumYear ? minimumYear : currentYear - 1;
+ maximumYear = maximumYear ? maximumYear : currentYear + 20;
+
+ for (var y = minimumYear; y <= maximumYear; ++y)
+ yearList.append({"value" : y}) // year
+
+ var nDays = dateTime.daysInMonth(internal.year, root.month);
+ for (var d = 1; d <= nDays; ++d)
+ dayList.append({"value" : d}) // day
+ for (var m = 1; m <= 12; ++m)
+ monthList.append({"value" : dateTime.shortMonthName(m)});
+
+ tumbler.privateInitialize();
+ internal.initialized = true;
+ }
+
+ function updateYearList() {
+ if (internal.initialized) {
+ var tmp = yearColumn.selectedIndex;
+ yearList.clear();
+ for (var i = internal.minYear; i <= root.maximumYear; ++i)
+ yearList.append({"value" : i})
+ if (tmp < yearList.count) {
+ yearColumn.selectedIndex = 0;
+ yearColumn.selectedIndex = tmp;
+ }
+ }
+ }
+
+ function validateDate() {
+ if (internal.year < 1){
+ internal.year = new Date().getFullYear()
+ if (maximumYear < internal.year)
+ root.maximumYear = dateTime.currentYear() + 20;
+ if (minimumYear > internal.year)
+ internal.minYear = dateTime.currentYear() - 1;
+ }
+
+ root.month = Math.max(1, Math.min(12, root.month))
+ var d = dateTime.daysInMonth(internal.year, root.month);
+ root.day = Math.max(1, Math.min(d, root.day))
+ }
+ }
+}