diff --git a/src/kontactplugin/korganizer/CMakeLists.txt b/src/kontactplugin/korganizer/CMakeLists.txt index 583e541d..b27e08f3 100644 --- a/src/kontactplugin/korganizer/CMakeLists.txt +++ b/src/kontactplugin/korganizer/CMakeLists.txt @@ -1,70 +1,70 @@ ########### next target ############### set(libcommon_SRCS korg_uniqueapp.cpp) ecm_qt_declare_logging_category(libcommon_SRCS HEADER korganizerplugin_debug.h IDENTIFIER KORGANIZERPLUGIN_LOG CATEGORY_NAME org.kde.pim.korganizer_plugin) set(kontact_korganizerplugin_PART_SRCS korganizerplugin.cpp apptsummarywidget.cpp summaryeventinfo.cpp ${libcommon_SRCS}) qt5_add_dbus_interfaces(kontact_korganizerplugin_PART_SRCS ${korganizer_SOURCE_DIR}/src/data/org.kde.Korganizer.Calendar.xml ${korganizer_SOURCE_DIR}/src/data/org.kde.korganizer.Korganizer.xml) add_library(kontact_korganizerplugin MODULE ${kontact_korganizerplugin_PART_SRCS}) -target_link_libraries(kontact_korganizerplugin KF5::AkonadiCalendar KF5::CalendarUtils KF5::Contacts KF5::CalendarCore KF5::Libkdepim KF5::KontactInterface korganizerprivate KF5::CalendarSupport KF5::AkonadiCalendar KF5::WindowSystem KF5::I18n KF5::IconThemes) +target_link_libraries(kontact_korganizerplugin KF5::AkonadiCalendar KF5::CalendarUtils KF5::Contacts KF5::CalendarCore KF5::Libkdepim KF5::KontactInterface korganizerprivate KF5::CalendarSupport KF5::AkonadiCalendar KF5::WindowSystem KF5::I18n) ########### next target ############### set(kontact_todoplugin_PART_SRCS todoplugin.cpp todosummarywidget.cpp ${libcommon_SRCS}) qt5_add_dbus_interfaces(kontact_todoplugin_PART_SRCS ${korganizer_SOURCE_DIR}/src/data/org.kde.Korganizer.Calendar.xml ${korganizer_SOURCE_DIR}/src/data/org.kde.korganizer.Korganizer.xml) add_library(kontact_todoplugin MODULE ${kontact_todoplugin_PART_SRCS}) -target_link_libraries(kontact_todoplugin KF5::AkonadiCalendar KF5::Contacts KF5::Libkdepim KF5::KontactInterface KF5::CalendarCore KF5::CalendarUtils KF5::CalendarSupport KF5::AkonadiCalendar KF5::IconThemes KF5::Notifications KF5::WindowSystem) +target_link_libraries(kontact_todoplugin KF5::AkonadiCalendar KF5::Contacts KF5::Libkdepim KF5::KontactInterface KF5::CalendarCore KF5::CalendarUtils KF5::CalendarSupport KF5::AkonadiCalendar KF5::WindowSystem) ########### next target ############### set(kontact_journalplugin_PART_SRCS journalplugin.cpp ${libcommon_SRCS}) qt5_add_dbus_interfaces(kontact_journalplugin_PART_SRCS ${korganizer_SOURCE_DIR}/src/data/org.kde.Korganizer.Calendar.xml) add_library(kontact_journalplugin MODULE ${kontact_journalplugin_PART_SRCS}) -target_link_libraries(kontact_journalplugin KF5::KontactInterface KF5::IconThemes KF5::WindowSystem) +target_link_libraries(kontact_journalplugin KF5::KontactInterface KF5::WindowSystem) ########### next target ############### set(kcm_apptsummary_PART_SRCS kcmapptsummary.cpp) ki18n_wrap_ui(kcm_apptsummary_PART_SRCS apptsummaryconfig_base.ui) add_library(kcm_apptsummary MODULE ${kcm_apptsummary_PART_SRCS}) target_link_libraries(kcm_apptsummary KF5::KCMUtils KF5::I18n) ########### next target ############### set(kcm_todosummary_PART_SRCS kcmtodosummary.cpp) ki18n_wrap_ui(kcm_todosummary_PART_SRCS todosummaryconfig_base.ui) add_library(kcm_todosummary MODULE ${kcm_todosummary_PART_SRCS}) target_link_libraries(kcm_todosummary Qt5::Widgets KF5::KCMUtils KF5::I18n) ########## Unit Test ########### if (BUILD_TESTING) add_subdirectory(autotests) endif() ########### install files ############### install(TARGETS kcm_apptsummary DESTINATION ${KDE_INSTALL_PLUGINDIR}) install(TARGETS kcm_todosummary DESTINATION ${KDE_INSTALL_PLUGINDIR}) install(TARGETS kontact_korganizerplugin DESTINATION ${KDE_INSTALL_PLUGINDIR}) install(TARGETS kontact_todoplugin DESTINATION ${KDE_INSTALL_PLUGINDIR}) install(TARGETS kontact_journalplugin DESTINATION ${KDE_INSTALL_PLUGINDIR}) install(FILES korganizerplugin.desktop todoplugin.desktop journalplugin.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}/kontact) install(FILES kcmapptsummary.desktop kcmtodosummary.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}) install(FILES korganizer.setdlg DESTINATION ${KDE_INSTALL_DATADIR}/kontact/ksettingsdialog) diff --git a/src/kontactplugin/korganizer/apptsummarywidget.cpp b/src/kontactplugin/korganizer/apptsummarywidget.cpp index ee4ee7af..00431370 100644 --- a/src/kontactplugin/korganizer/apptsummarywidget.cpp +++ b/src/kontactplugin/korganizer/apptsummarywidget.cpp @@ -1,310 +1,307 @@ /* This file is part of Kontact. Copyright (c) 2003 Tobias Koenig Copyright (c) 2005-2006,2008-2009 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 "apptsummarywidget.h" #include "korganizerplugin.h" #include "summaryeventinfo.h" #include "korganizerinterface.h" #include #include #include #include #include #include #include #include #include -#include #include #include #include #include #include #include #include +#include ApptSummaryWidget::ApptSummaryWidget(KOrganizerPlugin *plugin, QWidget *parent) : KontactInterface::Summary(parent) , mPlugin(plugin) { QVBoxLayout *mainLayout = new QVBoxLayout(this); mainLayout->setSpacing(3); mainLayout->setContentsMargins(3, 3, 3, 3); QWidget *header = createHeader( this, QStringLiteral("view-calendar-upcoming-events"), i18n("Upcoming Events")); mainLayout->addWidget(header); mLayout = new QGridLayout(); mainLayout->addItem(mLayout); mLayout->setSpacing(3); mLayout->setRowStretch(6, 1); QStringList mimeTypes; mimeTypes << KCalendarCore::Event::eventMimeType(); mCalendar = CalendarSupport::calendarSingleton(); mChanger = new Akonadi::IncidenceChanger(parent); connect( mCalendar.data(), &Akonadi::ETMCalendar::calendarChanged, this, &ApptSummaryWidget::updateView); connect( mPlugin->core(), &KontactInterface::Core::dayChanged, this, &ApptSummaryWidget::updateView); // Update Configuration configUpdated(); } ApptSummaryWidget::~ApptSummaryWidget() { } void ApptSummaryWidget::configUpdated() { KConfig config(QStringLiteral("kcmapptsummaryrc")); KConfigGroup group = config.group("Days"); mDaysAhead = group.readEntry("DaysToShow", 7); group = config.group("Show"); mShowBirthdaysFromCal = group.readEntry("BirthdaysFromCalendar", true); mShowAnniversariesFromCal = group.readEntry("AnniversariesFromCalendar", true); group = config.group("Groupware"); mShowMineOnly = group.readEntry("ShowMineOnly", false); updateView(); } void ApptSummaryWidget::updateView() { qDeleteAll(mLabels); mLabels.clear(); // The event print consists of the following fields: // icon:start date:days-to-go:summary:time range // where, // the icon is the typical event icon // the start date is the event start date // the days-to-go is the #days until the event starts // the summary is the event summary // the time range is the start-end time (only for non-floating events) QLabel *label = nullptr; int counter = 0; - KIconLoader loader(QStringLiteral("korganizer")); - QPixmap pm = loader.loadIcon(QStringLiteral("view-calendar-day"), KIconLoader::Small); - QPixmap pmb = loader.loadIcon(QStringLiteral("view-calendar-birthday"), KIconLoader::Small); - QPixmap pma = loader.loadIcon(QStringLiteral( - "view-calendar-wedding-anniversary"), KIconLoader::Small); + QPixmap pm = QIcon::fromTheme(QStringLiteral("view-calendar-day")).pixmap(style()->pixelMetric(QStyle::PM_SmallIconSize)); + QPixmap pmb = QIcon::fromTheme(QStringLiteral("view-calendar-birthday")).pixmap(style()->pixelMetric(QStyle::PM_SmallIconSize)); + QPixmap pma = QIcon::fromTheme(QStringLiteral("view-calendar-wedding-anniversary")).pixmap(style()->pixelMetric(QStyle::PM_SmallIconSize)); QStringList uidList; SummaryEventInfo::setShowSpecialEvents(mShowBirthdaysFromCal, mShowAnniversariesFromCal); QDate currentDate = QDate::currentDate(); const SummaryEventInfo::List events = SummaryEventInfo::eventsForRange(currentDate, currentDate.addDays( mDaysAhead - 1), mCalendar); QPalette todayPalette = palette(); KColorScheme::adjustBackground(todayPalette, KColorScheme::ActiveBackground, QPalette::Window); QPalette urgentPalette = palette(); KColorScheme::adjustBackground(urgentPalette, KColorScheme::NegativeBackground, QPalette::Window); for (SummaryEventInfo *event : events) { // Optionally, show only my Events /* if ( mShowMineOnly && !KCalendarCore::CalHelper::isMyCalendarIncidence( mCalendarAdaptor, event->ev ) ) { continue; } TODO: CalHelper is deprecated, remove this? */ KCalendarCore::Event::Ptr ev = event->ev; // print the first of the recurring event series only if (ev->recurs()) { if (uidList.contains(ev->instanceIdentifier())) { continue; } uidList.append(ev->instanceIdentifier()); } // Icon label label = new QLabel(this); if (ev->categories().contains(QLatin1String("BIRTHDAY"), Qt::CaseInsensitive)) { label->setPixmap(pmb); } else if (ev->categories().contains(QLatin1String("ANNIVERSARY"), Qt::CaseInsensitive)) { label->setPixmap(pma); } else { label->setPixmap(pm); } label->setMaximumWidth(label->minimumSizeHint().width()); mLayout->addWidget(label, counter, 0); mLabels.append(label); // Start date or date span label QString dateToDisplay = event->startDate; if (!event->dateSpan.isEmpty()) { dateToDisplay = event->dateSpan; } label = new QLabel(dateToDisplay, this); label->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); mLayout->addWidget(label, counter, 1); mLabels.append(label); if (event->makeBold) { QFont font = label->font(); font.setBold(true); label->setFont(font); if (!event->makeUrgent) { label->setPalette(todayPalette); } else { label->setPalette(urgentPalette); } label->setAutoFillBackground(true); } // Days to go label label = new QLabel(event->daysToGo, this); label->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); mLayout->addWidget(label, counter, 2); mLabels.append(label); // Summary label KUrlLabel *urlLabel = new KUrlLabel(this); urlLabel->setText(event->summaryText); urlLabel->setUrl(event->summaryUrl); urlLabel->installEventFilter(this); urlLabel->setTextFormat(Qt::RichText); urlLabel->setWordWrap(true); mLayout->addWidget(urlLabel, counter, 3); mLabels.append(urlLabel); connect(urlLabel, QOverload::of( &KUrlLabel::leftClickedUrl), this, &ApptSummaryWidget::viewEvent); connect(urlLabel, QOverload::of( &KUrlLabel::rightClickedUrl), this, &ApptSummaryWidget::popupMenu); if (!event->summaryTooltip.isEmpty()) { urlLabel->setToolTip(event->summaryTooltip); } // Time range label (only for non-floating events) if (!event->timeRange.isEmpty()) { label = new QLabel(event->timeRange, this); label->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); mLayout->addWidget(label, counter, 4); mLabels.append(label); } counter++; } qDeleteAll(events); if (!counter) { QLabel *noEvents = new QLabel( i18np("No upcoming events starting within the next day", "No upcoming events starting within the next %1 days", mDaysAhead), this); noEvents->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); mLayout->addWidget(noEvents, 0, 0); mLabels.append(noEvents); } for (QLabel *label : qAsConst(mLabels)) { label->show(); } } void ApptSummaryWidget::viewEvent(const QString &uid) { Akonadi::Item::Id id = mCalendar->item(uid).id(); if (id != -1) { mPlugin->core()->selectPlugin(QStringLiteral("kontact_korganizerplugin")); //ensure loaded OrgKdeKorganizerKorganizerInterface korganizer( QStringLiteral("org.kde.korganizer"), QStringLiteral( "/Korganizer"), QDBusConnection::sessionBus()); korganizer.editIncidence(QString::number(id)); } } void ApptSummaryWidget::removeEvent(const Akonadi::Item &item) { mChanger->deleteIncidence(item); } void ApptSummaryWidget::popupMenu(const QString &uid) { QMenu popup(this); // FIXME: Should say "Show Appointment" if we don't have rights to edit // Doesn't make sense to edit events from birthday resource for example QAction *editIt = popup.addAction(i18n("&Edit Appointment...")); QAction *delIt = popup.addAction(i18n("&Delete Appointment")); - delIt->setIcon(KIconLoader::global()-> - loadIcon(QStringLiteral("edit-delete"), KIconLoader::Small)); + delIt->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete"))); Akonadi::Item item = mCalendar->item(uid); delIt->setEnabled(mCalendar->hasRight(item, Akonadi::Collection::CanDeleteItem)); const QAction *selectedAction = popup.exec(QCursor::pos()); if (selectedAction == editIt) { viewEvent(uid); } else if (selectedAction == delIt) { removeEvent(item); } } bool ApptSummaryWidget::eventFilter(QObject *obj, QEvent *e) { if (obj->inherits("KUrlLabel")) { KUrlLabel *label = static_cast(obj); if (e->type() == QEvent::Enter) { Q_EMIT message(i18n("Edit Event: \"%1\"", label->text())); } if (e->type() == QEvent::Leave) { Q_EMIT message(QString()); } } return KontactInterface::Summary::eventFilter(obj, e); } QStringList ApptSummaryWidget::configModules() const { return QStringList() << QStringLiteral("kcmapptsummary.desktop"); } diff --git a/src/kontactplugin/korganizer/journalplugin.cpp b/src/kontactplugin/korganizer/journalplugin.cpp index 1f783acc..d222b5d1 100644 --- a/src/kontactplugin/korganizer/journalplugin.cpp +++ b/src/kontactplugin/korganizer/journalplugin.cpp @@ -1,132 +1,129 @@ /* This file is part of Kontact. Copyright (c) 2004,2009 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 "journalplugin.h" #include "calendarinterface.h" #include "korg_uniqueapp.h" #include #include -#include #include #include "korganizerplugin_debug.h" #include #include EXPORT_KONTACT_PLUGIN(JournalPlugin, journal) JournalPlugin::JournalPlugin(KontactInterface::Core *core, const QVariantList &) : KontactInterface::Plugin(core, core, "korganizer", "journal") , mIface(nullptr) { setComponentName(QStringLiteral("korganizer"), i18n("KOrganizer")); - KIconLoader::global()->addAppDir(QStringLiteral("korganizer")); - QAction *action = new QAction(QIcon::fromTheme(QStringLiteral("journal-new")), i18nc("@action:inmenu", "New Journal..."), this); actionCollection()->addAction(QStringLiteral("new_journal"), action); actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_J)); QString str = i18nc("@info:status", "Create a new journal"); action->setStatusTip(str); action->setToolTip(str); action->setWhatsThis( i18nc("@info:whatsthis", "You will be presented with a dialog where you can create " "a new journal entry.")); connect(action, &QAction::triggered, this, &JournalPlugin::slotNewJournal); insertNewAction(action); mUniqueAppWatcher = new KontactInterface::UniqueAppWatcher( new KontactInterface::UniqueAppHandlerFactory(), this); } JournalPlugin::~JournalPlugin() { } KParts::ReadOnlyPart *JournalPlugin::createPart() { KParts::ReadOnlyPart *part = loadPart(); if (!part) { return nullptr; } mIface = new OrgKdeKorganizerCalendarInterface( QStringLiteral("org.kde.korganizer"), QStringLiteral( "/Calendar"), QDBusConnection::sessionBus(), this); return part; } void JournalPlugin::select() { interface()->showJournalView(); } QStringList JournalPlugin::invisibleToolbarActions() const { QStringList invisible; invisible += QStringLiteral("new_event"); invisible += QStringLiteral("new_todo"); invisible += QStringLiteral("new_journal"); invisible += QStringLiteral("view_whatsnext"); invisible += QStringLiteral("view_day"); invisible += QStringLiteral("view_nextx"); invisible += QStringLiteral("view_month"); invisible += QStringLiteral("view_workweek"); invisible += QStringLiteral("view_week"); invisible += QStringLiteral("view_list"); invisible += QStringLiteral("view_todo"); invisible += QStringLiteral("view_journal"); invisible += QStringLiteral("view_timeline"); return invisible; } OrgKdeKorganizerCalendarInterface *JournalPlugin::interface() { if (!mIface) { part(); } Q_ASSERT(mIface); return mIface; } void JournalPlugin::slotNewJournal() { interface()->openJournalEditor(QString(), QDate()); } bool JournalPlugin::isRunningStandalone() const { return mUniqueAppWatcher->isRunningStandalone(); } #include "journalplugin.moc" diff --git a/src/kontactplugin/korganizer/korganizerplugin.cpp b/src/kontactplugin/korganizer/korganizerplugin.cpp index f465c8ad..a5b3e262 100644 --- a/src/kontactplugin/korganizer/korganizerplugin.cpp +++ b/src/kontactplugin/korganizer/korganizerplugin.cpp @@ -1,232 +1,230 @@ /* This file is part of Kontact. Copyright (c) 2001 Matthias Hoelzer-Kluepfel 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 "korganizerplugin.h" #include "apptsummarywidget.h" #include "calendarinterface.h" #include "korg_uniqueapp.h" #include #include #include #include #include #include #include #include #include "korganizerplugin_debug.h" #include -#include #include #include #include #include #include EXPORT_KONTACT_PLUGIN(KOrganizerPlugin, korganizer) KOrganizerPlugin::KOrganizerPlugin(KontactInterface::Core *core, const QVariantList &) : KontactInterface::Plugin(core, core, "korganizer", "calendar") , mIface(nullptr) { setComponentName(QStringLiteral("korganizer"), i18n("KOrganizer")); - KIconLoader::global()->addAppDir(QStringLiteral("korganizer")); QAction *action = new QAction(QIcon::fromTheme(QStringLiteral("appointment-new")), i18nc("@action:inmenu", "New Event..."), this); actionCollection()->addAction(QStringLiteral("new_event"), action); actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_E)); QString str = i18nc("@info:status", "Create a new event"); action->setStatusTip(str); action->setToolTip(str); action->setWhatsThis( i18nc("@info:whatsthis", "You will be presented with a dialog where you can create a new event item.")); connect(action, &QAction::triggered, this, &KOrganizerPlugin::slotNewEvent); insertNewAction(action); mUniqueAppWatcher = new KontactInterface::UniqueAppWatcher( new KontactInterface::UniqueAppHandlerFactory(), this); } KOrganizerPlugin::~KOrganizerPlugin() { } KontactInterface::Summary *KOrganizerPlugin::createSummaryWidget(QWidget *parent) { return new ApptSummaryWidget(this, parent); } KParts::ReadOnlyPart *KOrganizerPlugin::createPart() { KParts::ReadOnlyPart *part = loadPart(); if (!part) { return nullptr; } mIface = new OrgKdeKorganizerCalendarInterface( QStringLiteral("org.kde.korganizer"), QStringLiteral( "/Calendar"), QDBusConnection::sessionBus(), this); return part; } QStringList KOrganizerPlugin::invisibleToolbarActions() const { QStringList invisible; invisible += QStringLiteral("new_event"); invisible += QStringLiteral("new_todo"); invisible += QStringLiteral("new_journal"); invisible += QStringLiteral("view_todo"); invisible += QStringLiteral("view_journal"); return invisible; } void KOrganizerPlugin::select() { interface()->showEventView(); } OrgKdeKorganizerCalendarInterface *KOrganizerPlugin::interface() { if (!mIface) { part(); } Q_ASSERT(mIface); return mIface; } void KOrganizerPlugin::slotNewEvent() { interface()->openEventEditor(QString()); } bool KOrganizerPlugin::isRunningStandalone() const { return mUniqueAppWatcher->isRunningStandalone(); } bool KOrganizerPlugin::canDecodeMimeData(const QMimeData *mimeData) const { return mimeData->hasText() || KPIM::MailList::canDecode(mimeData) || KContacts::VCardDrag::canDecode(mimeData); } void KOrganizerPlugin::processDropEvent(QDropEvent *event) { const QMimeData *md = event->mimeData(); if (KContacts::VCardDrag::canDecode(md)) { KContacts::Addressee::List contacts; KContacts::VCardDrag::fromMimeData(md, contacts); KContacts::Addressee::List::ConstIterator it; KContacts::Addressee::List::ConstIterator end(contacts.constEnd()); QStringList attendees; for (it = contacts.constBegin(); it != end; ++it) { QString email = (*it).fullEmail(); if (email.isEmpty()) { attendees.append((*it).realName() + QStringLiteral("<>")); } else { attendees.append(email); } } interface()->openEventEditor(i18nc("@item", "Meeting"), QString(), QStringList(), attendees); return; } if (KCalUtils::ICalDrag::canDecode(event->mimeData())) { KCalendarCore::MemoryCalendar::Ptr cal( new KCalendarCore::MemoryCalendar(QTimeZone::systemTimeZone())); if (KCalUtils::ICalDrag::fromMimeData(event->mimeData(), cal)) { KCalendarCore::Incidence::List incidences = cal->incidences(); Q_ASSERT(incidences.count()); if (!incidences.isEmpty()) { event->accept(); KCalendarCore::Incidence::Ptr i = incidences.first(); QString summary; if (i->type() == KCalendarCore::Incidence::TypeJournal) { summary = i18nc("@item", "Note: %1", i->summary()); } else { summary = i->summary(); } interface()->openEventEditor(summary, i->description(), QStringList()); return; } // else fall through to text decoding } } if (md->hasText()) { const QString text = md->text(); qCDebug(KORGANIZERPLUGIN_LOG) << "DROP:" << text; interface()->openEventEditor(text); return; } if (KPIM::MailList::canDecode(md)) { KPIM::MailList mails = KPIM::MailList::fromMimeData(md); event->accept(); if (mails.count() != 1) { KMessageBox::sorry( core(), i18nc("@info", "Dropping multiple mails is not supported.")); } else { KPIM::MailSummary mail = mails.first(); QString txt = i18nc("@item", "From: %1\nTo: %2\nSubject: %3", mail.from(), mail.to(), mail.subject()); QTemporaryFile tf; tf.setAutoRemove(true); tf.open(); QString uri = QLatin1String("kmail:") + QString::number(mail.serialNumber()); tf.write(event->mimeData()->data(QStringLiteral("message/rfc822"))); interface()->openEventEditor( i18nc("@item", "Mail: %1", mail.subject()), txt, uri, tf.fileName(), QStringList(), QStringLiteral("message/rfc822")); tf.close(); } return; } qCWarning(KORGANIZERPLUGIN_LOG) << QStringLiteral("Cannot handle drop events of type '%1'.").arg( event->mimeData()->formats().join(QLatin1Char(';'))); } #include "korganizerplugin.moc" diff --git a/src/kontactplugin/korganizer/todoplugin.cpp b/src/kontactplugin/korganizer/todoplugin.cpp index 12043461..dc444eaf 100644 --- a/src/kontactplugin/korganizer/todoplugin.cpp +++ b/src/kontactplugin/korganizer/todoplugin.cpp @@ -1,240 +1,238 @@ /* This file is part of Kontact. Copyright (c) 2003 Cornelius Schumacher 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 "todoplugin.h" #include "calendarinterface.h" #include "korg_uniqueapp.h" #include "todosummarywidget.h" #include #include #include #include #include #include #include #include "korganizerplugin_debug.h" #include -#include #include #include #include #include EXPORT_KONTACT_PLUGIN(TodoPlugin, todo) TodoPlugin::TodoPlugin(KontactInterface::Core *core, const QVariantList &) : KontactInterface::Plugin(core, core, "korganizer", "todo") , mIface(nullptr) { setComponentName(QStringLiteral("korganizer"), i18n("KOrganizer")); - KIconLoader::global()->addAppDir(QStringLiteral("korganizer")); QAction *action = new QAction(QIcon::fromTheme(QStringLiteral("task-new")), i18nc("@action:inmenu", "New To-do..."), this); actionCollection()->addAction(QStringLiteral("new_todo"), action); actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_T)); QString str = i18nc("@info:status", "Create a new to-do"); action->setStatusTip(str); action->setToolTip(str); action->setWhatsThis( i18nc("@info:whatsthis", "You will be presented with a dialog where you can create a new to-do item.")); connect(action, &QAction::triggered, this, &TodoPlugin::slotNewTodo); insertNewAction(action); mUniqueAppWatcher = new KontactInterface::UniqueAppWatcher( new KontactInterface::UniqueAppHandlerFactory(), this); } TodoPlugin::~TodoPlugin() { } KontactInterface::Summary *TodoPlugin::createSummaryWidget(QWidget *parent) { return new TodoSummaryWidget(this, parent); } KParts::ReadOnlyPart *TodoPlugin::createPart() { KParts::ReadOnlyPart *part = loadPart(); if (!part) { return nullptr; } mIface = new OrgKdeKorganizerCalendarInterface( QStringLiteral("org.kde.korganizer"), QStringLiteral( "/Calendar"), QDBusConnection::sessionBus(), this); return part; } void TodoPlugin::select() { interface()->showTodoView(); } QStringList TodoPlugin::invisibleToolbarActions() const { QStringList invisible; invisible += QStringLiteral("new_event"); invisible += QStringLiteral("new_todo"); invisible += QStringLiteral("new_journal"); invisible += QStringLiteral("view_whatsnext"); invisible += QStringLiteral("view_day"); invisible += QStringLiteral("view_nextx"); invisible += QStringLiteral("view_month"); invisible += QStringLiteral("view_workweek"); invisible += QStringLiteral("view_week"); invisible += QStringLiteral("view_list"); invisible += QStringLiteral("view_todo"); invisible += QStringLiteral("view_journal"); invisible += QStringLiteral("view_timeline"); return invisible; } OrgKdeKorganizerCalendarInterface *TodoPlugin::interface() { if (!mIface) { part(); } Q_ASSERT(mIface); return mIface; } void TodoPlugin::slotNewTodo() { interface()->openTodoEditor(QString()); } bool TodoPlugin::canDecodeMimeData(const QMimeData *mimeData) const { return mimeData->hasText() || KPIM::MailList::canDecode(mimeData) || KContacts::VCardDrag::canDecode(mimeData) || KCalUtils::ICalDrag::canDecode(mimeData); } bool TodoPlugin::isRunningStandalone() const { return mUniqueAppWatcher->isRunningStandalone(); } void TodoPlugin::processDropEvent(QDropEvent *event) { const QMimeData *md = event->mimeData(); if (KContacts::VCardDrag::canDecode(md)) { KContacts::Addressee::List contacts; KContacts::VCardDrag::fromMimeData(md, contacts); KContacts::Addressee::List::ConstIterator it; QStringList attendees; KContacts::Addressee::List::ConstIterator end(contacts.constEnd()); for (it = contacts.constBegin(); it != end; ++it) { const QString email = (*it).fullEmail(); if (email.isEmpty()) { attendees.append((*it).realName() + QStringLiteral("<>")); } else { attendees.append(email); } } interface()->openTodoEditor(i18nc("@item", "Meeting"), QString(), QStringList(), attendees); return; } if (KCalUtils::ICalDrag::canDecode(event->mimeData())) { KCalendarCore::MemoryCalendar::Ptr cal(new KCalendarCore::MemoryCalendar(QTimeZone::systemTimeZone())); if (KCalUtils::ICalDrag::fromMimeData(event->mimeData(), cal)) { KCalendarCore::Incidence::List incidences = cal->incidences(); Q_ASSERT(incidences.count()); if (!incidences.isEmpty()) { event->accept(); KCalendarCore::Incidence::Ptr i = incidences.first(); QString summary; if (i->type() == KCalendarCore::Incidence::TypeJournal) { summary = i18nc("@item", "Note: %1", i->summary()); } else { summary = i->summary(); } interface()->openTodoEditor(summary, i->description(), QStringList()); return; } // else fall through to text decoding } } if (md->hasText()) { const QString text = md->text(); interface()->openTodoEditor(text); return; } if (KPIM::MailList::canDecode(md)) { KPIM::MailList mails = KPIM::MailList::fromMimeData(md); event->accept(); if (mails.count() != 1) { KMessageBox::sorry( core(), i18nc("@info", "Dropping multiple mails is not supported.")); } else { KPIM::MailSummary mail = mails.at(0); QString txt = i18nc("@item", "From: %1\nTo: %2\nSubject: %3", mail.from(), mail.to(), mail.subject()); QString uri = QStringLiteral("kmail:") +QString::number(mail.serialNumber()) + QLatin1Char('/') +mail.messageId(); QTemporaryFile tf; tf.setAutoRemove(true); tf.write(event->mimeData()->data(QStringLiteral("message/rfc822"))); interface()->openTodoEditor( i18nc("@item", "Mail: %1", mail.subject()), txt, uri, tf.fileName(), QStringList(), QStringLiteral("message/rfc822")); tf.close(); } return; } qCWarning(KORGANIZERPLUGIN_LOG) << QStringLiteral("Cannot handle drop events of type '%1'.").arg( event->mimeData()->formats().join(QLatin1Char(';'))); } #include "todoplugin.moc" diff --git a/src/kontactplugin/korganizer/todosummarywidget.cpp b/src/kontactplugin/korganizer/todosummarywidget.cpp index d4200de5..21ff6e97 100644 --- a/src/kontactplugin/korganizer/todosummarywidget.cpp +++ b/src/kontactplugin/korganizer/todosummarywidget.cpp @@ -1,439 +1,436 @@ /* This file is part of Kontact. Copyright (c) 2003 Tobias Koenig Copyright (c) 2005-2006,2008-2009 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 "todosummarywidget.h" #include "todoplugin.h" #include "korganizerinterface.h" #include #include #include #include #include #include #include #include #include -#include #include #include #include #include #include #include // for Qt::mightBeRichText #include +#include using namespace KCalUtils; TodoSummaryWidget::TodoSummaryWidget(TodoPlugin *plugin, QWidget *parent) : KontactInterface::Summary(parent) , mPlugin(plugin) { QVBoxLayout *mainLayout = new QVBoxLayout(this); mainLayout->setSpacing(3); mainLayout->setContentsMargins(3, 3, 3, 3); QWidget *header = createHeader(this, QStringLiteral("korg-todo"), i18n("Pending To-dos")); mainLayout->addWidget(header); mLayout = new QGridLayout(); mainLayout->addItem(mLayout); mLayout->setSpacing(3); mLayout->setRowStretch(6, 1); mCalendar = CalendarSupport::calendarSingleton(); mChanger = new Akonadi::IncidenceChanger(parent); connect( mCalendar.data(), &Akonadi::ETMCalendar::calendarChanged, this, &TodoSummaryWidget::updateView); connect( mPlugin->core(), &KontactInterface::Core::dayChanged, this, &TodoSummaryWidget::updateView); updateView(); } TodoSummaryWidget::~TodoSummaryWidget() { } void TodoSummaryWidget::updateView() { qDeleteAll(mLabels); mLabels.clear(); KConfig config(QStringLiteral("kcmtodosummaryrc")); KConfigGroup group = config.group("Days"); int mDaysToGo = group.readEntry("DaysToShow", 7); group = config.group("Hide"); mHideInProgress = group.readEntry("InProgress", false); mHideOverdue = group.readEntry("Overdue", false); mHideCompleted = group.readEntry("Completed", true); mHideOpenEnded = group.readEntry("OpenEnded", true); mHideNotStarted = group.readEntry("NotStarted", false); group = config.group("Groupware"); mShowMineOnly = group.readEntry("ShowMineOnly", false); // for each todo, // if it passes the filter, append to a list // else continue // sort todolist by summary // sort todolist by priority // sort todolist by due-date // print todolist // the filter is created by the configuration summary options, but includes // days to go before to-do is due // which types of to-dos to hide KCalendarCore::Todo::List prList; const QDate currDate = QDate::currentDate(); const KCalendarCore::Todo::List todos = mCalendar->todos(); for (const KCalendarCore::Todo::Ptr &todo : todos) { if (todo->hasDueDate()) { const int daysTo = currDate.daysTo(todo->dtDue().date()); if (daysTo >= mDaysToGo) { continue; } } if (mHideOverdue && todo->isOverdue()) { continue; } if (mHideInProgress && todo->isInProgress(false)) { continue; } if (mHideCompleted && todo->isCompleted()) { continue; } if (mHideOpenEnded && todo->isOpenEnded()) { continue; } if (mHideNotStarted && todo->isNotStarted(false)) { continue; } prList.append(todo); } if (!prList.isEmpty()) { prList = Akonadi::ETMCalendar::sortTodos(prList, KCalendarCore::TodoSortSummary, KCalendarCore::SortDirectionAscending); prList = Akonadi::ETMCalendar::sortTodos(prList, KCalendarCore::TodoSortPriority, KCalendarCore::SortDirectionAscending); prList = Akonadi::ETMCalendar::sortTodos(prList, KCalendarCore::TodoSortDueDate, KCalendarCore::SortDirectionAscending); } // The to-do print consists of the following fields: // icon:due date:days-to-go:priority:summary:status // where, // the icon is the typical to-do icon // the due date it the to-do due date // the days-to-go/past is the #days until/since the to-do is due // this field is left blank if the to-do is open-ended // the priority is the to-do priority // the summary is the to-do summary // the status is comma-separated list of: // overdue // in-progress (started, or >0% completed) // complete (100% completed) // open-ended // not-started (no start date and 0% completed) int counter = 0; QLabel *label = nullptr; if (!prList.isEmpty()) { - KIconLoader loader(QStringLiteral("korganizer")); - QPixmap pm = loader.loadIcon(QStringLiteral("view-calendar-tasks"), KIconLoader::Small); + QPixmap pm = QIcon::fromTheme(QStringLiteral("view-calendar-tasks")).pixmap(style()->pixelMetric(QStyle::PM_SmallIconSize)); QString str; for (const KCalendarCore::Todo::Ptr &todo : qAsConst(prList)) { bool makeBold = false; int daysTo = -1; // Optionally, show only my To-dos /* if ( mShowMineOnly && !KCalendarCore::CalHelper::isMyCalendarIncidence( mCalendarAdaptor, todo.get() ) ) { continue; } TODO: calhelper is deprecated, remove this? */ // Icon label label = new QLabel(this); label->setPixmap(pm); label->setMaximumWidth(label->minimumSizeHint().width()); mLayout->addWidget(label, counter, 0); mLabels.append(label); // Due date label str.clear(); if (todo->hasDueDate() && todo->dtDue().date().isValid()) { daysTo = currDate.daysTo(todo->dtDue().date()); if (daysTo == 0) { makeBold = true; str = i18nc("the to-do is due today", "Today"); } else if (daysTo == 1) { str = i18nc("the to-do is due tomorrow", "Tomorrow"); } else { const auto locale = QLocale::system(); for (int i = 3; i < 8; ++i) { if (daysTo < i * 24 * 60 * 60) { str = i18nc("1. weekday, 2. time", "%1 %2", locale.dayName(todo->dtDue().date().dayOfWeek(), QLocale::LongFormat), locale.toString(todo->dtDue().time(), QLocale::ShortFormat)); break; } } if (str.isEmpty()) { str = locale.toString(todo->dtDue(), QLocale::ShortFormat); } } } label = new QLabel(str, this); label->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); mLayout->addWidget(label, counter, 1); mLabels.append(label); if (makeBold) { QFont font = label->font(); font.setBold(true); label->setFont(font); } // Days togo/ago label str.clear(); if (todo->hasDueDate() && todo->dtDue().date().isValid()) { if (daysTo > 0) { str = i18np("in 1 day", "in %1 days", daysTo); } else if (daysTo < 0) { str = i18np("1 day ago", "%1 days ago", -daysTo); } else { str = i18nc("the to-do is due", "due"); } } label = new QLabel(str, this); label->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); mLayout->addWidget(label, counter, 2); mLabels.append(label); // Priority label str = QLatin1Char('[') + QString::number(todo->priority()) + QLatin1Char(']'); label = new QLabel(str, this); label->setAlignment(Qt::AlignRight | Qt::AlignVCenter); mLayout->addWidget(label, counter, 3); mLabels.append(label); // Summary label str = todo->summary(); if (!todo->relatedTo().isEmpty()) { // show parent only, not entire ancestry KCalendarCore::Incidence::Ptr inc = mCalendar->incidence(todo->relatedTo()); if (inc) { str = inc->summary() + QLatin1Char(':') + str; } } if (!Qt::mightBeRichText(str)) { str = str.toHtmlEscaped(); } KUrlLabel *urlLabel = new KUrlLabel(this); urlLabel->setText(str); urlLabel->setUrl(todo->uid()); urlLabel->installEventFilter(this); urlLabel->setTextFormat(Qt::RichText); urlLabel->setWordWrap(true); mLayout->addWidget(urlLabel, counter, 4); mLabels.append(urlLabel); connect(urlLabel, QOverload::of( &KUrlLabel::leftClickedUrl), this, &TodoSummaryWidget::viewTodo); connect(urlLabel, QOverload::of( &KUrlLabel::rightClickedUrl), this, &TodoSummaryWidget::popupMenu); // State text label str = stateStr(todo); label = new QLabel(str, this); label->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); mLayout->addWidget(label, counter, 5); mLabels.append(label); counter++; } } //foreach if (counter == 0) { QLabel *noTodos = new QLabel( i18np("No pending to-dos due within the next day", "No pending to-dos due within the next %1 days", mDaysToGo), this); noTodos->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); mLayout->addWidget(noTodos, 0, 0); mLabels.append(noTodos); } for (QLabel *label : qAsConst(mLabels)) { label->show(); } } void TodoSummaryWidget::viewTodo(const QString &uid) { const Akonadi::Item::Id id = mCalendar->item(uid).id(); if (id != -1) { mPlugin->core()->selectPlugin(QStringLiteral("kontact_todoplugin")); //ensure loaded OrgKdeKorganizerKorganizerInterface korganizer( QStringLiteral("org.kde.korganizer"), QStringLiteral( "/Korganizer"), QDBusConnection::sessionBus()); korganizer.editIncidence(QString::number(id)); } } void TodoSummaryWidget::removeTodo(const Akonadi::Item &item) { mChanger->deleteIncidence(item); } void TodoSummaryWidget::completeTodo(Akonadi::Item::Id id) { Akonadi::Item todoItem = mCalendar->item(id); if (todoItem.isValid()) { KCalendarCore::Todo::Ptr todo = CalendarSupport::todo(todoItem); if (!todo->isReadOnly()) { KCalendarCore::Todo::Ptr oldTodo(todo->clone()); todo->setCompleted(QDateTime::currentDateTime()); mChanger->modifyIncidence(todoItem, oldTodo); updateView(); } } } void TodoSummaryWidget::popupMenu(const QString &uid) { KCalendarCore::Todo::Ptr todo = mCalendar->todo(uid); if (!todo) { return; } Akonadi::Item item = mCalendar->item(uid); QMenu popup(this); QAction *editIt = popup.addAction(i18n("&Edit To-do...")); QAction *delIt = popup.addAction(i18n("&Delete To-do")); - delIt->setIcon(KIconLoader::global()->loadIcon(QStringLiteral( - "edit-delete"), KIconLoader::Small)); + delIt->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete"))); QAction *doneIt = nullptr; delIt->setEnabled(mCalendar->hasRight(item, Akonadi::Collection::CanDeleteItem)); if (!todo->isCompleted()) { doneIt = popup.addAction(i18n("&Mark To-do Completed")); - doneIt->setIcon(KIconLoader::global()->loadIcon(QStringLiteral("task-complete"), - KIconLoader::Small)); + doneIt->setIcon(QIcon::fromTheme(QStringLiteral("task-complete"))); doneIt->setEnabled(mCalendar->hasRight(item, Akonadi::Collection::CanChangeItem)); } // TODO: add icons to the menu actions const QAction *selectedAction = popup.exec(QCursor::pos()); if (selectedAction == editIt) { viewTodo(uid); } else if (selectedAction == delIt) { removeTodo(item); } else if (doneIt && selectedAction == doneIt) { completeTodo(item.id()); } } bool TodoSummaryWidget::eventFilter(QObject *obj, QEvent *e) { if (obj->inherits("KUrlLabel")) { KUrlLabel *label = static_cast(obj); if (e->type() == QEvent::Enter) { Q_EMIT message(i18n("Edit To-do: \"%1\"", label->text())); } if (e->type() == QEvent::Leave) { Q_EMIT message(QString()); } } return KontactInterface::Summary::eventFilter(obj, e); } QStringList TodoSummaryWidget::configModules() const { return QStringList() << QStringLiteral("kcmtodosummary.desktop"); } bool TodoSummaryWidget::startsToday(const KCalendarCore::Todo::Ptr &todo) { return todo->hasStartDate() && todo->dtStart().date() == QDate::currentDate(); } const QString TodoSummaryWidget::stateStr(const KCalendarCore::Todo::Ptr &todo) { QString str1, str2; if (todo->isOpenEnded()) { str1 = i18n("open-ended"); } else if (todo->isOverdue()) { str1 = QLatin1String("") +i18nc("the to-do is overdue", "overdue") +QLatin1String(""); } else if (startsToday(todo)) { str1 = i18nc("the to-do starts today", "starts today"); } if (todo->isNotStarted(false)) { str2 += i18nc("the to-do has not been started yet", "not-started"); } else if (todo->isCompleted()) { str2 += i18nc("the to-do is completed", "completed"); } else if (todo->isInProgress(false)) { str2 += i18nc("the to-do is in-progress", "in-progress "); str2 += QLatin1String(" (") + QString::number(todo->percentComplete()) + QLatin1String("%)"); } if (!str1.isEmpty() && !str2.isEmpty()) { str1 += i18nc("Separator for status like this: overdue, completed", ","); } return str1 + str2; } diff --git a/src/kontactplugin/specialdates/CMakeLists.txt b/src/kontactplugin/specialdates/CMakeLists.txt index 438a307a..42b2d9bc 100644 --- a/src/kontactplugin/specialdates/CMakeLists.txt +++ b/src/kontactplugin/specialdates/CMakeLists.txt @@ -1,43 +1,42 @@ ########### next target ############### set(kontact_specialdatesplugin_PART_SRCS specialdates_plugin.cpp sdsummarywidget.cpp) ecm_qt_declare_logging_category(kontact_specialdatesplugin_PART_SRCS HEADER korganizer_kontactplugins_specialdates_debug.h IDENTIFIER KORGANIZER_KONTACTPLUGINS_SPECIALDATES_LOG CATEGORY_NAME org.kde.pim.korganizer_kontactplugins_specialdates) add_library(kontact_specialdatesplugin MODULE ${kontact_specialdatesplugin_PART_SRCS}) set(_korganizerprivate_lib "korganizerprivate") target_link_libraries(kontact_specialdatesplugin KF5::Contacts KF5::CalendarCore KF5::Holidays KF5::KontactInterface KF5::AkonadiCore KF5::AkonadiContact KF5::CalendarSupport - KF5::IconThemes ) ########### next target ############### set(kcm_sdsummary_PART_SRCS kcmsdsummary.cpp) ki18n_wrap_ui(kcm_sdsummary_PART_SRCS sdsummaryconfig_base.ui) add_library(kcm_sdsummary MODULE ${kcm_sdsummary_PART_SRCS}) target_link_libraries(kcm_sdsummary Qt5::Widgets KF5::KCMUtils KF5::I18n) ########### install files ############### install(TARGETS kontact_specialdatesplugin DESTINATION ${KDE_INSTALL_PLUGINDIR}) install(TARGETS kcm_sdsummary DESTINATION ${KDE_INSTALL_PLUGINDIR}) install(FILES specialdatesplugin.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}/kontact) install(FILES kcmsdsummary.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}) install(FILES specialdates.setdlg DESTINATION ${KDE_INSTALL_DATADIR}/kontact/ksettingsdialog) diff --git a/src/kontactplugin/specialdates/sdsummarywidget.cpp b/src/kontactplugin/specialdates/sdsummarywidget.cpp index cf004ecc..84f2ebd7 100644 --- a/src/kontactplugin/specialdates/sdsummarywidget.cpp +++ b/src/kontactplugin/specialdates/sdsummarywidget.cpp @@ -1,759 +1,755 @@ /* This file is part of Kontact. Copyright (c) 2003 Tobias Koenig Copyright (c) 2004,2009 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 "sdsummarywidget.h" #include "korganizer_kontactplugins_specialdates_debug.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include #include #include #include #include #include #include #include #include +#include using namespace KHolidays; class BirthdaySearchJob : public Akonadi::ItemSearchJob { Q_OBJECT public: explicit BirthdaySearchJob(QObject *parent, int daysInAdvance); }; BirthdaySearchJob::BirthdaySearchJob(QObject *parent, int daysInAdvance) : ItemSearchJob(parent) { fetchScope().fetchFullPayload(); setMimeTypes({KContacts::Addressee::mimeType()}); Akonadi::SearchQuery query; query.addTerm(QStringLiteral("birthday"), QDate::currentDate().toJulianDay(), Akonadi::SearchTerm::CondGreaterOrEqual); query.addTerm(QStringLiteral("birthday"), QDate::currentDate().addDays( daysInAdvance).toJulianDay(), Akonadi::SearchTerm::CondLessOrEqual); ItemSearchJob::setQuery(query); } enum SDIncidenceType { IncidenceTypeContact, IncidenceTypeEvent }; enum SDCategory { CategoryBirthday, CategoryAnniversary, CategoryHoliday, CategorySeasonal, CategoryOther }; class SDEntry { public: SDIncidenceType type; SDCategory category; int yearsOld; int daysTo; QDate date; QString summary; QString desc; int span; // #days in the special occasion. KContacts::Addressee addressee; Akonadi::Item item; bool operator<(const SDEntry &entry) const { return daysTo < entry.daysTo; } }; SDSummaryWidget::SDSummaryWidget(KontactInterface::Plugin *plugin, QWidget *parent) : KontactInterface::Summary(parent) , mPlugin(plugin) , mHolidays(nullptr) { mCalendar = CalendarSupport::calendarSingleton(); // Create the Summary Layout QVBoxLayout *mainLayout = new QVBoxLayout(this); mainLayout->setSpacing(3); mainLayout->setContentsMargins(3, 3, 3, 3); QWidget *header = createHeader(this, QStringLiteral("view-calendar-special-occasion"), i18n("Upcoming Special Dates")); mainLayout->addWidget(header); mLayout = new QGridLayout(); mainLayout->addItem(mLayout); mLayout->setSpacing(3); mLayout->setRowStretch(6, 1); // Default settings mDaysAhead = 7; mShowBirthdaysFromKAB = true; mShowBirthdaysFromCal = true; mShowAnniversariesFromKAB = true; mShowAnniversariesFromCal = true; mShowHolidays = true; mJobRunning = false; mShowSpecialsFromCal = true; // Setup the Addressbook connect(mPlugin->core(), &KontactInterface::Core::dayChanged, this, &SDSummaryWidget::updateView); connect(mCalendar.data(), &Akonadi::ETMCalendar::calendarChanged, this, &SDSummaryWidget::updateView); // Update Configuration configUpdated(); } SDSummaryWidget::~SDSummaryWidget() { delete mHolidays; } void SDSummaryWidget::configUpdated() { KConfig config(QStringLiteral("kcmsdsummaryrc")); KConfigGroup group = config.group("Days"); mDaysAhead = group.readEntry("DaysToShow", 7); group = config.group("Show"); mShowBirthdaysFromKAB = group.readEntry("BirthdaysFromContacts", true); mShowBirthdaysFromCal = group.readEntry("BirthdaysFromCalendar", true); mShowAnniversariesFromKAB = group.readEntry("AnniversariesFromContacts", true); mShowAnniversariesFromCal = group.readEntry("AnniversariesFromCalendar", true); mShowHolidays = group.readEntry("HolidaysFromCalendar", true); mShowSpecialsFromCal = group.readEntry("SpecialsFromCalendar", true); group = config.group("Groupware"); mShowMineOnly = group.readEntry("ShowMineOnly", false); updateView(); } bool SDSummaryWidget::initHolidays() { KConfig _hconfig(QStringLiteral("korganizerrc")); KConfigGroup hconfig(&_hconfig, "Time & Date"); QString location = hconfig.readEntry("Holidays"); if (!location.isEmpty()) { delete mHolidays; mHolidays = new HolidayRegion(location); return true; } return false; } // number of days remaining in an Event int SDSummaryWidget::span(const KCalendarCore::Event::Ptr &event) const { int span = 1; if (event->isMultiDay() && event->allDay()) { QDate d = event->dtStart().date(); if (d < QDate::currentDate()) { d = QDate::currentDate(); } while (d < event->dtEnd().date()) { span++; d = d.addDays(1); } } return span; } // day of a multiday Event int SDSummaryWidget::dayof(const KCalendarCore::Event::Ptr &event, const QDate &date) const { int dayof = 1; QDate d = event->dtStart().date(); if (d < QDate::currentDate()) { d = QDate::currentDate(); } while (d < event->dtEnd().date()) { if (d < date) { dayof++; } d = d.addDays(1); } return dayof; } void SDSummaryWidget::slotBirthdayJobFinished(KJob *job) { // ;) BirthdaySearchJob *bJob = qobject_cast(job); if (bJob) { const auto items = bJob->items(); for (const Akonadi::Item &item : items) { if (item.hasPayload()) { const KContacts::Addressee addressee = item.payload(); const QDate birthday = addressee.birthday().date(); if (birthday.isValid()) { SDEntry entry; entry.type = IncidenceTypeContact; entry.category = CategoryBirthday; dateDiff(birthday, entry.daysTo, entry.yearsOld); if (entry.daysTo < mDaysAhead) { // We need to check the days ahead here because we don't // filter out Contact Birthdays by mDaysAhead in createLabels(). entry.date = birthday; entry.addressee = addressee; entry.item = item; entry.span = 1; mDates.append(entry); } } } } // Carry on. createLabels(); } mJobRunning = false; } void SDSummaryWidget::createLabels() { QLabel *label = nullptr; // Remove all special date labels from the layout and delete them, as we // will re-create all labels below. setUpdatesEnabled(false); for (QLabel *label : qAsConst(mLabels)) { mLayout->removeWidget(label); delete(label); update(); } mLabels.clear(); QDate dt; for (dt = QDate::currentDate(); dt <= QDate::currentDate().addDays(mDaysAhead - 1); dt = dt.addDays(1)) { const KCalendarCore::Event::List events = mCalendar->events(dt, mCalendar->timeZone(), KCalendarCore::EventSortStartDate, KCalendarCore::SortDirectionAscending); for (const KCalendarCore::Event::Ptr &ev : events) { // Optionally, show only my Events /* if ( mShowMineOnly && !KCalendarCore::CalHelper::isMyCalendarIncidence( mCalendarAdaptor, ev. ) ) { // FIXME; does isMyCalendarIncidence work !? It's deprecated too. continue; } // TODO: CalHelper is deprecated, remove this? */ if (ev->customProperty("KABC", "BIRTHDAY") == QLatin1String("YES")) { // Skipping, because these are got by the BirthdaySearchJob // See comments in updateView() continue; } if (!ev->categoriesStr().isEmpty()) { QStringList::ConstIterator it2; const QStringList c = ev->categories(); QStringList::ConstIterator end(c.constEnd()); for (it2 = c.constBegin(); it2 != end; ++it2) { const QString itUpper((*it2).toUpper()); // Append Birthday Event? if (mShowBirthdaysFromCal && (itUpper == QLatin1String("BIRTHDAY"))) { SDEntry entry; entry.type = IncidenceTypeEvent; entry.category = CategoryBirthday; entry.date = dt; entry.summary = ev->summary(); entry.desc = ev->description(); dateDiff(ev->dtStart().date(), entry.daysTo, entry.yearsOld); entry.span = 1; /* The following check is to prevent duplicate entries, * so in case of having a KCal incidence with category birthday * with summary and date equal to some KABC Attendee we don't show it * FIXME: port to akonadi, it's kresource based * */ if (/*!check( bdayRes, dt, ev->summary() )*/ true) { mDates.append(entry); } break; } // Append Anniversary Event? if (mShowAnniversariesFromCal && (itUpper == QLatin1String("ANNIVERSARY"))) { SDEntry entry; entry.type = IncidenceTypeEvent; entry.category = CategoryAnniversary; entry.date = dt; entry.summary = ev->summary(); entry.desc = ev->description(); dateDiff(ev->dtStart().date(), entry.daysTo, entry.yearsOld); entry.span = 1; if (/*!check( annvRes, dt, ev->summary() )*/ true) { mDates.append(entry); } break; } // Append Holiday Event? if (mShowHolidays && (itUpper == QLatin1String("HOLIDAY"))) { SDEntry entry; entry.type = IncidenceTypeEvent; entry.category = CategoryHoliday; entry.date = dt; entry.summary = ev->summary(); entry.desc = ev->description(); dateDiff(dt, entry.daysTo, entry.yearsOld); entry.yearsOld = -1; //ignore age of holidays entry.span = span(ev); if (entry.span > 1 && dayof(ev, dt) > 1) { // skip days 2,3,... break; } mDates.append(entry); break; } // Append Special Occasion Event? if (mShowSpecialsFromCal && (itUpper == QLatin1String("SPECIAL OCCASION"))) { SDEntry entry; entry.type = IncidenceTypeEvent; entry.category = CategoryOther; entry.date = dt; entry.summary = ev->summary(); entry.desc = ev->description(); dateDiff(dt, entry.daysTo, entry.yearsOld); entry.yearsOld = -1; //ignore age of special occasions entry.span = span(ev); if (entry.span > 1 && dayof(ev, dt) > 1) { // skip days 2,3,... break; } mDates.append(entry); break; } } } } } // Search for Holidays if (mShowHolidays) { if (initHolidays()) { for (dt = QDate::currentDate(); dt <= QDate::currentDate().addDays(mDaysAhead - 1); dt = dt.addDays(1)) { QList holidays = mHolidays->holidays(dt); QList::ConstIterator it = holidays.constBegin(); for (; it != holidays.constEnd(); ++it) { SDEntry entry; entry.type = IncidenceTypeEvent; if ((*it).categoryList().contains(QLatin1String("seasonal"))) { entry.category = CategorySeasonal; } else if ((*it).categoryList().contains(QLatin1String("public"))) { entry.category = CategoryHoliday; } else { entry.category = CategoryOther; } entry.date = dt; entry.summary = (*it).name(); dateDiff(dt, entry.daysTo, entry.yearsOld); entry.yearsOld = -1; //ignore age of holidays entry.span = 1; mDates.append(entry); } } } } // Sort, then Print the Special Dates std::sort(mDates.begin(), mDates.end()); if (!mDates.isEmpty()) { int counter = 0; QList::Iterator addrIt; QList::Iterator addrEnd(mDates.end()); for (addrIt = mDates.begin(); addrIt != addrEnd; ++addrIt) { const bool makeBold = (*addrIt).daysTo == 0; // i.e., today // Pixmap QImage icon_img; QString icon_name; KContacts::Picture pic; switch ((*addrIt).category) { case CategoryBirthday: icon_name = QStringLiteral("view-calendar-birthday"); pic = (*addrIt).addressee.photo(); if (pic.isIntern() && !pic.data().isNull()) { QImage img = pic.data(); if (img.width() > img.height()) { icon_img = img.scaledToWidth(32); } else { icon_img = img.scaledToHeight(32); } } break; case CategoryAnniversary: icon_name = QStringLiteral("view-calendar-wedding-anniversary"); pic = (*addrIt).addressee.photo(); if (pic.isIntern() && !pic.data().isNull()) { QImage img = pic.data(); if (img.width() > img.height()) { icon_img = img.scaledToWidth(32); } else { icon_img = img.scaledToHeight(32); } } break; case CategoryHoliday: icon_name = QStringLiteral("view-calendar-holiday"); break; case CategorySeasonal: case CategoryOther: icon_name = QStringLiteral("view-calendar-special-occasion"); break; } label = new QLabel(this); if (icon_img.isNull()) { - label->setPixmap(KIconLoader::global()->loadIcon(icon_name, KIconLoader::Small)); + label->setPixmap(QIcon::fromTheme(icon_name).pixmap(style()->pixelMetric(QStyle::PM_SmallIconSize))); } else { label->setPixmap(QPixmap::fromImage(icon_img)); } label->setMaximumWidth(label->minimumSizeHint().width()); label->setAlignment(Qt::AlignVCenter); mLayout->addWidget(label, counter, 0); mLabels.append(label); // Event date QString datestr; //Muck with the year -- change to the year 'daysTo' days away int year = QDate::currentDate().addDays((*addrIt).daysTo).year(); QDate sD = QDate(year, (*addrIt).date.month(), (*addrIt).date.day()); if ((*addrIt).daysTo == 0) { datestr = i18nc("the special day is today", "Today"); } else if ((*addrIt).daysTo == 1) { datestr = i18nc("the special day is tomorrow", "Tomorrow"); } else { const auto locale = QLocale::system(); for (int i = 3; i < 8; ++i) { if ((*addrIt).daysTo < i) { datestr = locale.dayName(sD.dayOfWeek(), QLocale::LongFormat); break; } } if (datestr.isEmpty()) { datestr = locale.toString(sD, QLocale::ShortFormat); } } // Print the date span for multiday, floating events, for the // first day of the event only. if ((*addrIt).span > 1) { QString endstr = QLocale::system().toString(sD.addDays( (*addrIt).span - 1), QLocale::LongFormat); datestr += QLatin1String(" -\n ") + endstr; } label = new QLabel(datestr, this); label->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); mLayout->addWidget(label, counter, 1); mLabels.append(label); if (makeBold) { QFont font = label->font(); font.setBold(true); label->setFont(font); } // Countdown label = new QLabel(this); if ((*addrIt).daysTo == 0) { label->setText(i18n("now")); } else { label->setText(i18np("in 1 day", "in %1 days", (*addrIt).daysTo)); } label->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); mLayout->addWidget(label, counter, 2); mLabels.append(label); // What QString what; switch ((*addrIt).category) { case CategoryBirthday: what = i18n("Birthday"); break; case CategoryAnniversary: what = i18n("Anniversary"); break; case CategoryHoliday: what = i18n("Holiday"); break; case CategorySeasonal: what = i18n("Change of Seasons"); break; case CategoryOther: what = i18n("Special Occasion"); break; } label = new QLabel(this); label->setText(what); label->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); mLayout->addWidget(label, counter, 3); mLabels.append(label); // Description if ((*addrIt).type == IncidenceTypeContact) { KUrlLabel *urlLabel = new KUrlLabel(this); urlLabel->installEventFilter(this); urlLabel->setUrl((*addrIt).item.url(Akonadi::Item::UrlWithMimeType).url()); urlLabel->setText((*addrIt).addressee.realName()); urlLabel->setTextFormat(Qt::RichText); urlLabel->setWordWrap(true); mLayout->addWidget(urlLabel, counter, 4); mLabels.append(urlLabel); connect(urlLabel, qOverload(&KUrlLabel::leftClickedUrl), this, &SDSummaryWidget::mailContact); connect(urlLabel, qOverload(&KUrlLabel::rightClickedUrl), this, &SDSummaryWidget::popupMenu); } else { label = new QLabel(this); label->setText((*addrIt).summary); label->setTextFormat(Qt::RichText); mLayout->addWidget(label, counter, 4); mLabels.append(label); if (!(*addrIt).desc.isEmpty()) { label->setToolTip((*addrIt).desc); } } // Age if ((*addrIt).category == CategoryBirthday || (*addrIt).category == CategoryAnniversary) { label = new QLabel(this); if ((*addrIt).yearsOld <= 0) { label->setText(QString()); } else { label->setText(i18np("one year", "%1 years", (*addrIt).yearsOld)); } label->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); mLayout->addWidget(label, counter, 5); mLabels.append(label); } counter++; } } else { label = new QLabel( i18np("No special dates within the next 1 day", "No special dates pending within the next %1 days", mDaysAhead), this); label->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); mLayout->addWidget(label, 0, 0); mLabels.append(label); } QList::ConstIterator lit; QList::ConstIterator endLit(mLabels.constEnd()); for (lit = mLabels.constBegin(); lit != endLit; ++lit) { (*lit)->show(); } setUpdatesEnabled(true); } void SDSummaryWidget::updateView() { mDates.clear(); /* KABC Birthdays are got through a ItemSearchJob/SPARQL Query * I then added an ETM/CalendarModel because we need to search * for calendar entries that have birthday/anniversary categories too. * * Also, we can't get KABC Anniversaries through nepomuk because the * current S.D.O doesn't support it, so i also them through the ETM. * * So basically we have: * Calendar anniversaries - ETM * Calendar birthdays - ETM * KABC birthdays - BirthdaySearchJob * KABC anniversaries - ETM ( needs Birthday Agent running ) * * We could remove thomas' BirthdaySearchJob and use the ETM for that * but it has the advantage that we don't need a Birthday agent running. * **/ // Search for Birthdays if (mShowBirthdaysFromKAB && !mJobRunning) { BirthdaySearchJob *job = new BirthdaySearchJob(this, mDaysAhead); connect(job, &BirthdaySearchJob::result, this, &SDSummaryWidget::slotBirthdayJobFinished); job->start(); mJobRunning = true; // The result slot will trigger the rest of the update } } void SDSummaryWidget::mailContact(const QString &url) { const Akonadi::Item item = Akonadi::Item::fromUrl(QUrl(url)); if (!item.isValid()) { qCDebug(KORGANIZER_KONTACTPLUGINS_SPECIALDATES_LOG) << QStringLiteral("Invalid item found"); return; } Akonadi::ItemFetchJob *job = new Akonadi::ItemFetchJob(item, this); job->fetchScope().fetchFullPayload(); connect(job, &Akonadi::ItemFetchJob::result, this, &SDSummaryWidget::slotItemFetchJobDone); } void SDSummaryWidget::slotItemFetchJobDone(KJob *job) { if (job->error()) { qCWarning(KORGANIZER_KONTACTPLUGINS_SPECIALDATES_LOG) << job->errorString(); return; } const Akonadi::Item::List lst = qobject_cast(job)->items(); if (lst.isEmpty()) { return; } const KContacts::Addressee contact = lst.first().payload(); QDesktopServices::openUrl(QUrl(contact.fullEmail())); } void SDSummaryWidget::viewContact(const QString &url) { const Akonadi::Item item = Akonadi::Item::fromUrl(QUrl(url)); if (!item.isValid()) { qCDebug(KORGANIZER_KONTACTPLUGINS_SPECIALDATES_LOG) << "Invalid item found"; return; } QPointer dlg = new Akonadi::ContactViewerDialog(this); dlg->setContact(item); dlg->exec(); delete dlg; } void SDSummaryWidget::popupMenu(const QString &url) { QMenu popup(this); const QAction *sendMailAction - = popup.addAction(KIconLoader::global()->loadIcon(QStringLiteral("mail-message-new"), - KIconLoader::Small), - i18n("Send &Mail")); + = popup.addAction(QIcon::fromTheme(QStringLiteral("mail-message-new")), i18n("Send &Mail")); const QAction *viewContactAction - = popup.addAction(KIconLoader::global()->loadIcon(QStringLiteral("view-pim-contacts"), - KIconLoader::Small), - i18n("View &Contact")); + = popup.addAction(QIcon::fromTheme(QStringLiteral("view-pim-contacts")), i18n("View &Contact")); const QAction *ret = popup.exec(QCursor::pos()); if (ret == sendMailAction) { mailContact(url); } else if (ret == viewContactAction) { viewContact(url); } } bool SDSummaryWidget::eventFilter(QObject *obj, QEvent *e) { if (obj->inherits("KUrlLabel")) { KUrlLabel *label = static_cast(obj); if (e->type() == QEvent::Enter) { Q_EMIT message(i18n("Mail to:\"%1\"", label->text())); } if (e->type() == QEvent::Leave) { Q_EMIT message(QString()); } } return KontactInterface::Summary::eventFilter(obj, e); } void SDSummaryWidget::dateDiff(const QDate &date, int &days, int &years) const { QDate currentDate; QDate eventDate; if (QDate::isLeapYear(date.year()) && date.month() == 2 && date.day() == 29) { currentDate = QDate(date.year(), QDate::currentDate().month(), QDate::currentDate().day()); if (!QDate::isLeapYear(QDate::currentDate().year())) { eventDate = QDate(date.year(), date.month(), 28); // celebrate one day earlier ;) } else { eventDate = QDate(date.year(), date.month(), date.day()); } } else { currentDate = QDate(QDate::currentDate().year(), QDate::currentDate().month(), QDate::currentDate().day()); eventDate = QDate(QDate::currentDate().year(), date.month(), date.day()); } int offset = currentDate.daysTo(eventDate); if (offset < 0) { days = 365 + offset; years = QDate::currentDate().year() + 1 - date.year(); } else { days = offset; years = QDate::currentDate().year() - date.year(); } } QStringList SDSummaryWidget::configModules() const { return QStringList() << QStringLiteral("kcmsdsummary.desktop"); } #include "sdsummarywidget.moc" diff --git a/src/widgets/navigatorbar.cpp b/src/widgets/navigatorbar.cpp index 4e883220..0c3ef080 100644 --- a/src/widgets/navigatorbar.cpp +++ b/src/widgets/navigatorbar.cpp @@ -1,233 +1,230 @@ /* This file is part of KOrganizer. Copyright (c) 2003 Cornelius Schumacher 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 "navigatorbar.h" #include "koglobals.h" -#include #include #include #include #include #include NavigatorBar::NavigatorBar(QWidget *parent) : QWidget(parent) { QFont tfont = font(); tfont.setPointSize(10); tfont.setBold(false); bool isRTL = KOGlobals::self()->reverseLayout(); mPrevYear = createNavigationButton( isRTL ? QStringLiteral("arrow-right-double") : QStringLiteral("arrow-left-double"), i18n("Scroll backward to the previous year"), i18n("Click this button to scroll the display to the " "same approximate day of the previous year")); mPrevMonth = createNavigationButton( isRTL ? QStringLiteral("arrow-right") : QStringLiteral("arrow-left"), i18n("Scroll backward to the previous month"), i18n("Click this button to scroll the display to the " "same approximate date of the previous month")); mNextMonth = createNavigationButton( isRTL ? QStringLiteral("arrow-left") : QStringLiteral("arrow-right"), i18n("Scroll forward to the next month"), i18n("Click this button to scroll the display to the " "same approximate date of the next month")); mNextYear = createNavigationButton( isRTL ? QStringLiteral("arrow-left-double") : QStringLiteral("arrow-right-double"), i18n("Scroll forward to the next year"), i18n("Click this button to scroll the display to the " "same approximate day of the next year")); // Create month name button mMonth = new QToolButton(this); mMonth->setPopupMode(QToolButton::InstantPopup); mMonth->setAutoRaise(true); mMonth->setFont(tfont); mMonth->setToolTip(i18n("Select a month")); // Create year button mYear = new QToolButton(this); mYear->setPopupMode(QToolButton::InstantPopup); mYear->setAutoRaise(true); mYear->setFont(tfont); mYear->setToolTip(i18n("Select a year")); // set up control frame layout QHBoxLayout *ctrlLayout = new QHBoxLayout(this); ctrlLayout->setContentsMargins(0, 0, 0, 0); ctrlLayout->addWidget(mPrevYear); ctrlLayout->addWidget(mPrevMonth); ctrlLayout->addStretch(); ctrlLayout->addWidget(mMonth); ctrlLayout->addWidget(mYear); ctrlLayout->addStretch(); ctrlLayout->addWidget(mNextMonth); ctrlLayout->addWidget(mNextYear); connect(mPrevYear, &QToolButton::clicked, this, &NavigatorBar::prevYearClicked); connect(mPrevMonth, &QToolButton::clicked, this, &NavigatorBar::prevMonthClicked); connect(mNextMonth, &QToolButton::clicked, this, &NavigatorBar::nextMonthClicked); connect(mNextYear, &QToolButton::clicked, this, &NavigatorBar::nextYearClicked); connect(mMonth, &QToolButton::clicked, this, &NavigatorBar::selectMonthFromMenu); connect(mYear, &QToolButton::clicked, this, &NavigatorBar::selectYearFromMenu); } NavigatorBar::~NavigatorBar() { } void NavigatorBar::showButtons(bool left, bool right) { if (left) { mPrevYear->show(); mPrevMonth->show(); } else { mPrevYear->hide(); mPrevMonth->hide(); } if (right) { mNextYear->show(); mNextMonth->show(); } else { mNextYear->hide(); mNextMonth->hide(); } } void NavigatorBar::selectDates(const KCalendarCore::DateList &dateList) { if (!dateList.isEmpty()) { mDate = dateList.first(); // set the label text at the top of the navigator mMonth->setText(i18nc("monthname", "%1", QLocale().monthName(mDate.month(), QLocale::LongFormat))); mYear->setText(i18nc("4 digit year", "%1", QLocale().toString(mDate, QLatin1String("yyyy")))); } } void NavigatorBar::selectMonthFromMenu() { int month = mDate.month(); const int months = 12; QMenu *menu = new QMenu(mMonth); QList act; QAction *activateAction = nullptr; act.reserve(months); for (int i = 1; i <= months; ++i) { QAction *monthAction = menu->addAction(QLocale().monthName(i, QLocale::LongFormat)); act.append(monthAction); if (i == month) { activateAction = monthAction; } } if (activateAction) { menu->setActiveAction(activateAction); } month = 0; QAction *selectedAct = menu->exec(mMonth->mapToGlobal(QPoint(0, 0))); if (selectedAct && (selectedAct != activateAction)) { for (int i = 0; i < months; ++i) { if (act[i] == selectedAct) { month = i + 1; } } } qDeleteAll(act); act.clear(); delete menu; if (month > 0) { Q_EMIT monthSelected(month); } } void NavigatorBar::selectYearFromMenu() { int year = mDate.year(); int years = 11; // odd number (show a few years ago -> a few years from now) int minYear = year - (years / 3); QMenu *menu = new QMenu(mYear); QList act; act.reserve(years); QString yearStr; QAction *activateAction = nullptr; int y = minYear; for (int i = 0; i < years; ++i) { QAction *yearAction = menu->addAction(yearStr.setNum(y)); act.append(yearAction); if (y == year) { activateAction = yearAction; } y++; } if (activateAction) { menu->setActiveAction(activateAction); } year = 0; QAction *selectedAct = menu->exec(mYear->mapToGlobal(QPoint(0, 0))); if (selectedAct && (selectedAct != activateAction)) { int y = minYear; for (int i = 0; i < years; ++i) { if (act[i] == selectedAct) { year = y; } y++; } } qDeleteAll(act); act.clear(); delete menu; if (year > 0) { Q_EMIT yearSelected(year); } } QToolButton *NavigatorBar::createNavigationButton(const QString &icon, const QString &toolTip, const QString &whatsThis) { QToolButton *button = new QToolButton(this); - button->setIcon( - KIconLoader::global()->loadIcon(icon, KIconLoader::Desktop, KIconLoader::SizeSmall)); - button->setIconSize(QSize(KIconLoader::SizeSmall, KIconLoader::SizeSmall)); + button->setIcon(QIcon::fromTheme(icon)); button->setToolButtonStyle(Qt::ToolButtonIconOnly); button->setAutoRaise(true); button->setToolTip(toolTip); button->setWhatsThis(whatsThis); return button; }