00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <qclipboard.h>
00022 #include <qptrlist.h>
00023 #include <qtooltip.h>
00024
00025 #include <kdebug.h>
00026 #include <kaction.h>
00027 #include <kxmlguifactory.h>
00028 #include <kxmlguibuilder.h>
00029 #include <ksystemtray.h>
00030 #include <klocale.h>
00031 #include <kiconeffect.h>
00032 #include <kstandarddirs.h>
00033 #include <kpopupmenu.h>
00034 #include <khelpmenu.h>
00035 #include <kfind.h>
00036 #include <kfinddialog.h>
00037 #include <kkeydialog.h>
00038 #include <kglobalaccel.h>
00039 #include <ksimpleconfig.h>
00040 #include <kwin.h>
00041 #include <kextsock.h>
00042
00043 #include <libkcal/journal.h>
00044 #include <libkcal/calendarlocal.h>
00045
00046 #include "knotesapp.h"
00047 #include "knote.h"
00048 #include "knotesalarm.h"
00049 #include "knoteconfigdlg.h"
00050 #include "knotesglobalconfig.h"
00051 #include "knoteslegacy.h"
00052 #include "knotesnetrecv.h"
00053
00054 #include "knotes/resourcemanager.h"
00055
00056
00057 class KNotesKeyDialog : public KDialogBase
00058 {
00059 public:
00060 KNotesKeyDialog( KGlobalAccel *globals, QWidget *parent, const char* name = 0 )
00061 : KDialogBase( parent, name, true, i18n("Configure Shortcuts"), Default|Ok|Cancel, Ok )
00062 {
00063 m_keyChooser = new KKeyChooser( globals, this );
00064 setMainWidget( m_keyChooser );
00065 connect( this, SIGNAL(defaultClicked()), m_keyChooser, SLOT(allDefault()) );
00066 }
00067
00068 void insert( KActionCollection *actions )
00069 {
00070 m_keyChooser->insert( actions, i18n("Note Actions") );
00071 }
00072
00073 void configure()
00074 {
00075 if ( exec() == Accepted )
00076 m_keyChooser->save();
00077 }
00078
00079 private:
00080 KKeyChooser *m_keyChooser;
00081 };
00082
00083
00084 int KNotesApp::KNoteActionList::compareItems( QPtrCollection::Item s1, QPtrCollection::Item s2 )
00085 {
00086 if ( ((KAction*)s1)->text() == ((KAction*)s2)->text() )
00087 return 0;
00088 return ( ((KAction*)s1)->text() < ((KAction*)s2)->text() ? -1 : 1 );
00089 }
00090
00091
00092 KNotesApp::KNotesApp()
00093 : DCOPObject("KNotesIface"), QLabel( 0, 0, WType_TopLevel ),
00094 m_alarm( 0 ), m_listener( 0 ), m_find( 0 ), m_findPos( 0 )
00095 {
00096 connect( kapp, SIGNAL(lastWindowClosed()), kapp, SLOT(quit()) );
00097
00098 m_noteList.setAutoDelete( true );
00099 m_noteActions.setAutoDelete( true );
00100
00101
00102 KWin::setSystemTrayWindowFor( winId(), qt_xrootwin() );
00103 QToolTip::add( this, i18n( "KNotes: Sticky notes for KDE" ) );
00104 setBackgroundMode( X11ParentRelative );
00105 setPixmap( KSystemTray::loadIcon( "knotes" ) );
00106
00107
00108 KNote::setStyle( KNotesGlobalConfig::style() );
00109
00110
00111 new KAction( i18n("New Note"), "filenew", 0,
00112 this, SLOT(newNote()), actionCollection(), "new_note" );
00113 new KAction( i18n("New Note From Clipboard"), "editpaste", 0,
00114 this, SLOT(newNoteFromClipboard()), actionCollection(), "new_note_clipboard" );
00115 new KAction( i18n("Show All Notes"), "knotes", 0,
00116 this, SLOT(showAllNotes()), actionCollection(), "show_all_notes" );
00117 new KAction( i18n("Hide All Notes"), "fileclose", 0,
00118 this, SLOT(hideAllNotes()), actionCollection(), "hide_all_notes" );
00119 new KHelpMenu( this, kapp->aboutData(), false, actionCollection() );
00120
00121 KStdAction::find( this, SLOT(slotOpenFindDialog()), actionCollection() );
00122 KStdAction::preferences( this, SLOT(slotPreferences()), actionCollection() );
00123 KStdAction::keyBindings( this, SLOT(slotConfigureAccels()), actionCollection() );
00124
00125 KStdAction::quit( this, SLOT(slotQuit()), actionCollection() )->setShortcut( 0 );
00126
00127 setXMLFile( instance()->instanceName() + "appui.rc" );
00128
00129 m_guiBuilder = new KXMLGUIBuilder( this );
00130 m_guiFactory = new KXMLGUIFactory( m_guiBuilder, this );
00131 m_guiFactory->addClient( this );
00132
00133 m_context_menu = static_cast<KPopupMenu*>(m_guiFactory->container( "knotes_context", this ));
00134 m_note_menu = static_cast<KPopupMenu*>(m_guiFactory->container( "notes_menu", this ));
00135
00136
00137 QString xmlFileName = instance()->instanceName() + "ui.rc";
00138 QString filter = QString::fromLatin1( instance()->instanceName() + '/' ) + xmlFileName;
00139 QStringList fileList = instance()->dirs()->findAllResources( "data", filter ) +
00140 instance()->dirs()->findAllResources( "data", xmlFileName );
00141
00142 QString doc;
00143 KXMLGUIClient::findMostRecentXMLFile( fileList, doc );
00144 m_noteGUI.setContent( doc );
00145
00146
00147 m_globalAccel = new KGlobalAccel( this, "global accel" );
00148 m_globalAccel->insert( "global_new_note", i18n("New Note"), "",
00149 ALT+SHIFT+Key_N, ALT+SHIFT+Key_N ,
00150 this, SLOT(newNote()), true, true );
00151 m_globalAccel->insert( "global_new_note_clipboard", i18n("New Note From Clipboard"), "",
00152 ALT+SHIFT+Key_C, ALT+SHIFT+Key_C,
00153 this, SLOT(newNoteFromClipboard()), true, true );
00154 m_globalAccel->insert( "global_hide_all_notes", i18n("Hide All Notes"), "",
00155 ALT+SHIFT+Key_H, ALT+SHIFT+Key_H ,
00156 this, SLOT(hideAllNotes()), true, true );
00157 m_globalAccel->insert( "global_show_all_notes", i18n("Show All Notes"), "",
00158 ALT+SHIFT+Key_S, ALT+SHIFT+Key_S,
00159 this, SLOT(showAllNotes()), true, true );
00160
00161 m_globalAccel->readSettings();
00162
00163 KConfig *config = KGlobal::config();
00164 config->setGroup( "Global Keybindings" );
00165 m_globalAccel->setEnabled( config->readBoolEntry( "Enabled", true ) );
00166
00167 updateGlobalAccels();
00168
00169
00170 KNotesLegacy::cleanUp();
00171
00172
00173 m_manager = new KNotesResourceManager();
00174 connect( m_manager, SIGNAL(sigRegisteredNote( KCal::Journal * )),
00175 this, SLOT(createNote( KCal::Journal * )) );
00176 connect( m_manager, SIGNAL(sigDeregisteredNote( KCal::Journal * )),
00177 this, SLOT(killNote( KCal::Journal * )) );
00178
00179
00180 m_manager->load();
00181
00182
00183 KCal::CalendarLocal calendar( QString::fromLatin1( "UTC" ) );
00184 if ( KNotesLegacy::convert( &calendar ) )
00185 {
00186 KCal::Journal::List notes = calendar.journals();
00187 KCal::Journal::List::ConstIterator it;
00188 for ( it = notes.begin(); it != notes.end(); ++it )
00189 m_manager->addNewNote( *it );
00190
00191 m_manager->save();
00192 }
00193
00194
00195
00196 m_alarm = new KNotesAlarm( m_manager, this );
00197
00198
00199 m_listener = new KExtendedSocket();
00200 m_listener->setSocketFlags( KExtendedSocket::passiveSocket | KExtendedSocket::inetSocket );
00201 connect( m_listener, SIGNAL(readyAccept()), SLOT(acceptConnection()) );
00202 updateNetworkListener();
00203
00204 if ( m_noteList.count() == 0 && !kapp->isRestored() )
00205 newNote();
00206
00207 updateNoteActions();
00208 }
00209
00210 KNotesApp::~KNotesApp()
00211 {
00212 saveNotes();
00213
00214 blockSignals( true );
00215 m_noteList.clear();
00216 blockSignals( false );
00217
00218 delete m_listener;
00219 delete m_manager;
00220 delete m_guiBuilder;
00221 }
00222
00223 bool KNotesApp::commitData( QSessionManager& )
00224 {
00225 saveConfigs();
00226 return true;
00227 }
00228
00229
00230
00231 QString KNotesApp::newNote( const QString& name, const QString& text )
00232 {
00233
00234 KCal::Journal *journal = new KCal::Journal();
00235
00236
00237 if ( !name.isEmpty() )
00238 journal->setSummary( name );
00239 else
00240 journal->setSummary( KGlobal::locale()->formatDateTime( QDateTime::currentDateTime() ) );
00241
00242
00243 journal->setDescription( text );
00244
00245 m_manager->addNewNote( journal );
00246
00247 showNote( journal->uid() );
00248
00249 return journal->uid();
00250 }
00251
00252 QString KNotesApp::newNoteFromClipboard( const QString& name )
00253 {
00254 const QString& text = KApplication::clipboard()->text();
00255 return newNote( name, text );
00256 }
00257
00258 void KNotesApp::hideAllNotes() const
00259 {
00260 QDictIterator<KNote> it( m_noteList );
00261 for ( ; *it; ++it )
00262 (*it)->close();
00263 }
00264
00265 void KNotesApp::showAllNotes() const
00266 {
00267 QDictIterator<KNote> it( m_noteList );
00268 for ( ; *it; ++it )
00269 {
00270 (*it)->show();
00271 (*it)->setFocus();
00272 }
00273 }
00274
00275 void KNotesApp::showNote( const QString& id ) const
00276 {
00277 KNote* note = m_noteList[id];
00278 if ( note )
00279 showNote( note );
00280 else
00281 kdWarning(5500) << "showNote: no note with id: " << id << endl;
00282 }
00283
00284 void KNotesApp::hideNote( const QString& id ) const
00285 {
00286 KNote* note = m_noteList[id];
00287 if ( note )
00288 note->hide();
00289 else
00290 kdWarning(5500) << "hideNote: no note with id: " << id << endl;
00291 }
00292
00293 void KNotesApp::killNote( const QString& id, bool force )
00294 {
00295 KNote* note = m_noteList[id];
00296 if ( note )
00297 note->slotKill( force );
00298 else
00299 kdWarning(5500) << "killNote: no note with id: " << id << endl;
00300 }
00301
00302
00303 void KNotesApp::killNote( const QString& id )
00304 {
00305 killNote( id, false );
00306 }
00307
00308 QMap<QString,QString> KNotesApp::notes() const
00309 {
00310 QMap<QString,QString> notes;
00311 QDictIterator<KNote> it( m_noteList );
00312
00313 for ( ; it.current(); ++it )
00314 notes.insert( it.current()->noteId(), it.current()->name() );
00315
00316 return notes;
00317 }
00318
00319 QString KNotesApp::name( const QString& id ) const
00320 {
00321 KNote* note = m_noteList[id];
00322 if ( note )
00323 return note->name();
00324 else
00325 return QString::null;
00326 }
00327
00328 QString KNotesApp::text( const QString& id ) const
00329 {
00330 KNote* note = m_noteList[id];
00331 if ( note )
00332 return note->text();
00333 else
00334 return QString::null;
00335 }
00336
00337 void KNotesApp::setName( const QString& id, const QString& newName )
00338 {
00339 KNote* note = m_noteList[id];
00340 if ( note )
00341 note->setName( newName );
00342 else
00343 kdWarning(5500) << "setName: no note with id: " << id << endl;
00344 }
00345
00346 void KNotesApp::setText( const QString& id, const QString& newText )
00347 {
00348 KNote* note = m_noteList[id];
00349 if ( note )
00350 note->setText( newText );
00351 else
00352 kdWarning(5500) << "setText: no note with id: " << id << endl;
00353 }
00354
00355 void KNotesApp::sync( const QString& app )
00356 {
00357 QDictIterator<KNote> it( m_noteList );
00358
00359 for ( ; it.current(); ++it )
00360 it.current()->sync( app );
00361 }
00362
00363 bool KNotesApp::isNew( const QString& app, const QString& id ) const
00364 {
00365 KNote* note = m_noteList[id];
00366 if ( note )
00367 return note->isNew( app );
00368 else
00369 return false;
00370 }
00371
00372 bool KNotesApp::isModified( const QString& app, const QString& id ) const
00373 {
00374 KNote* note = m_noteList[id];
00375 if ( note )
00376 return note->isModified( app );
00377 else
00378 return false;
00379 }
00380
00381
00382
00383
00384 void KNotesApp::mousePressEvent( QMouseEvent* e )
00385 {
00386 if ( !rect().contains( e->pos() ) )
00387 return;
00388
00389 switch ( e->button() )
00390 {
00391 case LeftButton:
00392 if ( m_noteList.count() == 1 )
00393 {
00394 QDictIterator<KNote> it( m_noteList );
00395 showNote( it.toFirst() );
00396 }
00397 else if ( m_note_menu->count() > 0 )
00398 m_note_menu->popup( e->globalPos() );
00399 break;
00400 case MidButton:
00401 newNote();
00402 break;
00403 case RightButton:
00404 m_context_menu->popup( e->globalPos() );
00405 default: break;
00406 }
00407 }
00408
00409
00410
00411 void KNotesApp::slotShowNote()
00412 {
00413
00414 showNote( QString::fromUtf8( sender()->name() ) );
00415 }
00416
00417 void KNotesApp::slotWalkThroughNotes()
00418 {
00419
00420 QDictIterator<KNote> it( m_noteList );
00421 KNote *first = it.toFirst();
00422 for ( ; *it; ++it )
00423 if ( (*it)->hasFocus() )
00424 {
00425 if ( ++it )
00426 showNote( *it );
00427 else
00428 showNote( first );
00429 break;
00430 }
00431 }
00432
00433 void KNotesApp::slotOpenFindDialog()
00434 {
00435 KFindDialog findDia( this, "find_dialog" );
00436 findDia.setHasSelection( false );
00437 findDia.setHasCursor( false );
00438 findDia.setSupportsBackwardsFind( false );
00439
00440 if ( findDia.exec() != QDialog::Accepted )
00441 return;
00442
00443 delete m_findPos;
00444 m_findPos = new QDictIterator<KNote>( m_noteList );
00445
00446
00447 delete m_find;
00448 m_find = new KFind( findDia.pattern(), findDia.options(), this );
00449
00450 slotFindNext();
00451 }
00452
00453 void KNotesApp::slotFindNext()
00454 {
00455 if ( **m_findPos )
00456 {
00457 KNote *note = **m_findPos;
00458 ++*m_findPos;
00459 note->find( m_find->pattern(), m_find->options() );
00460 }
00461 else
00462 {
00463 m_find->displayFinalDialog();
00464 delete m_find;
00465 m_find = 0;
00466 delete m_findPos;
00467 m_findPos = 0;
00468 }
00469 }
00470
00471 void KNotesApp::slotPreferences()
00472 {
00473
00474 if ( KNoteConfigDlg::showDialog( "KNotes Default Settings" ) )
00475 return;
00476
00477
00478 KNoteConfigDlg *dialog = new KNoteConfigDlg( 0, i18n("Settings"), this,
00479 "KNotes Settings" );
00480 connect( dialog, SIGNAL(settingsChanged()), this, SLOT(updateNetworkListener()) );
00481 connect( dialog, SIGNAL(settingsChanged()), this, SLOT(updateStyle()) );
00482 dialog->show();
00483 }
00484
00485 void KNotesApp::slotConfigureAccels()
00486 {
00487 KNotesKeyDialog keys( m_globalAccel, this );
00488 QDictIterator<KNote> notes( m_noteList );
00489 if ( !m_noteList.isEmpty() )
00490 keys.insert( (*notes)->actionCollection() );
00491 keys.configure();
00492
00493 m_globalAccel->writeSettings();
00494 updateGlobalAccels();
00495
00496
00497 m_noteGUI.setContent(
00498 KXMLGUIFactory::readConfigFile( instance()->instanceName() + "ui.rc", instance() )
00499 );
00500
00501 if ( m_noteList.isEmpty() )
00502 return;
00503
00504 notes.toFirst();
00505 QValueList<KAction *> list = (*notes)->actionCollection()->actions();
00506 for ( QValueList<KAction *>::iterator it = list.begin(); it != list.end(); ++it )
00507 {
00508 notes.toFirst();
00509 for ( ++notes; *notes; ++notes )
00510 {
00511 KAction *toChange = (*notes)->actionCollection()->action( (*it)->name() );
00512 if ( toChange->shortcut() != (*it)->shortcut() )
00513 toChange->setShortcut( (*it)->shortcut() );
00514 }
00515 }
00516 }
00517
00518 void KNotesApp::slotNoteKilled( KCal::Journal *journal )
00519 {
00520 m_manager->deleteNote( journal );
00521 saveNotes();
00522 }
00523
00524 void KNotesApp::slotQuit()
00525 {
00526 QDictIterator<KNote> it( m_noteList );
00527
00528 for ( ; *it; ++it )
00529 if ( (*it)->isModified() )
00530 (*it)->saveData();
00531
00532 saveConfigs();
00533 kapp->quit();
00534 }
00535
00536
00537
00538
00539 void KNotesApp::showNote( KNote* note ) const
00540 {
00541 note->show();
00542 KWin::setCurrentDesktop( KWin::windowInfo( note->winId() ).desktop() );
00543 KWin::forceActiveWindow( note->winId() );
00544 note->setFocus();
00545 }
00546
00547 void KNotesApp::createNote( KCal::Journal *journal )
00548 {
00549 KNote *newNote = new KNote( m_noteGUI, journal, 0, journal->uid().utf8() );
00550 m_noteList.insert( newNote->noteId(), newNote );
00551
00552 connect( newNote, SIGNAL(sigRequestNewNote()), SLOT(newNote()) );
00553 connect( newNote, SIGNAL(sigShowNextNote()), SLOT(slotWalkThroughNotes()) );
00554 connect( newNote, SIGNAL(sigKillNote( KCal::Journal* )),
00555 SLOT(slotNoteKilled( KCal::Journal* )) );
00556 connect( newNote, SIGNAL(sigNameChanged()), SLOT(updateNoteActions()) );
00557 connect( newNote, SIGNAL(sigDataChanged()), SLOT(saveNotes()) );
00558 connect( newNote, SIGNAL(sigColorChanged()), SLOT(updateNoteActions()) );
00559 connect( newNote, SIGNAL(sigFindFinished()), SLOT(slotFindNext()) );
00560
00561
00562 if ( m_alarm )
00563 updateNoteActions();
00564 }
00565
00566 void KNotesApp::killNote( KCal::Journal *journal )
00567 {
00568
00569 m_noteList.remove( journal->uid() );
00570 updateNoteActions();
00571 }
00572
00573 void KNotesApp::acceptConnection()
00574 {
00575
00576 KExtendedSocket *s;
00577 m_listener->accept( s );
00578 KNotesNetworkReceiver *recv = new KNotesNetworkReceiver( s );
00579 connect( recv, SIGNAL(sigNoteReceived( const QString &, const QString & )),
00580 this, SLOT(newNote( const QString &, const QString & )) );
00581 }
00582
00583 void KNotesApp::saveNotes()
00584 {
00585 KNotesGlobalConfig::writeConfig();
00586 m_manager->save();
00587 }
00588
00589 void KNotesApp::saveConfigs()
00590 {
00591 QDictIterator<KNote> it( m_noteList );
00592 for ( ; it.current(); ++it )
00593 it.current()->saveConfig();
00594 }
00595
00596 void KNotesApp::updateNoteActions()
00597 {
00598 unplugActionList( "notes" );
00599 m_noteActions.clear();
00600
00601 for ( QDictIterator<KNote> it( m_noteList ); it.current(); ++it )
00602 {
00603 KAction *action = new KAction( it.current()->name().replace("&", "&&"),
00604 KShortcut(), this, SLOT(slotShowNote()),
00605 (QObject *)0,
00606 it.current()->noteId().utf8() );
00607 KIconEffect effect;
00608 QPixmap icon = effect.apply( kapp->miniIcon(), KIconEffect::Colorize, 1,
00609 it.current()->paletteBackgroundColor(), false );
00610 action->setIconSet( icon );
00611 m_noteActions.append( action );
00612 }
00613
00614 m_noteActions.sort();
00615
00616 if ( m_noteActions.isEmpty() )
00617 {
00618 KAction *action = new KAction( i18n("No Notes") );
00619 m_noteActions.append( action );
00620 }
00621
00622 plugActionList( "notes", m_noteActions );
00623 }
00624
00625 void KNotesApp::updateGlobalAccels()
00626 {
00627 if ( m_globalAccel->isEnabled() )
00628 {
00629 KAction *action = actionCollection()->action( "new_note" );
00630 if ( action )
00631 action->setShortcut( m_globalAccel->shortcut( "global_new_note" ) );
00632 action = actionCollection()->action( "new_note_clipboard" );
00633 if ( action )
00634 action->setShortcut( m_globalAccel->shortcut( "global_new_note_clipboard" ) );
00635 action = actionCollection()->action( "hide_all_notes" );
00636 if ( action )
00637 action->setShortcut( m_globalAccel->shortcut( "global_hide_all_notes" ) );
00638 action = actionCollection()->action( "show_all_notes" );
00639 if ( action )
00640 action->setShortcut( m_globalAccel->shortcut( "global_show_all_notes" ) );
00641
00642 m_globalAccel->updateConnections();
00643 }
00644 else
00645 {
00646 KAction *action = actionCollection()->action( "new_note" );
00647 if ( action )
00648 action->setShortcut( 0 );
00649 action = actionCollection()->action( "new_note_clipboard" );
00650 if ( action )
00651 action->setShortcut( 0 );
00652 action = actionCollection()->action( "hide_all_notes" );
00653 if ( action )
00654 action->setShortcut( 0 );
00655 action = actionCollection()->action( "show_all_notes" );
00656 if ( action )
00657 action->setShortcut( 0 );
00658 }
00659 }
00660
00661 void KNotesApp::updateNetworkListener()
00662 {
00663 m_listener->reset();
00664
00665 if ( KNotesGlobalConfig::receiveNotes() )
00666 {
00667 m_listener->setPort( KNotesGlobalConfig::port() );
00668 m_listener->listen();
00669 }
00670 }
00671
00672 void KNotesApp::updateStyle()
00673 {
00674 KNote::setStyle( KNotesGlobalConfig::style() );
00675
00676 QDictIterator<KNote> it( m_noteList );
00677 for ( ; it.current(); ++it )
00678 QApplication::postEvent( *it, new QEvent( QEvent::LayoutHint ) );
00679 }
00680
00681 #include "knotesapp.moc"