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
00024 #include <kdebug.h>
00025 #include <kaction.h>
00026 #include <kxmlguifactory.h>
00027 #include <ksystemtray.h>
00028 #include <klocale.h>
00029 #include <kiconloader.h>
00030 #include <kstandarddirs.h>
00031 #include <kpopupmenu.h>
00032 #include <khelpmenu.h>
00033 #include <kkeydialog.h>
00034 #include <kglobalaccel.h>
00035 #include <kmessagebox.h>
00036 #include <ksimpleconfig.h>
00037 #include <kio/netaccess.h>
00038 #include <kwin.h>
00039
00040 #include <libkcal/journal.h>
00041 #include <libkcal/icalformat.h>
00042
00043 #include "knotesapp.h"
00044 #include "knote.h"
00045 #include "knoteconfig.h"
00046 #include "knoteconfigdlg.h"
00047 #include "knoteslegacy.h"
00048
00049
00050 int KNotesApp::KNoteActionList::compareItems( QPtrCollection::Item s1, QPtrCollection::Item s2 )
00051 {
00052 if ( ((KAction*)s1)->text() == ((KAction*)s2)->text() )
00053 return 0;
00054 return ( ((KAction*)s1)->text() < ((KAction*)s2)->text() ? -1 : 1 );
00055 }
00056
00057
00058 KNotesApp::KNotesApp()
00059 : DCOPObject("KNotesIface"), QLabel( 0, 0, WType_TopLevel ),
00060 KXMLGUIBuilder( this ),
00061 m_defaultConfig( 0 )
00062 {
00063 connect( kapp, SIGNAL(lastWindowClosed()), kapp, SLOT(quit()) );
00064
00065 m_noteList.setAutoDelete( true );
00066 m_noteActions.setAutoDelete( true );
00067
00068
00069 KWin::setSystemTrayWindowFor( winId(), qt_xrootwin() );
00070 setBackgroundMode( X11ParentRelative );
00071 setPixmap( KSystemTray::loadIcon( "knotes" ) );
00072
00073
00074 new KAction( i18n("New Note"), "filenew", 0,
00075 this, SLOT(newNote()), actionCollection(), "new_note" );
00076 new KAction( i18n("New Note From Clipboard"), "editpaste", 0,
00077 this, SLOT(newNoteFromClipboard()), actionCollection(), "new_note_clipboard" );
00078 new KHelpMenu( this, kapp->aboutData(), false, actionCollection() );
00079
00080 KStdAction::preferences( this, SLOT(slotPreferences()), actionCollection() );
00081 KStdAction::keyBindings( this, SLOT(slotConfigureAccels()), actionCollection() );
00082 KStdAction::quit( this, SLOT(slotQuit()), actionCollection() )->setShortcut( 0 );
00083
00084 setXMLFile( QString( instance()->instanceName() + "ui.rc" ) );
00085
00086 m_guiFactory = new KXMLGUIFactory( this, this, "guifactory" );
00087 m_guiFactory->addClient( this );
00088
00089 m_context_menu = static_cast<KPopupMenu*>(m_guiFactory->container( "knotes_context", this ));
00090 m_note_menu = static_cast<KPopupMenu*>(m_guiFactory->container( "notes_menu", this ));
00091
00092
00093 m_globalAccel = new KGlobalAccel( this, "global accel" );
00094 m_globalAccel->insert( "global_new_note", i18n("New Note"), "",
00095 ALT+SHIFT+Key_N, ALT+SHIFT+Key_N ,
00096 this, SLOT(newNote()), true, true );
00097 m_globalAccel->insert( "global_new_note_clipboard", i18n("New Note From Clipboard"), "",
00098 ALT+SHIFT+Key_C, ALT+SHIFT+Key_C,
00099 this, SLOT(newNoteFromClipboard()), true, true );
00100
00101 m_globalAccel->readSettings();
00102
00103 KConfig *config = KGlobal::config();
00104 config->setGroup( "Global Keybindings" );
00105 m_globalAccel->setEnabled( config->readBoolEntry( "Enabled", true ) );
00106
00107 updateGlobalAccels();
00108
00109
00110 KNotesLegacy::cleanUp();
00111
00112
00113 m_calendar.load( KGlobal::dirs()->saveLocation( "appdata" ) + "notes.ics" );
00114
00115
00116
00117
00118
00119
00120
00121 if ( KNotesLegacy::convert( &m_calendar ) )
00122 saveNotes();
00123
00124
00125 KCal::Journal::List notes = m_calendar.journals();
00126 KCal::Journal::List::ConstIterator end = notes.end();
00127 for ( KCal::Journal::List::ConstIterator it = notes.begin(); it != end; ++it )
00128 createNote( *it );
00129
00130 kapp->installEventFilter( this );
00131
00132 if ( m_noteList.count() == 0 && !kapp->isRestored() )
00133 newNote();
00134 }
00135
00136 KNotesApp::~KNotesApp()
00137 {
00138 saveNotes();
00139
00140 blockSignals( true );
00141 m_noteList.clear();
00142 blockSignals( false );
00143
00144 delete m_defaultConfig;
00145 }
00146
00147 bool KNotesApp::commitData( QSessionManager& )
00148 {
00149 saveConfigs();
00150 return true;
00151 }
00152
00153
00154
00155 QString KNotesApp::newNote( const QString& name, const QString& text )
00156 {
00157
00158 KCal::Journal *note = new KCal::Journal();
00159
00160
00161 if ( !name.isEmpty() )
00162 note->setSummary( name );
00163 else
00164 note->setSummary( KGlobal::locale()->formatDateTime( QDateTime::currentDateTime() ) );
00165
00166
00167 note->setDescription( text );
00168
00169 m_calendar.addJournal( note );
00170
00171 createNote( note );
00172 showNote( note->uid() );
00173
00174 return note->uid();
00175 }
00176
00177 QString KNotesApp::newNoteFromClipboard( const QString& name )
00178 {
00179 const QString& text = KApplication::clipboard()->text();
00180 return newNote( name, text );
00181 }
00182
00183 void KNotesApp::showNote( const QString& id ) const
00184 {
00185 KNote* note = m_noteList[id];
00186 if ( note )
00187 showNote( note );
00188 else
00189 kdWarning(5500) << "No note with id: " << id << endl;
00190 }
00191
00192 void KNotesApp::hideNote( const QString& id ) const
00193 {
00194 KNote* note = m_noteList[id];
00195 if ( note )
00196 note->hide();
00197 else
00198 kdWarning(5500) << "No note with id: " << id << endl;
00199 }
00200
00201 void KNotesApp::killNote( const QString& id, bool force )
00202 {
00203 KNote* note = m_noteList[id];
00204 if ( note )
00205 note->slotKill( force );
00206 else
00207 kdWarning(5500) << "No note with id: " << id << endl;
00208 }
00209
00210
00211 void KNotesApp::killNote( const QString& id )
00212 {
00213 killNote( id, false );
00214 }
00215
00216 QMap<QString,QString> KNotesApp::notes() const
00217 {
00218 QMap<QString,QString> notes;
00219 QDictIterator<KNote> it( m_noteList );
00220
00221 for ( ; it.current(); ++it )
00222 notes.insert( it.current()->noteId(), it.current()->name() );
00223
00224 return notes;
00225 }
00226
00227 QString KNotesApp::name( const QString& id ) const
00228 {
00229 KNote* note = m_noteList[id];
00230 if ( note )
00231 return note->name();
00232 else
00233 return QString::null;
00234 }
00235
00236 QString KNotesApp::text( const QString& id ) const
00237 {
00238 KNote* note = m_noteList[id];
00239 if ( note )
00240 return note->text();
00241 else
00242 return QString::null;
00243 }
00244
00245 void KNotesApp::setName( const QString& id, const QString& newName )
00246 {
00247 KNote* note = m_noteList[id];
00248 if ( note )
00249 note->setName( newName );
00250 else
00251 kdWarning(5500) << "No note with id: " << id << endl;
00252 }
00253
00254 void KNotesApp::setText( const QString& id, const QString& newText )
00255 {
00256 KNote* note = m_noteList[id];
00257 if ( note )
00258 note->setText( newText );
00259 else
00260 kdWarning(5500) << "No note with id: " << id << endl;
00261 }
00262
00263 void KNotesApp::sync( const QString& app )
00264 {
00265 QDictIterator<KNote> it( m_noteList );
00266
00267 for ( ; it.current(); ++it )
00268 it.current()->sync( app );
00269 }
00270
00271 bool KNotesApp::isNew( const QString& app, const QString& id ) const
00272 {
00273 KNote* note = m_noteList[id];
00274 if ( note )
00275 return note->isNew( app );
00276 else
00277 return false;
00278 }
00279
00280 bool KNotesApp::isModified( const QString& app, const QString& id ) const
00281 {
00282 KNote* note = m_noteList[id];
00283 if ( note )
00284 return note->isModified( app );
00285 else
00286 return false;
00287 }
00288
00289
00290
00291
00292 void KNotesApp::mousePressEvent( QMouseEvent* e )
00293 {
00294 if ( !rect().contains( e->pos() ) )
00295 return;
00296
00297 switch ( e->button() )
00298 {
00299 case LeftButton:
00300 if ( m_noteList.count() == 1 )
00301 {
00302 QDictIterator<KNote> it( m_noteList );
00303 showNote( it.toFirst() );
00304 }
00305 else if ( m_note_menu->count() > 0 )
00306 m_note_menu->popup( e->globalPos() );
00307 break;
00308 case MidButton:
00309 newNote();
00310 break;
00311 case RightButton:
00312 m_context_menu->popup( e->globalPos() );
00313 default: break;
00314 }
00315 }
00316
00317 bool KNotesApp::eventFilter( QObject* o, QEvent* ev )
00318 {
00319 if ( ev->type() == QEvent::KeyPress )
00320 {
00321 QKeyEvent* ke = (QKeyEvent*)ev;
00322
00323 if ( ke->key() == Key_BackTab )
00324 {
00325
00326 QDictIterator<KNote> it( m_noteList );
00327 KNote *first = it.toFirst();
00328 for ( ; it.current(); ++it )
00329 if ( it.current()->hasFocus() )
00330 {
00331 if ( ++it )
00332 showNote( it.current() );
00333 else
00334 showNote( first );
00335 break;
00336 }
00337
00338 ke->accept();
00339 return true;
00340 }
00341 else
00342 ke->ignore();
00343 }
00344
00345 return QLabel::eventFilter( o, ev );
00346 }
00347
00348
00349
00350
00351 void KNotesApp::slotShowNote()
00352 {
00353
00354 showNote( QString::fromUtf8( sender()->name() ) );
00355 }
00356
00357 void KNotesApp::slotPreferences()
00358 {
00359
00360 if ( KNoteConfigDlg::showDialog( "KNotes Default Settings" ) )
00361 return;
00362
00363
00364 if ( !m_defaultConfig )
00365 {
00366 QString configFile = KGlobal::dirs()->saveLocation( "config" ) + "knotesrc";
00367 KSharedConfig::Ptr config = KSharedConfig::openConfig( configFile, false, false );
00368 m_defaultConfig = new KNoteConfig( config );
00369 }
00370
00371
00372 KNoteConfigDlg *dialog = new KNoteConfigDlg( m_defaultConfig,
00373 i18n("KNotes Defaults"), true, this, "KNotes Default Settings" );
00374 dialog->show();
00375 }
00376
00377 void KNotesApp::slotConfigureAccels()
00378 {
00379 KKeyDialog::configure( m_globalAccel, this, false );
00380 m_globalAccel->writeSettings();
00381 updateGlobalAccels();
00382 }
00383
00384 void KNotesApp::slotNoteKilled( KCal::Journal *journal )
00385 {
00386
00387 m_noteList.remove( journal->uid() );
00388 m_calendar.deleteJournal( journal );
00389
00390 saveNotes();
00391 updateNoteActions();
00392 }
00393
00394 void KNotesApp::slotQuit()
00395 {
00396 saveConfigs();
00397 kapp->quit();
00398 }
00399
00400
00401
00402
00403 void KNotesApp::showNote( KNote* note ) const
00404 {
00405 if ( !note->isHidden() )
00406 {
00407
00408
00409 KWin::setCurrentDesktop( KWin::windowInfo( note->winId() ).desktop() );
00410 KWin::forceActiveWindow( note->winId() );
00411 note->setFocus();
00412 }
00413 else
00414 {
00415
00416 note->show();
00417 note->toDesktop( KWin::currentDesktop() );
00418 KWin::forceActiveWindow( note->winId() );
00419 note->setFocus();
00420 }
00421 }
00422
00423 void KNotesApp::createNote( KCal::Journal *journal )
00424 {
00425 KNote *newNote = new KNote( this, domDocument(), journal,
00426 0, journal->uid().utf8() );
00427 m_noteList.insert( newNote->noteId(), newNote );
00428
00429 connect( newNote, SIGNAL(sigRequestNewNote()), SLOT(newNote()) );
00430 connect( newNote, SIGNAL(sigKillNote( KCal::Journal* )),
00431 SLOT(slotNoteKilled( KCal::Journal* )) );
00432 connect( newNote, SIGNAL(sigNameChanged()), SLOT(updateNoteActions()) );
00433 connect( newNote, SIGNAL(sigDataChanged()), SLOT(saveNotes()) );
00434 connect( newNote, SIGNAL(sigColorChanged()), SLOT(updateNoteActions()) );
00435
00436 updateNoteActions();
00437 }
00438
00439 void KNotesApp::saveNotes()
00440 {
00441 QString file = KGlobal::dirs()->saveLocation( "appdata" ) + "notes.ics";
00442 QString backup = file + "~";
00443
00444
00445
00446
00447 if ( KIO::NetAccess::exists( KURL( file ), true, 0 ) &&
00448 !KIO::NetAccess::file_copy( KURL( file ), KURL( backup ), -1, true ) )
00449 {
00450 KMessageBox::error( 0,
00451 i18n("<qt>Unable to save the notes backup to "
00452 "<b>%1</b>! Check that there is sufficient "
00453 "disk space!</qt>").arg( backup ) );
00454 }
00455 else if ( !m_calendar.save( file, new KCal::ICalFormat() ) )
00456 {
00457 KMessageBox::error( 0,
00458 i18n("<qt>Unable to save the notes to <b>%1</b>! "
00459 "Check that there is sufficient disk space."
00460 "<br>There should be a backup in <b>%2</b> "
00461 "though.</qt>").arg( file ).arg( backup ) );
00462 }
00463 }
00464
00465 void KNotesApp::saveConfigs()
00466 {
00467 QDictIterator<KNote> it( m_noteList );
00468 for ( ; it.current(); ++it )
00469 it.current()->saveConfig();
00470 }
00471
00472 void KNotesApp::updateNoteActions()
00473 {
00474 unplugActionList( "notes" );
00475 m_noteActions.clear();
00476
00477 for ( QDictIterator<KNote> it( m_noteList ); it.current(); ++it )
00478 {
00479 KAction *action = new KAction( it.current()->name().replace("&", "&&"),
00480 KShortcut(), this, SLOT(slotShowNote()),
00481 (QObject *)0,
00482 it.current()->noteId().utf8() );
00483 QPixmap pix( 16, 16 );
00484 pix.fill( it.current()->paletteBackgroundColor() );
00485 action->setIconSet( pix );
00486 m_noteActions.append( action );
00487 }
00488
00489 m_noteActions.sort();
00490
00491 if ( m_noteActions.isEmpty() )
00492 {
00493 KAction *action = new KAction( i18n("No Notes") );
00494 m_noteActions.append( action );
00495 }
00496
00497 plugActionList( "notes", m_noteActions );
00498 }
00499
00500 void KNotesApp::updateGlobalAccels()
00501 {
00502 if ( m_globalAccel->isEnabled() )
00503 {
00504 KAction *action = actionCollection()->action( "new_note" );
00505 if ( action )
00506 action->setShortcut( m_globalAccel->shortcut( "global_new_note" ) );
00507 action = actionCollection()->action( "new_note_clipboard" );
00508 if ( action )
00509 action->setShortcut( m_globalAccel->shortcut( "global_new_note_clipboard" ) );
00510
00511 m_globalAccel->updateConnections();
00512 }
00513 else
00514 {
00515 KAction *action = actionCollection()->action( "new_note" );
00516 if ( action )
00517 action->setShortcut( 0 );
00518 action = actionCollection()->action( "new_note_clipboard" );
00519 if ( action )
00520 action->setShortcut( 0 );
00521 }
00522 }
00523
00524 #include "knotesapp.moc"