- Qt 5.0
- CalendarDemo
- Qt 5.0.0 Reference Documentation

# CalendarDemo

     /****************************************************************************
     **
     ** Copyright (C) 2017 The Qt Company Ltd.
     ** Contact: https://www.qt.io/licensing/
     **
     ** This file is part of the examples for the Qt PIM module of the Qt Toolkit.
     **
     ** $QT_BEGIN_LICENSE:BSD$
     ** Commercial License Usage
     ** Licensees holding valid commercial Qt licenses may use this file in
     ** accordance with the commercial license agreement provided with the
     ** Software or, alternatively, in accordance with the terms contained in
     ** a written agreement between you and The Qt Company. For licensing terms
     ** and conditions see https://www.qt.io/terms-conditions. For further
     ** information use the contact form at https://www.qt.io/contact-us.
     **
     ** BSD License Usage
     ** Alternatively, 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 The Qt Company Ltd 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$
     **
     ****************************************************************************/

     #include <QLocale>
     #include <QtWidgets>
     #include <QtOrganizer/qorganizer.h>
     #include <QtOrganizer/qorganizerabstractrequest.h>

     #include "monthpage.h"
     #include "calendardemo.h"

     QTORGANIZER_USE_NAMESPACE

     Q_DECLARE_METATYPE(QOrganizerItem)

     MonthPage::MonthPage(QWidget *parent)
         :QWidget(parent),
         m_manager(0),
         m_calendarWidget(0),
         m_dateLabel(0),
         m_itemList(0),
         m_ignoreShowDayPageOnceFlag(false)
     {
         // Create widgets
         QFormLayout *mainlayout = new QFormLayout(this);

         m_managerComboBox = new QComboBox(this);
         foreach (const QString& manager, QOrganizerManager::availableManagers()) {
             if (manager != "invalid" && manager != "skeleton")
                 m_managerComboBox->addItem(manager);
         }
         mainlayout->addRow("Backend:", m_managerComboBox);
         connect(m_managerComboBox, SIGNAL(currentIndexChanged(const QString &)), this, SLOT(backendChanged(const QString &)));

         m_dateLabel = new QLabel(this);
         m_dateLabel->setAlignment(Qt::AlignCenter);
         mainlayout->addRow(m_dateLabel);

         m_calendarWidget = new QCalendarWidget(this);
         m_calendarWidget->setGridVisible(true);
         m_calendarWidget->setHorizontalHeaderFormat(QCalendarWidget::SingleLetterDayNames);
         m_calendarWidget->setNavigationBarVisible(false);
         mainlayout->addRow(m_calendarWidget);
         connect(m_calendarWidget, SIGNAL(selectionChanged()), this, SLOT(refreshDayItems()));
         connect(m_calendarWidget, SIGNAL(currentPageChanged(int, int)), this, SLOT(currentMonthChanged()));
         connect(m_calendarWidget, SIGNAL(activated(QDate)), this, SLOT(dayDoubleClicked(QDate)));

         m_itemList = new QListWidget(this);
         m_itemList->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
         m_itemList->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
         m_itemList->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
         m_itemList->setFocusPolicy(Qt::NoFocus);
         mainlayout->addRow(m_itemList);
         connect(m_itemList, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(itemDoubleClicked(QListWidgetItem*)));

         setLayout(mainlayout);
     }

     // This is separate from the constructor so we can do it after connecting the signals
     void MonthPage::init()
     {
         backendChanged(m_managerComboBox->currentText());
         currentMonthChanged();
     }

     MonthPage::~MonthPage()
     {

     }

     void MonthPage::backendChanged(const QString &managerName)
     {
         // Nothing to change
         if (m_manager && m_manager->managerName() == managerName)
             return;

         // Try creating a new manager
         QMap<QString, QString> parameters;
         QOrganizerManager* newManager = new QOrganizerManager(managerName, parameters, this);
         if (!newManager || newManager->error()) {
             QMessageBox::information(this, tr("Failed!"), QString("Failed to create manager"));
             delete newManager;
             m_managerComboBox->setCurrentIndex(m_managerComboBox->findText(m_manager->managerName()));
         } else {
             // Success: Replace the old one
             delete m_manager;
             m_manager = newManager;
             emit managerChanged(m_manager);
             refresh();
         }
     }

     void MonthPage::editItem()
     {
         QListWidgetItem *listItem = m_itemList->currentItem();
         if (!listItem)
             return;

         QOrganizerItem organizerItem = listItem->data(ORGANIZER_ITEM_ROLE).value<QOrganizerItem>();
         if (!organizerItem.isEmpty())
             emit showEditPage(organizerItem);
     }

     void MonthPage::removeItem()
     {
         QListWidgetItem *listItem = m_itemList->currentItem();
         if (!listItem)
             return;

         QOrganizerItem organizerItem = listItem->data(ORGANIZER_ITEM_ROLE).value<QOrganizerItem>();
         if (organizerItem.isEmpty())
             return;

         m_manager->removeItem(organizerItem.id());
         refresh();
     }

     void MonthPage::refresh()
     {
         // fetch all current months items
         QDate start(m_calendarWidget->yearShown(), m_calendarWidget->monthShown(), 1);
         QDate end = start.addDays(start.daysInMonth());
         QDateTime startDateTime(start, QTime(0, 0, 0, 0));
         QDateTime endDateTime(end, QTime(23, 59, 59, 0));
         // Remove all previous formatting
         for (int i=0; i<start.daysInMonth(); i++) {
             QTextCharFormat cf = m_calendarWidget->dateTextFormat(start.addDays(i));
             cf.setFontItalic(false);
             cf.setFontUnderline(false);
             cf.clearBackground();
             m_calendarWidget->setDateTextFormat(start.addDays(i), cf);
         }

         // Underline current date
         QTextCharFormat cf = m_calendarWidget->dateTextFormat(QDate::currentDate());
         cf.setFontUnderline(true);
         m_calendarWidget->setDateTextFormat(QDate::currentDate(), cf);

         // TODO: switch to item instances when theres a backed
         QList<QOrganizerItem> items = m_manager->items(startDateTime, endDateTime);

         // Get dates for all items
         QList<QDate> dates;
         foreach (const QOrganizerItem &item, items)
         {
             QDate startDate;
             QDate endDate;

             QOrganizerEventTime eventTime = item.detail(QOrganizerItemDetail::TypeEventTime);
             if (!eventTime.isEmpty()) {
                 startDate = eventTime.startDateTime().date();
                 endDate = eventTime.endDateTime().date();
             } else {
                 QOrganizerTodoTime todoTime = item.detail(QOrganizerItemDetail::TypeTodoTime);
                 if (!todoTime.isEmpty()) {
                     startDate = todoTime.startDateTime().date();
                     endDate = todoTime.dueDateTime().date();
                 } else {
                     QOrganizerJournalTime journalTime = item.detail(QOrganizerItemDetail::TypeJournalTime);
                     if (!journalTime.isEmpty())
                         startDate = endDate = journalTime.entryDateTime().date();
                 }
             }

             if (!startDate.isNull()) {
                 while (startDate <= endDate) {
                     dates << startDate;
                     startDate = startDate.addDays(1);
                 }
             }
         }

         // Mark all dates which has events.
         QBrush brush;
         brush.setColor(Qt::green);
         foreach (QDate date, dates) {
             if (date == QDate())
                 continue;
             QTextCharFormat cf = m_calendarWidget->dateTextFormat(date);
             cf.setFontItalic(true); // TODO: find a better way to mark dates
             cf.setBackground(brush);
             m_calendarWidget->setDateTextFormat(date, cf);
         }

         // As the day item list is not showed do not refresh
         // the day items to improve performance
         refreshDayItems();
     }

     void MonthPage::refreshDayItems()
     {
         QDate selectedDate = m_calendarWidget->selectedDate();
         emit currentDayChanged(selectedDate);

         QDateTime startOfDay(selectedDate, QTime(0, 0, 0));
         QDateTime endOfDay(selectedDate, QTime(23, 59, 59));
         // Clear items shown
         m_itemList->clear();

         // Find all items for today
         QList<QOrganizerItem> items = m_manager->items(startOfDay, endOfDay);

         foreach (const QOrganizerItem &item, items)
         {
             QOrganizerEventTime eventTime = item.detail(QOrganizerItemDetail::TypeEventTime);
             if (!eventTime.isEmpty()) {
                 QString time = eventTime.startDateTime().time().toString("hh:mm");
                 QListWidgetItem* listItem = new QListWidgetItem();
                 listItem->setText(QString("Event:%1-%2").arg(time).arg(item.displayLabel()));
                 QVariant data = QVariant::fromValue<QOrganizerItem>(item);
                 listItem->setData(ORGANIZER_ITEM_ROLE, data);
                 m_itemList->addItem(listItem);
             }

             QOrganizerTodoTime todoTime = item.detail(QOrganizerItemDetail::TypeTodoTime);
             if (!todoTime.isEmpty()) {
                 QString time = todoTime.startDateTime().time().toString("hh:mm");
                 QListWidgetItem* listItem = new QListWidgetItem();
                 listItem->setText(QString("Todo:%1-%2").arg(time).arg(item.displayLabel()));
                 QVariant data = QVariant::fromValue<QOrganizerItem>(item);
                 listItem->setData(ORGANIZER_ITEM_ROLE, data);
                 m_itemList->addItem(listItem);
             }

             QOrganizerJournalTime journalTime = item.detail(QOrganizerItemDetail::TypeJournalTime);
             if (!journalTime.isEmpty()) {
                 QString time = journalTime.entryDateTime().time().toString("hh:mm");
                 QListWidgetItem* listItem = new QListWidgetItem();
                 listItem->setText(QString("Journal:%1-%2").arg(time).arg(item.displayLabel()));
                 QVariant data = QVariant::fromValue<QOrganizerItem>(item);
                 listItem->setData(ORGANIZER_ITEM_ROLE, data);
                 m_itemList->addItem(listItem);
             }

             // TODO: other item types
             // TODO: icons for event/todo/journal would be nice
         }
         if (m_itemList->count() == 0)
             m_itemList->addItem("(no entries)");
     }

     void MonthPage::currentMonthChanged()
     {
         int month = m_calendarWidget->monthShown();
         int year = m_calendarWidget->yearShown();
         m_dateLabel->setText(QString("%1 %2").arg(QLocale().standaloneMonthName(month)).arg(year));
         refresh();
         m_ignoreShowDayPageOnceFlag = true;
     }

     void MonthPage::dayDoubleClicked(QDate date)
     {
         if (!m_ignoreShowDayPageOnceFlag)
             emit showDayPage(date);
         else
             m_ignoreShowDayPageOnceFlag = false;
     }

     void MonthPage::openDay()
     {
         emit showDayPage(m_calendarWidget->selectedDate());
     }

     void MonthPage::itemDoubleClicked(QListWidgetItem *listItem)
     {
         if (!listItem)
             return;

         QOrganizerItem organizerItem = listItem->data(ORGANIZER_ITEM_ROLE).value<QOrganizerItem>();
         if (!organizerItem.isEmpty())
             emit showEditPage(organizerItem);
     }

     void MonthPage::showEvent(QShowEvent *event)
     {
         window()->setWindowTitle("Calendar Demo");
         QWidget::showEvent(event);
     }