File indexing completed on 2024-05-05 05:21:06

0001 /*
0002    SPDX-FileCopyrightText: 2013-2024 Laurent Montel <montel@kde.org>
0003 
0004    SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 #include "notesagentalarmdialog.h"
0007 #include "alarms/notealarmdialog.h"
0008 #include "attributes/notealarmattribute.h"
0009 #include "notesagent_debug.h"
0010 #include "notesagentnotedialog.h"
0011 #include "widget/notelistwidget.h"
0012 #include <KMime/KMimeMessage>
0013 
0014 #include <Akonadi/ItemFetchJob>
0015 #include <Akonadi/ItemFetchScope>
0016 #include <Akonadi/ItemModifyJob>
0017 
0018 #include <KLocalizedString>
0019 #include <KMessageBox>
0020 #include <QAction>
0021 #include <QDateTime>
0022 #include <QIcon>
0023 #include <QMenu>
0024 
0025 #include <KConfigGroup>
0026 #include <KSharedConfig>
0027 #include <KWindowConfig>
0028 #include <QDialogButtonBox>
0029 #include <QLabel>
0030 #include <QListWidget>
0031 #include <QLocale>
0032 #include <QPointer>
0033 #include <QPushButton>
0034 #include <QVBoxLayout>
0035 #include <QWindow>
0036 
0037 namespace
0038 {
0039 static const char myNotesAgentAlarmDialogName[] = "NotesAgentAlarmDialog";
0040 }
0041 NotesAgentAlarmDialog::NotesAgentAlarmDialog(QWidget *parent)
0042     : QDialog(parent)
0043 {
0044     setWindowTitle(i18nc("@title:window", "Alarm"));
0045     setWindowIcon(QIcon::fromTheme(QStringLiteral("knotes")));
0046     setAttribute(Qt::WA_DeleteOnClose);
0047     auto mainLayout = new QVBoxLayout(this);
0048 
0049     auto vbox = new QVBoxLayout;
0050     mainLayout->addLayout(vbox);
0051 
0052     mCurrentDateTime = new QLabel(this);
0053     mCurrentDateTime->setText(QLocale().toString((QDateTime::currentDateTime()), QLocale::ShortFormat));
0054     vbox->addWidget(mCurrentDateTime);
0055 
0056     auto lab = new QLabel(i18n("The following notes triggered alarms:"), this);
0057     vbox->addWidget(lab);
0058 
0059     mListWidget = new NoteShared::NoteListWidget(this);
0060     mListWidget->setContextMenuPolicy(Qt::CustomContextMenu);
0061     connect(mListWidget, &NoteShared::NoteListWidget::itemDoubleClicked, this, &NotesAgentAlarmDialog::slotItemDoubleClicked);
0062     connect(mListWidget, &NoteShared::NoteListWidget::customContextMenuRequested, this, &NotesAgentAlarmDialog::slotCustomContextMenuRequested);
0063 
0064     mainLayout->addWidget(mListWidget);
0065 
0066     auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Close, this);
0067     connect(buttonBox, &QDialogButtonBox::rejected, this, &NotesAgentAlarmDialog::reject);
0068     buttonBox->button(QDialogButtonBox::Close)->setDefault(true);
0069 
0070     mainLayout->addWidget(buttonBox);
0071     readConfig();
0072 }
0073 
0074 NotesAgentAlarmDialog::~NotesAgentAlarmDialog()
0075 {
0076     writeConfig();
0077 }
0078 
0079 void NotesAgentAlarmDialog::removeAlarm(const Akonadi::Item &note)
0080 {
0081     mListWidget->removeNote(note);
0082     if (mListWidget->count() == 0) {
0083         close();
0084     }
0085 }
0086 
0087 void NotesAgentAlarmDialog::slotCustomContextMenuRequested(const QPoint &pos)
0088 {
0089     if (mListWidget->selectedItems().isEmpty()) {
0090         return;
0091     }
0092     Q_UNUSED(pos)
0093     auto entriesContextMenu = new QMenu(this);
0094     auto removeAlarm = new QAction(QIcon::fromTheme(QStringLiteral("edit-delete")), i18n("Remove Alarm"), entriesContextMenu);
0095     connect(removeAlarm, &QAction::triggered, this, &NotesAgentAlarmDialog::slotRemoveAlarm);
0096     auto showNote = new QAction(i18n("Show Note..."), entriesContextMenu);
0097     connect(showNote, &QAction::triggered, this, &NotesAgentAlarmDialog::slotShowNote);
0098     auto modifyAlarm = new QAction(i18n("Modify Alarm..."), entriesContextMenu);
0099     connect(modifyAlarm, &QAction::triggered, this, &NotesAgentAlarmDialog::slotModifyAlarm);
0100     entriesContextMenu->addAction(showNote);
0101     entriesContextMenu->addAction(modifyAlarm);
0102 
0103     entriesContextMenu->addSeparator();
0104     entriesContextMenu->addAction(removeAlarm);
0105     entriesContextMenu->exec(QCursor::pos());
0106     delete entriesContextMenu;
0107 }
0108 
0109 void NotesAgentAlarmDialog::readConfig()
0110 {
0111     create(); // ensure a window is created
0112     windowHandle()->resize(QSize(300, 200));
0113     KConfigGroup group(KSharedConfig::openStateConfig(), QLatin1StringView(myNotesAgentAlarmDialogName));
0114     KWindowConfig::restoreWindowSize(windowHandle(), group);
0115     resize(windowHandle()->size()); // workaround for QTBUG-40584
0116 }
0117 
0118 void NotesAgentAlarmDialog::writeConfig()
0119 {
0120     KConfigGroup group(KSharedConfig::openStateConfig(), QLatin1StringView(myNotesAgentAlarmDialogName));
0121     KWindowConfig::saveWindowSize(windowHandle(), group);
0122     group.sync();
0123 }
0124 
0125 void NotesAgentAlarmDialog::addListAlarm(const Akonadi::Item::List &lstAlarm)
0126 {
0127     mListWidget->setNotes(lstAlarm);
0128     mCurrentDateTime->setText(QLocale().toString((QDateTime::currentDateTime()), QLocale::ShortFormat));
0129 }
0130 
0131 void NotesAgentAlarmDialog::slotItemDoubleClicked(QListWidgetItem *item)
0132 {
0133     if (item) {
0134         slotShowNote();
0135     }
0136 }
0137 
0138 void NotesAgentAlarmDialog::slotShowNote()
0139 {
0140     // deleted on close
0141     const Akonadi::Item::Id id = mListWidget->currentItemId();
0142     if (id != -1) {
0143         auto dlg = new NotesAgentNoteDialog;
0144         dlg->setNoteId(id);
0145         dlg->show();
0146     }
0147 }
0148 
0149 void NotesAgentAlarmDialog::slotRemoveAlarm()
0150 {
0151     const int answer = KMessageBox::warningTwoActions(this,
0152                                                       i18n("Are you sure to remove alarm?"),
0153                                                       i18nc("@title:window", "Remove Alarm"),
0154                                                       KStandardGuiItem::remove(),
0155                                                       KStandardGuiItem::cancel());
0156     if (answer == KMessageBox::ButtonCode::PrimaryAction) {
0157         const Akonadi::Item::Id id = mListWidget->currentItemId();
0158         if (id != -1) {
0159             Akonadi::Item item(id);
0160             auto job = new Akonadi::ItemFetchJob(item, this);
0161             job->fetchScope().fetchAttribute<NoteShared::NoteAlarmAttribute>();
0162             connect(job, &Akonadi::ItemFetchJob::result, this, &NotesAgentAlarmDialog::slotFetchItem);
0163         }
0164     }
0165 }
0166 
0167 void NotesAgentAlarmDialog::slotFetchItem(KJob *job)
0168 {
0169     if (job->error()) {
0170         qCDebug(NOTESAGENT_LOG) << "fetch item failed " << job->errorString();
0171         return;
0172     }
0173     auto itemFetchJob = static_cast<Akonadi::ItemFetchJob *>(job);
0174     Akonadi::Item::List items = itemFetchJob->items();
0175     if (!items.isEmpty()) {
0176         Akonadi::Item item = items.first();
0177         item.removeAttribute<NoteShared::NoteAlarmAttribute>();
0178         auto modify = new Akonadi::ItemModifyJob(item);
0179         connect(modify, &Akonadi::ItemModifyJob::result, this, &NotesAgentAlarmDialog::slotModifyItem);
0180     }
0181 }
0182 
0183 void NotesAgentAlarmDialog::slotModifyItem(KJob *job)
0184 {
0185     if (job->error()) {
0186         qCDebug(NOTESAGENT_LOG) << "modify item failed " << job->errorString();
0187         return;
0188     }
0189 }
0190 
0191 void NotesAgentAlarmDialog::slotModifyAlarm()
0192 {
0193     const Akonadi::Item::Id id = mListWidget->currentItemId();
0194     if (id != -1) {
0195         Akonadi::Item item(id);
0196         auto job = new Akonadi::ItemFetchJob(item, this);
0197         job->fetchScope().fetchFullPayload(true);
0198         job->fetchScope().fetchAttribute<NoteShared::NoteAlarmAttribute>();
0199         connect(job, &Akonadi::ItemFetchJob::result, this, &NotesAgentAlarmDialog::slotFetchAlarmItem);
0200     }
0201 }
0202 
0203 void NotesAgentAlarmDialog::slotFetchAlarmItem(KJob *job)
0204 {
0205     if (job->error()) {
0206         qCDebug(NOTESAGENT_LOG) << "fetch item failed " << job->errorString();
0207         return;
0208     }
0209     auto itemFetchJob = static_cast<Akonadi::ItemFetchJob *>(job);
0210     Akonadi::Item::List items = itemFetchJob->items();
0211     if (!items.isEmpty()) {
0212         Akonadi::Item item = items.first();
0213         auto attr = item.attribute<NoteShared::NoteAlarmAttribute>();
0214         if (attr) {
0215             auto noteMessage = item.payload<KMime::Message::Ptr>();
0216             if (!noteMessage) {
0217                 qCDebug(NOTESAGENT_LOG) << "Error this note doesn't have payload ";
0218                 KMessageBox::error(this, i18n("Error during fetch alarm info."), i18n("Alarm"));
0219                 return;
0220             }
0221             const KMime::Headers::Subject *const subject = noteMessage->subject(false);
0222             QString caption;
0223             if (subject) {
0224                 caption = subject->asUnicodeString();
0225             }
0226             QPointer<NoteShared::NoteAlarmDialog> dlg = new NoteShared::NoteAlarmDialog(caption, this);
0227             dlg->setAlarm(attr->dateTime());
0228             if (dlg->exec()) {
0229                 const QDateTime date = dlg->alarm();
0230                 if (date.isValid()) {
0231                     attr->setDateTime(dlg->alarm());
0232                 } else {
0233                     item.removeAttribute<NoteShared::NoteAlarmAttribute>();
0234                 }
0235                 auto modify = new Akonadi::ItemModifyJob(item);
0236                 connect(modify, &Akonadi::ItemModifyJob::result, this, &NotesAgentAlarmDialog::slotModifyItem);
0237             }
0238             delete dlg;
0239         }
0240     }
0241 }
0242 
0243 #include "moc_notesagentalarmdialog.cpp"