QtMobility Reference Documentation

ToDo Example

Files:

The ToDo example shows how to organize todo items using the QtMobility Organizer framework.

Most organizing software, e.g., calendar applications, lets the user create todo items, which describe an activity that should be completed. Other items may include meetings, notes, and events. A todo item typically includes the following information:

  • A timestamp for when the item was created.
  • A timestamp for when the activity should be completed.
  • A timestamp for when the activity was completed.
  • A priority for how important the activity is.
  • Information on whether the todo is recurring (i.e., if it should be repeated at regular intervals).
  • A description of the activity.

A todo item is represented in Qt with the QOrganizerTodo class. Instances are managed by a QOrganizerManager, which can save todos created by a program and return the todo items it manages. QOrganizerTodo contains the information mentioned in the list above. In Qt, we call this item details. They are represented by QOrganizerItemDetail and its subclasses. For instance, QOrganizerTodo keeps a QOrganizerItemPriority (which inherits QOrganizerItemDetail).

The item details available for a QOrganizerTodo follows a standardized schema, i.e, a todo item has a standard set of item details. Most QOrganizerManager backends will follow this schema. A backend is the implementation of the QOrganizerManager's functionality for a specific platform. Some backends may not support all details, and possibly include others.

The example consists of two classes:

  • Window: Lets the user select a date and create todo items for the date selected. It also displays a list with todo items for the date selected.
  • TodoEditor: Lets the user edit a todo item using standard Qt widgets.

We will now look at the definitions and implementations of Window and TodoEditor.

Window Class Definition

The Window class is responsible for setting up the GUI of the example. It creates QOrganizerTodo items and send them to the TodoEditor for editing. It saves and retrieves todo items from the organizer item manager.

Let's take a look at its definition.

 class Window : public QWidget
 {
     Q_OBJECT

 public:
     Window();
     ~Window();

 private slots:
     void editNewTodo();
     void editTodo(QListWidgetItem *item);
     void saveTodo(QOrganizerTodo &todo);
     void refreshList();
     void deleteTodo();

 private:
     void setupGui();

     QOrganizerManager *manager;

     TodoEditor *todoEditor;

     QListWidget *listWidget;
     QStackedWidget *stackedWidget;
     QPushButton *newTodoButton;
     QPushButton *deletTodoButton;
     QCalendarWidget *calendarWidget;
 };

The slots are connected to the widgets of Window, and handles user requests to create a new todo item, edit an existing item, and delete an item. The saveTodo() slot is invoked when the user has finished editing a todo item. refreshList() updates the Todo Item List when todo items are added, deleted, or edited.

We'll now go through the slots and constructor of Window. The only other function, setupGui(), initializes and lays out the widgets, and that is treated in other examples.

Window Class Implementation

The constructor creates the QOrganizerManager instance:

 Window::Window()
 {
     setupGui();

     manager = new QOrganizerManager("memory");

     setWindowTitle(tr("ToDo Example"));
     refreshList();
 }

We here instruct that the manger should use the memory backend. This backend implements the default schema and uses the computers memory for storing items. This way, we can be sure that the backend will behave equally on all platforms.

The editNewTodo() slot is connected to the New Todo Button, and sets up a new QOrganizerTodo for editing.

 void Window::editNewTodo()
 {
     QOrganizerTodo newTodo;
     newTodo.setPriority(QOrganizerItemPriority::HighPriority);
     newTodo.setStatus(QOrganizerTodoProgress::StatusNotStarted);
     QDateTime currentDateTime(calendarWidget->selectedDate(),
         QTime::currentTime());
     newTodo.setStartDateTime(currentDateTime);
     newTodo.setDueDateTime(currentDateTime.addSecs(60*60));

     todoEditor->editTodo(newTodo);

     stackedWidget->setCurrentWidget(todoEditor);
 }

Here we set the item details of the new QOrganizerTodo to reasonable defaults. The editTodo() slot sets up the widgets of the TodoEditor with the data from the new todo. Finally, the stacked widget is set to show the todo editor.

The editTodo() slot is invoked when the player double clicks a todo item in the Todo Item List with the mouse.

 Q_DECLARE_METATYPE(QOrganizerTodo)

 void Window::editTodo(QListWidgetItem *item)
 {
     QVariant variant = item->data(Qt::UserRole);
     if (!variant.canConvert<QOrganizerTodo>())
         return;

     QOrganizerTodo todo = variant.value<QOrganizerTodo>();
     todoEditor->editTodo(todo);
     stackedWidget->setCurrentWidget(todoEditor);
 }

The slot is invoked with the QListWidgetItem that was double clicked. We have saved the QOrganizerTodo in the list widget item. The list widget item stores data in QVariants, so we need to include the Q_DECLARE_METATYPE() macro, which helps make QOrganizerTodos usable with QVariant.

When we have retrieved the todo item, we send it to the TodoEditor for editing, which we show on the screen.

The saveTodo() slot is invoked by the TodoEditor when the user has finished editing.

 void Window::saveTodo(QOrganizerTodo &todo)
 {
     manager->saveItem(&todo);

     stackedWidget->setCurrentIndex(0);
     refreshList();
 }

Saving a QOrganizerTodo in the QOrganizerManager is easy using the saveItem() function. We call the refreshList() slot to update the Todo Item List so that new and edited todos is displayed correctly.

The deleteTodo() slot is connected to the Delete Todo Button, and will delete the currently selected todo in the Todo List from the manager.

 void Window::deleteTodo()
 {
     QList<QListWidgetItem *> items = listWidget->selectedItems();
     if (!items.isEmpty()) {
         QVariant variant = items.at(0)->data(Qt::UserRole);
         if (variant.canConvert<QOrganizerTodo>()) {
             QOrganizerTodo theTodo = variant.value<QOrganizerTodo>();
             manager->removeItem(theTodo.id());
             refreshList();
         }
     }
 }

Here we fetch the selected list widget item from the list. To delete the item in the manager, we send the items id to the manager's removeItem() function. An item's id uniquely identifies it in its manager.

We now move on to the refreshList() function, which set's up the Todo List with the todo items currently stored in the manager.

 void Window::refreshList()
 {
     listWidget->clear();

     QOrganizerItemSortOrder sortOrder;
     sortOrder.setDetailDefinitionName(QOrganizerTodoTime::DefinitionName,
         QOrganizerTodoTime::FieldDueDateTime);

     QList<QOrganizerItem> items =
         manager->items(QOrganizerItemFilter(), QList<QOrganizerItemSortOrder>() << sortOrder);

First we remove all items from the list widget, i.e., we set up the list from scratch each time refreshList() is called.

The items() functions retrieves QOrganizerItems from the manager. By giving the manager a QOrganizerItemSortOrder, the manager will sort the items for us. The sort order takes the item detail it should sort after. You also need to specify which field of the detail should be used for sorting. Note that all details have a DefinitionName constant declared. They also keep constants for all of their fields. The items() takes a list of sort orders in case one wants to sort by more than one field.

It is also possible to let the manager filter items. You can look up the QOrganizerItemFilter class description for details.

     foreach(QOrganizerItem item, items) {
         if (item.type() == QOrganizerItemType::TypeTodo) {
             QOrganizerTodo todo = static_cast<QOrganizerTodo>(item);
             if (todo.startDateTime() >
                     QDateTime(calendarWidget->selectedDate(), QTime(23,59)) ||
                 todo.dueDateTime() <
                     QDateTime(calendarWidget->selectedDate(), QTime(0, 0)))
                 continue;

             QString display = todo.startDateTime().toString("yy/MM/dd hh:mm") +
                 "-" + todo.dueDateTime().toString("yy/MM/dd hh:mm") +
                 " - "+ todo.displayLabel();

             QListWidgetItem *listItem =
                 new QListWidgetItem(display, listWidget);
             listItem->setData(Qt::UserRole, QVariant::fromValue(todo));
         }
     }
 }

We iterate through the todo items in the manager, keeping the items that are active, i.e., the date selected in the calendar is between the start and due dates of the item.

We create a list widget item for the todo. We set its text to the item's start sate, due date, and displayLabel().

We save the QOrganizerTodo itself in the Qt::UserRole of the list widget item. We have seen previously how to retrieve it.

TodoEditor Class Definition

The TodoEditor contains widgets for editing a QOrganizerTodo.

Here is the TodoEditor class's definition:

 class TodoEditor : public QWidget
 {
     Q_OBJECT

 public:
     TodoEditor();

 signals:
     void editingFinished(QOrganizerTodo &todo);

 public slots:
     void editTodo(const QOrganizerTodo &todo);

 private slots:
     void updateSubject();
     void updateDescription();
     void updateDates();
     void updateStatus(int index);
     void updatePriority(int index);
     void updateAlarm(int index);
     void finishEditing();

 private:
     void setupGui();
     void setupCombos();

     QOrganizerTodo todo;

     QDateTimeEdit *startDateEdit;
     QDateTimeEdit *dueDateEdit;
     QComboBox *statusCombo;
     QComboBox *priorityCombo;
     QComboBox *alarmCombo;
     QLineEdit *subjectLineEdit;
     QTextEdit *descriptionTextEdit;
     QPushButton *doneButton;
 };

The editTodo() slot is called by Window when a todo item should be edited. finishEditing() is connected to doneButton, and emits the editingFinished() signal. This signal is connected to the saveTodo() slot of the Window.

The rest of slots are connected to the widgets that edit the todo item's details.

setupGui() creates, lays out, and connects the widgets to the slots of TodoEditor. setupCombos() helps setupGui() by creating the comboboxes and by filling their drop-down lists.

TodoEditor Class Implementation

We start by taking a quick look at setupCombos(), which sets up the QComboBoxes.

 void TodoEditor::setupCombos()
 {
     priorityCombo = new QComboBox;
     priorityCombo->addItem("Unknown", QOrganizerItemPriority::UnknownPriority);
     priorityCombo->addItem("Highest", QOrganizerItemPriority::HighestPriority);
     priorityCombo->addItem("Extremely high",
         QOrganizerItemPriority::ExtremelyHighPriority);
     priorityCombo->addItem("Very high",
         QOrganizerItemPriority::VeryHighPriority);
     priorityCombo->addItem("High", QOrganizerItemPriority::HighPriority);
     priorityCombo->addItem("Medium", QOrganizerItemPriority::MediumPriority);
     priorityCombo->addItem("Low", QOrganizerItemPriority::LowPriority);
     priorityCombo->addItem("Very low", QOrganizerItemPriority::VeryLowPriority);
     priorityCombo->addItem("Extremely low",
         QOrganizerItemPriority::ExtremelyLowPriority);
     priorityCombo->addItem("Lowest", QOrganizerItemPriority::LowestPriority);

     statusCombo = new QComboBox;
     statusCombo->addItem("Not started",
         QOrganizerTodoProgress::StatusNotStarted);
     statusCombo->addItem("In progress", QOrganizerTodoProgress::StatusInProgress);
     statusCombo->addItem("Complete",
         QOrganizerTodoProgress::StatusComplete);

     alarmCombo = new QComboBox;
     QStringList alarmList;
     alarmList << "None" << "15 minutes" << "30 minutes" << "45 minutes"
               << "1 hour";
     alarmCombo->addItems(alarmList);
 }

As with list widget items, you can also store user data in an item of QComboBox's drop-down list. Here we save a QOrganizerTodo's possible values for its priority() and status() details. The alarmCombo helps the user select a time for when to be reminded of the todo.

The editTodo() slot is called when a new QOrganizerTodo should be edited.

 void TodoEditor::editTodo(const QOrganizerTodo &newTodo)
 {
     todo = newTodo;

     subjectLineEdit->setText(todo.displayLabel());
     startDateEdit->setDateTime(todo.startDateTime());
     dueDateEdit->setDateTime(todo.dueDateTime());
     priorityCombo->setCurrentIndex(
         priorityCombo->findData(QVariant(todo.priority())));
     statusCombo->setCurrentIndex(
         statusCombo->findData(QVariant(todo.status())));
     descriptionTextEdit->setText(todo.description());

We set the contents of our widgets to the details of the todo item. The functions we use here are utility functions provided by QOrganizerTodo that accesses the QOrganizerItemDetails for us. We could also have accessed them by using the value() functions of QOrganizerItemDetail.

     if (!todo.details(QOrganizerItemVisualReminder::DefinitionName).isEmpty()){
         QOrganizerItemVisualReminder reminder =
             todo.detail<QOrganizerItemVisualReminder>();
         int seconds = reminder.secondsBeforeStart();
         alarmCombo->setCurrentIndex(seconds/(15*60));
     } else
         alarmCombo->setCurrentIndex(0);
 }

Many backends support notifying the user when a todo item is due. We can request this by adding a QOrganizerItemRemainder detail to the QOrganizerTodo. We first check whether a remainder detail is present on the todo item. If it is we update the Alarm Combo Box. The secsTo() function returns the difference between two QDateTimes in seconds.

The next two slots update the subject and description of the todo item.

 void TodoEditor::updateSubject()
 {
     todo.setDisplayLabel(subjectLineEdit->text());
 }

 void TodoEditor::updateDescription()
 {
     todo.setDescription(descriptionTextEdit->toPlainText());
 }

We save the subject in the item's displayLabel(), which is meant for displaying a short description that can be used in item views. The description() is a longer text describing the item.

The updateDates() slot is connected to the two QDateTimeEdits that let the user select start and due dates for the todo item.

 void TodoEditor::updateDates()
 {
     QDateTime startTime = startDateEdit->dateTime();
     QDateTime dueDateTime = dueDateEdit->dateTime();

     todo.setStartDateTime(startTime);
     todo.setDueDateTime(dueDateTime);

     updateAlarm(alarmCombo->currentIndex());
 }

Note that we need to update the remainder detail when the due date changes because the remainder is calculated relative to the due date. We do that in updateAlarm(), which we will come back to later.

The updateStatus() and updatePriority() functions are connected to the combo boxes that we created in setupCombos().

 void TodoEditor::updateStatus(int index)
 {
     QOrganizerTodoProgress::Status status =
         (QOrganizerTodoProgress::Status) statusCombo->itemData(index).toInt();
     todo.setStatus(status);
 }

 void TodoEditor::updatePriority(int index)
 {
     QOrganizerItemPriority::Priority priority =
         (QOrganizerItemPriority::Priority)
             priorityCombo->itemData(index).toInt();
     todo.setPriority(priority);
 }

The only thing to notice here is that enum values are saved as ints in the drop-down list items.

The updateAlarm() function is connected to the alarmCombo as we saw earlier.

 void TodoEditor::updateAlarm(int index)
 {
     int seconds = index * (15*60);
     QDateTime dueDate = todo.dueDateTime();

     QOrganizerItemVisualReminder oldReminder =
         todo.detail(QOrganizerItemVisualReminder::DefinitionName);
     todo.removeDetail(&oldReminder);

     if (seconds == 0)
         return;

     QOrganizerItemVisualReminder reminder;
     reminder.setSecondsBeforeStart(seconds);

     todo.saveDetail(&reminder);
 }

We first calculate the time before the todo is due the alarm should go off. We calculate this in seconds because QDateTime's addSecs() function gives us an easy way of finding the time from the todo's due time.

Before we add the new reminder, we need to remove any previously added reminders; if not, the QOrganizerTodo item would have several QOrganizerItemVisualReminders registered with it.

The reminder is not accessible through the convenience functions of QOrganizerTodo, so we add it using the item detail access functions from QOrganizerItem.

X

Thank you for giving your feedback.

Make sure it is related to this specific page. For more general bugs and requests, please use the Qt Bug Tracker.