26 #include "noteshared/akonadi/notesakonaditreemodel.h"
27 #include "noteshared/akonadi/noteschangerecorder.h"
28 #include "noteshared/attributes/notelockattribute.h"
29 #include "noteshared/attributes/notedisplayattribute.h"
30 #include "noteshared/attributes/notealarmattribute.h"
31 #include "noteshared/attributes/showfoldernotesattribute.h"
32 #include "noteshared/resources/localresourcecreator.h"
33 #include "noteshared/job/createnewnotejob.h"
34 #include "noteshared/attributes/notealarmattribute.h"
35 #include "noteshared/attributes/notedisplayattribute.h"
36 #include "noteshared/attributes/notelockattribute.h"
39 #include "dialog/selectednotefolderdialog.h"
41 #include "notesharedglobalconfig.h"
43 #include "knotesadaptor.h"
47 #include "knotesglobalconfig.h"
53 #include <KMime/KMimeMessage>
54 #include <Akonadi/Notes/NoteUtils>
55 #include <Akonadi/ItemCreateJob>
56 #include <Akonadi/ItemDeleteJob>
57 #include <Akonadi/EntityDisplayAttribute>
58 #include <Akonadi/ItemFetchJob>
59 #include <Akonadi/ItemFetchScope>
61 #include <akonadi/control.h>
62 #include <Akonadi/ChangeRecorder>
63 #include <Akonadi/Collection>
64 #include <Akonadi/EntityTreeModel>
65 #include <Akonadi/Session>
66 #include <KMime/KMimeMessage>
67 #include <KActionCollection>
69 #include <KMessageBox>
72 #include <khelpmenu.h>
74 #include <kiconeffect.h>
77 #include <kshortcutsdialog.h>
78 #include <ksocketfactory.h>
79 #include <kstandardaction.h>
80 #include <kstandarddirs.h>
81 #include <ksystemtrayicon.h>
82 #include <kwindowsystem.h>
83 #include <kxmlguibuilder.h>
84 #include <kxmlguifactory.h>
85 #include <KFileDialog>
87 #include <kiconloader.h>
91 #include <QDBusConnection>
94 #include <dnssd/publicservice.h>
107 Akonadi::Control::widgetNeedsAkonadi(
this);
110 if (!qgetenv(
"KDEPIM_BALOO_DEBUG").isEmpty()) {
114 if (KNotesGlobalConfig::self()->autoCreateResourceOnStart()) {
115 NoteShared::LocalResourceCreator *creator =
new NoteShared::LocalResourceCreator(
this );
116 creator->createIfMissing();
119 new KNotesAdaptor(
this );
121 kapp->setQuitOnLastWindowClosed(
false );
123 KAction *action =
new KAction( KIcon(
QLatin1String(
"document-new") ),
124 i18n(
"New Note" ),
this );
125 actionCollection()->addAction(
QLatin1String(
"new_note"), action );
126 action->setGlobalShortcut( KShortcut( Qt::ALT + Qt::SHIFT + Qt::Key_N ));
130 i18n(
"New Note From Clipboard" ),
this );
131 actionCollection()->addAction(
QLatin1String(
"new_note_clipboard"), action );
132 action->setGlobalShortcut( KShortcut( Qt::ALT + Qt::SHIFT + Qt::Key_C ));
135 action =
new KAction( KIcon(
QLatin1String(
"document-open") ),
136 i18n(
"New Note From Text File..." ),
this );
137 actionCollection()->addAction(
QLatin1String(
"new_note_from_text_file"), action );
138 connect( action, SIGNAL(triggered()), SLOT(newNoteFromTextFile()) );
141 action =
new KAction( KIcon(
QLatin1String(
"knotes") ), i18n(
"Show All Notes" ),
this );
142 actionCollection()->addAction(
QLatin1String(
"show_all_notes"), action );
143 action->setGlobalShortcut( KShortcut( Qt::ALT + Qt::SHIFT + Qt::Key_S ));
146 action =
new KAction( KIcon(
QLatin1String(
"window-close") ),
147 i18n(
"Hide All Notes" ),
this );
148 actionCollection()->addAction(
QLatin1String(
"hide_all_notes"), action );
149 action->setGlobalShortcut( KShortcut( Qt::ALT + Qt::SHIFT + Qt::Key_H ));
152 action =
new KAction( KIcon(
QLatin1String(
"document-print") ),
153 i18nc(
"@action:inmenu",
"Print Selected Notes..." ),
this );
154 actionCollection()->addAction(
QLatin1String(
"print_selected_notes"), action );
155 connect( action, SIGNAL(triggered()), SLOT(slotPrintSelectedNotes()) );
158 i18nc(
"@action:inmenu",
"Delete Selected Notes..." ),
this );
159 actionCollection()->addAction(
QLatin1String(
"delete_selected_notes"), action );
160 connect( action, SIGNAL(triggered()), SLOT(slotDeleteSelectedNotes()) );
162 KAction *act = KStandardAction::find(
this, SLOT(slotOpenFindDialog()), actionCollection());
168 new KHelpMenu(
this, KGlobal::mainComponent().aboutData(),
false,
169 actionCollection() );
171 KStandardAction::preferences(
this, SLOT(slotPreferences()),
172 actionCollection() );
173 KStandardAction::keyBindings(
this, SLOT(slotConfigureAccels()),
174 actionCollection() );
176 KStandardAction::quit(
this, SLOT(slotQuit()),
177 actionCollection() )->setShortcut( 0 );
178 setXMLFile( componentData().componentName() +
QLatin1String(
"appui.rc") );
180 m_guiBuilder =
new KXMLGUIBuilder(
this );
181 m_guiFactory =
new KXMLGUIFactory( m_guiBuilder,
this );
182 m_guiFactory->addClient(
this );
184 KMenu *contextMenu =
static_cast<KMenu *
>( m_guiFactory->container(
187 m_noteMenu =
static_cast<KMenu *
>( m_guiFactory->container(
194 componentData().dirs()->findAllResources(
"data", filter ) +
195 componentData().dirs()->findAllResources(
"data", xmlFileName );
198 KXMLGUIClient::findMostRecentXMLFile( fileList, doc );
202 updateNetworkListener();
204 Akonadi::Session *session =
new Akonadi::Session(
"KNotes Session",
this );
205 mNoteRecorder =
new NoteShared::NotesChangeRecorder(
this);
206 mNoteRecorder->changeRecorder()->setSession(session);
208 connect( mTray, SIGNAL(activateRequested(
bool,
QPoint)),
this, SLOT(slotActivateRequested(
bool,
QPoint)) );
209 connect( mTray, SIGNAL(secondaryActivateRequested(
QPoint)),
this, SLOT(slotSecondaryActivateRequested(
QPoint)) );
211 mTray->setContextMenu( contextMenu );
212 mNoteTreeModel =
new NoteShared::NotesAkonadiTreeModel(mNoteRecorder->changeRecorder(),
this);
218 connect( mNoteRecorder->changeRecorder(), SIGNAL(itemRemoved(Akonadi::Item)), SLOT(slotItemRemoved(Akonadi::Item)) );
225 qDeleteAll( m_noteActions );
226 m_noteActions.
clear();
236 void KNotesApp::slotDeleteSelectedNotes()
239 Akonadi::Item::List lst;
241 while (i.hasNext()) {
243 Akonadi::Item item = i.value()->item();
244 if (!item.hasAttribute<NoteShared::NoteLockAttribute>()) {
250 Akonadi::Item::List lst = dlg->selectedNotes();
251 if (!lst.isEmpty()) {
252 Akonadi::ItemDeleteJob *deleteJob =
new Akonadi::ItemDeleteJob(lst,
this);
253 connect( deleteJob, SIGNAL(result(KJob*)), SLOT(slotNoteDeleteFinished(KJob*)) );
259 void KNotesApp::slotItemRemoved(
const Akonadi::Item &item)
261 qDebug()<<
" note removed"<<item.id();
263 delete mNotes.
find(item.id()).value();
270 void KNotesApp::slotItemChanged(
const Akonadi::Item &item,
const QSet<QByteArray> &set)
273 qDebug()<<
" item changed "<<item.id()<<
" info "<<set.
toList();
279 void KNotesApp::slotRowInserted(
const QModelIndex &parent,
int start,
int end)
281 bool needUpdate =
false;
282 for (
int i = start; i <= end; ++i) {
283 if ( mNoteTreeModel->hasIndex( i, 0, parent ) ) {
286 mNoteTreeModel->data( child, Akonadi::EntityTreeModel::ItemRole ).value<Akonadi::Item>();
287 Akonadi::Collection parentCollection = mNoteTreeModel->data( child, Akonadi::EntityTreeModel::ParentCollectionRole).value<Akonadi::Collection>();
288 if (parentCollection.hasAttribute<NoteShared::ShowFolderNotesAttribute>()) {
300 void KNotesApp::createNote(
const Akonadi::Item &item)
302 if ( item.hasPayload<KMime::Message::Ptr>() ) {
304 KNote *note =
new KNote(m_noteGUI,item, mDebugBaloo);
305 mNotes.
insert(item.id(), note);
306 connect( note, SIGNAL(sigShowNextNote()),
307 SLOT(slotWalkThroughNotes()) ) ;
308 connect( note, SIGNAL(sigRequestNewNote()),
311 SLOT(updateNoteActions()) );
312 connect( note, SIGNAL(sigColorChanged()),
313 SLOT(updateNoteActions()) );
314 connect( note, SIGNAL(sigKillNote(Akonadi::Item::Id)),
315 SLOT(slotNoteKilled(Akonadi::Item::Id)) );
319 void KNotesApp::updateSystray()
321 if (KNotesGlobalConfig::self()->systemTrayShowNotes()) {
328 NoteShared::CreateNewNoteJob *job =
new NoteShared::CreateNewNoteJob(
this,
this);
329 job->setRichText(KNotesGlobalConfig::self()->richText());
330 job->setNote(name, text);
340 kWarning( 5500 ) <<
"hideNote: no note with id:" << id;
349 note->
toDesktop( KWindowSystem::currentDesktop() );
351 KWindowSystem::setCurrentDesktop(
352 KWindowSystem::windowInfo( note->
winId(), NET::WMDesktop ).desktop() );
354 KWindowSystem::forceActiveWindow( note->
winId() );
366 kWarning( 5500 ) <<
"hideNote: no note with id:" << id;
376 i.
value()->slotClose();
395 const QString &
text = KApplication::clipboard()->text();
399 void KNotesApp::newNoteFromTextFile()
402 const QString filename = KFileDialog::getOpenFileName( KUrl(),
405 i18n(
"Select Text File") );
408 if (f.open(QIODevice::ReadOnly|QIODevice::Text)) {
411 KMessageBox::error(
this, i18n(
"Error during open text file: %1", f.errorString()), i18n(
"Open Text File"));
414 newNote( i18n(
"Note from file '%1'",filename), text);
418 void KNotesApp::updateNetworkListener()
423 if ( NoteShared::NoteSharedGlobalConfig::receiveNotes() ) {
425 m_publisher=
new DNSSD::PublicService(NoteShared::NoteSharedGlobalConfig::senderID(),
QLatin1String(
"_knotes._tcp"), NoteShared::NoteSharedGlobalConfig::port());
426 m_publisher->publishAsync();
433 return mNotes.
value(
id)->name();
441 return mNotes.
value(
id)->text();
449 mNotes.
value(
id)->setName(newName);
451 kWarning( 5500 ) <<
"setName: no note with id:" << id;
458 mNotes.
value(
id)->setText( newText );
460 kWarning( 5500 ) <<
"setText: no note with id:" << id;
464 void KNotesApp::updateNoteActions()
467 m_noteActions.
clear();
470 while (i.hasNext()) {
472 KNote *note = i.value();
475 if ( realName.
count() > 50 ) {
478 replaceText = realName;
483 action->setToolTip(realName);
485 connect( action, SIGNAL(triggered(
bool)), SLOT(slotShowNote()) );
488 effect.apply( qApp->windowIcon().pixmap( IconSize( KIconLoader::Small ),
489 IconSize( KIconLoader::Small ) ),
490 KIconEffect::Colorize,
495 action->setIcon( icon );
496 m_noteActions.
append( action );
499 if ( m_noteActions.
isEmpty() ) {
500 actionCollection()->action(
QLatin1String(
"hide_all_notes") )->setEnabled(
false );
501 actionCollection()->action(
QLatin1String(
"show_all_notes") )->setEnabled(
false );
502 actionCollection()->action(
QLatin1String(
"print_selected_notes") )->setEnabled(
false );
503 actionCollection()->action(
QLatin1String(
"edit_find") )->setEnabled(
false );
504 KAction *action =
new KAction( i18n(
"No Notes" ),
this );
505 action->setEnabled(
false);
506 m_noteActions.
append( action );
509 actionCollection()->action(
QLatin1String(
"hide_all_notes") )->setEnabled(
true );
510 actionCollection()->action(
QLatin1String(
"show_all_notes") )->setEnabled(
true );
511 actionCollection()->action(
QLatin1String(
"print_selected_notes") )->setEnabled(
true );
512 actionCollection()->action(
QLatin1String(
"edit_find") )->setEnabled(
true );
518 void KNotesApp::slotActivateRequested(
bool,
const QPoint&)
520 if ( mNotes.
size() == 1 ) {
527 void KNotesApp::slotSecondaryActivateRequested(
const QPoint & )
532 void KNotesApp::slotShowNote()
538 void KNotesApp::slotWalkThroughNotes()
541 while (i.hasNext()) {
543 KNote *note = i.value();
545 if ( i.value() != mNotes.
end().value() ) {
555 void KNotesApp::slotPreferences()
559 connect( dialog, SIGNAL(configCommitted()),
this, SLOT(slotConfigUpdated()));
563 void KNotesApp::slotConfigUpdated()
565 updateNetworkListener();
571 void KNotesApp::slotCollectionChanged(
const Akonadi::Collection &col,
const QSet<QByteArray> &set)
573 if (set.
contains(
"showfoldernotesattribute")) {
575 if (col.hasAttribute<NoteShared::ShowFolderNotesAttribute>()) {
576 fetchNotesFromCollection(col);
579 while (i.hasNext()) {
581 Akonadi::Item item = i.value()->item();
582 if (item.parentCollection() == col) {
583 slotItemRemoved(item);
590 void KNotesApp::slotConfigureAccels()
594 KActionCollection *actionCollection = 0;
596 actionCollection = mNotes.
begin().value()->actionCollection();
597 keys->insert( actionCollection );
604 KXMLGUIFactory::readConfigFile( componentData().componentName() +
QLatin1String(
"ui.rc"),
609 if ( actionCollection ) {
611 while (i.hasNext()) {
613 foreach (
QAction *action, actionCollection->actions() ) {
614 QAction *toChange = i.value()->actionCollection()->action( action->
objectName() );
626 void KNotesApp::slotNoteKilled( Akonadi::Item::Id
id)
628 Akonadi::ItemDeleteJob *deleteJob =
new Akonadi::ItemDeleteJob(Akonadi::Item(
id),
this);
629 connect( deleteJob, SIGNAL(result(KJob*)), SLOT(slotNoteDeleteFinished(KJob*)) );
632 void KNotesApp::slotNoteDeleteFinished(KJob* job)
635 kWarning() << job->errorString();
640 void KNotesApp::slotPrintSelectedNotes()
643 dlg->setNotes(mNotes);
647 const QString selectedTheme = dlg->selectedTheme();
649 printer.
printNotes( lst, selectedTheme, dlg->preview() );
656 void KNotesApp::saveNotes(
bool force,
bool sync)
658 KNotesGlobalConfig::self()->writeConfig();
660 while (i.hasNext()) {
662 i.value()->saveNote(force, sync);
666 void KNotesApp::slotQuit()
668 saveNotes(
true,
true);
674 saveNotes(
true,
true);
678 void KNotesApp::slotSelectNote(Akonadi::Item::Id
id)
683 void KNotesApp::slotOpenFindDialog()
687 connect(mFindDialog, SIGNAL(noteSelected(Akonadi::Item::Id)),
this, SLOT(slotSelectNote(Akonadi::Item::Id)));
692 while (i.hasNext()) {
694 lst.
insert(i.key(), i.value()->item());
696 mFindDialog->setExistingNotes(lst);
700 void KNotesApp::fetchNotesFromCollection(
const Akonadi::Collection &col)
702 Akonadi::ItemFetchJob *job =
new Akonadi::ItemFetchJob( col );
703 job->fetchScope().fetchFullPayload(
true);
704 job->fetchScope().fetchAttribute<NoteShared::NoteLockAttribute>();
705 job->fetchScope().fetchAttribute<NoteShared::NoteDisplayAttribute>();
706 job->fetchScope().fetchAttribute<NoteShared::NoteAlarmAttribute>();
707 job->fetchScope().setAncestorRetrieval(Akonadi::ItemFetchScope::Parent);
708 connect( job, SIGNAL(result(KJob*)), SLOT(slotItemFetchFinished(KJob*)) );
711 void KNotesApp::slotItemFetchFinished(KJob *job)
713 if ( job->error() ) {
714 qDebug() <<
"Error occurred during item fetch:"<<job->errorString();
718 Akonadi::ItemFetchJob *fetchJob = qobject_cast<Akonadi::ItemFetchJob*>( job );
720 const Akonadi::Item::List items = fetchJob->items();
721 foreach (
const Akonadi::Item &item, items ) {
724 if (!items.isEmpty()) {
QObject * child(const char *objName, const char *inheritsClass, bool recursiveSearch) const
void showAllNotes() const
iterator insert(const Key &key, const T &value)
void printNotes(const QList< KNotePrintObject * > lst, const QString &themePath, bool preview)
void setText(const Akonadi::Item::Id &id, const QString &newText)
bool registerObject(const QString &path, QObject *object, QFlags< QDBusConnection::RegisterOption > options)
QList< QKeySequence > shortcuts() const
bool isDesktopAssigned() const
QDBusConnection sessionBus()
int count(const Key &key) const
QString text(const Akonadi::Item::Id &id) const
void hideAllNotes() const
const char * name() const
QString number(int n, int base)
void append(const T &value)
void setShortcuts(const QList< QKeySequence > &shortcuts)
QString fromUtf8(const char *str, int size)
QString objectName() const
void newNoteFromClipboard(const QString &name=QString())
void showNote(const Akonadi::Item::Id &id) const
int remove(const Key &key)
KNOTES_EXPORT void migrateToAkonadi()
void setChangeItem(const Akonadi::Item &item, const QSet< QByteArray > &set=QSet< QByteArray >())
const T value(const Key &key) const
iterator find(const Key &key)
bool contains(const T &value) const
bool commitData(QSessionManager &)
void hideNote(const Akonadi::Item::Id &id) const
QString & replace(int position, int n, QChar after)
Akonadi::Item::Id noteId() const
KNOTES_EXPORT void updateConfiguration()
void newNote(const QString &name=QString(), const QString &text=QString())
QString left(int n) const
QList< T > toList() const
bool contains(const Key &key) const
void toDesktop(int desktop)
void setName(const Akonadi::Item::Id &id, const QString &newName)
static bool qActionLessThan(const QAction *a1, const QAction *a2)
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void updateNumberOfNotes(int number)
bool setContent(const QByteArray &data, bool namespaceProcessing, QString *errorMsg, int *errorLine, int *errorColumn)