From 53bd4b768ea773723f6eba338ecb2cee0facf591 Mon Sep 17 00:00:00 2001 From: Lauro Neto Date: Tue, 11 Oct 2011 15:27:17 -0300 Subject: Add QtOrganizer example. It's a little bit verbose on the code (like the phonebook) as QtContact and QtOrganizer are quite complex modules (lots of classes and enums) Reviewer: Luciano Wolf Reviewer: Bruno Araujo --- mobility/organizer/qml/OverviewPage.qml | 56 +++++++ mobility/organizer/qml/TodoEdit.qml | 239 ++++++++++++++++++++++++++++ mobility/organizer/qml/main.qml | 10 ++ mobility/organizer/qml/qmltodo.py | 274 ++++++++++++++++++++++++++++++++ 4 files changed, 579 insertions(+) create mode 100644 mobility/organizer/qml/OverviewPage.qml create mode 100644 mobility/organizer/qml/TodoEdit.qml create mode 100644 mobility/organizer/qml/main.qml create mode 100644 mobility/organizer/qml/qmltodo.py (limited to 'mobility') diff --git a/mobility/organizer/qml/OverviewPage.qml b/mobility/organizer/qml/OverviewPage.qml new file mode 100644 index 0000000..4f4f4ed --- /dev/null +++ b/mobility/organizer/qml/OverviewPage.qml @@ -0,0 +1,56 @@ + +import QtQuick 1.1 +import com.nokia.meego 1.0 +import com.nokia.extras 1.1 + +Page { + id: overviewPage + anchors.margins: UiConstants.DefaultMargin + orientationLock: PageOrientation.LockPortrait + + Label { + anchors.centerIn: parent + text: "No tasks" + visible: manager.todos.length == 0 + } + + Flickable { + anchors.fill: parent + clip: true + + flickableDirection: Flickable.VerticalFlick + contentHeight: todoButtons.height + contentWidth: todoButtons.width + + ButtonColumn { + id: todoButtons + + // On N9 it seems that displayWidth keeps pointing to the larger + // side of the screen, even in portrait mode... + width: screen.displayHeight - 2 * UiConstants.DefaultMargin + + Repeater { + model: manager.todos + Button { + text: modelData + onClicked: { + manager.editExistingTodo(index) + pageStack.push(Qt.createComponent("TodoEdit.qml")) + } + } + } + } + } + + tools: ToolBarLayout { + id: mainTools + ToolButton { + text: "Add Task" + onClicked: { + manager.editNewTodo() // Prepare new todo info + pageStack.push(Qt.createComponent("TodoEdit.qml")) + } + } + } + +} diff --git a/mobility/organizer/qml/TodoEdit.qml b/mobility/organizer/qml/TodoEdit.qml new file mode 100644 index 0000000..65c60d6 --- /dev/null +++ b/mobility/organizer/qml/TodoEdit.qml @@ -0,0 +1,239 @@ + +import QtQuick 1.1 +import com.nokia.meego 1.0 +import com.nokia.extras 1.1 + +Page { + id: editPage + anchors.margins: UiConstants.DefaultMargin + orientationLock: PageOrientation.LockPortrait + + property int todoId: -1 + + Flickable { + anchors.fill: parent + contentHeight: editCol.height + flickableDirection: Flickable.VerticalFlick + + Column { + id: editCol + + width: parent.width + anchors.horizontalCenter: parent.horizontalCenter + spacing: 10 + + Label { + text: "Subject" + } + + TextField { + id: subjectField + text: manager.todoSubject + + Keys.onReturnPressed: { + parent.focus = true; + } + } + + Label { + text: "Start Date" + } + + Column { + spacing: 20 + Button { + id: selectStartDateButton + text: manager.todoStartDateTime[1] + "/" + manager.todoStartDateTime[2] + "/" + manager.todoStartDateTime[0] + + onClicked: { + startDateSelector.day = manager.todoStartDateTime[2]; + startDateSelector.month = manager.todoStartDateTime[1]; + startDateSelector.year = manager.todoStartDateTime[0]; + startDateSelector.open() + } + + DatePickerDialog { + id: startDateSelector + + onAccepted: { + manager.setTodoStartDate(year, month, day) + } + } + } + + Button { + id: selectStartTimeButton + text: manager.todoStartDateTime[3]+ ":" + manager.todoStartDateTime[4] + + onClicked: { + startTimeSelector.hour = manager.todoStartDateTime[3]; + startTimeSelector.minute = manager.todoStartDateTime[4]; + startTimeSelector.open() + } + + TimePickerDialog { + id: startTimeSelector + fields: DateTime.Hours | DateTime.Minutes + acceptButtonText: "Confirm" + rejectButtonText: "Cancel" + + onAccepted: { + manager.setTodoStartTime(hour, minute) + } + + } + } + + } + + Label { + text: "Due Date" + } + + Column { + spacing: 20 + Button { + id: selectDueDateButton + text: manager.todoDueDateTime[1] + "/" + manager.todoDueDateTime[2] + "/" + manager.todoDueDateTime[0] + + onClicked: { + dueDateSelector.day = manager.todoDueDateTime[2]; + dueDateSelector.month = manager.todoDueDateTime[1]; + dueDateSelector.year = manager.todoDueDateTime[0]; + dueDateSelector.open() + } + + DatePickerDialog { + id: dueDateSelector + + onAccepted: { + manager.setTodoDueDate(year, month, day) + } + } + } + + Button { + id: selectDueTimeButton + text: manager.todoDueDateTime[3]+ ":" + manager.todoDueDateTime[4] + + onClicked: { + dueTimeSelector.hour = manager.todoDueDateTime[3]; + dueTimeSelector.minute = manager.todoDueDateTime[4]; + dueTimeSelector.open() + } + + TimePickerDialog { + id: dueTimeSelector + fields: DateTime.Hours | DateTime.Minutes + acceptButtonText: "Confirm" + rejectButtonText: "Cancel" + + onAccepted: { + manager.setTodoDueTime(hour, minute) + } + } + } + + } + + Label { + text: "Status" + } + + Button { + id: statusButton + text: statusSelection.model.get(statusSelection.selectedIndex).name + + onClicked: { + statusSelection.open(); + } + + + SelectionDialog { + id: statusSelection + titleText: "Select status" + selectedIndex: manager.todoStatus + + model: ListModel { + ListElement { name: "Not started" } + ListElement { name: "In progress" } + ListElement { name: "Complete" } + } + + onAccepted: { + manager.todoStatus = statusSelection.selectedIndex; + } + } + } + + Label { + text: "Priority" + } + + Button { + id: priorityButton + text: prioritySelection.model.get(prioritySelection.selectedIndex).name + + onClicked: { + prioritySelection.open(); + } + + + SelectionDialog { + id: prioritySelection + titleText: "Select priority" + selectedIndex: manager.todoPriority + + model: ListModel { + ListElement { name: "Unknown" } + ListElement { name: "Highest" } + ListElement { name: "Extremely high" } + ListElement { name: "Very high" } + ListElement { name: "High" } + ListElement { name: "Medium" } + ListElement { name: "Low" } + ListElement { name: "Very low" } + ListElement { name: "Extremely low" } + ListElement { name: "Lowest" } + } + + onAccepted: { + manager.todoPriority = prioritySelection.selectedIndex; + } + } + } + } + } + + tools: ToolBarLayout { + id: editTools + ToolButton { + text: "Save" + onClicked: { + console.log("Saving new task") + manager.todoSubject = subjectField.text; // Other fields are handled by dialog.accept signal + manager.saveTodo(); + pageStack.pop(); + } + } + ToolButton { + text: "Delete" + enabled: !manager.isNewTodo + onClicked: { + console.log("Deleting todo."); + manager.deleteCurrent(); + pageStack.pop(); + } + } + ToolButton { + text: "Cancel" + onClicked: { + console.log("Cancel task edit"); + console.log("Is new todo?" + manager.isNewTodo); + manager.reload(); + pageStack.pop(); + } + } + } + +} diff --git a/mobility/organizer/qml/main.qml b/mobility/organizer/qml/main.qml new file mode 100644 index 0000000..88c1b95 --- /dev/null +++ b/mobility/organizer/qml/main.qml @@ -0,0 +1,10 @@ + +import QtQuick 1.1 +import com.nokia.meego 1.0 + +PageStackWindow { + + id: rootWindow + showStatusBar: false + initialPage: OverviewPage { } +} diff --git a/mobility/organizer/qml/qmltodo.py b/mobility/organizer/qml/qmltodo.py new file mode 100644 index 0000000..a3523f2 --- /dev/null +++ b/mobility/organizer/qml/qmltodo.py @@ -0,0 +1,274 @@ +''' + 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 Mobility Components. + + $QT_BEGIN_LICENSE:LGPL$ + No Commercial Usage + This file contains pre-release code and may not be distributed. + You may use this file in accordance with the terms and conditions + contained in the Technology Preview License Agreement accompanying + this package. + + GNU Lesser General Public License Usage + Alternatively, this file may be used under the terms of the GNU Lesser + General Public License version 2.1 as published by the Free Software + Foundation and appearing in the file LICENSE.LGPL included in the + packaging of this file. Please review the following information to + ensure the GNU Lesser General Public License version 2.1 requirements + will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. + + In addition, as a special exception, Nokia gives you certain additional + rights. These rights are described in the Nokia Qt LGPL Exception + version 1.1, included in the file LGPL_EXCEPTION.txt in this package. + + If you have questions regarding the use of this file, please contact + Nokia at qt-info@nokia.com. +''' + +import os +import sys + +from PySide.QtCore import QObject, Signal, Slot, Property, QUrl, qWarning +from PySide.QtCore import QAbstractItemModel, QDate, QDateTime, QTime +from PySide.QtGui import QApplication +from PySide.QtDeclarative import QDeclarativeView +from QtMobility.Organizer import QOrganizerManager, QOrganizerItemSortOrder +from QtMobility.Organizer import QOrganizerTodo, QOrganizerTodoTime +from QtMobility.Organizer import QOrganizerItemFilter, QOrganizerItemDetailFilter +from QtMobility.Organizer import QOrganizerItemPriority, QOrganizerTodoProgress +from QtMobility.Organizer import QOrganizerItemType + + +class TodoManager(QObject): + + def __init__(self): + QObject.__init__(self) + + self.manager = QOrganizerManager("memory") + self._todos = [] # FIXME Use a model instead of a string list as model + self._todo = None # Current todo being edited or created + + self.reload() + + @Slot() + def reload(self): + self._todos = [] + + sortOrder = QOrganizerItemSortOrder() + sortOrder.setDetailDefinitionName(QOrganizerTodoTime.DefinitionName, + QOrganizerTodoTime.FieldDueDateTime) + + todoFilter = QOrganizerItemFilter() + + items = self.manager.items(todoFilter, [sortOrder]) + + todos = [] + for item in items: + if item.type() == QOrganizerItemType.TypeTodo: + todo = QOrganizerTodo(item) + + display = todo.startDateTime().toString("yy/MM/dd hh:mm") +\ + "-" + todo.dueDateTime().toString("yy/MM/dd hh:mm") +\ + "\n" + todo.displayLabel() + + todos.append((display, todo)) + + self._todos = todos + self.todosChanged.emit() + + @Slot() + def deleteCurrent(self): + self.manager.removeItem(self._todo.id()) + self.reload() + + currentTodoChanged = Signal() + + @Slot() + def editNewTodo(self): + """Sets the current todo to a newly created todo""" + newTodo = QOrganizerTodo() + newTodo.setPriority(QOrganizerItemPriority.HighPriority) + newTodo.setStatus(QOrganizerTodoProgress.StatusNotStarted) + currentDateTime = QDateTime(QDate.currentDate(), QTime.currentTime()) + newTodo.setStartDateTime(currentDateTime) + newTodo.setDueDateTime(currentDateTime.addSecs(60*60)) + + self._todo = newTodo + self._todo.isNewTodo = True + self.currentTodoChanged.emit() + + @Property(bool, notify=currentTodoChanged) + def isNewTodo(self): + return self._todo.isNewTodo if self._todo else True + + @Slot(int) + def editExistingTodo(self, index): + self._todo = self._todos[index][1] + self._todo.isNewTodo = False + self.currentTodoChanged.emit() + + @Slot() + def saveTodo(self): + self.manager.saveItem(self._todo) + self._todo = None + self.reload() + + todosChanged = Signal() + @Property("QStringList", notify=todosChanged) + def todos(self): + return [x[0] for x in self._todos] + + @todos.setter + def setTodo(self, value): + self._todos = value + self.todosChanged.emit() + + # Subject + currentTodoSubjectChanged = Signal() + + @Property(str, notify=currentTodoSubjectChanged) + def todoSubject(self): + return self._todo.displayLabel() + + @todoSubject.setter + def setTodoSubject(self, value): + self._todo.setDisplayLabel(value) + self.currentTodoSubjectChanged.emit() + + # Dates and times + def datetimeToStrList(self, datetime): + date = datetime.date() + time = datetime.time() + return (("%02d "*5) % (date.year(), date.month(), date.day(), + time.hour(), time.minute())).split() + +# @Slot(result="QStringList") + @Property("QStringList", notify=currentTodoChanged) + def todoStartDateTime(self): + return self.datetimeToStrList(self._todo.startDateTime()) + + @Slot(int, int, int) + def setTodoStartDate(self, year, month, day): + orig_time = self._todo.startDateTime().time() + date = QDate(year, month, day) + datetime = QDateTime(date, orig_time) + + self._todo.setStartDateTime(datetime) + self.currentTodoChanged.emit() + + @Slot(int, int) + def setTodoStartTime(self, hour, minute): + orig_date = self._todo.startDateTime().date() + time = QTime(hour, minute) + datetime = QDateTime(orig_date, time) + + self._todo.setStartDateTime(datetime) + self.currentTodoChanged.emit() + + @Property("QStringList", notify=currentTodoChanged) + def todoDueDateTime(self): + return self.datetimeToStrList(self._todo.dueDateTime()) + + @Slot(int, int, int) + def setTodoDueDate(self, year, month, day): + orig_time = self._todo.dueDateTime().time() + date = QDate(year, month, day) + datetime = QDateTime(date, orig_time) + + self._todo.setDueDateTime(datetime) + + self.currentTodoChanged.emit() + + @Slot(int, int) + def setTodoDueTime(self, hour, minute): + orig_date = self._todo.dueDateTime().date() + time = QTime(hour, minute) + datetime = QDateTime(orig_date, time) + + self._todo.setDueDateTime(datetime) + + self.currentTodoChanged.emit() + + # Status + + Status = [ + QOrganizerTodoProgress.StatusNotStarted, + QOrganizerTodoProgress.StatusInProgress, + QOrganizerTodoProgress.StatusComplete, + ] + + @Property(int, notify=currentTodoChanged) + def todoStatus(self): + status = self._todo.status() + try: + index = self.Status.index(status) + return index + except ValueError: + return 0 + + @todoStatus.setter + def setTodoStatus(self, value): + try: + self._todo.setStatus(self.Status[value]) + self.currentTodoChanged.emit() + except IndexError: + pass # Fail silently... + + # Priority + + Priority = [ + QOrganizerItemPriority.UnknownPriority, + QOrganizerItemPriority.HighestPriority, + QOrganizerItemPriority.ExtremelyHighPriority, + QOrganizerItemPriority.VeryHighPriority, + QOrganizerItemPriority.HighPriority, + QOrganizerItemPriority.MediumPriority, + QOrganizerItemPriority.LowPriority, + QOrganizerItemPriority.VeryLowPriority, + QOrganizerItemPriority.ExtremelyLowPriority, + QOrganizerItemPriority.LowestPriority, + ] + + @Property(int, notify=currentTodoChanged) + def todoPriority(self): + priority = self._todo.priority() + try: + index = self.Priority.index(priority) + return index + except ValueError: + return 0 + + @todoPriority.setter + def setTodoPriority(self, value): + try: + self._todo.setPriority(self.Priority[value]) + self.currentTodoChanged.emit() + except IndexError: + pass # Fail silently... + + +def main(): + app = QApplication([]) + view = QDeclarativeView() + manager = TodoManager() + context = view.rootContext() + context.setContextProperty("manager", manager) + + url = QUrl('main.qml') + view.setSource(url) + + if "-no-fs" not in sys.argv: + view.showFullScreen() + else: + view.show() + + app.exec_() + + +if __name__ == '__main__': + main() + + -- cgit v1.2.3