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"