File indexing completed on 2025-01-19 04:51:21

0001 /*
0002   This file is part of Kontact.
0003 
0004   SPDX-FileCopyrightText: 2003 Tobias Koenig <tokoe@kde.org>
0005   SPDX-FileCopyrightText: 2014-2024 Laurent Montel <montel@kde.org>
0006 
0007   SPDX-License-Identifier: GPL-2.0-or-later WITH Qt-Commercial-exception-1.0
0008 */
0009 
0010 #include "summarywidget.h"
0011 #include "akonadi/notesakonaditreemodel.h"
0012 #include "akonadi/noteschangerecorder.h"
0013 #include "knotesinterface.h"
0014 
0015 #include <Akonadi/ChangeRecorder>
0016 #include <Akonadi/ETMViewStateSaver>
0017 #include <Akonadi/Session>
0018 
0019 #include <KontactInterface/Core>
0020 #include <KontactInterface/Plugin>
0021 
0022 #include <KCheckableProxyModel>
0023 #include <KLocalizedString>
0024 #include <KMime/Message>
0025 #include <KSharedConfig>
0026 #include <KUrlLabel>
0027 
0028 #include <QItemSelectionModel>
0029 #include <QLabel>
0030 #include <QMenu>
0031 #include <QVBoxLayout>
0032 
0033 KNotesSummaryWidget::KNotesSummaryWidget(KontactInterface::Plugin *plugin, QWidget *parent)
0034     : KontactInterface::Summary(parent)
0035     , mPlugin(plugin)
0036 {
0037     auto mainLayout = new QVBoxLayout(this);
0038     mainLayout->setSpacing(3);
0039     mainLayout->setContentsMargins(3, 3, 3, 3);
0040 
0041     QWidget *header = createHeader(this, QStringLiteral("view-pim-notes"), i18n("Popup Notes"));
0042     mainLayout->addWidget(header);
0043 
0044     mLayout = new QGridLayout();
0045     mainLayout->addLayout(mLayout);
0046     mLayout->setSpacing(3);
0047     mLayout->setRowStretch(6, 1);
0048 
0049     auto session = new Akonadi::Session("KNotes Session", this);
0050     mNoteRecorder = new NoteShared::NotesChangeRecorder(this);
0051     mNoteRecorder->changeRecorder()->setSession(session);
0052     mNoteTreeModel = new NoteShared::NotesAkonadiTreeModel(mNoteRecorder->changeRecorder(), this);
0053 
0054     connect(mNoteTreeModel, &NoteShared::NotesAkonadiTreeModel::rowsInserted, this, &KNotesSummaryWidget::updateFolderList);
0055 
0056     connect(mNoteRecorder->changeRecorder(), &Akonadi::Monitor::itemChanged, this, &KNotesSummaryWidget::updateFolderList);
0057 
0058     connect(mNoteRecorder->changeRecorder(), &Akonadi::Monitor::itemRemoved, this, &KNotesSummaryWidget::updateFolderList);
0059 
0060     mSelectionModel = new QItemSelectionModel(mNoteTreeModel);
0061     mModelProxy = new KCheckableProxyModel(this);
0062     mModelProxy->setSelectionModel(mSelectionModel);
0063     mModelProxy->setSourceModel(mNoteTreeModel);
0064 
0065     KSharedConfigPtr _config = KSharedConfig::openConfig(QStringLiteral("kcmknotessummaryrc"));
0066 
0067     mModelState = new KViewStateMaintainer<Akonadi::ETMViewStateSaver>(_config->group(QStringLiteral("CheckState")), this);
0068     mModelState->setSelectionModel(mSelectionModel);
0069 }
0070 
0071 KNotesSummaryWidget::~KNotesSummaryWidget() = default;
0072 
0073 void KNotesSummaryWidget::updateFolderList()
0074 {
0075     if (mInProgress) {
0076         return;
0077     }
0078     mInProgress = true;
0079     qDeleteAll(mLabels);
0080     mLabels.clear();
0081     int counter = 0;
0082 
0083     mModelState->restoreState();
0084     displayNotes(QModelIndex(), counter);
0085     mInProgress = false;
0086 
0087     if (counter == 0) {
0088         auto label = new QLabel(i18n("No notes found"), this);
0089         label->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
0090         mLayout->addWidget(label, 0, 0);
0091         mLabels.append(label);
0092     }
0093     QList<QLabel *>::const_iterator lit;
0094     QList<QLabel *>::const_iterator lend(mLabels.constEnd());
0095     for (lit = mLabels.constBegin(); lit != lend; ++lit) {
0096         (*lit)->show();
0097     }
0098 }
0099 
0100 void KNotesSummaryWidget::displayNotes(const QModelIndex &parent, int &counter)
0101 {
0102     const int nbCol = mModelProxy->rowCount(parent);
0103     for (int i = 0; i < nbCol; ++i) {
0104         const QModelIndex child = mModelProxy->index(i, 0, parent);
0105         const auto item = mModelProxy->data(child, Akonadi::EntityTreeModel::ItemRole).value<Akonadi::Item>();
0106         if (item.isValid()) {
0107             createNote(item, counter);
0108             ++counter;
0109         }
0110         displayNotes(child, counter);
0111     }
0112 }
0113 
0114 void KNotesSummaryWidget::slotPopupMenu(const QString &note)
0115 {
0116     QMenu popup(this);
0117     const QAction *modifyNoteAction = popup.addAction(QIcon::fromTheme(QStringLiteral("document-edit")), i18n("Modify Note..."));
0118     popup.addSeparator();
0119     const QAction *deleteNoteAction = popup.addAction(QIcon::fromTheme(QStringLiteral("edit-delete")), i18n("Delete Note..."));
0120 
0121     const QAction *ret = popup.exec(QCursor::pos());
0122     if (ret == deleteNoteAction) {
0123         deleteNote(note);
0124     } else if (ret == modifyNoteAction) {
0125         slotSelectNote(note);
0126     }
0127 }
0128 
0129 void KNotesSummaryWidget::deleteNote(const QString &note)
0130 {
0131     org::kde::kontact::KNotes knotes(QStringLiteral("org.kde.kontact"), QStringLiteral("/KNotes"), QDBusConnection::sessionBus());
0132     knotes.killNote(note.toLongLong());
0133 }
0134 
0135 void KNotesSummaryWidget::createNote(const Akonadi::Item &item, int counter)
0136 {
0137     if (!item.hasPayload<KMime::Message::Ptr>()) {
0138         return;
0139     }
0140 
0141     auto noteMessage = item.payload<KMime::Message::Ptr>();
0142     if (!noteMessage) {
0143         return;
0144     }
0145     const KMime::Headers::Subject *const subject = noteMessage->subject(false);
0146     const QString subStr = subject ? subject->asUnicodeString() : QString();
0147     auto urlLabel = new KUrlLabel(QString::number(item.id()), subStr, this);
0148 
0149     urlLabel->installEventFilter(this);
0150     urlLabel->setAlignment(Qt::AlignLeft);
0151     urlLabel->setWordWrap(true);
0152     connect(urlLabel, &KUrlLabel::leftClickedUrl, this, [this, urlLabel]() {
0153         slotSelectNote(urlLabel->url());
0154     });
0155 
0156     connect(urlLabel, &KUrlLabel::rightClickedUrl, this, [this, urlLabel]() {
0157         slotPopupMenu(urlLabel->url());
0158     });
0159     mLayout->addWidget(urlLabel, counter, 1);
0160 
0161     auto label = new QLabel(this);
0162     label->setAlignment(Qt::AlignVCenter);
0163     QIcon icon = QIcon::fromTheme(QStringLiteral("note"));
0164     label->setPixmap(icon.pixmap(style()->pixelMetric(QStyle::PM_SmallIconSize)));
0165     label->setMaximumWidth(label->minimumSizeHint().width());
0166     mLayout->addWidget(label, counter, 0);
0167     mLabels.append(label);
0168     mLabels.append(urlLabel);
0169 }
0170 
0171 void KNotesSummaryWidget::updateSummary(bool force)
0172 {
0173     Q_UNUSED(force)
0174     updateFolderList();
0175 }
0176 
0177 void KNotesSummaryWidget::slotSelectNote(const QString &note)
0178 {
0179     if (!mPlugin->isRunningStandalone()) {
0180         mPlugin->core()->selectPlugin(mPlugin);
0181     } else {
0182         mPlugin->bringToForeground();
0183     }
0184 
0185     org::kde::kontact::KNotes knotes(QStringLiteral("org.kde.kontact"), QStringLiteral("/KNotes"), QDBusConnection::sessionBus());
0186     knotes.editNote(note.toLongLong());
0187 }
0188 
0189 bool KNotesSummaryWidget::eventFilter(QObject *obj, QEvent *e)
0190 {
0191     if (obj->inherits("KUrlLabel")) {
0192         auto label = static_cast<KUrlLabel *>(obj);
0193         if (e->type() == QEvent::Enter) {
0194             Q_EMIT message(i18n("Read Popup Note: \"%1\"", label->text()));
0195         } else if (e->type() == QEvent::Leave) {
0196             Q_EMIT message(QString());
0197         }
0198     }
0199 
0200     return KontactInterface::Summary::eventFilter(obj, e);
0201 }
0202 
0203 QStringList KNotesSummaryWidget::configModules() const
0204 {
0205     return QStringList() << QStringLiteral("kcmknotessummary.desktop");
0206 }
0207 
0208 #include "moc_summarywidget.cpp"