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