File indexing completed on 2024-06-02 05:26:02
0001 /* 0002 This file is part of the KDE project 0003 0004 SPDX-FileCopyrightText: 2002-2003 Daniel Molkentin <molkentin@kde.org> 0005 SPDX-FileCopyrightText: 2004-2006 Michael Brade <brade@kde.org> 0006 SPDX-FileCopyrightText: 2013-2024 Laurent Montel <montel@kde.org> 0007 0008 SPDX-License-Identifier: GPL-2.0-or-later 0009 */ 0010 0011 #include "knotes_part.h" 0012 #include "akonadi/notesakonaditreemodel.h" 0013 #include "akonadi/noteschangerecorder.h" 0014 #include "alarms/notealarmdialog.h" 0015 #include "attributes/notealarmattribute.h" 0016 #include "attributes/notedisplayattribute.h" 0017 #include "attributes/notelockattribute.h" 0018 #include "attributes/showfoldernotesattribute.h" 0019 #include "configdialog/knoteconfigdialog.h" 0020 #include "configdialog/knotesimpleconfigdialog.h" 0021 #include "finddialog/knotefinddialog.h" 0022 #include "job/createnewnotejob.h" 0023 #include "knoteedit.h" 0024 #include "knotes_kontact_plugin_debug.h" 0025 #include "knotesadaptor.h" 0026 #include "knoteseditdialog.h" 0027 #include "knotesglobalconfig.h" 0028 #include "knotesiconview.h" 0029 #include "knotesselectdeletenotesdialog.h" 0030 #include "knoteswidget.h" 0031 #include "notesharedglobalconfig.h" 0032 #include "noteutils.h" 0033 #include "print/knoteprinter.h" 0034 #include "print/knoteprintobject.h" 0035 #include "print/knoteprintselectthemedialog.h" 0036 #include "resources/localresourcecreator.h" 0037 #include "utils/knoteutils.h" 0038 0039 #include <Akonadi/ChangeRecorder> 0040 #include <Akonadi/ControlGui> 0041 #include <Akonadi/ETMViewStateSaver> 0042 #include <Akonadi/ItemDeleteJob> 0043 #include <Akonadi/ItemFetchJob> 0044 #include <Akonadi/ItemFetchScope> 0045 #include <Akonadi/ItemModifyJob> 0046 #include <Akonadi/Session> 0047 0048 #include <KMime/KMimeMessage> 0049 0050 #include <KActionCollection> 0051 #include <KCheckableProxyModel> 0052 #include <KDNSSD/PublicService> 0053 #include <KLocalizedString> 0054 #include <KMessageBox> 0055 0056 #include <QApplication> 0057 #include <QCheckBox> 0058 #include <QClipboard> 0059 #include <QFileDialog> 0060 #include <QInputDialog> 0061 #include <QItemSelectionModel> 0062 #include <QMenu> 0063 0064 KNotesPart::KNotesPart(QObject *parent) 0065 : KParts::Part(parent) 0066 , mNotesWidget(nullptr) 0067 , mPublisher(nullptr) 0068 , mNotePrintPreview(nullptr) 0069 , mNoteTreeModel(nullptr) 0070 { 0071 (void)new KNotesAdaptor(this); 0072 QDBusConnection::sessionBus().registerObject(QStringLiteral("/KNotes"), this); 0073 0074 setComponentName(QStringLiteral("knotes"), i18n("KNotes")); 0075 0076 Akonadi::ControlGui::widgetNeedsAkonadi(widget()); 0077 0078 if (KNotesGlobalConfig::self()->autoCreateResourceOnStart()) { 0079 auto creator = new NoteShared::LocalResourceCreator(this); 0080 creator->createIfMissing(); 0081 } 0082 0083 // create the actions 0084 mNewNote = new QAction(QIcon::fromTheme(QStringLiteral("knotes")), i18nc("@action:inmenu create new popup note", "&New"), this); 0085 actionCollection()->addAction(QStringLiteral("file_new"), mNewNote); 0086 connect(mNewNote, &QAction::triggered, this, [this]() { 0087 newNote(); 0088 }); 0089 actionCollection()->setDefaultShortcut(mNewNote, QKeySequence(Qt::CTRL | Qt::Key_N)); 0090 // mNewNote->setHelpText( 0091 // i18nc( "@info:status", "Create a new popup note" ) ); 0092 mNewNote->setWhatsThis(i18nc("@info:whatsthis", "You will be presented with a dialog where you can add a new popup note.")); 0093 0094 mNoteEdit = new QAction(QIcon::fromTheme(QStringLiteral("document-edit")), i18nc("@action:inmenu", "Edit..."), this); 0095 actionCollection()->addAction(QStringLiteral("edit_note"), mNoteEdit); 0096 connect(mNoteEdit, &QAction::triggered, this, [this]() { 0097 editNote(); 0098 }); 0099 // mNoteEdit->setHelpText( 0100 // i18nc( "@info:status", "Edit popup note" ) ); 0101 mNoteEdit->setWhatsThis(i18nc("@info:whatsthis", "You will be presented with a dialog where you can modify an existing popup note.")); 0102 0103 mNoteRename = new QAction(QIcon::fromTheme(QStringLiteral("edit-rename")), i18nc("@action:inmenu", "Rename..."), this); 0104 actionCollection()->setDefaultShortcut(mNoteRename, QKeySequence(Qt::Key_F2)); 0105 actionCollection()->addAction(QStringLiteral("edit_rename"), mNoteRename); 0106 connect(mNoteRename, &QAction::triggered, this, &KNotesPart::renameNote); 0107 // mNoteRename->setHelpText( 0108 // i18nc( "@info:status", "Rename popup note" ) ); 0109 mNoteRename->setWhatsThis(i18nc("@info:whatsthis", "You will be presented with a dialog where you can rename an existing popup note.")); 0110 0111 mNoteDelete = new QAction(QIcon::fromTheme(QStringLiteral("edit-delete")), i18nc("@action:inmenu", "Delete"), this); 0112 actionCollection()->addAction(QStringLiteral("edit_delete"), mNoteDelete); 0113 connect(mNoteDelete, &QAction::triggered, this, &KNotesPart::killSelectedNotes); 0114 actionCollection()->setDefaultShortcut(mNoteDelete, QKeySequence(Qt::Key_Delete)); 0115 // mNoteDelete->setHelpText( 0116 // i18nc( "@info:status", "Delete popup note" ) ); 0117 mNoteDelete->setWhatsThis(i18nc("@info:whatsthis", 0118 "You will be prompted if you really want to permanently remove " 0119 "the selected popup note.")); 0120 0121 mNotePrint = new QAction(QIcon::fromTheme(QStringLiteral("document-print")), i18nc("@action:inmenu", "Print Selected Notes..."), this); 0122 actionCollection()->addAction(QStringLiteral("print_note"), mNotePrint); 0123 connect(mNotePrint, &QAction::triggered, this, &KNotesPart::slotPrintSelectedNotes); 0124 // mNotePrint->setHelpText( 0125 // i18nc( "@info:status", "Print popup note" ) ); 0126 mNotePrint->setWhatsThis(i18nc("@info:whatsthis", "You will be prompted to print the selected popup note.")); 0127 0128 mNotePrintPreview = 0129 new QAction(QIcon::fromTheme(QStringLiteral("document-print-preview")), i18nc("@action:inmenu", "Print Preview Selected Notes..."), this); 0130 actionCollection()->addAction(QStringLiteral("print_preview_note"), mNotePrintPreview); 0131 0132 connect(mNotePrintPreview, &QAction::triggered, this, &KNotesPart::slotPrintPreviewSelectedNotes); 0133 0134 mNoteConfigure = new QAction(QIcon::fromTheme(QStringLiteral("configure")), i18n("Note settings..."), this); 0135 actionCollection()->addAction(QStringLiteral("configure_note"), mNoteConfigure); 0136 connect(mNoteConfigure, &QAction::triggered, this, &KNotesPart::slotNotePreferences); 0137 0138 auto act = new QAction(QIcon::fromTheme(QStringLiteral("configure")), i18n("Preferences KNotes..."), this); 0139 actionCollection()->addAction(QStringLiteral("knotes_configure"), act); 0140 connect(act, &QAction::triggered, this, &KNotesPart::slotPreferences); 0141 0142 mNoteSendMail = new QAction(QIcon::fromTheme(QStringLiteral("mail-send")), i18n("Mail..."), this); 0143 actionCollection()->addAction(QStringLiteral("mail_note"), mNoteSendMail); 0144 connect(mNoteSendMail, &QAction::triggered, this, &KNotesPart::slotMail); 0145 0146 mNoteSendNetwork = new QAction(QIcon::fromTheme(QStringLiteral("network-wired")), i18n("Send..."), this); 0147 actionCollection()->addAction(QStringLiteral("send_note"), mNoteSendNetwork); 0148 connect(mNoteSendNetwork, &QAction::triggered, this, &KNotesPart::slotSendToNetwork); 0149 0150 mNoteSetAlarm = new QAction(QIcon::fromTheme(QStringLiteral("knotes_alarm")), i18n("Set Alarm..."), this); 0151 actionCollection()->addAction(QStringLiteral("set_alarm"), mNoteSetAlarm); 0152 connect(mNoteSetAlarm, &QAction::triggered, this, &KNotesPart::slotSetAlarm); 0153 0154 act = new QAction(QIcon::fromTheme(QStringLiteral("edit-paste")), i18n("New Note From Clipboard"), this); 0155 actionCollection()->addAction(QStringLiteral("new_note_clipboard"), act); 0156 connect(act, &QAction::triggered, this, &KNotesPart::slotNewNoteFromClipboard); 0157 0158 act = new QAction(QIcon::fromTheme(QStringLiteral("document-open")), i18n("New Note From Text File..."), this); 0159 actionCollection()->addAction(QStringLiteral("new_note_from_text_file"), act); 0160 connect(act, &QAction::triggered, this, &KNotesPart::slotNewNoteFromTextFile); 0161 0162 mSaveAs = new QAction(QIcon::fromTheme(QStringLiteral("document-save-as")), i18n("Save As..."), this); 0163 actionCollection()->addAction(QStringLiteral("save_note"), mSaveAs); 0164 connect(mSaveAs, &QAction::triggered, this, &KNotesPart::slotSaveAs); 0165 0166 mReadOnly = new KToggleAction(QIcon::fromTheme(QStringLiteral("object-locked")), i18n("Lock"), this); 0167 actionCollection()->addAction(QStringLiteral("lock_note"), mReadOnly); 0168 connect(mReadOnly, &KToggleAction::triggered, this, &KNotesPart::slotUpdateReadOnly); 0169 mReadOnly->setCheckedState(KGuiItem(i18n("Unlock"), QStringLiteral("object-unlocked"))); 0170 0171 KStandardAction::find(this, &KNotesPart::slotOpenFindDialog, actionCollection()); 0172 0173 auto session = new Akonadi::Session("KNotes Session", this); 0174 mNoteRecorder = new NoteShared::NotesChangeRecorder(this); 0175 mNoteRecorder->changeRecorder()->setSession(session); 0176 mNoteTreeModel = new NoteShared::NotesAkonadiTreeModel(mNoteRecorder->changeRecorder(), this); 0177 0178 connect(mNoteTreeModel, &NoteShared::NotesAkonadiTreeModel::rowsInserted, this, &KNotesPart::slotRowInserted); 0179 0180 connect(mNoteRecorder->changeRecorder(), &Akonadi::Monitor::itemChanged, this, &KNotesPart::slotItemChanged); 0181 0182 connect(mNoteRecorder->changeRecorder(), &Akonadi::Monitor::itemRemoved, this, &KNotesPart::slotItemRemoved); 0183 0184 connect(mNoteRecorder->changeRecorder(), 0185 qOverload<const Akonadi::Collection &, const QSet<QByteArray> &>(&Akonadi::ChangeRecorder::collectionChanged), 0186 this, 0187 &KNotesPart::slotCollectionChanged); 0188 0189 mSelectionModel = new QItemSelectionModel(mNoteTreeModel); 0190 mModelProxy = new KCheckableProxyModel(this); 0191 mModelProxy->setSelectionModel(mSelectionModel); 0192 mModelProxy->setSourceModel(mNoteTreeModel); 0193 0194 KSharedConfigPtr _config = KSharedConfig::openConfig(QStringLiteral("kcmknotessummaryrc")); 0195 0196 mModelState = new KViewStateMaintainer<Akonadi::ETMViewStateSaver>(_config->group(QStringLiteral("CheckState")), this); 0197 mModelState->setSelectionModel(mSelectionModel); 0198 0199 mNotesWidget = new KNotesWidget(this, widget()); 0200 0201 mQuickSearchAction = new QAction(i18n("Set Focus to Quick Search"), this); 0202 // If change shortcut change in quicksearchwidget->lineedit->setPlaceholderText 0203 actionCollection()->setDefaultShortcut(mQuickSearchAction, QKeySequence(Qt::ALT | Qt::Key_Q)); 0204 actionCollection()->addAction(QStringLiteral("focus_to_quickseach"), mQuickSearchAction); 0205 connect(mQuickSearchAction, &QAction::triggered, mNotesWidget, &KNotesWidget::slotFocusQuickSearch); 0206 0207 connect(mNotesWidget->notesView(), &QListWidget::itemDoubleClicked, this, qOverload<QListWidgetItem *>(&KNotesPart::editNote)); 0208 0209 connect(mNotesWidget->notesView(), &QListWidget::itemSelectionChanged, this, &KNotesPart::slotOnCurrentChanged); 0210 slotOnCurrentChanged(); 0211 0212 setWidget(mNotesWidget); 0213 setXMLFile(QStringLiteral("knotes_part.rc")); 0214 updateNetworkListener(); 0215 updateClickMessage(); 0216 } 0217 0218 KNotesPart::~KNotesPart() 0219 { 0220 delete mPublisher; 0221 mPublisher = nullptr; 0222 } 0223 0224 void KNotesPart::updateClickMessage() 0225 { 0226 mNotesWidget->updateClickMessage(mQuickSearchAction->shortcut().toString()); 0227 } 0228 0229 void KNotesPart::slotItemRemoved(const Akonadi::Item &item) 0230 { 0231 KNotesIconViewItem *iconView = mNotesWidget->notesView()->iconView(item.id()); 0232 delete iconView; 0233 } 0234 0235 void KNotesPart::slotRowInserted(const QModelIndex &parent, int start, int end) 0236 { 0237 for (int i = start; i <= end; ++i) { 0238 if (mNoteTreeModel->hasIndex(i, 0, parent)) { 0239 const QModelIndex child = mNoteTreeModel->index(i, 0, parent); 0240 auto parentCollection = mNoteTreeModel->data(child, Akonadi::EntityTreeModel::ParentCollectionRole).value<Akonadi::Collection>(); 0241 if (parentCollection.hasAttribute<NoteShared::ShowFolderNotesAttribute>()) { 0242 auto item = mNoteTreeModel->data(child, Akonadi::EntityTreeModel::ItemRole).value<Akonadi::Item>(); 0243 if (!item.hasPayload<KMime::Message::Ptr>()) { 0244 continue; 0245 } 0246 mNotesWidget->notesView()->addNote(item); 0247 } 0248 } 0249 } 0250 } 0251 0252 QStringList KNotesPart::notesList() const 0253 { 0254 QStringList notes; 0255 QHashIterator<Akonadi::Item::Id, KNotesIconViewItem *> i(mNotesWidget->notesView()->noteList()); 0256 while (i.hasNext()) { 0257 i.next(); 0258 notes.append(QString::number(i.key())); 0259 } 0260 return notes; 0261 } 0262 0263 void KNotesPart::slotPrintPreviewSelectedNotes() 0264 { 0265 printSelectedNotes(true); 0266 } 0267 0268 void KNotesPart::slotPrintSelectedNotes() 0269 { 0270 printSelectedNotes(false); 0271 } 0272 0273 void KNotesPart::printSelectedNotes(bool preview) 0274 { 0275 const QList<QListWidgetItem *> lst = mNotesWidget->notesView()->selectedItems(); 0276 if (lst.isEmpty()) { 0277 KMessageBox::information(mNotesWidget, 0278 i18nc("@info", "To print notes, first select the notes to print from the list."), 0279 i18nc("@title:window", "Print Popup Notes")); 0280 return; 0281 } 0282 KNotesGlobalConfig *globalConfig = KNotesGlobalConfig::self(); 0283 QString printingTheme = globalConfig->theme(); 0284 if (printingTheme.isEmpty()) { 0285 QPointer<KNotePrintSelectThemeDialog> dlg = new KNotePrintSelectThemeDialog(widget()); 0286 if (dlg->exec()) { 0287 printingTheme = dlg->selectedTheme(); 0288 } 0289 delete dlg; 0290 } 0291 if (!printingTheme.isEmpty()) { 0292 QList<KNotePrintObject *> listPrintObj; 0293 listPrintObj.reserve(lst.count()); 0294 for (QListWidgetItem *item : lst) { 0295 listPrintObj.append(new KNotePrintObject(static_cast<KNotesIconViewItem *>(item)->item())); 0296 } 0297 KNotePrinter printer; 0298 printer.printNotes(listPrintObj, printingTheme, preview); 0299 qDeleteAll(listPrintObj); 0300 } 0301 } 0302 0303 // public KNotes D-Bus interface implementation 0304 0305 void KNotesPart::newNote(const QString &name, const QString &text) 0306 { 0307 auto job = new NoteShared::CreateNewNoteJob(this, widget()); 0308 job->setRichText(KNotesGlobalConfig::self()->richText()); 0309 job->setNote(name, text); 0310 job->start(); 0311 } 0312 0313 void KNotesPart::slotNoteCreationFinished(KJob *job) 0314 { 0315 if (job->error()) { 0316 qCWarning(KNOTES_KONTACT_PLUGIN_LOG) << job->errorString(); 0317 NoteShared::NoteSharedGlobalConfig::self()->setDefaultFolder(-1); 0318 NoteShared::NoteSharedGlobalConfig::self()->save(); 0319 KMessageBox::error(widget(), i18n("Note was not created."), i18n("Create new note")); 0320 return; 0321 } 0322 } 0323 0324 void KNotesPart::newNoteFromClipboard(const QString &name) 0325 { 0326 const QString &text = QApplication::clipboard()->text(); 0327 newNote(name, text); 0328 } 0329 0330 void KNotesPart::killNote(Akonadi::Item::Id id) 0331 { 0332 killNote(id, false); 0333 } 0334 0335 void KNotesPart::killNote(Akonadi::Item::Id id, bool force) 0336 { 0337 KNotesIconViewItem *note = mNotesWidget->notesView()->iconView(id); 0338 if (note 0339 && ((!force 0340 && KMessageBox::warningContinueCancelList(mNotesWidget, 0341 i18nc("@info", "Do you really want to delete this note?"), 0342 QStringList(note->realName()), 0343 i18nc("@title:window", "Confirm Delete"), 0344 KStandardGuiItem::del()) 0345 == KMessageBox::Continue) 0346 || force)) { 0347 auto job = new Akonadi::ItemDeleteJob(note->item()); 0348 connect(job, &Akonadi::ItemDeleteJob::result, this, &KNotesPart::slotDeleteNotesFinished); 0349 } 0350 } 0351 0352 QString KNotesPart::name(Akonadi::Item::Id id) const 0353 { 0354 KNotesIconViewItem *note = mNotesWidget->notesView()->iconView(id); 0355 if (note) { 0356 return note->text(); 0357 } else { 0358 return {}; 0359 } 0360 } 0361 0362 QString KNotesPart::text(Akonadi::Item::Id id) const 0363 { 0364 // TODO return plaintext ? 0365 KNotesIconViewItem *note = mNotesWidget->notesView()->iconView(id); 0366 if (note) { 0367 return note->description(); 0368 } else { 0369 return {}; 0370 } 0371 } 0372 0373 void KNotesPart::setName(Akonadi::Item::Id id, const QString &newName) 0374 { 0375 KNotesIconViewItem *note = mNotesWidget->notesView()->iconView(id); 0376 if (note) { 0377 note->setIconText(newName); 0378 } 0379 } 0380 0381 void KNotesPart::setText(Akonadi::Item::Id id, const QString &newText) 0382 { 0383 KNotesIconViewItem *note = mNotesWidget->notesView()->iconView(id); 0384 if (note) { 0385 note->setDescription(newText); 0386 } 0387 } 0388 0389 QMap<QString, QString> KNotesPart::notes() const 0390 { 0391 QMap<QString, QString> notes; 0392 QHashIterator<Akonadi::Item::Id, KNotesIconViewItem *> i(mNotesWidget->notesView()->noteList()); 0393 while (i.hasNext()) { 0394 i.next(); 0395 notes.insert(QString::number(i.key()), i.value()->realName()); 0396 } 0397 return notes; 0398 } 0399 0400 // private stuff 0401 0402 void KNotesPart::killSelectedNotes() 0403 { 0404 const QList<QListWidgetItem *> lst = mNotesWidget->notesView()->selectedItems(); 0405 if (lst.isEmpty()) { 0406 return; 0407 } 0408 QList<KNotesIconViewItem *> items; 0409 items.reserve(lst.count()); 0410 for (QListWidgetItem *item : lst) { 0411 auto knivi = static_cast<KNotesIconViewItem *>(item); 0412 items.append(knivi); 0413 } 0414 0415 if (items.isEmpty()) { 0416 return; 0417 } 0418 QPointer<KNotesSelectDeleteNotesDialog> dlg = new KNotesSelectDeleteNotesDialog(items, widget()); 0419 if (dlg->exec()) { 0420 Akonadi::Item::List lstItem; 0421 QListIterator<KNotesIconViewItem *> kniviIt(items); 0422 while (kniviIt.hasNext()) { 0423 KNotesIconViewItem *iconViewIcon = kniviIt.next(); 0424 if (!iconViewIcon->readOnly()) { 0425 lstItem.append(iconViewIcon->item()); 0426 } 0427 } 0428 if (!lstItem.isEmpty()) { 0429 auto job = new Akonadi::ItemDeleteJob(lstItem); 0430 connect(job, &Akonadi::ItemDeleteJob::result, this, &KNotesPart::slotDeleteNotesFinished); 0431 } 0432 } 0433 delete dlg; 0434 } 0435 0436 void KNotesPart::slotDeleteNotesFinished(KJob *job) 0437 { 0438 if (job->error()) { 0439 qCDebug(KNOTES_KONTACT_PLUGIN_LOG) << " problem during delete job note:" << job->errorString(); 0440 } 0441 } 0442 0443 void KNotesPart::popupRMB(QListWidgetItem *item, const QPoint &pos, const QPoint &globalPos) 0444 { 0445 Q_UNUSED(item) 0446 0447 auto contextMenu = new QMenu(widget()); 0448 if (mNotesWidget->notesView()->itemAt(pos)) { 0449 contextMenu->addAction(mNewNote); 0450 const bool uniqueNoteSelected = (mNotesWidget->notesView()->selectedItems().count() == 1); 0451 const bool readOnly = uniqueNoteSelected ? static_cast<KNotesIconViewItem *>(mNotesWidget->notesView()->selectedItems().at(0))->readOnly() : false; 0452 0453 if (uniqueNoteSelected) { 0454 if (!readOnly) { 0455 contextMenu->addSeparator(); 0456 contextMenu->addAction(mNoteSetAlarm); 0457 } 0458 contextMenu->addSeparator(); 0459 contextMenu->addAction(mSaveAs); 0460 contextMenu->addSeparator(); 0461 contextMenu->addAction(mNoteEdit); 0462 contextMenu->addAction(mReadOnly); 0463 if (!readOnly) { 0464 contextMenu->addAction(mNoteRename); 0465 } 0466 contextMenu->addSeparator(); 0467 contextMenu->addAction(mNoteSendMail); 0468 contextMenu->addSeparator(); 0469 contextMenu->addAction(mNoteSendNetwork); 0470 } 0471 contextMenu->addSeparator(); 0472 contextMenu->addAction(mNotePrint); 0473 contextMenu->addAction(mNotePrintPreview); 0474 0475 if (!readOnly) { 0476 contextMenu->addSeparator(); 0477 contextMenu->addAction(mNoteConfigure); 0478 contextMenu->addSeparator(); 0479 contextMenu->addAction(mNoteDelete); 0480 } 0481 } else { 0482 contextMenu->addAction(mNewNote); 0483 } 0484 0485 contextMenu->exec(globalPos); 0486 delete contextMenu; 0487 } 0488 0489 void KNotesPart::editNote(Akonadi::Item::Id id) 0490 { 0491 KNotesIconViewItem *knoteItem = mNotesWidget->notesView()->iconView(id); 0492 if (knoteItem) { 0493 mNotesWidget->notesView()->setCurrentItem(knoteItem); 0494 editNote(knoteItem); 0495 } 0496 } 0497 0498 void KNotesPart::editNote(QListWidgetItem *item) 0499 { 0500 auto knotesItem = static_cast<KNotesIconViewItem *>(item); 0501 QPointer<KNoteEditDialog> dlg = new KNoteEditDialog(knotesItem->readOnly(), widget()); 0502 dlg->setTitle(knotesItem->realName()); 0503 dlg->setText(knotesItem->description()); 0504 dlg->setColor(knotesItem->textForegroundColor(), knotesItem->textBackgroundColor()); 0505 0506 dlg->setAcceptRichText(knotesItem->isRichText()); 0507 dlg->setTabSize(knotesItem->tabSize()); 0508 dlg->setAutoIndentMode(knotesItem->autoIndent()); 0509 dlg->setTextFont(knotesItem->textFont()); 0510 0511 dlg->setCursorPositionFromStart(knotesItem->cursorPositionFromStart()); 0512 0513 dlg->noteEdit()->setFocus(); 0514 if (dlg->exec() == QDialog::Accepted) { 0515 knotesItem->setChangeIconTextAndDescription(dlg->title(), dlg->text(), dlg->cursorPositionFromStart()); 0516 } 0517 delete dlg; 0518 } 0519 0520 void KNotesPart::editNote() 0521 { 0522 QListWidgetItem *item = mNotesWidget->notesView()->currentItem(); 0523 if (item) { 0524 editNote(item); 0525 } 0526 } 0527 0528 void KNotesPart::renameNote() 0529 { 0530 auto knoteItem = static_cast<KNotesIconViewItem *>(mNotesWidget->notesView()->currentItem()); 0531 0532 const QString oldName = knoteItem->realName(); 0533 bool ok = false; 0534 const QString newName = 0535 QInputDialog::getText(mNotesWidget, i18nc("@title:window", "Rename Popup Note"), i18nc("@label:textbox", "New Name:"), QLineEdit::Normal, oldName, &ok); 0536 if (ok && (newName != oldName)) { 0537 knoteItem->setIconText(newName); 0538 } 0539 } 0540 0541 void KNotesPart::slotOnCurrentChanged() 0542 { 0543 const bool uniqueNoteSelected = (mNotesWidget->notesView()->selectedItems().count() == 1); 0544 const bool enabled(mNotesWidget->notesView()->currentItem()); 0545 mNoteRename->setEnabled(enabled && uniqueNoteSelected); 0546 mNoteEdit->setEnabled(enabled && uniqueNoteSelected); 0547 mNoteConfigure->setEnabled(uniqueNoteSelected); 0548 mNoteSendMail->setEnabled(uniqueNoteSelected); 0549 mNoteSendNetwork->setEnabled(uniqueNoteSelected); 0550 mNoteSetAlarm->setEnabled(uniqueNoteSelected); 0551 mSaveAs->setEnabled(uniqueNoteSelected); 0552 mReadOnly->setEnabled(uniqueNoteSelected); 0553 if (uniqueNoteSelected) { 0554 const bool readOnly = static_cast<KNotesIconViewItem *>(mNotesWidget->notesView()->selectedItems().at(0))->readOnly(); 0555 mReadOnly->setChecked(readOnly); 0556 mNoteEdit->setText(readOnly ? i18n("Show Note...") : i18nc("@action:inmenu", "Edit...")); 0557 } else { 0558 mNoteEdit->setText(i18nc("@action:inmenu", "Edit...")); 0559 } 0560 } 0561 0562 void KNotesPart::slotNotePreferences() 0563 { 0564 if (!mNotesWidget->notesView()->currentItem()) { 0565 return; 0566 } 0567 auto knoteItem = static_cast<KNotesIconViewItem *>(mNotesWidget->notesView()->currentItem()); 0568 QPointer<KNoteSimpleConfigDialog> dialog = new KNoteSimpleConfigDialog(knoteItem->realName(), widget()); 0569 Akonadi::Item item = knoteItem->item(); 0570 dialog->load(item, knoteItem->isRichText()); 0571 if (dialog->exec()) { 0572 KNoteUtils::updateConfiguration(); 0573 bool isRichText; 0574 dialog->save(item, isRichText); 0575 auto message = item.payload<KMime::Message::Ptr>(); 0576 message->contentType(true)->setMimeType(isRichText ? "text/html" : "text/plain"); 0577 message->assemble(); 0578 auto job = new Akonadi::ItemModifyJob(item); 0579 connect(job, &Akonadi::ItemModifyJob::result, this, &KNotesPart::slotNoteSaved); 0580 } 0581 delete dialog; 0582 } 0583 0584 void KNotesPart::slotPreferences() 0585 { 0586 // create a new preferences dialog... 0587 auto dialog = new KNoteConfigDialog(i18n("Settings"), widget()); 0588 connect(dialog, qOverload<>(&KCMultiDialog::configCommitted), this, &KNotesPart::slotConfigUpdated); 0589 dialog->show(); 0590 } 0591 0592 void KNotesPart::updateConfig() 0593 { 0594 updateNetworkListener(); 0595 } 0596 0597 void KNotesPart::slotConfigUpdated() 0598 { 0599 updateNetworkListener(); 0600 } 0601 0602 void KNotesPart::slotMail() 0603 { 0604 if (!mNotesWidget->notesView()->currentItem()) { 0605 return; 0606 } 0607 auto knoteItem = static_cast<KNotesIconViewItem *>(mNotesWidget->notesView()->currentItem()); 0608 NoteShared::NoteUtils noteUtils; 0609 noteUtils.sendToMail(widget(), knoteItem->realName(), knoteItem->description()); 0610 } 0611 0612 void KNotesPart::slotSendToNetwork() 0613 { 0614 if (!mNotesWidget->notesView()->currentItem()) { 0615 return; 0616 } 0617 auto knoteItem = static_cast<KNotesIconViewItem *>(mNotesWidget->notesView()->currentItem()); 0618 NoteShared::NoteUtils noteUtils; 0619 noteUtils.sendToNetwork(widget(), knoteItem->realName(), knoteItem->description()); 0620 } 0621 0622 void KNotesPart::updateNetworkListener() 0623 { 0624 delete mPublisher; 0625 mPublisher = nullptr; 0626 0627 if (NoteShared::NoteSharedGlobalConfig::receiveNotes()) { 0628 // create the socket and start listening for connections 0629 mPublisher = new KDNSSD::PublicService(NoteShared::NoteSharedGlobalConfig::senderID(), 0630 QStringLiteral("_knotes._tcp"), 0631 NoteShared::NoteSharedGlobalConfig::port()); 0632 mPublisher->publishAsync(); 0633 } 0634 } 0635 0636 void KNotesPart::slotSetAlarm() 0637 { 0638 if (!mNotesWidget->notesView()->currentItem()) { 0639 return; 0640 } 0641 auto knoteItem = static_cast<KNotesIconViewItem *>(mNotesWidget->notesView()->currentItem()); 0642 QPointer<NoteShared::NoteAlarmDialog> dlg = new NoteShared::NoteAlarmDialog(knoteItem->realName(), widget()); 0643 Akonadi::Item item = knoteItem->item(); 0644 if (item.hasAttribute<NoteShared::NoteAlarmAttribute>()) { 0645 dlg->setAlarm(item.attribute<NoteShared::NoteAlarmAttribute>()->dateTime()); 0646 } 0647 if (dlg->exec()) { 0648 bool needToModify = true; 0649 QDateTime dateTime = dlg->alarm(); 0650 if (dateTime.isValid()) { 0651 auto attribute = item.attribute<NoteShared::NoteAlarmAttribute>(Akonadi::Item::AddIfMissing); 0652 attribute->setDateTime(dateTime); 0653 } else { 0654 if (item.hasAttribute<NoteShared::NoteAlarmAttribute>()) { 0655 item.removeAttribute<NoteShared::NoteAlarmAttribute>(); 0656 } else { 0657 needToModify = false; 0658 } 0659 } 0660 if (needToModify) { 0661 auto job = new Akonadi::ItemModifyJob(item); 0662 connect(job, &Akonadi::ItemModifyJob::result, this, &KNotesPart::slotNoteSaved); 0663 } 0664 } 0665 delete dlg; 0666 } 0667 0668 void KNotesPart::slotNoteSaved(KJob *job) 0669 { 0670 qCDebug(KNOTES_KONTACT_PLUGIN_LOG) << " void KNote::slotNoteSaved(KJob *job)"; 0671 if (job->error()) { 0672 qCDebug(KNOTES_KONTACT_PLUGIN_LOG) << " problem during save note:" << job->errorString(); 0673 } 0674 } 0675 0676 void KNotesPart::slotNewNoteFromClipboard() 0677 { 0678 const QString &text = QApplication::clipboard()->text(); 0679 newNote(QString(), text); 0680 } 0681 0682 void KNotesPart::slotSaveAs() 0683 { 0684 if (!mNotesWidget->notesView()->currentItem()) { 0685 return; 0686 } 0687 auto knoteItem = static_cast<KNotesIconViewItem *>(mNotesWidget->notesView()->currentItem()); 0688 0689 QStringList filters; 0690 if (knoteItem->isRichText()) { 0691 filters << i18n("Rich text (*.html)"); 0692 } 0693 filters << i18n("Plain text (*.txt)"); 0694 0695 QString format; 0696 const QString fileName = QFileDialog::getSaveFileName(widget(), i18n("Save As"), QString(), filters.join(QLatin1StringView(";;")), &format); 0697 if (fileName.isEmpty()) { 0698 return; 0699 } 0700 const bool htmlFormatAndSaveAsHtml = (knoteItem->isRichText() && !format.contains(QLatin1StringView("(*.txt)"))); 0701 0702 QFile file(fileName); 0703 if (file.exists() 0704 && KMessageBox::warningContinueCancel(widget(), 0705 i18n("<qt>A file named <b>%1</b> already exists.<br />" 0706 "Are you sure you want to overwrite it?</qt>", 0707 QFileInfo(file).fileName())) 0708 != KMessageBox::Continue) { 0709 return; 0710 } 0711 0712 if (file.open(QIODevice::WriteOnly)) { 0713 QTextStream stream(&file); 0714 QTextDocument doc; 0715 doc.setHtml(knoteItem->description()); 0716 if (htmlFormatAndSaveAsHtml) { 0717 QString htmlStr = doc.toHtml(); 0718 htmlStr.replace(QStringLiteral("meta name=\"qrichtext\" content=\"1\""), 0719 QStringLiteral("meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"")); 0720 stream << htmlStr; 0721 } else { 0722 stream << knoteItem->realName() + QLatin1Char('\n'); 0723 stream << doc.toPlainText(); 0724 } 0725 } 0726 } 0727 0728 void KNotesPart::slotUpdateReadOnly() 0729 { 0730 QListWidgetItem *item = mNotesWidget->notesView()->currentItem(); 0731 if (!item) { 0732 return; 0733 } 0734 auto knoteItem = static_cast<KNotesIconViewItem *>(item); 0735 0736 const bool readOnly = mReadOnly->isChecked(); 0737 0738 mNoteEdit->setText(readOnly ? i18n("Show Note...") : i18nc("@action:inmenu", "Edit...")); 0739 knoteItem->setReadOnly(readOnly); 0740 } 0741 0742 void KNotesPart::slotItemChanged(const Akonadi::Item &item, const QSet<QByteArray> &set) 0743 { 0744 KNotesIconViewItem *knoteItem = mNotesWidget->notesView()->iconView(item.id()); 0745 if (knoteItem) { 0746 knoteItem->setChangeItem(item, set); 0747 } 0748 } 0749 0750 void KNotesPart::slotOpenFindDialog() 0751 { 0752 if (!mNoteFindDialog) { 0753 mNoteFindDialog = new KNoteFindDialog(widget()); 0754 connect(mNoteFindDialog.data(), &KNoteFindDialog::noteSelected, this, &KNotesPart::slotSelectNote); 0755 } 0756 QHash<Akonadi::Item::Id, Akonadi::Item> lst; 0757 QHashIterator<Akonadi::Item::Id, KNotesIconViewItem *> i(mNotesWidget->notesView()->noteList()); 0758 while (i.hasNext()) { 0759 i.next(); 0760 lst.insert(i.key(), i.value()->item()); 0761 } 0762 mNoteFindDialog->setExistingNotes(lst); 0763 mNoteFindDialog->show(); 0764 } 0765 0766 void KNotesPart::slotSelectNote(Akonadi::Item::Id id) 0767 { 0768 editNote(id); 0769 } 0770 0771 void KNotesPart::slotCollectionChanged(const Akonadi::Collection &col, const QSet<QByteArray> &set) 0772 { 0773 if (set.contains("showfoldernotesattribute")) { 0774 // qCDebug(KNOTES_KONTACT_PLUGIN_LOG)<<" collection Changed "<<set<<" col "<<col; 0775 if (col.hasAttribute<NoteShared::ShowFolderNotesAttribute>()) { 0776 fetchNotesFromCollection(col); 0777 } else { 0778 QHashIterator<Akonadi::Item::Id, KNotesIconViewItem *> i(mNotesWidget->notesView()->noteList()); 0779 while (i.hasNext()) { 0780 i.next(); 0781 Akonadi::Item item = i.value()->item(); 0782 if (item.parentCollection() == col) { 0783 slotItemRemoved(item); 0784 } 0785 } 0786 } 0787 } 0788 } 0789 0790 void KNotesPart::fetchNotesFromCollection(const Akonadi::Collection &col) 0791 { 0792 auto job = new Akonadi::ItemFetchJob(col); 0793 job->fetchScope().fetchFullPayload(true); 0794 job->fetchScope().fetchAttribute<NoteShared::NoteLockAttribute>(); 0795 job->fetchScope().fetchAttribute<NoteShared::NoteDisplayAttribute>(); 0796 job->fetchScope().fetchAttribute<NoteShared::NoteAlarmAttribute>(); 0797 job->fetchScope().setAncestorRetrieval(Akonadi::ItemFetchScope::Parent); 0798 connect(job, &Akonadi::ItemFetchJob::result, this, &KNotesPart::slotItemFetchFinished); 0799 } 0800 0801 void KNotesPart::slotItemFetchFinished(KJob *job) 0802 { 0803 if (job->error()) { 0804 qCDebug(KNOTES_KONTACT_PLUGIN_LOG) << "Error occurred during item fetch:" << job->errorString(); 0805 return; 0806 } 0807 0808 auto fetchJob = qobject_cast<Akonadi::ItemFetchJob *>(job); 0809 0810 const Akonadi::Item::List items = fetchJob->items(); 0811 for (const Akonadi::Item &item : items) { 0812 if (!item.hasPayload<KMime::Message::Ptr>()) { 0813 continue; 0814 } 0815 mNotesWidget->notesView()->addNote(item); 0816 } 0817 } 0818 0819 void KNotesPart::slotNewNoteFromTextFile() 0820 { 0821 QString text; 0822 const QString filename = QFileDialog::getOpenFileName(widget(), i18n("Select Text File"), QString(), QStringLiteral("%1 (*.txt)").arg(i18n("Text File"))); 0823 if (!filename.isEmpty()) { 0824 QFile f(filename); 0825 if (f.open(QIODevice::ReadOnly | QIODevice::Text)) { 0826 text = QString::fromUtf8(f.readAll()); 0827 } else { 0828 KMessageBox::error(widget(), i18n("Error during open text file: %1", f.errorString()), i18n("Open Text File")); 0829 return; 0830 } 0831 newNote(i18n("Note from file '%1'", filename), text); 0832 } 0833 } 0834 0835 #include "moc_knotes_part.cpp"