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

0001 /*
0002    SPDX-FileCopyrightText: 2013-2024 Laurent Montel <montel@kde.org>
0003 
0004    SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "knotesiconview.h"
0008 #include "attributes/notedisplayattribute.h"
0009 #include "attributes/notelockattribute.h"
0010 #include "knotes_kontact_plugin_debug.h"
0011 #include "notes/knotedisplaysettings.h"
0012 #include "noteutils.h"
0013 #include "utils/knoteutils.h"
0014 
0015 #include <Akonadi/ItemModifyJob>
0016 
0017 #include <KMime/Message>
0018 
0019 #include <KIconEffect>
0020 #include <QEvent>
0021 #include <QMouseEvent>
0022 #include <QToolTip>
0023 
0024 //#define DEBUG_SAVE_NOTE 1
0025 
0026 KNotesIconView::KNotesIconView(KNotesPart *part, QWidget *parent)
0027     : QListWidget(parent)
0028     , m_part(part)
0029 {
0030     setViewMode(QListView::IconMode);
0031     setMovement(QListView::Static);
0032     setResizeMode(QListView::Adjust);
0033 
0034     setSelectionMode(QAbstractItemView::ExtendedSelection);
0035     setWordWrap(true);
0036     setMouseTracking(true);
0037 }
0038 
0039 KNotesIconView::~KNotesIconView() = default;
0040 
0041 bool KNotesIconView::event(QEvent *e)
0042 {
0043     if (e->type() != QEvent::ToolTip) {
0044         return QListWidget::event(e);
0045     }
0046     auto he = static_cast<QHelpEvent *>(e);
0047 
0048     QPoint pnt = viewport()->mapFromGlobal(mapToGlobal(he->pos()));
0049 
0050     if (pnt.y() < 0) {
0051         return true;
0052     }
0053 
0054     QListWidgetItem *item = itemAt(pnt);
0055     if (item) {
0056         auto noteItem = static_cast<KNotesIconViewItem *>(item);
0057         NoteShared::NoteUtils noteUtils;
0058         const QString toolTip = noteUtils.createToolTip(noteItem->item());
0059         QToolTip::showText(he->globalPos(), toolTip, viewport(), visualItemRect(item));
0060     }
0061     return true;
0062 }
0063 
0064 void KNotesIconView::mousePressEvent(QMouseEvent *e)
0065 {
0066     if (e->button() == Qt::RightButton) {
0067         QListView::mousePressEvent(e);
0068         m_part->popupRMB(currentItem(), e->pos(), e->globalPosition().toPoint());
0069     } else {
0070         QListView::mousePressEvent(e);
0071     }
0072 }
0073 
0074 void KNotesIconView::addNote(const Akonadi::Item &item)
0075 {
0076     auto iconView = new KNotesIconViewItem(item, this);
0077     mNoteList.insert(item.id(), iconView);
0078 }
0079 
0080 KNotesIconViewItem *KNotesIconView::iconView(Akonadi::Item::Id id) const
0081 {
0082     return mNoteList.value(id);
0083 }
0084 
0085 QHash<Akonadi::Item::Id, KNotesIconViewItem *> KNotesIconView::noteList() const
0086 {
0087     return mNoteList;
0088 }
0089 
0090 KNotesIconViewItem::KNotesIconViewItem(const Akonadi::Item &item, QListWidget *parent)
0091     : QListWidgetItem(parent)
0092     , mItem(item)
0093     , mDisplayAttribute(new KNoteDisplaySettings)
0094     , mReadOnly(false)
0095 {
0096     if (mItem.hasAttribute<NoteShared::NoteDisplayAttribute>()) {
0097         mDisplayAttribute->setDisplayAttribute(mItem.attribute<NoteShared::NoteDisplayAttribute>());
0098     } else {
0099         setDisplayDefaultValue();
0100         // save default display value
0101     }
0102     prepare();
0103 }
0104 
0105 KNotesIconViewItem::~KNotesIconViewItem()
0106 {
0107     delete mDisplayAttribute;
0108 }
0109 
0110 void KNotesIconViewItem::prepare()
0111 {
0112     const auto noteMessage = mItem.payload<KMime::Message::Ptr>();
0113     const KMime::Headers::Subject *const subject = noteMessage ? noteMessage->subject(false) : nullptr;
0114     setText(subject ? subject->asUnicodeString() : QString());
0115 
0116     if (mItem.hasAttribute<NoteShared::NoteLockAttribute>()) {
0117         mReadOnly = true;
0118     } else {
0119         mReadOnly = false;
0120     }
0121     updateSettings();
0122 }
0123 
0124 bool KNotesIconViewItem::readOnly() const
0125 {
0126     return mReadOnly;
0127 }
0128 
0129 void KNotesIconViewItem::setReadOnly(bool b, bool save)
0130 {
0131     mReadOnly = b;
0132     if (mItem.hasAttribute<NoteShared::NoteLockAttribute>()) {
0133         if (!mReadOnly) {
0134             mItem.removeAttribute<NoteShared::NoteLockAttribute>();
0135         }
0136     } else {
0137         if (mReadOnly) {
0138             mItem.attribute<NoteShared::NoteLockAttribute>(Akonadi::Item::AddIfMissing);
0139         }
0140     }
0141     if (save) {
0142         auto job = new Akonadi::ItemModifyJob(mItem);
0143 #ifdef DEBUG_SAVE_NOTE
0144         qCDebug(KNOTES_KONTACT_PLUGIN_LOG) << " KNotesIconViewItem::setReadOnly savenote";
0145 #endif
0146         connect(job, &Akonadi::ItemModifyJob::result, this, &KNotesIconViewItem::slotNoteSaved);
0147     }
0148 }
0149 
0150 void KNotesIconViewItem::setDisplayDefaultValue()
0151 {
0152     KNoteUtils::setDefaultValue(mItem);
0153     auto job = new Akonadi::ItemModifyJob(mItem);
0154     connect(job, &Akonadi::ItemModifyJob::result, this, &KNotesIconViewItem::slotNoteSaved);
0155 }
0156 
0157 void KNotesIconViewItem::slotNoteSaved(KJob *job)
0158 {
0159     qCDebug(KNOTES_KONTACT_PLUGIN_LOG) << " void KNotesIconViewItem::slotNoteSaved(KJob *job)";
0160     if (job->error()) {
0161         qCDebug(KNOTES_KONTACT_PLUGIN_LOG) << " problem during save note:" << job->errorString();
0162     }
0163 }
0164 
0165 void KNotesIconViewItem::setChangeIconTextAndDescription(const QString &iconText, const QString &description, int position)
0166 {
0167     setIconText(iconText, false);
0168     saveNoteContent(iconText, description, position);
0169 }
0170 
0171 void KNotesIconViewItem::setIconText(const QString &text, bool save)
0172 {
0173     QString replaceText;
0174     if (text.length() > 50) {
0175         replaceText = text.left(50) + QLatin1StringView("...");
0176     } else {
0177         replaceText = text;
0178     }
0179 
0180     setText(replaceText);
0181     if (save) {
0182         saveNoteContent(text);
0183     }
0184 }
0185 
0186 QString KNotesIconViewItem::realName() const
0187 {
0188     const auto noteMessage = mItem.payload<KMime::Message::Ptr>();
0189     const KMime::Headers::Subject *const subject = noteMessage ? noteMessage->subject(false) : nullptr;
0190     return subject ? subject->asUnicodeString() : QString();
0191 }
0192 
0193 int KNotesIconViewItem::tabSize() const
0194 {
0195     return mDisplayAttribute->tabSize();
0196 }
0197 
0198 QColor KNotesIconViewItem::textBackgroundColor() const
0199 {
0200     return mDisplayAttribute->backgroundColor();
0201 }
0202 
0203 QColor KNotesIconViewItem::textForegroundColor() const
0204 {
0205     return mDisplayAttribute->foregroundColor();
0206 }
0207 
0208 bool KNotesIconViewItem::autoIndent() const
0209 {
0210     return mDisplayAttribute->autoIndent();
0211 }
0212 
0213 QFont KNotesIconViewItem::textFont() const
0214 {
0215     return mDisplayAttribute->font();
0216 }
0217 
0218 bool KNotesIconViewItem::isRichText() const
0219 {
0220     const auto noteMessage = mItem.payload<KMime::Message::Ptr>();
0221     return noteMessage->contentType()->isHTMLText();
0222 }
0223 
0224 QString KNotesIconViewItem::description() const
0225 {
0226     const auto noteMessage = mItem.payload<KMime::Message::Ptr>();
0227     return QString::fromUtf8(noteMessage->mainBodyPart()->decodedContent());
0228 }
0229 
0230 int KNotesIconViewItem::cursorPositionFromStart() const
0231 {
0232     int pos = 0;
0233     const auto noteMessage = mItem.payload<KMime::Message::Ptr>();
0234     if (auto hrd = noteMessage->headerByType("X-Cursor-Position")) {
0235         pos = hrd->asUnicodeString().toInt();
0236     }
0237     return pos;
0238 }
0239 
0240 void KNotesIconViewItem::setDescription(const QString &description)
0241 {
0242     saveNoteContent(QString(), description);
0243 }
0244 
0245 KNoteDisplaySettings *KNotesIconViewItem::displayAttribute() const
0246 {
0247     return mDisplayAttribute;
0248 }
0249 
0250 Akonadi::Item KNotesIconViewItem::item()
0251 {
0252     return mItem;
0253 }
0254 
0255 void KNotesIconViewItem::saveNoteContent(const QString &subject, const QString &description, int position)
0256 {
0257     auto message = mItem.payload<KMime::Message::Ptr>();
0258     const QByteArray encoding("utf-8");
0259     if (!subject.isEmpty()) {
0260         message->subject(true)->fromUnicodeString(subject, encoding);
0261     }
0262     message->contentType(true)->setMimeType(isRichText() ? "text/html" : "text/plain");
0263     message->contentType()->setCharset(encoding);
0264     message->contentTransferEncoding(true)->setEncoding(KMime::Headers::CEquPr);
0265     message->date(true)->setDateTime(QDateTime::currentDateTime());
0266     if (!description.isEmpty()) {
0267         message->mainBodyPart()->fromUnicodeString(description);
0268     } else if (message->mainBodyPart()->decodedText().isEmpty()) {
0269         message->mainBodyPart()->fromUnicodeString(QStringLiteral(" "));
0270     }
0271 
0272     if (position >= 0) {
0273         auto header = new KMime::Headers::Generic("X-Cursor-Position");
0274         header->fromUnicodeString(QString::number(position), "utf-8");
0275         message->setHeader(header);
0276     }
0277 
0278     message->assemble();
0279 
0280     mItem.setPayload(message);
0281     auto job = new Akonadi::ItemModifyJob(mItem);
0282 #ifdef DEBUG_SAVE_NOTE
0283     qCDebug(KNOTES_KONTACT_PLUGIN_LOG) << " KNotesIconViewItem::saveNoteContent savenote";
0284 #endif
0285     connect(job, &Akonadi::ItemModifyJob::result, this, &KNotesIconViewItem::slotNoteSaved);
0286 }
0287 
0288 void KNotesIconViewItem::setChangeItem(const Akonadi::Item &item, const QSet<QByteArray> &set)
0289 {
0290     mItem = item;
0291     if (item.hasAttribute<NoteShared::NoteDisplayAttribute>()) {
0292         mDisplayAttribute->setDisplayAttribute(item.attribute<NoteShared::NoteDisplayAttribute>());
0293     }
0294     if (set.contains("KJotsLockAttribute")) {
0295         setReadOnly(item.hasAttribute<NoteShared::NoteLockAttribute>(), false);
0296     }
0297     if (set.contains("PLD:RFC822")) {
0298         const auto noteMessage = item.payload<KMime::Message::Ptr>();
0299         const KMime::Headers::Subject *const subject = noteMessage ? noteMessage->subject(false) : nullptr;
0300         setIconText(subject ? subject->asUnicodeString() : QString(), false);
0301     }
0302     if (set.contains("NoteDisplayAttribute")) {
0303         updateSettings();
0304     }
0305 }
0306 
0307 void KNotesIconViewItem::updateSettings()
0308 {
0309     KIconEffect effect;
0310     const QColor color(mDisplayAttribute->backgroundColor());
0311     if (mDefaultPixmap.isNull()) {
0312         mDefaultPixmap = QIcon::fromTheme(QStringLiteral("knotes")).pixmap(48);
0313     }
0314     QPixmap icon = effect.apply(mDefaultPixmap, KIconEffect::Colorize, 1, color, false);
0315     setFont(mDisplayAttribute->titleFont());
0316     setIcon(icon);
0317 }
0318 
0319 #include "moc_knotesiconview.cpp"