diff --git a/CMakeLists.txt b/CMakeLists.txt index a34e724..b1446b3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,95 +1,95 @@ cmake_minimum_required(VERSION 3.5) set(PIM_VERSION "5.11.40") project(calendarsupport VERSION ${PIM_VERSION}) set(KF5_MIN_VERSION "5.59.0") find_package(ECM ${KF5_MIN_VERSION} CONFIG REQUIRED) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH}) set(LIBRARY_NAMELINK) include(GenerateExportHeader) include(ECMSetupVersion) include(ECMGenerateHeaders) include(ECMGeneratePriFile) include(ECMSetupVersion) include(FeatureSummary) include(KDEInstallDirs) include(KDECMakeSettings) include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE) include(ECMQtDeclareLoggingCategory) include(ECMAddTests) set(CALENDARSUPPORT_LIB_VERSION ${PIM_VERSION}) set(AKONADI_MIMELIB_VERSION "5.11.40") set(KDEPIM_LIB_VERSION "5.11.40") set(QT_REQUIRED_VERSION "5.10.0") set(KMIME_LIB_VERSION "5.11.40") set(CALENDARUTILS_LIB_VERSION "5.11.40") -set(KCALENDARCORE_LIB_VERSION "5.11.42") +set(KCALENDARCORE_LIB_VERSION "5.11.44") set(IDENTITYMANAGEMENT_LIB_VERSION "5.11.40") set(AKONADICALENDAR_LIB_VERSION "5.11.40") set(PIMCOMMON_LIB_VERSION "5.11.40") set(AKONADI_VERSION "5.11.40") find_package(KF5Akonadi ${AKONADI_VERSION} CONFIG REQUIRED) find_package(Qt5 ${QT_REQUIRED_VERSION} CONFIG REQUIRED Widgets Test UiTools PrintSupport) find_package(KF5I18n ${KF5_MIN_VERSION} CONFIG REQUIRED) find_package(KF5IconThemes ${KF5_MIN_VERSION} CONFIG REQUIRED) find_package(KF5GuiAddons ${KF5_MIN_VERSION} CONFIG REQUIRED) find_package(KF5KIO ${KF5_MIN_VERSION} CONFIG REQUIRED) find_package(KF5Mime ${KMIME_LIB_VERSION} CONFIG REQUIRED) find_package(KF5AkonadiMime ${AKONADI_MIMELIB_VERSION} CONFIG REQUIRED) find_package(KF5Codecs ${KF5_MIN_VERSION} CONFIG REQUIRED) find_package(KF5CalendarUtils ${CALENDARUTILS_LIB_VERSION} CONFIG REQUIRED) find_package(KF5CalendarCore ${KCALENDARCORE_LIB_VERSION} CONFIG REQUIRED) find_package(KF5IdentityManagement ${IDENTITYMANAGEMENT_LIB_VERSION} CONFIG REQUIRED) find_package(KF5Holidays ${KF5_MIN_VERSION} CONFIG REQUIRED) find_package(KF5AkonadiCalendar ${AKONADICALENDAR_LIB_VERSION} CONFIG REQUIRED) find_package(KF5PimCommon ${PIMCOMMON_LIB_VERSION} CONFIG REQUIRED) find_package(KF5KdepimDBusInterfaces ${KDEPIM_LIB_VERSION} CONFIG REQUIRED) ecm_setup_version(PROJECT VARIABLE_PREFIX CALENDARSUPPORT VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/calendarsupport_version.h" PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF5CalendarSupportConfigVersion.cmake" SOVERSION 5 ) ########### Targets ########### add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x060000) ########### CMake Config Files ########### set(CMAKECONFIG_INSTALL_DIR "${KDE_INSTALL_CMAKEPACKAGEDIR}/KF5CalendarSupport") configure_package_config_file( "${CMAKE_CURRENT_SOURCE_DIR}/KF5CalendarSupportConfig.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/KF5CalendarSupportConfig.cmake" INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR} ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/KF5CalendarSupportConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/KF5CalendarSupportConfigVersion.cmake" DESTINATION "${CMAKECONFIG_INSTALL_DIR}" COMPONENT Devel ) install(EXPORT KF5CalendarSupportTargets DESTINATION "${CMAKECONFIG_INSTALL_DIR}" FILE KF5CalendarSupportTargets.cmake NAMESPACE KF5::) install( FILES ${CMAKE_CURRENT_BINARY_DIR}/calendarsupport_version.h DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5} COMPONENT Devel ) add_definitions(-DQT_NO_FOREACH) add_subdirectory(src) install(FILES calendarsupport.categories calendarsupport.renamecategories DESTINATION ${KDE_INSTALL_LOGGINGCATEGORIESDIR}) feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/src/freebusymodel/autotests/testfreebusyitemmodel.cpp b/src/freebusymodel/autotests/testfreebusyitemmodel.cpp index 2aa6c1e..4dfca61 100644 --- a/src/freebusymodel/autotests/testfreebusyitemmodel.cpp +++ b/src/freebusymodel/autotests/testfreebusyitemmodel.cpp @@ -1,248 +1,243 @@ /* Copyright (C) 2010 Casey Link Copyright (C) 2009-2010 Klaralvdalens Datakonsult AB, a KDAB Group company This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "testfreebusyitemmodel.h" #include "modeltest.h" #include "../freebusyitemmodel.h" #include "../freebusyitem.h" #include #include using namespace CalendarSupport; // Workaround QTBUG-51789 causing a crash when QtWebEngineWidgets // is linked into a QCoreApplication. QTEST_GUILESS_MAIN(FreeBusyItemModelTest) void FreeBusyItemModelTest::testModelValidity() { FreeBusyItemModel *model = new FreeBusyItemModel(this); new ModelTest(model, this); QVERIFY(model->rowCount() == 0); const QDateTime dt1(QDate(2010, 7, 24), QTime(7, 0, 0), Qt::UTC); const QDateTime dt2(QDate(2010, 7, 24), QTime(10, 0, 0), Qt::UTC); - KCalCore::Attendee::Ptr a1(new KCalCore::Attendee(QStringLiteral("fred"), QStringLiteral( - "fred@example.com"))); + KCalCore::Attendee a1(QStringLiteral("fred"), QStringLiteral( "fred@example.com")); KCalCore::FreeBusy::Ptr fb1(new KCalCore::FreeBusy()); fb1->addPeriod(dt1, KCalCore::Duration(60 * 60)); fb1->addPeriod(dt2, KCalCore::Duration(60 * 60)); FreeBusyItem::Ptr item1(new FreeBusyItem(a1, nullptr)); item1->setFreeBusy(fb1); model->addItem(item1); QVERIFY(model->rowCount() == 1); QVERIFY(model->containsAttendee(a1)); QModelIndex i = model->index(0, 0); - QCOMPARE(a1->fullName(), model->data(i, Qt::DisplayRole).toString()); + QCOMPARE(a1.fullName(), model->data(i, Qt::DisplayRole).toString()); QCOMPARE(a1, - model->data(i, FreeBusyItemModel::AttendeeRole).value()); + model->data(i, FreeBusyItemModel::AttendeeRole).value()); QCOMPARE(item1->freeBusy(), model->data(i, FreeBusyItemModel::FreeBusyRole).value()); QCOMPARE(model->rowCount(i), 2); model->removeRow(0); QVERIFY(model->rowCount() == 0); model->addItem(item1); QVERIFY(model->rowCount() == 1); model->removeAttendee(a1); QVERIFY(model->rowCount() == 0); model->addItem(item1); QVERIFY(model->rowCount() == 1); model->removeItem(item1); QVERIFY(model->rowCount() == 0); model->addItem(item1); QVERIFY(model->rowCount() == 1); model->clear(); QVERIFY(model->rowCount() == 0); } void FreeBusyItemModelTest::testModelValidity2() { FreeBusyItemModel *model = new FreeBusyItemModel(this); new ModelTest(model, this); const QDateTime dt1(QDate(2010, 7, 24), QTime(7, 0, 0), Qt::UTC); const QDateTime dt2(QDate(2010, 7, 24), QTime(10, 0, 0), Qt::UTC); const QDateTime dt3(QDate(2010, 7, 24), QTime(12, 0, 0), Qt::UTC); const QDateTime dt4(QDate(2010, 7, 24), QTime(14, 0, 0), Qt::UTC); - KCalCore::Attendee::Ptr a1(new KCalCore::Attendee(QStringLiteral("fred"), QStringLiteral( - "fred@example.com"))); - KCalCore::Attendee::Ptr a2(new KCalCore::Attendee(QStringLiteral("joe"), QStringLiteral( - "joe@example.com"))); - KCalCore::Attendee::Ptr a3(new KCalCore::Attendee(QStringLiteral("max"), QStringLiteral( - "max@example.com"))); + KCalCore::Attendee a1(QStringLiteral("fred"), QStringLiteral( "fred@example.com")); + KCalCore::Attendee a2(QStringLiteral("joe"), QStringLiteral( "joe@example.com")); + KCalCore::Attendee a3(QStringLiteral("max"), QStringLiteral( "max@example.com")); KCalCore::FreeBusy::Ptr fb1(new KCalCore::FreeBusy()); KCalCore::FreeBusy::Ptr fb2(new KCalCore::FreeBusy()); KCalCore::FreeBusy::Ptr fb3(new KCalCore::FreeBusy()); fb1->addPeriod(dt1, KCalCore::Duration(60 * 60)); fb1->addPeriod(dt2, KCalCore::Duration(60 * 60)); fb2->addPeriod(dt1, KCalCore::Duration(60 * 60)); fb2->addPeriod(dt2, KCalCore::Duration(60 * 60)); fb2->addPeriod(dt3, KCalCore::Duration(60 * 60)); fb3->addPeriod(dt1, KCalCore::Duration(60 * 60)); fb3->addPeriod(dt2, KCalCore::Duration(60 * 60)); fb3->addPeriod(dt4, KCalCore::Duration(60 * 60 * 2)); FreeBusyItem::Ptr item1(new FreeBusyItem(a1, nullptr)); item1->setFreeBusy(fb1); FreeBusyItem::Ptr item2(new FreeBusyItem(a2, nullptr)); FreeBusyItem::Ptr item3(new FreeBusyItem(a3, nullptr)); model->addItem(item1); model->addItem(item2); model->addItem(item3); QCOMPARE(model->rowCount(), 3); QVERIFY(model->containsAttendee(a1)); QVERIFY(model->containsAttendee(a2)); QVERIFY(model->containsAttendee(a3)); QModelIndex i1 = model->index(0, 0); - QCOMPARE(a1->fullName(), model->data(i1, Qt::DisplayRole).toString()); + QCOMPARE(a1.fullName(), model->data(i1, Qt::DisplayRole).toString()); QCOMPARE(a1, - model->data(i1, FreeBusyItemModel::AttendeeRole).value()); + model->data(i1, FreeBusyItemModel::AttendeeRole).value()); QCOMPARE(item1->freeBusy(), model->data(i1, FreeBusyItemModel::FreeBusyRole).value()); QModelIndex i2 = model->index(1, 0); - QCOMPARE(a2->fullName(), model->data(i2, Qt::DisplayRole).toString()); + QCOMPARE(a2.fullName(), model->data(i2, Qt::DisplayRole).toString()); QCOMPARE(a2, - model->data(i2, FreeBusyItemModel::AttendeeRole).value()); + model->data(i2, FreeBusyItemModel::AttendeeRole).value()); QVERIFY(model->rowCount(i2) == 0); QVERIFY(model->data(i2, FreeBusyItemModel::FreeBusyRole).isValid() == false); QModelIndex i3 = model->index(2, 0); - QCOMPARE(a3->fullName(), + QCOMPARE(a3.fullName(), model->data(i3, Qt::DisplayRole).toString()); QCOMPARE(a3, - model->data(i3, FreeBusyItemModel::AttendeeRole).value()); + model->data(i3, FreeBusyItemModel::AttendeeRole).value()); QVERIFY(model->rowCount(i3) == 0); QVERIFY(model->data(i3, FreeBusyItemModel::FreeBusyRole).isValid() == false); model->slotInsertFreeBusy(fb2, QStringLiteral("joe@example.com")); QCOMPARE(item2->freeBusy(), model->data(i2, FreeBusyItemModel::FreeBusyRole).value()); QVERIFY(model->rowCount(i2) == fb2->fullBusyPeriods().size()); QModelIndex i2_0 = model->index(0, 0, i2); QCOMPARE(fb2->fullBusyPeriods().first(), model->data( i2_0, FreeBusyItemModel::FreeBusyPeriodRole).value()); QModelIndex i2_1 = model->index(1, 0, i2); QCOMPARE(fb2->fullBusyPeriods().at(1), model->data( i2_1, FreeBusyItemModel::FreeBusyPeriodRole).value()); QModelIndex i2_2 = model->index(2, 0, i2); QCOMPARE(fb2->fullBusyPeriods().last(), model->data( i2_2, FreeBusyItemModel::FreeBusyPeriodRole).value()); model->slotInsertFreeBusy(fb3, QStringLiteral("max@example.com")); QCOMPARE(item3->freeBusy(), model->data(i3, FreeBusyItemModel::FreeBusyRole).value()); QVERIFY(model->rowCount(i3) == fb3->fullBusyPeriods().size()); QModelIndex i3_0 = model->index(0, 0, i3); QCOMPARE(fb3->fullBusyPeriods().first(), model->data( i3_0, FreeBusyItemModel::FreeBusyPeriodRole).value()); QModelIndex i3_1 = model->index(1, 0, i3); QCOMPARE(fb3->fullBusyPeriods().at(1), model->data( i3_1, FreeBusyItemModel::FreeBusyPeriodRole).value()); QModelIndex i3_2 = model->index(2, 0, i3); QCOMPARE(fb3->fullBusyPeriods().last(), model->data( i3_2, FreeBusyItemModel::FreeBusyPeriodRole).value()); model->removeAttendee(a2); QCOMPARE(2, model->rowCount()); QVERIFY(model->containsAttendee(a1) == true); QVERIFY(model->containsAttendee(a2) == false); QVERIFY(model->containsAttendee(a3) == true); i3_0 = model->index(0, 0, i3); QCOMPARE(fb3->fullBusyPeriods().first(), model->data( i3_0, FreeBusyItemModel::FreeBusyPeriodRole).value()); i3_1 = model->index(1, 0, i3); QCOMPARE(fb3->fullBusyPeriods().at(1), model->data( i3_1, FreeBusyItemModel::FreeBusyPeriodRole).value()); i3_2 = model->index(2, 0, i3); QCOMPARE(fb3->fullBusyPeriods().last(), model->data( i3_2, FreeBusyItemModel::FreeBusyPeriodRole).value()); } void FreeBusyItemModelTest::testInsertFreeBusy() { FreeBusyItemModel *model = new FreeBusyItemModel(this); new ModelTest(model, this); const QDateTime dt1(QDate(2010, 7, 24), QTime(7, 0, 0), Qt::UTC); const QDateTime dt2(QDate(2010, 7, 24), QTime(10, 0, 0), Qt::UTC); - KCalCore::Attendee::Ptr a1(new KCalCore::Attendee(QStringLiteral("fred"), QStringLiteral( - "fred@example.com"))); + KCalCore::Attendee a1(QStringLiteral("fred"), QStringLiteral( "fred@example.com")); KCalCore::FreeBusy::Ptr fb1(new KCalCore::FreeBusy()); fb1->addPeriod(dt1, KCalCore::Duration(60 * 60)); fb1->addPeriod(dt2, KCalCore::Duration(60 * 60)); const QDateTime dt3(QDate(2010, 7, 24), QTime(12, 0, 0), Qt::UTC); const QDateTime dt4(QDate(2010, 7, 24), QTime(14, 0, 0), Qt::UTC); KCalCore::FreeBusy::Ptr fb2(new KCalCore::FreeBusy()); fb2->addPeriod(dt1, KCalCore::Duration(60 * 60)); fb2->addPeriod(dt2, KCalCore::Duration(60 * 60)); fb2->addPeriod(dt3, KCalCore::Duration(60 * 60)); fb2->addPeriod(dt4, KCalCore::Duration(60 * 60 * 2)); FreeBusyItem::Ptr item1(new FreeBusyItem(a1, nullptr)); item1->setFreeBusy(fb1); model->addItem(item1); QModelIndex i = model->index(0, 0); QCOMPARE(model->rowCount(i), 2); model->slotInsertFreeBusy(fb2, QStringLiteral("fred@example.com")); QCOMPARE(model->rowCount(i), 4); } diff --git a/src/freebusymodel/freebusyitem.cpp b/src/freebusymodel/freebusyitem.cpp index a2bdd9e..213e155 100644 --- a/src/freebusymodel/freebusyitem.cpp +++ b/src/freebusymodel/freebusyitem.cpp @@ -1,87 +1,87 @@ /* Copyright (c) 2000,2001,2004 Cornelius Schumacher Copyright (c) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Copyright (c) 2010 Andras Mantia Copyright (C) 2010 Casey Link This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "freebusyitem.h" #include using namespace CalendarSupport; -FreeBusyItem::FreeBusyItem(const KCalCore::Attendee::Ptr &attendee, QWidget *parentWidget) +FreeBusyItem::FreeBusyItem(const KCalCore::Attendee &attendee, QWidget *parentWidget) : mAttendee(attendee) , mTimerID(0) , mIsDownloading(false) , mParentWidget(parentWidget) { - Q_ASSERT(attendee); + Q_ASSERT(!attendee.isNull()); setFreeBusy(KCalCore::FreeBusy::Ptr()); } -KCalCore::Attendee::Ptr FreeBusyItem::attendee() const +KCalCore::Attendee FreeBusyItem::attendee() const { return mAttendee; } void FreeBusyItem::setFreeBusy(const KCalCore::FreeBusy::Ptr &fb) { mFreeBusy = fb; mIsDownloading = false; } KCalCore::FreeBusy::Ptr FreeBusyItem::freeBusy() const { return mFreeBusy; } QString FreeBusyItem::email() const { - return mAttendee->email(); + return mAttendee.email(); } void FreeBusyItem::setUpdateTimerID(int id) { mTimerID = id; } int FreeBusyItem::updateTimerID() const { return mTimerID; } void FreeBusyItem::startDownload(bool forceDownload) { mIsDownloading = true; Akonadi::FreeBusyManager *m = Akonadi::FreeBusyManager::self(); - if (!m->retrieveFreeBusy(attendee()->email(), forceDownload, mParentWidget)) { + if (!m->retrieveFreeBusy(attendee().email(), forceDownload, mParentWidget)) { mIsDownloading = false; } } void FreeBusyItem::setIsDownloading(bool d) { mIsDownloading = d; } bool FreeBusyItem::isDownloading() const { return mIsDownloading; } diff --git a/src/freebusymodel/freebusyitem.h b/src/freebusymodel/freebusyitem.h index 081dc1e..f432a00 100644 --- a/src/freebusymodel/freebusyitem.h +++ b/src/freebusymodel/freebusyitem.h @@ -1,76 +1,76 @@ /* Copyright (c) 2000,2001,2004 Cornelius Schumacher Copyright (c) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Copyright (c) 2010 Andras Mantia Copyright (C) 2010 Casey Link This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef INCIDENCEEDITOR_FREEBUSYITEM_H #define INCIDENCEEDITOR_FREEBUSYITEM_H #include "calendarsupport_export.h" #include namespace CalendarSupport { /** * The FreeBusyItem is the whole line for a given attendee.. */ class CALENDARSUPPORT_EXPORT FreeBusyItem { public: typedef QSharedPointer Ptr; /** * @param parentWidget is passed to Akonadi when fetching free/busy data. */ - FreeBusyItem(const KCalCore::Attendee::Ptr &attendee, QWidget *parentWidget); + FreeBusyItem(const KCalCore::Attendee &attendee, QWidget *parentWidget); ~FreeBusyItem() { } - KCalCore::Attendee::Ptr attendee() const; + KCalCore::Attendee attendee() const; void setFreeBusy(const KCalCore::FreeBusy::Ptr &fb); KCalCore::FreeBusy::Ptr freeBusy() const; Q_REQUIRED_RESULT QString email() const; void setUpdateTimerID(int id); Q_REQUIRED_RESULT int updateTimerID() const; void startDownload(bool forceDownload); void setIsDownloading(bool d); Q_REQUIRED_RESULT bool isDownloading() const; Q_SIGNALS: - void attendeeChanged(const KCalCore::Attendee::Ptr &attendee); + void attendeeChanged(const KCalCore::Attendee &attendee); void freebusyChanged(const KCalCore::FreeBusy::Ptr fb); private: - KCalCore::Attendee::Ptr mAttendee; + KCalCore::Attendee mAttendee; KCalCore::FreeBusy::Ptr mFreeBusy; // This is used for the update timer int mTimerID; // Only run one download job at a time bool mIsDownloading = false; QWidget *mParentWidget = nullptr; }; } #endif diff --git a/src/freebusymodel/freebusyitemmodel.cpp b/src/freebusymodel/freebusyitemmodel.cpp index 48aa01e..b3d45ac 100644 --- a/src/freebusymodel/freebusyitemmodel.cpp +++ b/src/freebusymodel/freebusyitemmodel.cpp @@ -1,425 +1,425 @@ /* Copyright (C) 2010 Casey Link Copyright (C) 2009-2010 Klaralvdalens Datakonsult AB, a KDAB Group company This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "freebusyitemmodel.h" #include #include #include #include using namespace CalendarSupport; class ItemPrivateData { public: ItemPrivateData(ItemPrivateData *parent) : parentItem(parent) { } ~ItemPrivateData() { qDeleteAll(childItems); } ItemPrivateData *child(int row) { return childItems.value(row); } void appendChild(ItemPrivateData *item) { childItems.append(item); } ItemPrivateData *removeChild(int row) { return childItems.takeAt(row); } int childCount() const { return childItems.count(); } int row() const { if (parentItem) { return parentItem->childItems.indexOf(const_cast(this)); } return 0; } ItemPrivateData *parent() { return parentItem; } private: QList childItems; ItemPrivateData *parentItem = nullptr; }; class CalendarSupport::FreeBusyItemModelPrivate { public: FreeBusyItemModelPrivate() : mForceDownload(false) , mRootData(nullptr) { } ~FreeBusyItemModelPrivate() { delete mRootData; } QTimer mReloadTimer; bool mForceDownload = false; QList mFreeBusyItems; ItemPrivateData *mRootData = nullptr; }; FreeBusyItemModel::FreeBusyItemModel(QObject *parent) : QAbstractItemModel(parent) , d(new CalendarSupport::FreeBusyItemModelPrivate) { - qRegisterMetaType("KCalCore::Attendee::Ptr"); + qRegisterMetaType(); qRegisterMetaType("KCalCore::FreeBusy::Ptr"); qRegisterMetaType("KCalCore::Period"); Akonadi::FreeBusyManager *m = Akonadi::FreeBusyManager::self(); connect(m, &Akonadi::FreeBusyManager::freeBusyRetrieved, this, &FreeBusyItemModel::slotInsertFreeBusy); connect(&d->mReloadTimer, &QTimer::timeout, this, &FreeBusyItemModel::autoReload); d->mReloadTimer.setSingleShot(true); d->mRootData = new ItemPrivateData(nullptr); } FreeBusyItemModel::~FreeBusyItemModel() { delete d; } QVariant FreeBusyItemModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return QVariant(); } ItemPrivateData *data = (ItemPrivateData *)index.internalPointer(); if (data->parent() == d->mRootData) { int row = index.row(); if (row >= d->mFreeBusyItems.size()) { return QVariant(); } switch (role) { case Qt::DisplayRole: - return d->mFreeBusyItems.at(row)->attendee()->fullName(); + return d->mFreeBusyItems.at(row)->attendee().fullName(); case FreeBusyItemModel::AttendeeRole: return QVariant::fromValue(d->mFreeBusyItems.at(row)->attendee()); case FreeBusyItemModel::FreeBusyRole: if (d->mFreeBusyItems.at(row)->freeBusy()) { return QVariant::fromValue(d->mFreeBusyItems.at(row)->freeBusy()); } else { return QVariant(); } default: return QVariant(); } } FreeBusyItem::Ptr fbitem = d->mFreeBusyItems.at(data->parent()->row()); if (!fbitem->freeBusy() || index.row() >= fbitem->freeBusy()->busyPeriods().size()) { return QVariant(); } KCalCore::FreeBusyPeriod period = fbitem->freeBusy()->fullBusyPeriods().at(index.row()); switch (role) { case Qt::DisplayRole: // return something to make modeltest happy return QStringLiteral("%1 - %2"). arg(QLocale().toString(period.start().toLocalTime(), QLocale::ShortFormat), QLocale().toString(period.end().toLocalTime(), QLocale::ShortFormat)); case FreeBusyItemModel::FreeBusyPeriodRole: return QVariant::fromValue(period); default: return QVariant(); } } int FreeBusyItemModel::rowCount(const QModelIndex &parent) const { ItemPrivateData *parentData = nullptr; if (parent.column() > 0) { return 0; } if (!parent.isValid()) { parentData = d->mRootData; } else { parentData = static_cast(parent.internalPointer()); } return parentData->childCount(); } int FreeBusyItemModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent); return 1; } QModelIndex FreeBusyItemModel::index(int row, int column, const QModelIndex &parent) const { if (!hasIndex(row, column, parent)) { return QModelIndex(); } ItemPrivateData *parentData = nullptr; if (!parent.isValid()) { parentData = d->mRootData; } else { parentData = static_cast(parent.internalPointer()); } ItemPrivateData *childData = parentData->child(row); if (childData) { return createIndex(row, column, childData); } else { return QModelIndex(); } } QModelIndex FreeBusyItemModel::parent(const QModelIndex &child) const { if (!child.isValid()) { return QModelIndex(); } ItemPrivateData *childData = static_cast(child.internalPointer()); ItemPrivateData *parentData = childData->parent(); if (parentData == d->mRootData) { return QModelIndex(); } return createIndex(parentData->row(), 0, parentData); } QVariant FreeBusyItemModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role == Qt::DisplayRole && orientation == Qt::Horizontal && section == 0) { return i18n("Attendee"); } return QVariant(); } void FreeBusyItemModel::addItem(const FreeBusyItem::Ptr &freebusy) { int row = d->mFreeBusyItems.size(); beginInsertRows(QModelIndex(), row, row); d->mFreeBusyItems.append(freebusy); ItemPrivateData *data = new ItemPrivateData(d->mRootData); d->mRootData->appendChild(data); endInsertRows(); if (freebusy->freeBusy() && freebusy->freeBusy()->fullBusyPeriods().size() > 0) { QModelIndex parent = index(row, 0); setFreeBusyPeriods(parent, freebusy->freeBusy()->fullBusyPeriods()); } updateFreeBusyData(freebusy); } void FreeBusyItemModel::setFreeBusyPeriods(const QModelIndex &parent, const KCalCore::FreeBusyPeriod::List &list) { if (!parent.isValid()) { return; } ItemPrivateData *parentData = static_cast(parent.internalPointer()); int fb_count = list.size(); int childCount = parentData->childCount(); QModelIndex first = index(0, 0, parent); QModelIndex last = index(childCount - 1, 0, parent); if (childCount > 0 && fb_count < childCount) { beginRemoveRows(parent, fb_count - 1 < 0 ? 0 : fb_count - 1, childCount - 1); for (int i = childCount - 1; i > fb_count; --i) { delete parentData->removeChild(i); } endRemoveRows(); if (fb_count > 0) { last = index(fb_count - 1, 0, parent); Q_EMIT dataChanged(first, last); } } else if (fb_count > childCount) { beginInsertRows(parent, childCount, fb_count - 1); for (int i = childCount; i < fb_count; ++i) { ItemPrivateData *childData = new ItemPrivateData(parentData); parentData->appendChild(childData); } endInsertRows(); if (childCount > 0) { last = index(childCount - 1, 0, parent); Q_EMIT dataChanged(first, last); } } else if (fb_count == childCount && fb_count > 0) { Q_EMIT dataChanged(first, last); } } void FreeBusyItemModel::clear() { beginResetModel(); d->mFreeBusyItems.clear(); delete d->mRootData; d->mRootData = new ItemPrivateData(nullptr); endResetModel(); } void FreeBusyItemModel::removeRow(int row) { beginRemoveRows(QModelIndex(), row, row); d->mFreeBusyItems.removeAt(row); ItemPrivateData *data = d->mRootData->removeChild(row); delete data; endRemoveRows(); } void FreeBusyItemModel::removeItem(const FreeBusyItem::Ptr &freebusy) { int row = d->mFreeBusyItems.indexOf(freebusy); if (row >= 0) { removeRow(row); } } -void FreeBusyItemModel::removeAttendee(const KCalCore::Attendee::Ptr &attendee) +void FreeBusyItemModel::removeAttendee(const KCalCore::Attendee &attendee) { FreeBusyItem::Ptr anItem; for (int i = 0; i < d->mFreeBusyItems.count(); ++i) { anItem = d->mFreeBusyItems[i]; - if (*anItem->attendee() == *attendee) { + if (anItem->attendee() == attendee) { if (anItem->updateTimerID() != 0) { killTimer(anItem->updateTimerID()); } removeRow(i); break; } } } -bool FreeBusyItemModel::containsAttendee(const KCalCore::Attendee::Ptr &attendee) +bool FreeBusyItemModel::containsAttendee(const KCalCore::Attendee &attendee) { FreeBusyItem::Ptr anItem; for (int i = 0; i < d->mFreeBusyItems.count(); ++i) { anItem = d->mFreeBusyItems[i]; - if (*anItem->attendee() == *attendee) { + if (anItem->attendee() == attendee) { return true; } } return false; } void FreeBusyItemModel::updateFreeBusyData(const FreeBusyItem::Ptr &item) { if (item->isDownloading()) { // This item is already in the process of fetching the FB list return; } if (item->updateTimerID() != 0) { // An update timer is already running. Reset it killTimer(item->updateTimerID()); } // This item does not have a download running, and no timer is set // Do the download in one second item->setUpdateTimerID(startTimer(1000)); } void FreeBusyItemModel::timerEvent(QTimerEvent *event) { killTimer(event->timerId()); for (FreeBusyItem::Ptr item : qAsConst(d->mFreeBusyItems)) { if (item->updateTimerID() == event->timerId()) { item->setUpdateTimerID(0); item->startDownload(d->mForceDownload); return; } } } void FreeBusyItemModel::slotInsertFreeBusy(const KCalCore::FreeBusy::Ptr &fb, const QString &email) { if (!fb) { return; } if (fb->fullBusyPeriods().isEmpty()) { return; } fb->sortList(); for (FreeBusyItem::Ptr item : qAsConst(d->mFreeBusyItems)) { if (item->email() == email) { item->setFreeBusy(fb); const int row = d->mFreeBusyItems.indexOf(item); const QModelIndex parent = index(row, 0); Q_EMIT dataChanged(parent, parent); setFreeBusyPeriods(parent, fb->fullBusyPeriods()); } } } void FreeBusyItemModel::autoReload() { d->mForceDownload = false; reload(); } void FreeBusyItemModel::reload() { for (FreeBusyItem::Ptr item : qAsConst(d->mFreeBusyItems)) { if (d->mForceDownload) { item->startDownload(d->mForceDownload); } else { updateFreeBusyData(item); } } } void FreeBusyItemModel::triggerReload() { d->mReloadTimer.start(1000); } void FreeBusyItemModel::cancelReload() { d->mReloadTimer.stop(); } diff --git a/src/freebusymodel/freebusyitemmodel.h b/src/freebusymodel/freebusyitemmodel.h index 0846d26..2782b4d 100644 --- a/src/freebusymodel/freebusyitemmodel.h +++ b/src/freebusymodel/freebusyitemmodel.h @@ -1,106 +1,106 @@ /* Copyright (C) 2010 Casey Link Copyright (C) 2009-2010 Klaralvdalens Datakonsult AB, a KDAB Group company This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef FBMODEL_FREEBUSYITEMMODEL_H #define FBMODEL_FREEBUSYITEMMODEL_H #include "calendarsupport_export.h" #include "freebusyitem.h" #include #include class ItemPrivateData; namespace CalendarSupport { /** * The FreeBusyItemModel is a 2-level tree structure. * * The top level parent nodes represent the freebusy items, and * the 2nd-level child nodes represent the FreeBusyPeriods of the parent * freebusy item. */ class FreeBusyItemModelPrivate; class CALENDARSUPPORT_EXPORT FreeBusyItemModel : public QAbstractItemModel { Q_OBJECT public: enum Roles { AttendeeRole = Qt::UserRole, FreeBusyRole, FreeBusyPeriodRole }; explicit FreeBusyItemModel(QObject *parent = nullptr); ~FreeBusyItemModel() override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; int rowCount(const QModelIndex &parent = QModelIndex()) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override; QModelIndex index(int row, int column = 0, const QModelIndex &parent = QModelIndex()) const override; QModelIndex parent(const QModelIndex &child) const override; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; void addItem(const FreeBusyItem::Ptr &freebusy); void clear(); - void removeAttendee(const KCalCore::Attendee::Ptr &attendee); + void removeAttendee(const KCalCore::Attendee &attendee); void removeItem(const FreeBusyItem::Ptr &freebusy); void removeRow(int row); - Q_REQUIRED_RESULT bool containsAttendee(const KCalCore::Attendee::Ptr &attendee); + Q_REQUIRED_RESULT bool containsAttendee(const KCalCore::Attendee &attendee); /** * Queues a reload of free/busy data. * All current attendees will have their free/busy data * redownloaded from Akonadi. */ void triggerReload(); /** * cancel reloading */ void cancelReload(); /** * Reload FB items */ void reload(); public Q_SLOTS: void slotInsertFreeBusy(const KCalCore::FreeBusy::Ptr &fb, const QString &email); protected: void timerEvent(QTimerEvent *) override; private: // Only download FB if the auto-download option is set in config void autoReload(); void setFreeBusyPeriods(const QModelIndex &parent, const KCalCore::FreeBusyPeriod::List &list); void updateFreeBusyData(const FreeBusyItem::Ptr &); FreeBusyItemModelPrivate *const d; }; } #endif diff --git a/src/printing/calprintdefaultplugins.cpp b/src/printing/calprintdefaultplugins.cpp index c1d6803..31b2455 100644 --- a/src/printing/calprintdefaultplugins.cpp +++ b/src/printing/calprintdefaultplugins.cpp @@ -1,1660 +1,1660 @@ /* Copyright (c) 1998 Preston Brown Copyright (C) 2003 Reinhold Kainhofer Copyright (c) 2003 Cornelius Schumacher Copyright (c) 2008 Ron Goodheart Copyright (C) 2010-2019 Laurent Montel Copyright (c) 2012-2013 Allen Winter This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. As a special exception, permission is given to link this program with any edition of Qt, and distribute the resulting executable, without including the source code for Qt in the source distribution. */ #include "calprintdefaultplugins.h" #include "kcalprefs.h" #include "utils.h" #include #include #include #include #include #include #include #include using namespace CalendarSupport; static QString cleanStr(const QString &instr) { QString ret = instr; return ret.replace(QLatin1Char('\n'), QLatin1Char(' ')); } /************************************************************** * Print Incidence **************************************************************/ CalPrintIncidence::CalPrintIncidence() : CalPrintPluginBase() { } CalPrintIncidence::~CalPrintIncidence() { } QWidget *CalPrintIncidence::createConfigWidget(QWidget *w) { return new CalPrintIncidenceConfig(w); } void CalPrintIncidence::readSettingsWidget() { CalPrintIncidenceConfig *cfg = dynamic_cast((QWidget *)mConfigWidget); if (cfg) { mUseColors = cfg->mColors->isChecked(); mPrintFooter = cfg->mPrintFooter->isChecked(); mShowOptions = cfg->mShowDetails->isChecked(); mShowSubitemsNotes = cfg->mShowSubitemsNotes->isChecked(); mShowAttendees = cfg->mShowAttendees->isChecked(); mShowAttachments = cfg->mShowAttachments->isChecked(); mShowNoteLines = cfg->mShowNoteLines->isChecked(); } } void CalPrintIncidence::setSettingsWidget() { CalPrintIncidenceConfig *cfg = dynamic_cast((QWidget *)mConfigWidget); if (cfg) { cfg->mColors->setChecked(mUseColors); cfg->mPrintFooter->setChecked(mPrintFooter); cfg->mShowDetails->setChecked(mShowOptions); cfg->mShowSubitemsNotes->setChecked(mShowSubitemsNotes); cfg->mShowAttendees->setChecked(mShowAttendees); cfg->mShowAttachments->setChecked(mShowAttachments); cfg->mShowNoteLines->setChecked(mShowNoteLines); } } void CalPrintIncidence::loadConfig() { if (mConfig) { KConfigGroup grp(mConfig, groupName()); mShowOptions = grp.readEntry("Show Options", false); mShowSubitemsNotes = grp.readEntry("Show Subitems and Notes", false); mShowAttendees = grp.readEntry("Use Attendees", false); mShowAttachments = grp.readEntry("Use Attachments", false); mShowNoteLines = grp.readEntry("Note Lines", false); } setSettingsWidget(); } void CalPrintIncidence::saveConfig() { readSettingsWidget(); if (mConfig) { KConfigGroup grp(mConfig, groupName()); grp.writeEntry("Show Options", mShowOptions); grp.writeEntry("Show Subitems and Notes", mShowSubitemsNotes); grp.writeEntry("Use Attendees", mShowAttendees); grp.writeEntry("Use Attachments", mShowAttachments); grp.writeEntry("Note Lines", mShowNoteLines); } } class TimePrintStringsVisitor : public KCalCore::Visitor { public: TimePrintStringsVisitor() { } bool act(KCalCore::IncidenceBase::Ptr incidence) { return incidence->accept(*this, incidence); } QString mStartCaption, mStartString; QString mEndCaption, mEndString; QString mDurationCaption, mDurationString; protected: bool visit(const KCalCore::Event::Ptr &event) override { if (event->dtStart().isValid()) { mStartCaption = i18n("Start date: "); mStartString = KCalUtils::IncidenceFormatter::dateTimeToString( event->dtStart(), event->allDay(), false); } else { mStartCaption = i18n("No start date"); mStartString.clear(); } if (event->hasEndDate()) { mEndCaption = i18n("End date: "); mEndString = KCalUtils::IncidenceFormatter::dateTimeToString( event->dtEnd(), event->allDay(), false); } else if (event->hasDuration()) { mEndCaption = i18n("Duration: "); int mins = event->duration().asSeconds() / 60; if (mins >= 60) { mEndString += i18np("1 hour ", "%1 hours ", mins / 60); } if (mins % 60 > 0) { mEndString += i18np("1 minute ", "%1 minutes ", mins % 60); } } else { mEndCaption = i18n("No end date"); mEndString.clear(); } return true; } bool visit(const KCalCore::Todo::Ptr &todo) override { if (todo->hasStartDate()) { mStartCaption = i18n("Start date: "); mStartString = KCalUtils::IncidenceFormatter::dateTimeToString( todo->dtStart(), todo->allDay(), false); } else { mStartCaption = i18n("No start date"); mStartString.clear(); } if (todo->hasDueDate()) { mEndCaption = i18n("Due date: "); mEndString = KCalUtils::IncidenceFormatter::dateTimeToString( todo->dtDue(), todo->allDay(), false); } else { mEndCaption = i18n("No due date"); mEndString.clear(); } return true; } bool visit(const KCalCore::Journal::Ptr &journal) override { mStartCaption = i18n("Start date: "); mStartString = KCalUtils::IncidenceFormatter::dateTimeToString( journal->dtStart(), journal->allDay(), false); mEndCaption.clear(); mEndString.clear(); return true; } bool visit(const KCalCore::FreeBusy::Ptr &fb) override { Q_UNUSED(fb); return true; } }; int CalPrintIncidence::printCaptionAndText(QPainter &p, const QRect &box, const QString &caption, const QString &text, const QFont &captionFont, const QFont &textFont) { QFontMetrics captionFM(captionFont); int textWd = captionFM.boundingRect(caption).width(); QRect textRect(box); QFont oldFont(p.font()); p.setFont(captionFont); p.drawText(box, Qt::AlignLeft | Qt::AlignTop | Qt::TextSingleLine, caption); if (!text.isEmpty()) { textRect.setLeft(textRect.left() + textWd); p.setFont(textFont); p.drawText(textRect, Qt::AlignLeft | Qt::AlignTop | Qt::TextSingleLine, text); } p.setFont(oldFont); return textRect.bottom(); } void CalPrintIncidence::print(QPainter &p, int width, int height) { QFont oldFont(p.font()); QFont textFont(QStringLiteral("sans-serif"), 11, QFont::Normal); QFont captionFont(QStringLiteral("sans-serif"), 11, QFont::Bold); p.setFont(textFont); int lineHeight = p.fontMetrics().lineSpacing(); QString cap, txt; KCalCore::Incidence::List::ConstIterator it; for (it = mSelectedIncidences.constBegin(); it != mSelectedIncidences.constEnd(); ++it) { // don't do anything on a 0-pointer! if (!(*it)) { continue; } if (it != mSelectedIncidences.constBegin()) { mPrinter->newPage(); } const bool isJournal = ((*it)->type() == KCalCore::Incidence::TypeJournal); // PAGE Layout (same for landscape and portrait! astonishingly, it looks good with both!): // +-----------------------------------+ // | Header: Summary | // +===================================+ // | start: ______ end: _________ | // | repeats: ___________________ | // | reminder: __________________ | // +-----------------------------------+ // | Location: ______________________ | // +------------------------+----------+ // | Description: | Notes or | // | | Subitems | // | | | // | | | // | | | // | | | // | | | // | | | // | | | // | | | // +------------------------+----------+ // | Attachments: | Settings | // | | | // +------------------------+----------+ // | Attendees: | // | | // +-----------------------------------+ // | Categories: _____________________ | // +-----------------------------------+ QRect box(0, 0, width, height); QRect titleBox(box); titleBox.setHeight(headerHeight()); QColor headerColor = categoryBgColor(*it); // Draw summary as header, no small calendars in title bar, expand height if needed int titleBottom = drawHeader(p, (*it)->summary(), QDate(), QDate(), titleBox, true, headerColor); titleBox.setBottom(titleBottom); QRect timesBox(titleBox); timesBox.setTop(titleBox.bottom() + padding()); timesBox.setHeight(height / 8); TimePrintStringsVisitor stringVis; int h = timesBox.top(); if (stringVis.act(*it)) { QRect textRect(timesBox.left() + padding(), timesBox.top() + padding(), 0, lineHeight); textRect.setRight(timesBox.center().x()); h = printCaptionAndText(p, textRect, stringVis.mStartCaption, stringVis.mStartString, captionFont, textFont); textRect.setLeft(textRect.right()); textRect.setRight(timesBox.right() - padding()); h = qMax(printCaptionAndText(p, textRect, stringVis.mEndCaption, stringVis.mEndString, captionFont, textFont), h); } // Recurrence Printing if ((*it)->recurs()) { QRect recurBox(timesBox.left() + padding(), h + padding(), timesBox.right() - padding(), lineHeight); KCalCore::Recurrence *recurs = (*it)->recurrence(); QString displayString = KCalUtils::IncidenceFormatter::recurrenceString((*it)); // exception dates QString exceptString; if (!recurs->exDates().isEmpty()) { exceptString = i18nc("except for listed dates", " except"); for (int i = 0; i < recurs->exDates().size(); ++i) { exceptString.append(QLatin1Char(' ')); exceptString.append(QLocale::system().toString(recurs->exDates().at(i), QLocale::ShortFormat)); } } displayString.append(exceptString); h = qMax(printCaptionAndText(p, recurBox, i18n("Repeats: "), displayString, captionFont, textFont), h); } if (!isJournal) { // Alarms Printing QRect alarmBox(timesBox.left() + padding(), h + padding(), timesBox.right() - padding(), lineHeight); KCalCore::Alarm::List alarms = (*it)->alarms(); if (alarms.isEmpty()) { cap = i18n("No reminders"); txt.clear(); } else { cap = i18np("Reminder: ", "%1 reminders: ", alarms.count()); QStringList alarmStrings; KCalCore::Alarm::List::ConstIterator it; alarmStrings.reserve(alarms.count()); for (it = alarms.constBegin(); it != alarms.constEnd(); ++it) { KCalCore::Alarm::Ptr alarm = *it; // Alarm offset, copied from koeditoralarms.cpp: KLocalizedString offsetstr; int offset = 0; if (alarm->hasStartOffset()) { offset = alarm->startOffset().asSeconds(); if (offset < 0) { offsetstr = ki18nc("N days/hours/minutes before/after the start/end", "%1 before the start"); offset = -offset; } else { offsetstr = ki18nc("N days/hours/minutes before/after the start/end", "%1 after the start"); } } else if (alarm->hasEndOffset()) { offset = alarm->endOffset().asSeconds(); if (offset < 0) { offsetstr = ki18nc("N days/hours/minutes before/after the start/end", "%1 before the end"); offset = -offset; } else { offsetstr = ki18nc("N days/hours/minutes before/after the start/end", "%1 after the end"); } } offset = offset / 60; // make minutes int useoffset = offset; if (offset % (24 * 60) == 0 && offset > 0) { // divides evenly into days? useoffset = offset / (24 * 60); offsetstr = offsetstr.subs(i18np("1 day", "%1 days", useoffset)); } else if (offset % 60 == 0 && offset > 0) { // divides evenly into hours? useoffset = offset / 60; offsetstr = offsetstr.subs(i18np("1 hour", "%1 hours", useoffset)); } else { useoffset = offset; offsetstr = offsetstr.subs(i18np("1 minute", "%1 minutes", useoffset)); } alarmStrings << offsetstr.toString(); } txt = alarmStrings.join(i18nc("Spacer for the joined list of categories", ", ")); } h = qMax(printCaptionAndText(p, alarmBox, cap, txt, captionFont, textFont), h); } QRect organizerBox(timesBox.left() + padding(), h + padding(), timesBox.right() - padding(), lineHeight); h = qMax(printCaptionAndText(p, organizerBox, i18n("Organizer: "), (*it)->organizer().fullName(), captionFont, textFont), h); // Finally, draw the frame around the time information... timesBox.setBottom(qMax(timesBox.bottom(), h + padding())); drawBox(p, BOX_BORDER_WIDTH, timesBox); QRect locationBox(timesBox); locationBox.setTop(timesBox.bottom() + padding()); locationBox.setHeight(0); int locationBottom = 0; if (!isJournal) { locationBottom = drawBoxWithCaption(p, locationBox, i18n("Location: "), (*it)->location(), /*sameLine=*/ true, /*expand=*/ true, captionFont, textFont); } locationBox.setBottom(locationBottom); // Now start constructing the boxes from the bottom: QRect footerBox(locationBox); footerBox.setBottom(box.bottom()); footerBox.setTop(footerBox.bottom() - lineHeight - 2 * padding()); QRect categoriesBox(footerBox); categoriesBox.setBottom(footerBox.top()); categoriesBox.setTop(categoriesBox.bottom() - lineHeight - 2 * padding()); QRect attendeesBox(box.left(), categoriesBox.top() - padding() - box.height() / 9, box.width(), box.height() / 9); QRect attachmentsBox(box.left(), attendeesBox.top() - padding() - box.height() / 9, box.width() * 3 / 4 - padding(), box.height() / 9); QRect optionsBox(isJournal ? box.left() : attachmentsBox.right() + padding(), attachmentsBox.top(), 0, 0); optionsBox.setRight(box.right()); optionsBox.setBottom(attachmentsBox.bottom()); QRect notesBox(optionsBox.left(), isJournal ? (timesBox.bottom() + padding()) : (locationBox.bottom() + padding()), optionsBox.width(), 0); notesBox.setBottom(optionsBox.top() - padding()); QRect descriptionBox(notesBox); descriptionBox.setLeft(box.left()); descriptionBox.setRight(attachmentsBox.right()); // Adjust boxes depending on the show options... if (!mShowSubitemsNotes || isJournal) { descriptionBox.setRight(box.right()); } if (!mShowAttachments || !mShowAttendees) { descriptionBox.setBottom(attachmentsBox.bottom()); optionsBox.setTop(attendeesBox.top()); optionsBox.setBottom(attendeesBox.bottom()); notesBox.setBottom(attachmentsBox.bottom()); if (mShowOptions) { attendeesBox.setRight(attachmentsBox.right()); } if (!mShowAttachments && !mShowAttendees) { if (mShowSubitemsNotes) { descriptionBox.setBottom(attendeesBox.bottom()); } if (!mShowOptions) { descriptionBox.setBottom(attendeesBox.bottom()); notesBox.setBottom(attendeesBox.bottom()); } } } if (mShowAttachments && !isJournal) { if (!mShowOptions) { attachmentsBox.setRight(box.right()); attachmentsBox.setRight(box.right()); } if (!mShowAttendees) { attachmentsBox.setTop(attendeesBox.top()); attachmentsBox.setBottom(attendeesBox.bottom()); } } int newBottom = drawBoxWithCaption(p, descriptionBox, i18n("Description:"), (*it)->description(), /*sameLine=*/ false, /*expand=*/ false, captionFont, textFont, (*it)->descriptionIsRich()); if (mShowNoteLines) { drawNoteLines(p, descriptionBox, newBottom); } Akonadi::Item item = mCalendar->item((*it)->uid()); Akonadi::Item::List relations = mCalendar->childItems(item.id()); if (mShowSubitemsNotes && !isJournal) { if (relations.isEmpty() || (*it)->type() != KCalCore::Incidence::TypeTodo) { int notesPosition = drawBoxWithCaption(p, notesBox, i18n("Notes:"), QString(), /*sameLine=*/ false, /*expand=*/ false, captionFont, textFont); drawNoteLines(p, notesBox, notesPosition); } else { QString subitemCaption; if (relations.isEmpty()) { subitemCaption = i18n("No Subitems"); txt.clear(); } else { subitemCaption = i18np("1 Subitem:", "%1 Subitems:", relations.count()); } QString subitemString; QString statusString; QString datesString; int count = 0; for (const Akonadi::Item &item : qAsConst(relations)) { KCalCore::Todo::Ptr todo = CalendarSupport::todo(item); ++count; if (!todo) { // defensive, skip any zero pointers continue; } // format the status statusString = KCalUtils::Stringify::incidenceStatus(todo->status()); if (statusString.isEmpty()) { if (todo->status() == KCalCore::Incidence::StatusNone) { statusString = i18nc("no status", "none"); } else { statusString = i18nc("unknown status", "unknown"); } } // format the dates if provided datesString.clear(); if (todo->dtStart().isValid()) { datesString += i18nc("subitem start date", "Start Date: %1\n", QLocale().toString(todo->dtStart().toLocalTime().date(), QLocale::ShortFormat)); if (!todo->allDay()) { datesString += i18nc("subitem start time", "Start Time: %1\n", QLocale().toString(todo->dtStart().toLocalTime(). time(), QLocale::ShortFormat)); } } if (todo->dateTime(KCalCore::Incidence::RoleEnd).isValid()) { subitemString += i18nc("subitem due date", "Due Date: %1\n", QLocale().toString(todo->dateTime(KCalCore::Incidence ::RoleEnd). toLocalTime().date(), QLocale::ShortFormat)); if (!todo->allDay()) { subitemString += i18nc("subitem due time", "Due Time: %1\n", QLocale().toString(todo->dateTime(KCalCore:: Incidence:: RoleEnd). toLocalTime().time(), QLocale::ShortFormat)); } } subitemString += i18nc("subitem counter", "%1: ", count); subitemString += todo->summary(); subitemString += QLatin1Char('\n'); if (!datesString.isEmpty()) { subitemString += datesString; subitemString += QLatin1Char('\n'); } subitemString += i18nc("subitem Status: statusString", "Status: %1\n", statusString); subitemString += KCalUtils::IncidenceFormatter::recurrenceString(todo) + QLatin1Char('\n'); subitemString += i18nc("subitem Priority: N", "Priority: %1\n", QString::number(todo->priority())); subitemString += i18nc("subitem Secrecy: secrecyString", "Secrecy: %1\n", KCalUtils::Stringify::incidenceSecrecy(todo->secrecy())); subitemString += QLatin1Char('\n'); } drawBoxWithCaption(p, notesBox, subitemCaption, subitemString, /*sameLine=*/ false, /*expand=*/ false, captionFont, textFont); } } if (mShowAttachments && !isJournal) { const KCalCore::Attachment::List attachments = (*it)->attachments(); QString attachmentCaption; if (attachments.isEmpty()) { attachmentCaption = i18n("No Attachments"); txt.clear(); } else { attachmentCaption = i18np("1 Attachment:", "%1 Attachments:", attachments.count()); } QString attachmentString; KCalCore::Attachment::List::ConstIterator ait = attachments.constBegin(); for (; ait != attachments.constEnd(); ++ait) { if (!attachmentString.isEmpty()) { attachmentString += i18nc("Spacer for list of attachments", " "); } attachmentString.append((*ait)->label()); } drawBoxWithCaption(p, attachmentsBox, attachmentCaption, attachmentString, /*sameLine=*/ false, /*expand=*/ false, captionFont, textFont); } if (mShowAttendees) { const KCalCore::Attendee::List attendees = (*it)->attendees(); QString attendeeCaption; if (attendees.isEmpty()) { attendeeCaption = i18n("No Attendees"); } else { attendeeCaption = i18np("1 Attendee:", "%1 Attendees:", attendees.count()); } QString attendeeString; KCalCore::Attendee::List::ConstIterator ait = attendees.constBegin(); for (; ait != attendees.constEnd(); ++ait) { if (!attendeeString.isEmpty()) { attendeeString += QLatin1Char('\n'); } attendeeString += i18nc( "Formatting of an attendee: " "'Name (Role): Status', e.g. 'Reinhold Kainhofer " " (Participant): Awaiting Response'", "%1 (%2): %3", - (*ait)->fullName(), - KCalUtils::Stringify::attendeeRole((*ait)->role()), - KCalUtils::Stringify::attendeeStatus((*ait)->status())); + (*ait).fullName(), + KCalUtils::Stringify::attendeeRole((*ait).role()), + KCalUtils::Stringify::attendeeStatus((*ait).status())); } drawBoxWithCaption(p, attendeesBox, attendeeCaption, attendeeString, /*sameLine=*/ false, /*expand=*/ false, captionFont, textFont); } if (mShowOptions) { QString optionsString; if (!KCalUtils::Stringify::incidenceStatus((*it)->status()).isEmpty()) { optionsString += i18n("Status: %1", KCalUtils::Stringify::incidenceStatus((*it)->status())); optionsString += QLatin1Char('\n'); } if (!KCalUtils::Stringify::incidenceSecrecy((*it)->secrecy()).isEmpty()) { optionsString += i18n("Secrecy: %1", KCalUtils::Stringify::incidenceSecrecy((*it)->secrecy())); optionsString += QLatin1Char('\n'); } if ((*it)->type() == KCalCore::Incidence::TypeEvent) { KCalCore::Event::Ptr e = (*it).staticCast(); if (e->transparency() == KCalCore::Event::Opaque) { optionsString += i18n("Show as: Busy"); } else { optionsString += i18n("Show as: Free"); } optionsString += QLatin1Char('\n'); } else if ((*it)->type() == KCalCore::Incidence::TypeTodo) { KCalCore::Todo::Ptr t = (*it).staticCast(); if (t->isOverdue()) { optionsString += i18n("This task is overdue!"); optionsString += QLatin1Char('\n'); } } else if ((*it)->type() == KCalCore::Incidence::TypeJournal) { //TODO: Anything Journal-specific? } drawBoxWithCaption(p, optionsBox, i18n("Settings: "), optionsString, /*sameLine=*/ false, /*expand=*/ false, captionFont, textFont); } drawBoxWithCaption(p, categoriesBox, i18n("Categories: "), (*it)->categories().join(i18nc("Spacer for the joined list of categories", ", ")), /*sameLine=*/ true, /*expand=*/ false, captionFont, textFont); if (mPrintFooter) { drawFooter(p, footerBox); } } p.setFont(oldFont); } /************************************************************** * Print Day **************************************************************/ CalPrintDay::CalPrintDay() : CalPrintPluginBase() { } CalPrintDay::~CalPrintDay() { } QWidget *CalPrintDay::createConfigWidget(QWidget *w) { return new CalPrintDayConfig(w); } void CalPrintDay::readSettingsWidget() { CalPrintDayConfig *cfg = dynamic_cast((QWidget *)mConfigWidget); if (cfg) { mFromDate = cfg->mFromDate->date(); mToDate = cfg->mToDate->date(); if (cfg->mPrintTypeFilofax->isChecked()) { mDayPrintType = Filofax; } else if (cfg->mPrintTypeTimetable->isChecked()) { mDayPrintType = Timetable; } else { mDayPrintType = SingleTimetable; } mStartTime = cfg->mFromTime->time(); mEndTime = cfg->mToTime->time(); mIncludeAllEvents = cfg->mIncludeAllEvents->isChecked(); mIncludeDescription = cfg->mIncludeDescription->isChecked(); mSingleLineLimit = cfg->mSingleLineLimit->isChecked(); mIncludeTodos = cfg->mIncludeTodos->isChecked(); mUseColors = cfg->mColors->isChecked(); mPrintFooter = cfg->mPrintFooter->isChecked(); mShowNoteLines = cfg->mShowNoteLines->isChecked(); mExcludeTime = cfg->mExcludeTime->isChecked(); mExcludeConfidential = cfg->mExcludeConfidential->isChecked(); mExcludePrivate = cfg->mExcludePrivate->isChecked(); } } void CalPrintDay::setSettingsWidget() { CalPrintDayConfig *cfg = dynamic_cast((QWidget *)mConfigWidget); if (cfg) { cfg->mFromDate->setDate(mFromDate); cfg->mToDate->setDate(mToDate); cfg->mPrintTypeFilofax->setChecked(mDayPrintType == Filofax); cfg->mPrintTypeTimetable->setChecked(mDayPrintType == Timetable); cfg->mPrintTypeSingleTimetable->setChecked(mDayPrintType == SingleTimetable); cfg->mFromTime->setTime(mStartTime); cfg->mToTime->setTime(mEndTime); cfg->mIncludeAllEvents->setChecked(mIncludeAllEvents); cfg->mIncludeDescription->setChecked(mIncludeDescription); cfg->mSingleLineLimit->setChecked(mSingleLineLimit); cfg->mIncludeTodos->setChecked(mIncludeTodos); cfg->mColors->setChecked(mUseColors); cfg->mPrintFooter->setChecked(mPrintFooter); cfg->mShowNoteLines->setChecked(mShowNoteLines); cfg->mExcludeTime->setChecked(mExcludeTime); cfg->mExcludeConfidential->setChecked(mExcludeConfidential); cfg->mExcludePrivate->setChecked(mExcludePrivate); } } void CalPrintDay::loadConfig() { if (mConfig) { KConfigGroup grp(mConfig, groupName()); QDate dt = QDate::currentDate(); // any valid QDate will do QTime tm1(dayStart()); QDateTime startTm(dt, tm1); QDateTime endTm(dt, tm1.addSecs(12 * 60 * 60)); mStartTime = grp.readEntry("Start time", startTm).time(); mEndTime = grp.readEntry("End time", endTm).time(); mIncludeDescription = grp.readEntry("Include description", false); mIncludeTodos = grp.readEntry("Include todos", false); mIncludeAllEvents = grp.readEntry("Include all events", false); mDayPrintType = static_cast(grp.readEntry("Print type", static_cast(Timetable))); mSingleLineLimit = grp.readEntry("Single line limit", false); mShowNoteLines = grp.readEntry("Note Lines", false); mExcludeTime = grp.readEntry("Exclude time", false); mExcludeConfidential = grp.readEntry("Exclude confidential", true); mExcludePrivate = grp.readEntry("Exclude private", true); } setSettingsWidget(); } void CalPrintDay::saveConfig() { readSettingsWidget(); if (mConfig) { KConfigGroup grp(mConfig, groupName()); QDateTime dt = QDateTime::currentDateTime(); // any valid QDateTime will do dt.setTime(mStartTime); grp.writeEntry("Start time", dt); dt.setTime(mEndTime); grp.writeEntry("End time", dt); grp.writeEntry("Include description", mIncludeDescription); grp.writeEntry("Include todos", mIncludeTodos); grp.writeEntry("Include all events", mIncludeAllEvents); grp.writeEntry("Print type", int(mDayPrintType)); grp.writeEntry("Single line limit", mSingleLineLimit); grp.writeEntry("Note Lines", mShowNoteLines); grp.writeEntry("Exclude time", mExcludeTime); grp.writeEntry("Exclude confidential", mExcludeConfidential); grp.writeEntry("Exclude private", mExcludePrivate); } } void CalPrintDay::setDateRange(const QDate &from, const QDate &to) { CalPrintPluginBase::setDateRange(from, to); CalPrintDayConfig *cfg = dynamic_cast((QWidget *)mConfigWidget); if (cfg) { cfg->mFromDate->setDate(from); cfg->mToDate->setDate(to); } } void CalPrintDay::print(QPainter &p, int width, int height) { QDate curDay(mFromDate); QRect headerBox(0, 0, width, headerHeight()); QRect footerBox(0, height - footerHeight(), width, footerHeight()); height -= footerHeight(); auto local = QLocale::system(); switch (mDayPrintType) { case Filofax: case SingleTimetable: { QRect daysBox(headerBox); daysBox.setTop(headerBox.bottom() + padding()); daysBox.setBottom(height); QString line1 = local.toString(mFromDate, QLocale::ShortFormat); QString line2 = local.toString(mToDate, QLocale::ShortFormat); QString title; if (orientation() == QPrinter::Landscape) { title = i18nc("date from-to", "%1 - %2", line1, line2); } else { title = i18nc("date from-\nto", "%1 -\n%2", line1, line2); } drawHeader(p, title, mFromDate, QDate(), headerBox); if (mDayPrintType == Filofax) { drawDays(p, mFromDate, mToDate, mStartTime, mEndTime, daysBox, mSingleLineLimit, mShowNoteLines, mIncludeDescription, mExcludeConfidential, mExcludePrivate); } else if (mDayPrintType == SingleTimetable) { drawTimeTable(p, mFromDate, mToDate, mIncludeAllEvents, mStartTime, mEndTime, daysBox, mIncludeDescription, mExcludeTime, mExcludeConfidential, mExcludePrivate); } if (mPrintFooter) { drawFooter(p, footerBox); } break; } case Timetable: default: do { QTime curStartTime(mStartTime); QTime curEndTime(mEndTime); // For an invalid time range, simply show one hour, starting at the hour // before the given start time if (curEndTime <= curStartTime) { curStartTime = QTime(curStartTime.hour(), 0, 0); curEndTime = curStartTime.addSecs(3600); } drawHeader(p, local.toString(curDay, QLocale::ShortFormat), curDay, QDate(), headerBox); KCalCore::Event::List eventList = mCalendar->events(curDay, QTimeZone::systemTimeZone(), KCalCore::EventSortStartDate, KCalCore::SortDirectionAscending); // split out the all day events as they will be printed in a separate box KCalCore::Event::List alldayEvents, timedEvents; for (const KCalCore::Event::Ptr &event : qAsConst(eventList)) { if (event->allDay()) { alldayEvents.append(event); } else { timedEvents.append(event); } } int fontSize = 11; QFont textFont(QStringLiteral("sans-serif"), fontSize, QFont::Normal); p.setFont(textFont); int lineSpacing = p.fontMetrics().lineSpacing(); int maxAllDayEvents = 8; // the max we allow to be printed, sorry. int allDayHeight = qMin(alldayEvents.count(), maxAllDayEvents) * lineSpacing; allDayHeight = qMax(allDayHeight, (5 * lineSpacing)) + (2 * padding()); QRect allDayBox(TIMELINE_WIDTH + padding(), headerBox.bottom() + padding(), width - TIMELINE_WIDTH - padding(), allDayHeight); if (!alldayEvents.isEmpty()) { // draw the side bar for all-day events QFont oldFont(p.font()); p.setFont(QFont(QStringLiteral("sans-serif"), 9, QFont::Normal)); drawVerticalBox(p, BOX_BORDER_WIDTH, QRect(0, headerBox.bottom() + padding(), TIMELINE_WIDTH, allDayHeight), i18n("Today's Events"), Qt::AlignHCenter | Qt::AlignVCenter | Qt::TextWordWrap); p.setFont(oldFont); // now draw at most maxAllDayEvents in the all-day box drawBox(p, BOX_BORDER_WIDTH, allDayBox); QRect eventBox(allDayBox); eventBox.setLeft(TIMELINE_WIDTH + (2 * padding())); eventBox.setTop(eventBox.top() + padding()); eventBox.setBottom(eventBox.top() + lineSpacing); int count = 0; for (const KCalCore::Event::Ptr &event : qAsConst(alldayEvents)) { if (count == maxAllDayEvents) { break; } count++; QString str; if (event->location().isEmpty()) { str = cleanStr(event->summary()); } else { str = i18nc("summary, location", "%1, %2", cleanStr(event->summary()), cleanStr(event->location())); } printEventString(p, eventBox, str); eventBox.setTop(eventBox.bottom()); eventBox.setBottom(eventBox.top() + lineSpacing); } } else { allDayBox.setBottom(headerBox.bottom()); } QRect dayBox(allDayBox); dayBox.setTop(allDayBox.bottom() + padding()); dayBox.setBottom(height); QList workDays = CalendarSupport::workDays(curDay, curDay); drawAgendaDayBox(p, timedEvents, curDay, mIncludeAllEvents, curStartTime, curEndTime, dayBox, mIncludeDescription, mExcludeTime, mExcludeConfidential, mExcludePrivate, workDays); QRect tlBox(dayBox); tlBox.setLeft(0); tlBox.setWidth(TIMELINE_WIDTH); drawTimeLine(p, curStartTime, curEndTime, tlBox); if (mPrintFooter) { drawFooter(p, footerBox); } curDay = curDay.addDays(1); if (curDay <= mToDate) { mPrinter->newPage(); } } while (curDay <= mToDate); } //switch } /************************************************************** * Print Week **************************************************************/ CalPrintWeek::CalPrintWeek() : CalPrintPluginBase() { } CalPrintWeek::~CalPrintWeek() { } QWidget *CalPrintWeek::createConfigWidget(QWidget *w) { return new CalPrintWeekConfig(w); } void CalPrintWeek::readSettingsWidget() { CalPrintWeekConfig *cfg = dynamic_cast((QWidget *)mConfigWidget); if (cfg) { mFromDate = cfg->mFromDate->date(); mToDate = cfg->mToDate->date(); if (cfg->mPrintTypeFilofax->isChecked()) { mWeekPrintType = Filofax; } else if (cfg->mPrintTypeTimetable->isChecked()) { mWeekPrintType = Timetable; } else if (cfg->mPrintTypeSplitWeek->isChecked()) { mWeekPrintType = SplitWeek; } else { mWeekPrintType = Timetable; } mStartTime = cfg->mFromTime->time(); mEndTime = cfg->mToTime->time(); mShowNoteLines = cfg->mShowNoteLines->isChecked(); mSingleLineLimit = cfg->mSingleLineLimit->isChecked(); mIncludeTodos = cfg->mIncludeTodos->isChecked(); mUseColors = cfg->mColors->isChecked(); mPrintFooter = cfg->mPrintFooter->isChecked(); mIncludeDescription = cfg->mIncludeDescription->isChecked(); mExcludeTime = cfg->mExcludeTime->isChecked(); mExcludeConfidential = cfg->mExcludeConfidential->isChecked(); mExcludePrivate = cfg->mExcludePrivate->isChecked(); } } void CalPrintWeek::setSettingsWidget() { CalPrintWeekConfig *cfg = dynamic_cast((QWidget *)mConfigWidget); if (cfg) { cfg->mFromDate->setDate(mFromDate); cfg->mToDate->setDate(mToDate); cfg->mPrintTypeFilofax->setChecked(mWeekPrintType == Filofax); cfg->mPrintTypeTimetable->setChecked(mWeekPrintType == Timetable); cfg->mPrintTypeSplitWeek->setChecked(mWeekPrintType == SplitWeek); cfg->mFromTime->setTime(mStartTime); cfg->mToTime->setTime(mEndTime); cfg->mShowNoteLines->setChecked(mShowNoteLines); cfg->mSingleLineLimit->setChecked(mSingleLineLimit); cfg->mIncludeTodos->setChecked(mIncludeTodos); cfg->mColors->setChecked(mUseColors); cfg->mPrintFooter->setChecked(mPrintFooter); cfg->mIncludeDescription->setChecked(mIncludeDescription); cfg->mExcludeTime->setChecked(mExcludeTime); cfg->mExcludeConfidential->setChecked(mExcludeConfidential); cfg->mExcludePrivate->setChecked(mExcludePrivate); } } void CalPrintWeek::loadConfig() { if (mConfig) { KConfigGroup grp(mConfig, groupName()); QDate dt = QDate::currentDate(); // any valid QDate will do QTime tm1(dayStart()); QDateTime startTm(dt, tm1); QDateTime endTm(dt, tm1.addSecs(43200)); mStartTime = grp.readEntry("Start time", startTm).time(); mEndTime = grp.readEntry("End time", endTm).time(); mShowNoteLines = grp.readEntry("Note Lines", false); mSingleLineLimit = grp.readEntry("Single line limit", false); mIncludeTodos = grp.readEntry("Include todos", false); mWeekPrintType = (eWeekPrintType)(grp.readEntry("Print type", (int)Filofax)); mIncludeDescription = grp.readEntry("Include Description", false); mExcludeTime = grp.readEntry("Exclude Time", false); mExcludeConfidential = grp.readEntry("Exclude confidential", true); mExcludePrivate = grp.readEntry("Exclude private", true); } setSettingsWidget(); } void CalPrintWeek::saveConfig() { readSettingsWidget(); if (mConfig) { KConfigGroup grp(mConfig, groupName()); QDateTime dt = QDateTime::currentDateTime(); // any valid QDateTime will do dt.setTime(mStartTime); grp.writeEntry("Start time", dt); dt.setTime(mEndTime); grp.writeEntry("End time", dt); grp.writeEntry("Note Lines", mShowNoteLines); grp.writeEntry("Single line limit", mSingleLineLimit); grp.writeEntry("Include todos", mIncludeTodos); grp.writeEntry("Print type", int(mWeekPrintType)); grp.writeEntry("Include Description", mIncludeDescription); grp.writeEntry("Exclude Time", mExcludeTime); grp.writeEntry("Exclude confidential", mExcludeConfidential); grp.writeEntry("Exclude private", mExcludePrivate); } } QPrinter::Orientation CalPrintWeek::defaultOrientation() const { if (mWeekPrintType == Filofax) { return QPrinter::Portrait; } else if (mWeekPrintType == SplitWeek) { return QPrinter::Portrait; } else { return QPrinter::Landscape; } } void CalPrintWeek::setDateRange(const QDate &from, const QDate &to) { CalPrintPluginBase::setDateRange(from, to); CalPrintWeekConfig *cfg = dynamic_cast((QWidget *)mConfigWidget); if (cfg) { cfg->mFromDate->setDate(from); cfg->mToDate->setDate(to); } } void CalPrintWeek::print(QPainter &p, int width, int height) { QDate curWeek, fromWeek, toWeek; // correct begin and end to first and last day of week int weekdayCol = weekdayColumn(mFromDate.dayOfWeek()); fromWeek = mFromDate.addDays(-weekdayCol); weekdayCol = weekdayColumn(mToDate.dayOfWeek()); toWeek = mToDate.addDays(6 - weekdayCol); curWeek = fromWeek.addDays(6); auto local = QLocale::system(); QString line1, line2, title; QRect headerBox(0, 0, width, headerHeight()); QRect footerBox(0, height - footerHeight(), width, footerHeight()); height -= footerHeight(); QRect weekBox(headerBox); weekBox.setTop(headerBox.bottom() + padding()); weekBox.setBottom(height); switch (mWeekPrintType) { case Filofax: do { line1 = local.toString(curWeek.addDays(-6), QLocale::ShortFormat); line2 = local.toString(curWeek, QLocale::ShortFormat); if (orientation() == QPrinter::Landscape) { title = i18nc("date from-to", "%1 - %2", line1, line2); } else { title = i18nc("date from-\nto", "%1 -\n%2", line1, line2); } drawHeader(p, title, curWeek.addDays(-6), QDate(), headerBox); drawWeek(p, curWeek, mStartTime, mEndTime, weekBox, mSingleLineLimit, mShowNoteLines, mIncludeDescription, mExcludeConfidential, mExcludePrivate); if (mPrintFooter) { drawFooter(p, footerBox); } curWeek = curWeek.addDays(7); if (curWeek <= toWeek) { mPrinter->newPage(); } } while (curWeek <= toWeek); break; case Timetable: default: do { line1 = local.toString(curWeek.addDays(-6), QLocale::ShortFormat); line2 = local.toString(curWeek, QLocale::ShortFormat); if (orientation() == QPrinter::Landscape) { title = i18nc("date from - to (week number)", "%1 - %2 (Week %3)", line1, line2, curWeek.weekNumber()); } else { title = i18nc("date from -\nto (week number)", "%1 -\n%2 (Week %3)", line1, line2, curWeek.weekNumber()); } drawHeader(p, title, curWeek, QDate(), headerBox); drawTimeTable(p, fromWeek, curWeek, false, mStartTime, mEndTime, weekBox, mIncludeDescription, mExcludeTime, mExcludeConfidential, mExcludePrivate); if (mPrintFooter) { drawFooter(p, footerBox); } fromWeek = fromWeek.addDays(7); curWeek = fromWeek.addDays(6); if (curWeek <= toWeek) { mPrinter->newPage(); } } while (curWeek <= toWeek); break; case SplitWeek: { QRect weekBox1(weekBox); // On the left side there are four days (mo-th) plus the timeline, // on the right there are only three days (fr-su) plus the timeline. Don't // use the whole width, but rather give them the same width as on the left. weekBox1.setRight(int((width - TIMELINE_WIDTH) * 3. / 4. + TIMELINE_WIDTH)); do { QDate endLeft(fromWeek.addDays(3)); int hh = headerHeight(); drawSplitHeaderRight(p, fromWeek, curWeek, QDate(), width, hh); drawTimeTable(p, fromWeek, endLeft, false, mStartTime, mEndTime, weekBox, mIncludeDescription, mExcludeTime, mExcludeConfidential, mExcludePrivate); if (mPrintFooter) { drawFooter(p, weekBox1); } mPrinter->newPage(); drawSplitHeaderRight(p, fromWeek, curWeek, QDate(), width, hh); drawTimeTable(p, endLeft.addDays(1), curWeek, false, mStartTime, mEndTime, weekBox1, mIncludeDescription, mExcludeTime, mExcludeConfidential, mExcludePrivate); if (mPrintFooter) { drawFooter(p, footerBox); } fromWeek = fromWeek.addDays(7); curWeek = fromWeek.addDays(6); if (curWeek <= toWeek) { mPrinter->newPage(); } } while (curWeek <= toWeek); break; } } } /************************************************************** * Print Month **************************************************************/ CalPrintMonth::CalPrintMonth() : CalPrintPluginBase() { } CalPrintMonth::~CalPrintMonth() { } QWidget *CalPrintMonth::createConfigWidget(QWidget *w) { return new CalPrintMonthConfig(w); } void CalPrintMonth::readSettingsWidget() { CalPrintMonthConfig *cfg = dynamic_cast((QWidget *)mConfigWidget); if (cfg) { mFromDate = QDate(cfg->mFromYear->value(), cfg->mFromMonth->currentIndex() + 1, 1); mToDate = QDate(cfg->mToYear->value(), cfg->mToMonth->currentIndex() + 1, 1); mWeekNumbers = cfg->mWeekNumbers->isChecked(); mRecurDaily = cfg->mRecurDaily->isChecked(); mRecurWeekly = cfg->mRecurWeekly->isChecked(); mIncludeTodos = cfg->mIncludeTodos->isChecked(); mShowNoteLines = cfg->mShowNoteLines->isChecked(); mSingleLineLimit = cfg->mSingleLineLimit->isChecked(); mUseColors = cfg->mColors->isChecked(); mPrintFooter = cfg->mPrintFooter->isChecked(); mIncludeDescription = cfg->mIncludeDescription->isChecked(); mExcludeConfidential = cfg->mExcludeConfidential->isChecked(); mExcludePrivate = cfg->mExcludePrivate->isChecked(); } } void CalPrintMonth::setSettingsWidget() { CalPrintMonthConfig *cfg = dynamic_cast((QWidget *)mConfigWidget); if (cfg) { setDateRange(mFromDate, mToDate); cfg->mWeekNumbers->setChecked(mWeekNumbers); cfg->mRecurDaily->setChecked(mRecurDaily); cfg->mRecurWeekly->setChecked(mRecurWeekly); cfg->mIncludeTodos->setChecked(mIncludeTodos); cfg->mShowNoteLines->setChecked(mShowNoteLines); cfg->mSingleLineLimit->setChecked(mSingleLineLimit); cfg->mColors->setChecked(mUseColors); cfg->mPrintFooter->setChecked(mPrintFooter); cfg->mIncludeDescription->setChecked(mIncludeDescription); cfg->mExcludeConfidential->setChecked(mExcludeConfidential); cfg->mExcludePrivate->setChecked(mExcludePrivate); } } void CalPrintMonth::loadConfig() { if (mConfig) { KConfigGroup grp(mConfig, groupName()); mWeekNumbers = grp.readEntry("Print week numbers", true); mRecurDaily = grp.readEntry("Print daily incidences", true); mRecurWeekly = grp.readEntry("Print weekly incidences", true); mIncludeTodos = grp.readEntry("Include todos", false); mSingleLineLimit = grp.readEntry("Single line limit", false); mShowNoteLines = grp.readEntry("Note Lines", false); mIncludeDescription = grp.readEntry("Include description", false); mExcludeConfidential = grp.readEntry("Exclude confidential", true); mExcludePrivate = grp.readEntry("Exclude private", true); } setSettingsWidget(); } void CalPrintMonth::saveConfig() { readSettingsWidget(); if (mConfig) { KConfigGroup grp(mConfig, groupName()); grp.writeEntry("Print week numbers", mWeekNumbers); grp.writeEntry("Print daily incidences", mRecurDaily); grp.writeEntry("Print weekly incidences", mRecurWeekly); grp.writeEntry("Include todos", mIncludeTodos); grp.writeEntry("Single line limit", mSingleLineLimit); grp.writeEntry("Note Lines", mShowNoteLines); grp.writeEntry("Include description", mIncludeDescription); grp.writeEntry("Exclude confidential", mExcludeConfidential); grp.writeEntry("Exclude private", mExcludePrivate); } } void CalPrintMonth::setDateRange(const QDate &from, const QDate &to) { CalPrintPluginBase::setDateRange(from, to); CalPrintMonthConfig *cfg = dynamic_cast((QWidget *)mConfigWidget); if (cfg) { cfg->mFromMonth->clear(); for (int i = 0; i < 12; ++i) { cfg->mFromMonth->addItem(QLocale().monthName(i + 1, QLocale::LongFormat)); } cfg->mToMonth->clear(); for (int i = 0; i < 12; ++i) { cfg->mToMonth->addItem(QLocale().monthName(i + 1, QLocale::LongFormat)); } cfg->mFromMonth->setCurrentIndex(from.month() - 1); cfg->mFromYear->setValue(to.year()); cfg->mToMonth->setCurrentIndex(mToDate.month() - 1); cfg->mToYear->setValue(mToDate.year()); } } void CalPrintMonth::print(QPainter &p, int width, int height) { QDate curMonth, fromMonth, toMonth; fromMonth = mFromDate.addDays(-(mFromDate.day() - 1)); toMonth = mToDate.addDays(mToDate.daysInMonth() - mToDate.day()); curMonth = fromMonth; QRect headerBox(0, 0, width, headerHeight()); QRect footerBox(0, height - footerHeight(), width, footerHeight()); height -= footerHeight(); QRect monthBox(0, 0, width, height); monthBox.setTop(headerBox.bottom() + padding()); do { QString title(i18nc("monthname year", "%1 %2", QLocale::system().monthName(curMonth.month()), QString::number(curMonth.year()))); QDate tmp(fromMonth); int weekdayCol = weekdayColumn(tmp.dayOfWeek()); tmp = tmp.addDays(-weekdayCol); drawHeader(p, title, curMonth.addMonths(-1), curMonth.addMonths(1), headerBox); drawMonthTable(p, curMonth, QTime(), QTime(), mWeekNumbers, mRecurDaily, mRecurWeekly, mSingleLineLimit, mShowNoteLines, mIncludeDescription, mExcludeConfidential, mExcludePrivate, monthBox); if (mPrintFooter) { drawFooter(p, footerBox); } curMonth = curMonth.addDays(curMonth.daysInMonth()); if (curMonth <= toMonth) { mPrinter->newPage(); } } while (curMonth <= toMonth); } /************************************************************** * Print Todos **************************************************************/ CalPrintTodos::CalPrintTodos() : CalPrintPluginBase() { mTodoSortField = TodoFieldUnset; mTodoSortDirection = TodoDirectionUnset; } CalPrintTodos::~CalPrintTodos() { } QWidget *CalPrintTodos::createConfigWidget(QWidget *w) { return new CalPrintTodoConfig(w); } void CalPrintTodos::readSettingsWidget() { CalPrintTodoConfig *cfg = dynamic_cast((QWidget *)mConfigWidget); if (cfg) { mPageTitle = cfg->mTitle->text(); if (cfg->mPrintAll->isChecked()) { mTodoPrintType = TodosAll; } else if (cfg->mPrintUnfinished->isChecked()) { mTodoPrintType = TodosUnfinished; } else if (cfg->mPrintDueRange->isChecked()) { mTodoPrintType = TodosDueRange; } else { mTodoPrintType = TodosAll; } mFromDate = cfg->mFromDate->date(); mToDate = cfg->mToDate->date(); mIncludeDescription = cfg->mDescription->isChecked(); mIncludePriority = cfg->mPriority->isChecked(); mIncludeDueDate = cfg->mDueDate->isChecked(); mIncludePercentComplete = cfg->mPercentComplete->isChecked(); mConnectSubTodos = cfg->mConnectSubTodos->isChecked(); mStrikeOutCompleted = cfg->mStrikeOutCompleted->isChecked(); mExcludeConfidential = cfg->mExcludeConfidential->isChecked(); mExcludePrivate = cfg->mExcludePrivate->isChecked(); mTodoSortField = (eTodoSortField)cfg->mSortField->currentIndex(); mTodoSortDirection = (eTodoSortDirection)cfg->mSortDirection->currentIndex(); mPrintFooter = cfg->mPrintFooter->isChecked(); } } void CalPrintTodos::setSettingsWidget() { CalPrintTodoConfig *cfg = dynamic_cast((QWidget *)mConfigWidget); if (cfg) { cfg->mTitle->setText(mPageTitle); cfg->mPrintAll->setChecked(mTodoPrintType == TodosAll); cfg->mPrintUnfinished->setChecked(mTodoPrintType == TodosUnfinished); cfg->mPrintDueRange->setChecked(mTodoPrintType == TodosDueRange); cfg->mFromDate->setDate(mFromDate); cfg->mToDate->setDate(mToDate); cfg->mDescription->setChecked(mIncludeDescription); cfg->mPriority->setChecked(mIncludePriority); cfg->mDueDate->setChecked(mIncludeDueDate); cfg->mPercentComplete->setChecked(mIncludePercentComplete); cfg->mConnectSubTodos->setChecked(mConnectSubTodos); cfg->mStrikeOutCompleted->setChecked(mStrikeOutCompleted); cfg->mExcludeConfidential->setChecked(mExcludeConfidential); cfg->mExcludePrivate->setChecked(mExcludePrivate); if (mTodoSortField != TodoFieldUnset) { // do not insert if already done so. cfg->mSortField->addItem(i18nc("@option sort by title", "Title")); cfg->mSortField->addItem(i18nc("@option sort by start date/time", "Start Date")); cfg->mSortField->addItem(i18nc("@option sort by due date/time", "Due Date")); cfg->mSortField->addItem(i18nc("@option sort by priority", "Priority")); cfg->mSortField->addItem(i18nc("@option sort by percent completed", "Percent Complete")); cfg->mSortField->setCurrentIndex(mTodoSortField); } if (mTodoSortDirection != TodoDirectionUnset) { // do not insert if already done so. cfg->mSortDirection->addItem(i18nc("@option sort in increasing order", "Ascending")); cfg->mSortDirection->addItem(i18nc("@option sort in descreasing order", "Descending")); cfg->mSortDirection->setCurrentIndex(mTodoSortDirection); } cfg->mPrintFooter->setChecked(mPrintFooter); } } void CalPrintTodos::loadConfig() { if (mConfig) { KConfigGroup grp(mConfig, groupName()); mPageTitle = grp.readEntry("Page title", i18n("To-do list")); mTodoPrintType = (eTodoPrintType)grp.readEntry("Print type", static_cast(TodosAll)); mIncludeDescription = grp.readEntry("Include description", true); mIncludePriority = grp.readEntry("Include priority", true); mIncludeDueDate = grp.readEntry("Include due date", true); mIncludePercentComplete = grp.readEntry("Include percentage completed", true); mConnectSubTodos = grp.readEntry("Connect subtodos", true); mStrikeOutCompleted = grp.readEntry("Strike out completed summaries", true); mTodoSortField = (eTodoSortField)grp.readEntry("Sort field", static_cast(TodoFieldSummary)); mTodoSortDirection = (eTodoSortDirection)grp.readEntry("Sort direction", static_cast(TodoDirectionAscending)); mExcludeConfidential = grp.readEntry("Exclude confidential", true); mExcludePrivate = grp.readEntry("Exclude private", true); } setSettingsWidget(); } void CalPrintTodos::saveConfig() { readSettingsWidget(); if (mConfig) { KConfigGroup grp(mConfig, groupName()); grp.writeEntry("Page title", mPageTitle); grp.writeEntry("Print type", int(mTodoPrintType)); grp.writeEntry("Include description", mIncludeDescription); grp.writeEntry("Include priority", mIncludePriority); grp.writeEntry("Include due date", mIncludeDueDate); grp.writeEntry("Include percentage completed", mIncludePercentComplete); grp.writeEntry("Connect subtodos", mConnectSubTodos); grp.writeEntry("Strike out completed summaries", mStrikeOutCompleted); grp.writeEntry("Sort field", static_cast(mTodoSortField)); grp.writeEntry("Sort direction", static_cast(mTodoSortDirection)); grp.writeEntry("Exclude confidential", mExcludeConfidential); grp.writeEntry("Exclude private", mExcludePrivate); } } void CalPrintTodos::print(QPainter &p, int width, int height) { // TODO: Find a good way to guarantee a nicely designed output int pospriority = 0; int possummary = 100; int posdue = width - 65; int poscomplete = posdue - 70; //Complete column is to right of the Due column QRect headerBox(0, 0, width, headerHeight()); QRect footerBox(0, height - footerHeight(), width, footerHeight()); height -= footerHeight(); // Draw the First Page Header drawHeader(p, mPageTitle, mFromDate, QDate(), headerBox); // Draw the Column Headers int mCurrentLinePos = headerHeight() + 5; QString outStr; QFont oldFont(p.font()); p.setFont(QFont(QStringLiteral("sans-serif"), 9, QFont::Bold)); int lineSpacing = p.fontMetrics().lineSpacing(); mCurrentLinePos += lineSpacing; if (mIncludePriority) { outStr += i18n("Priority"); p.drawText(pospriority, mCurrentLinePos - 2, outStr); } else { pospriority = -1; } outStr.truncate(0); outStr += i18nc("@label to-do summary", "Title"); p.drawText(possummary, mCurrentLinePos - 2, outStr); if (mIncludePercentComplete) { if (!mIncludeDueDate) { //move Complete column to the right poscomplete = posdue; //if not print the Due Date column } outStr.truncate(0); outStr += i18nc("@label to-do percentage complete", "Complete"); p.drawText(poscomplete, mCurrentLinePos - 2, outStr); } else { poscomplete = -1; } if (mIncludeDueDate) { outStr.truncate(0); outStr += i18nc("@label to-do due date", "Due"); p.drawText(posdue, mCurrentLinePos - 2, outStr); } else { posdue = -1; } p.setFont(QFont(QStringLiteral("sans-serif"), 10)); //fontHeight = p.fontMetrics().height(); KCalCore::Todo::List todoList; KCalCore::Todo::List tempList; KCalCore::SortDirection sortDirection = KCalCore::SortDirectionAscending; switch (mTodoSortDirection) { case TodoDirectionAscending: sortDirection = KCalCore::SortDirectionAscending; break; case TodoDirectionDescending: sortDirection = KCalCore::SortDirectionDescending; break; case TodoDirectionUnset: break; } KCalCore::TodoSortField sortField = KCalCore::TodoSortSummary; switch (mTodoSortField) { case TodoFieldSummary: sortField = KCalCore::TodoSortSummary; break; case TodoFieldStartDate: sortField = KCalCore::TodoSortStartDate; break; case TodoFieldDueDate: sortField = KCalCore::TodoSortDueDate; break; case TodoFieldPriority: sortField = KCalCore::TodoSortPriority; break; case TodoFieldPercentComplete: sortField = KCalCore::TodoSortPercentComplete; break; case TodoFieldUnset: break; } // Create list of to-dos which will be printed todoList = mCalendar->todos(sortField, sortDirection); switch (mTodoPrintType) { case TodosAll: break; case TodosUnfinished: for (const KCalCore::Todo::Ptr &todo : qAsConst(todoList)) { Q_ASSERT(todo); if (!todo->isCompleted()) { tempList.append(todo); } } todoList = tempList; break; case TodosDueRange: for (const KCalCore::Todo::Ptr &todo : qAsConst(todoList)) { Q_ASSERT(todo); if (todo->hasDueDate()) { if (todo->dtDue().date() >= mFromDate && todo->dtDue().date() <= mToDate) { tempList.append(todo); } } else { tempList.append(todo); } } todoList = tempList; break; } // Print to-dos int count = 0; for (const KCalCore::Todo::Ptr &todo : qAsConst(todoList)) { if ((mExcludeConfidential && todo->secrecy() == KCalCore::Incidence::SecrecyConfidential) || (mExcludePrivate && todo->secrecy() == KCalCore::Incidence::SecrecyPrivate)) { continue; } // Skip sub-to-dos. They will be printed recursively in drawTodo() if (todo->relatedTo().isEmpty()) { //review(AKONADI_PORT) count++; drawTodo(count, todo, p, sortField, sortDirection, mConnectSubTodos, mStrikeOutCompleted, mIncludeDescription, pospriority, possummary, posdue, poscomplete, 0, 0, mCurrentLinePos, width, height, todoList, nullptr, mExcludeConfidential, mExcludePrivate); } } if (mPrintFooter) { drawFooter(p, footerBox); } p.setFont(oldFont); }