/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the examples of the Qt Mobility Components. ** ** $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 Digia Plc 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$ ** ****************************************************************************/ #include "calendardemo.h" #include "monthpage.h" #include "daypage.h" #include "eventeditpage.h" #include "todoeditpage.h" #include "journaleditpage.h" #include "eventoccurrenceeditpage.h" #include "addcalendarpage.h" #include "editcalendarspage.h" #ifdef BUILD_VERSIT #include "qversitreader.h" #include "qversitwriter.h" #include "qversitorganizerimporter.h" #include "qversitorganizerexporter.h" #endif #include #include #include QTM_USE_NAMESPACE CalendarDemo::CalendarDemo(QWidget *parent) :QMainWindow(parent), m_stackedWidget(0), m_monthPage(0), m_dayPage(0), m_eventEditPage(0), m_eventOccurrenceEditPage(0) { m_stackedWidget = new QStackedWidget(this); m_dayPage = new DayPage(m_stackedWidget); m_monthPage = new MonthPage(m_stackedWidget); m_eventEditPage = new EventEditPage(m_stackedWidget); m_todoEditPage = new TodoEditPage(m_stackedWidget); m_journalEditPage = new JournalEditPage(m_stackedWidget); m_eventOccurrenceEditPage = new EventOccurrenceEditPage(m_stackedWidget); m_addCalendarPage = new AddCalendarPage(m_stackedWidget); m_editCalendarsPage = new EditCalendarsPage(m_stackedWidget); //qRegisterMetaType("QOrganizerManager"); qRegisterMetaType("QOrganizerItem"); qRegisterMetaType("QOrganizerItemId"); qRegisterMetaType("QOrganizerCollection"); qRegisterMetaType("QOrganizerAbstractRequest::State"); connect(m_monthPage, SIGNAL(showDayPage(QDate)), this, SLOT(activateDayPage()), Qt::QueuedConnection); connect(m_monthPage, SIGNAL(showEditPage(const QOrganizerItem &)), this, SLOT(activateEditPage(const QOrganizerItem &)), Qt::QueuedConnection); connect(m_monthPage, SIGNAL(addNewEvent()), this, SLOT(addNewEvent()), Qt::QueuedConnection); connect(m_monthPage, SIGNAL(addNewTodo()), this, SLOT(addNewTodo()), Qt::QueuedConnection); connect(m_monthPage, SIGNAL(managerChanged(QOrganizerManager*)), this, SLOT(changeManager(QOrganizerManager*)), Qt::QueuedConnection); connect(m_monthPage, SIGNAL(managerChanged(QOrganizerManager*)), m_dayPage, SLOT(changeManager(QOrganizerManager*)), Qt::QueuedConnection); connect(m_monthPage, SIGNAL(currentDayChanged(QDate)), this, SLOT(updateSelectedDay(QDate))); connect(m_dayPage, SIGNAL(showMonthPage()), this, SLOT(activateMonthPage()), Qt::QueuedConnection); connect(m_dayPage, SIGNAL(showEditPage(const QOrganizerItem &)), this, SLOT(activateEditPage(const QOrganizerItem &)), Qt::QueuedConnection); connect(m_dayPage, SIGNAL(addNewEvent()), this, SLOT(addNewEvent()), Qt::QueuedConnection); connect(m_dayPage, SIGNAL(addNewTodo()), this, SLOT(addNewTodo()), Qt::QueuedConnection); connect(m_eventEditPage, SIGNAL(showDayPage()), this, SLOT(activateDayPage()), Qt::QueuedConnection); connect(m_todoEditPage, SIGNAL(showDayPage()), this, SLOT(activateDayPage()), Qt::QueuedConnection); connect(m_journalEditPage, SIGNAL(showDayPage()), this, SLOT(activateDayPage()), Qt::QueuedConnection); connect(m_eventOccurrenceEditPage, SIGNAL(showDayPage()), this, SLOT(activateDayPage()), Qt::QueuedConnection); connect(m_addCalendarPage, SIGNAL(showPreviousPage()), this, SLOT(activatePreviousPage()), Qt::QueuedConnection); connect(m_editCalendarsPage, SIGNAL(showAddCalendarPage(QOrganizerManager*,QOrganizerCollection*)), this, SLOT(editExistingCalendar(QOrganizerManager*,QOrganizerCollection*)), Qt::QueuedConnection); connect(m_editCalendarsPage, SIGNAL(showPreviousPage()), this, SLOT(activateMonthPage()), Qt::QueuedConnection); connect(m_editCalendarsPage, SIGNAL(addClicked()), this, SLOT(addCalendar()), Qt::QueuedConnection); // Connect to the save and remove request status change signals connect(&m_saveReq, SIGNAL(stateChanged(QOrganizerAbstractRequest::State)), this, SLOT(saveReqStateChanged(QOrganizerAbstractRequest::State))); connect(&m_remReq, SIGNAL(stateChanged(QOrganizerAbstractRequest::State)), this, SLOT(removeReqStateChanged(QOrganizerAbstractRequest::State))); m_monthPage->init(); m_stackedWidget->addWidget(m_monthPage); m_stackedWidget->addWidget(m_dayPage); m_stackedWidget->addWidget(m_eventEditPage); m_stackedWidget->addWidget(m_todoEditPage); m_stackedWidget->addWidget(m_journalEditPage); m_stackedWidget->addWidget(m_eventOccurrenceEditPage); m_stackedWidget->addWidget(m_addCalendarPage); m_stackedWidget->addWidget(m_editCalendarsPage); m_stackedWidget->setCurrentIndex(0); setCentralWidget(m_stackedWidget); buildMenu(); activateMonthPage(); } CalendarDemo::~CalendarDemo() { } void CalendarDemo::buildMenu() { // Build Options menu #if defined(Q_WS_MAEMO_5) || defined(Q_WS_MAEMO_6) || defined(Q_OS_WINCE) // These platforms need their menu items added directly to the menu bar. QMenuBar *optionsMenu = menuBar(); #else QMenu *optionsMenu = new QMenu("&Options", this); #if !(defined(Q_OS_SYMBIAN) || defined(Q_WS_SIMULATOR)) // We add the options menu to the softkey manually later menuBar()->addMenu(optionsMenu); #endif #endif // Add editing options in the menu for Symbian (other platforms get buttons) QOrganizerManager defaultManager; QStringList supportedItemTypes = defaultManager.supportedItemTypes(); if (supportedItemTypes.contains(QOrganizerItemType::TypeEvent)) { QAction* addEventAction = optionsMenu->addAction("Add E&vent"); connect(addEventAction, SIGNAL(triggered(bool)), this, SLOT(addNewEvent())); } if (supportedItemTypes.contains(QOrganizerItemType::TypeTodo)) { QAction* addTodoAction = optionsMenu->addAction("Add &Todo"); connect(addTodoAction, SIGNAL(triggered(bool)), this, SLOT(addNewTodo())); } if (supportedItemTypes.contains(QOrganizerItemType::TypeJournal)) { QAction* addJournalAction = optionsMenu->addAction("Add &Journal"); connect(addJournalAction, SIGNAL(triggered(bool)), this, SLOT(addNewJournal())); } optionsMenu->addSeparator(); QAction* editAction = optionsMenu->addAction("&Edit"); connect(editAction, SIGNAL(triggered(bool)), this, SLOT(editItem())); QAction* removeAction = optionsMenu->addAction("&Remove"); connect(removeAction, SIGNAL(triggered(bool)), this, SLOT(removeItem())); optionsMenu->addSeparator(); m_switchViewAction = optionsMenu->addAction("&Open Day"); connect(m_switchViewAction, SIGNAL(triggered(bool)), this, SLOT(switchView())); optionsMenu->addSeparator(); QAction* addHugeEntries = optionsMenu->addAction("Add Test Events"); connect(addHugeEntries, SIGNAL(triggered(bool)), this, SLOT(addEvents())); QAction* importItems = optionsMenu->addAction("&Import Items..."); connect(importItems, SIGNAL(triggered(bool)), this, SLOT(importItems())); QAction* exportItems = optionsMenu->addAction("Ex&port Items..."); connect(exportItems, SIGNAL(triggered(bool)), this, SLOT(exportItems())); QAction* deleteAllEntries = optionsMenu->addAction("Delete All Items"); connect(deleteAllEntries, SIGNAL(triggered(bool)), this, SLOT(deleteAllEntries())); QAction* addCalendar = optionsMenu->addAction("New calendar"); connect(addCalendar, SIGNAL(triggered(bool)), this, SLOT(addCalendar())); QAction* editCalendar = optionsMenu->addAction("Edit calendars"); connect(editCalendar, SIGNAL(triggered(bool)), this, SLOT(editCalendar())); #if defined(Q_OS_SYMBIAN) || defined(Q_WS_SIMULATOR) // add the menu to the softkey for these pages m_monthPage->setMenu(optionsMenu); m_dayPage->setMenu(optionsMenu); #endif } void CalendarDemo::activateMonthPage() { #if !(defined(Q_OS_SYMBIAN) || defined(Q_WS_SIMULATOR) || defined(Q_WS_MAEMO_5) || defined(Q_WS_MAEMO_6)) menuBar()->setVisible(true); #endif m_monthPage->refresh(); m_stackedWidget->setCurrentWidget(m_monthPage); m_switchViewAction->setText("&Open Day"); } void CalendarDemo::activateDayPage() { #if !(defined(Q_OS_SYMBIAN) || defined(Q_WS_SIMULATOR) || defined(Q_WS_MAEMO_5) || defined(Q_WS_MAEMO_6)) menuBar()->setVisible(true); #endif m_dayPage->refresh(); m_stackedWidget->setCurrentWidget(m_dayPage); m_switchViewAction->setText("View &Month"); } void CalendarDemo::activateEditPage(const QOrganizerItem &item) { m_previousItem = item; #if !(defined(Q_OS_SYMBIAN) || defined(Q_WS_SIMULATOR) || defined(Q_WS_MAEMO_5) || defined(Q_WS_MAEMO_6)) menuBar()->setVisible(false); #endif if (item.type() == QOrganizerItemType::TypeEvent) { QOrganizerEvent event = static_cast(item); m_dayPage->dayChanged(event.startDateTime().date()); // edit always comes back to day page m_eventEditPage->eventChanged(m_manager, event); m_stackedWidget->setCurrentWidget(m_eventEditPage); } else if (item.type() == QOrganizerItemType::TypeTodo) { QOrganizerTodo todo = static_cast(item); m_dayPage->dayChanged(todo.startDateTime().date()); // edit always comes back to day page m_todoEditPage->todoChanged(m_manager, todo); m_stackedWidget->setCurrentWidget(m_todoEditPage); } else if (item.type() == QOrganizerItemType::TypeJournal) { QOrganizerJournal journal = static_cast(item); m_dayPage->dayChanged(journal.dateTime().date()); // edit always comes back to day page m_journalEditPage->journalChanged(m_manager, journal); m_stackedWidget->setCurrentWidget(m_journalEditPage); } else if (item.type() == QOrganizerItemType::TypeEventOccurrence) { QOrganizerEventOccurrence eventOccurrence = static_cast(item); QMessageBox msgBox; msgBox.setText(tr("This is a recurring event")); msgBox.setInformativeText(tr("Do you want to open this occurrence or the recurring event series?")); QAbstractButton *occurrenceButton = msgBox.addButton(tr("Occurrence"), QMessageBox::ActionRole); QAbstractButton *seriesButton = msgBox.addButton(tr("Series"), QMessageBox::ActionRole); msgBox.exec(); if (msgBox.clickedButton() == seriesButton) { QOrganizerItemId parentEventId = eventOccurrence.parentId(); QOrganizerEvent parentEvent = m_manager->item(parentEventId); m_dayPage->dayChanged(parentEvent.startDateTime().date()); // edit always comes back to day page m_eventEditPage->eventChanged(m_manager, parentEvent); m_stackedWidget->setCurrentWidget(m_eventEditPage); } else if (msgBox.clickedButton() == occurrenceButton) { m_dayPage->dayChanged(eventOccurrence.startDateTime().date()); // edit always comes back to day page m_eventOccurrenceEditPage->eventOccurrenceChanged(m_manager, eventOccurrence); m_stackedWidget->setCurrentWidget(m_eventOccurrenceEditPage); } } // TODO: //else if (item.type() == QOrganizerItemType::TypeNote) } void CalendarDemo::activatePreviousPage() { if (m_previousPage == m_stackedWidget->indexOf(m_monthPage)) activateMonthPage(); else if (m_previousPage == m_stackedWidget->indexOf(m_dayPage)) activateDayPage(); else if (m_previousPage == m_stackedWidget->indexOf(m_editCalendarsPage)) editCalendar(); else activateEditPage(m_previousItem); } void CalendarDemo::addNewEvent() { QOrganizerEvent newEvent; QDateTime time(m_currentDate); newEvent.setStartDateTime(time); time = time.addSecs(60*30); // add 30 minutes to end time newEvent.setEndDateTime(time); activateEditPage(newEvent); } void CalendarDemo::addNewTodo() { QOrganizerTodo newTodo; QDateTime time(m_currentDate); newTodo.setStartDateTime(time); time = time.addSecs(60*30); // add 30 minutes to due time newTodo.setDueDateTime(time); activateEditPage(newTodo); } void CalendarDemo::addNewJournal() { QOrganizerJournal newJournal; QDateTime time(m_currentDate); newJournal.setDateTime(time); activateEditPage(newJournal); } void CalendarDemo::switchView() { if (m_stackedWidget->currentWidget() == m_dayPage) { activateMonthPage(); } else if (m_stackedWidget->currentWidget() == m_monthPage) { activateDayPage(); } } void CalendarDemo::editItem() { if (m_stackedWidget->currentWidget() == m_dayPage) { m_dayPage->editItem(); } else if (m_stackedWidget->currentWidget() == m_monthPage) { m_monthPage->editItem(); } } void CalendarDemo::removeItem() { if (m_stackedWidget->currentWidget() == m_dayPage) { m_dayPage->removeItem(); } else if (m_stackedWidget->currentWidget() == m_monthPage) { m_monthPage->removeItem(); } } void CalendarDemo::addEvents() { QList items; // Create a large number of events asynchronously QOrganizerCollectionId defaultCollectionId = m_manager->defaultCollection().id(); for(int index=0 ; index < 100 ; index++) { QOrganizerItem item; item.setType(QOrganizerItemType::TypeEvent); item.setDescription(QString("Event %1").arg(index)); item.setDisplayLabel(QString("Subject for event %1").arg(index + 1)); // Set the start date to index to add events to next 5000 days QOrganizerEventTime timeRange; timeRange.setStartDateTime(QDateTime::currentDateTime().addDays(index)); timeRange.setEndDateTime(QDateTime::currentDateTime().addDays(index).addSecs(60 * 60)); item.saveDetail(&timeRange); item.setCollectionId(defaultCollectionId); items.append(item); } // Now create a save request and execute it m_saveReq.setItems(items); m_saveReq.setManager(m_manager); m_saveReq.start(); } void CalendarDemo::importItems() { #ifdef BUILD_VERSIT QString messageTitle(tr("Import of Items failed")); if (!m_manager) { QMessageBox::warning(this, messageTitle, tr("No manager selected; cannot import")); return; } QString docPath = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation); if (docPath.isEmpty()) docPath = QDesktopServices::storageLocation(QDesktopServices::HomeLocation); if (docPath.isEmpty()) docPath = "."; QString fileName = QFileDialog::getOpenFileName(this, tr("Select iCalendar file"), docPath, tr("iCalendar files (*.ics)")); // user chose to cancel file dialog? if (fileName.isEmpty()) return; QFile file(fileName); if (!file.open(QIODevice::ReadOnly) || !file.isReadable()){ QMessageBox::warning(this, messageTitle, tr("Unable to read from file: %1").arg(fileName)); return; } QVersitReader reader; reader.setDevice(&file); if (!reader.startReading() || !reader.waitForFinished()) { QMessageBox::warning(this, messageTitle, tr("Versit reader failed: %1").arg(reader.error())); return; } QVersitOrganizerImporter importer; QList allItems; QString errorMessage; foreach (const QVersitDocument& document, reader.results()) { if (!importer.importDocument(document)) { errorMessage += tr("Import failed,"); QMap::const_iterator iterator = importer.errorMap().constBegin(); while(iterator != importer.errorMap().constEnd()){ switch (iterator.value()){ case QVersitOrganizerImporter::InvalidDocumentError: errorMessage += QString(" index %1:").arg(iterator.key()); errorMessage += tr("One of the documents is not an iCalendar file"); break; case QVersitOrganizerImporter::EmptyDocumentError: errorMessage += QString(" index %1:").arg(iterator.key()); errorMessage += tr("One of the documents is empty"); break; default: errorMessage += QString(" index %1:").arg(iterator.key()); errorMessage += tr("Unknown error"); } ++iterator; } errorMessage += QLatin1String("\n"); continue; } QList items = importer.items(); foreach (const QOrganizerItem& item, items) { allItems.append(m_manager->compatibleItem(item)); } } if (!errorMessage.isEmpty()) QMessageBox::warning(this, messageTitle, errorMessage); m_manager->saveItems(&allItems); m_monthPage->refresh(); m_dayPage->refresh(); #endif } void CalendarDemo::exportItems() { #ifdef BUILD_VERSIT QString messageTitle(tr("Export of Items failed")); if (!m_manager) { QMessageBox::warning(this, messageTitle, tr("No manager selected; cannot export")); return; } QString docPath = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation); if (docPath.isEmpty()) docPath = QDesktopServices::storageLocation(QDesktopServices::HomeLocation); if (docPath.isEmpty()) docPath = "."; docPath.append("/calendar.ics"); QString fileName = QFileDialog::getSaveFileName(this, tr("Save iCalendar"), docPath, tr("iCalendar files (*.ics)")); // user chose to cancel file dialog? if (fileName.isEmpty()) return; QFile file(fileName); if (!file.open(QIODevice::WriteOnly) || !file.isWritable()) { QMessageBox::warning(this, messageTitle, tr("Unable to write to file: %1").arg(fileName)); return; } QList items(m_manager->itemsForExport()); QVersitOrganizerExporter exporter; QString errorMessage; if (!exporter.exportItems(items)) { errorMessage += tr("Export failed,"); QMap::const_iterator iterator = exporter.errorMap().constBegin(); while(iterator != exporter.errorMap().constEnd()){ switch (iterator.value()){ case QVersitOrganizerExporter::EmptyOrganizerError: errorMessage += QString(" index %1:").arg(iterator.key()); errorMessage += tr("One of the documents is not an iCalendar file"); break; case QVersitOrganizerExporter::UnknownComponentTypeError: errorMessage += QString(" index %1:").arg(iterator.key()); errorMessage += tr("One of the components in the iCalendar file is" " not supported"); break; case QVersitOrganizerExporter::UnderspecifiedOccurrenceError: errorMessage += QString(" index %1:").arg(iterator.key()); errorMessage += tr("An event or todo exception was found which" " did not specify both its parent and a specifier for" " which instance to override"); break; default: errorMessage += QString(" index %1:%2 ").arg(iterator.key()) .arg(tr("Unknown error")); } ++iterator; } errorMessage += QLatin1String("\n"); if (!errorMessage.isEmpty()){ QMessageBox::warning(this, messageTitle, errorMessage); return; } } QVersitDocument document = exporter.document(); QVersitWriter writer; writer.setDevice(&file); if (!writer.startWriting(QList() << document) || !writer.waitForFinished()) { QMessageBox::warning(this, messageTitle, tr("Versit writing of organizer items failed: %1").arg(writer.error())); } #endif } void CalendarDemo::deleteAllEntries() { // Fetch all the entries QList ids = m_manager->itemIds(); if(ids.count()) { m_remReq.setItemIds(ids); m_remReq.setManager(m_manager); m_remReq.start(); } } void CalendarDemo::addCalendar() { // Get default collection QOrganizerCollection defaultCollection = m_manager->defaultCollection(); QOrganizerCollection newCollection = defaultCollection; newCollection.setId(QOrganizerCollectionId()); // reset collection id #if defined(Q_WS_MAEMO_5) newCollection.setMetaData("Name", "New calendar"); #endif m_addCalendarPage->calendarChanged(m_manager, newCollection); m_previousPage = m_stackedWidget->currentIndex(); m_stackedWidget->setCurrentWidget(m_addCalendarPage); } void CalendarDemo::editCalendar() { m_editCalendarsPage->showPage(m_manager); m_previousPage = m_stackedWidget->currentIndex(); m_stackedWidget->setCurrentWidget(m_editCalendarsPage); } void CalendarDemo::editExistingCalendar(QOrganizerManager *manager, QOrganizerCollection* calendar) { m_addCalendarPage->calendarChanged(manager, *calendar); m_previousPage = m_stackedWidget->currentIndex(); m_stackedWidget->setCurrentWidget(m_addCalendarPage); } void CalendarDemo::saveReqStateChanged(QOrganizerAbstractRequest::State reqState) { if(QOrganizerAbstractRequest::ActiveState == reqState) { // Request started. Show a progress or wait dialog m_progressDlg = new QProgressDialog("Saving events..", "Cancel", 100, 100, this); m_progressDlg->setAttribute(Qt::WA_DeleteOnClose); connect(m_progressDlg, SIGNAL(canceled()), &m_saveReq, SLOT(cancel())); m_progressDlg->show(); } else if (QOrganizerAbstractRequest::FinishedState == reqState || QOrganizerAbstractRequest::CanceledState == reqState) { // Request finished or cancelled. Stop showing the progress dialog and refresh m_progressDlg->done(0); m_monthPage->refresh(); m_dayPage->refresh(); } } void CalendarDemo::removeReqStateChanged(QOrganizerAbstractRequest::State reqState) { if(QOrganizerAbstractRequest::ActiveState == reqState) { // Request started. Show a progress or wait dialog m_progressDlg = new QProgressDialog("Removing events..", "Cancel", 100, 100, this); m_progressDlg->setAttribute(Qt::WA_DeleteOnClose); connect(m_progressDlg, SIGNAL(canceled()), &m_remReq, SLOT(cancel())); m_progressDlg->show(); } else if (QOrganizerAbstractRequest::FinishedState == reqState || QOrganizerAbstractRequest::CanceledState == reqState) { // Request finished or cancelled. Stop showing the progress dialog and refresh m_progressDlg->done(0); m_monthPage->refresh(); m_dayPage->refresh(); } } void CalendarDemo::changeManager(QOrganizerManager *manager) { m_manager = manager; } void CalendarDemo::updateSelectedDay(const QDate& date) { m_dayPage->dayChanged(date); m_currentDate = date; }