File indexing completed on 2025-01-05 04:54:20

0001 /*
0002    SPDX-FileCopyrightText: 2013-2024 Laurent Montel <montel@kde.org>
0003 
0004    SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 #include "knotefinddialog.h"
0007 #include "config-knotes.h"
0008 #include "widget/notelistwidget.h"
0009 
0010 #include <TextUtils/ConvertText>
0011 
0012 #include <PIM/notequery.h>
0013 #include <PIM/resultiterator.h>
0014 
0015 #include <KLocalizedString>
0016 #include <QIcon>
0017 #include <QLineEdit>
0018 #include <QPushButton>
0019 
0020 #include <KConfigGroup>
0021 #include <KSharedConfig>
0022 #include <KWindowConfig>
0023 #include <QDialogButtonBox>
0024 #include <QLabel>
0025 #include <QListWidget>
0026 #include <QMenu>
0027 #include <QVBoxLayout>
0028 #include <QWindow>
0029 
0030 #include <KLineEditEventHandler>
0031 
0032 KNoteFindDialog::KNoteFindDialog(QWidget *parent)
0033     : QDialog(parent)
0034     , mNoteFindWidget(new KNoteFindWidget(this))
0035 {
0036     setWindowTitle(i18nc("@title:window", "Search Notes"));
0037     auto mainLayout = new QVBoxLayout(this);
0038     auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Close, this);
0039     connect(buttonBox, &QDialogButtonBox::rejected, this, &KNoteFindDialog::reject);
0040     setAttribute(Qt::WA_DeleteOnClose);
0041     connect(mNoteFindWidget, &KNoteFindWidget::noteSelected, this, &KNoteFindDialog::noteSelected);
0042     mainLayout->addWidget(mNoteFindWidget);
0043     mainLayout->addWidget(buttonBox);
0044     readConfig();
0045 }
0046 
0047 KNoteFindDialog::~KNoteFindDialog()
0048 {
0049     writeConfig();
0050 }
0051 
0052 void KNoteFindDialog::setExistingNotes(const QHash<Akonadi::Item::Id, Akonadi::Item> &notes)
0053 {
0054     mNoteFindWidget->setExistingNotes(notes);
0055 }
0056 
0057 namespace
0058 {
0059 static const char myKNoteFindDialogName[] = "KNoteFindDialog";
0060 }
0061 void KNoteFindDialog::readConfig()
0062 {
0063     create(); // ensure a window is created
0064     windowHandle()->resize(QSize(600, 300));
0065     KConfigGroup group(KSharedConfig::openStateConfig(), QLatin1StringView(myKNoteFindDialogName));
0066     KWindowConfig::restoreWindowSize(windowHandle(), group);
0067     resize(windowHandle()->size()); // workaround for QTBUG-40584
0068 }
0069 
0070 void KNoteFindDialog::writeConfig()
0071 {
0072     KConfigGroup group(KSharedConfig::openStateConfig(), QLatin1StringView(myKNoteFindDialogName));
0073     KWindowConfig::saveWindowSize(windowHandle(), group);
0074     group.sync();
0075 }
0076 
0077 KNoteFindWidget::KNoteFindWidget(QWidget *parent)
0078     : QWidget(parent)
0079     , mResultSearch(new QLabel(this))
0080     , mSearchLineEdit(new QLineEdit(this))
0081     , mSearchButton(new QPushButton(QIcon::fromTheme(QStringLiteral("edit-find")), i18nc("@action:button Search notes", "Search..."), this))
0082     , mNoteList(new NoteShared::NoteListWidget(this))
0083 {
0084     auto vbox = new QVBoxLayout(this);
0085     vbox->setContentsMargins(0, 0, 0, 0);
0086     auto hbox = new QHBoxLayout;
0087     vbox->addLayout(hbox);
0088     auto lab = new QLabel(i18nc("@label:textbox", "Search notes:"), this);
0089     hbox->addWidget(lab);
0090     mSearchLineEdit->setClearButtonEnabled(true);
0091     KLineEditEventHandler::catchReturnKey(mSearchLineEdit);
0092     connect(mSearchLineEdit, &QLineEdit::returnPressed, this, &KNoteFindWidget::slotSearchNote);
0093     connect(mSearchLineEdit, &QLineEdit::textChanged, this, &KNoteFindWidget::slotTextChanged);
0094     hbox->addWidget(mSearchLineEdit);
0095 
0096     connect(mSearchButton, &QPushButton::clicked, this, &KNoteFindWidget::slotSearchNote);
0097     hbox->addWidget(mSearchButton);
0098     mSearchButton->setEnabled(false);
0099 
0100     // Result
0101     mNoteList->setContextMenuPolicy(Qt::CustomContextMenu);
0102     mNoteList->setSelectionMode(QAbstractItemView::SingleSelection);
0103     connect(mNoteList, &NoteShared::NoteListWidget::itemDoubleClicked, this, &KNoteFindWidget::slotItemDoubleClicked);
0104     connect(mNoteList, &NoteShared::NoteListWidget::customContextMenuRequested, this, &KNoteFindWidget::customContextMenuRequested);
0105     vbox->addWidget(mNoteList);
0106 
0107     mResultSearch->setTextFormat(Qt::PlainText);
0108     vbox->addWidget(mResultSearch);
0109 
0110     mSearchLineEdit->setFocus();
0111 }
0112 
0113 KNoteFindWidget::~KNoteFindWidget() = default;
0114 
0115 void KNoteFindWidget::setExistingNotes(const QHash<Akonadi::Item::Id, Akonadi::Item> &notes)
0116 {
0117     mNotes = notes;
0118 }
0119 
0120 void KNoteFindWidget::slotItemDoubleClicked(QListWidgetItem *item)
0121 {
0122     Q_EMIT noteSelected(mNoteList->itemId(item));
0123 }
0124 
0125 void KNoteFindWidget::slotSearchNote()
0126 {
0127     const QString searchStr = mSearchLineEdit->text().trimmed();
0128     if (searchStr.trimmed().isEmpty()) {
0129         return;
0130     }
0131     auto config = KConfig(QStringLiteral("akonadi_indexing_agent"));
0132     KConfigGroup cfg = config.group(QStringLiteral("General"));
0133     const bool respectDiacriticAndAccents = cfg.readEntry("respectDiacriticAndAccents", true);
0134     const QString searchString = respectDiacriticAndAccents ? searchStr : TextUtils::ConvertText::normalize(searchStr);
0135     Akonadi::Search::PIM::NoteQuery query;
0136     query.matchNote(searchString);
0137     query.matchTitle(searchString);
0138 
0139     Akonadi::Search::PIM::ResultIterator it = query.exec();
0140 
0141     Akonadi::Item::List lst;
0142     while (it.next()) {
0143         const Akonadi::Item::Id id = it.id();
0144         if (mNotes.contains(id)) {
0145             lst << mNotes.value(id);
0146         }
0147     }
0148     mNoteList->setNotes(lst);
0149     if (lst.isEmpty()) {
0150         mResultSearch->setText(i18nc("@label", "No Results found in search."));
0151     } else {
0152         mResultSearch->clear();
0153     }
0154 }
0155 
0156 void KNoteFindWidget::slotTextChanged(const QString &text)
0157 {
0158     mSearchButton->setEnabled(!text.trimmed().isEmpty());
0159 }
0160 
0161 void KNoteFindWidget::customContextMenuRequested(const QPoint &)
0162 {
0163     QListWidgetItem *item = mNoteList->currentItem();
0164     QMenu menu(this);
0165     if (item) {
0166         menu.addAction(i18n("Show Note"), this, [this, item]() {
0167             Q_EMIT noteSelected(mNoteList->itemId(item));
0168         });
0169         menu.exec(QCursor::pos());
0170     }
0171 }
0172 
0173 #include "moc_knotefinddialog.cpp"