knotes Library API Documentation

knotesapp.cpp

00001 /*******************************************************************
00002  KNotes -- Notes for the KDE project
00003 
00004  Copyright (c) 1997-2003, The KNotes Developers
00005 
00006  This program is free software; you can redistribute it and/or
00007  modify it under the terms of the GNU General Public License
00008  as published by the Free Software Foundation; either version 2
00009  of the License, or (at your option) any later version.
00010 
00011  This program is distributed in the hope that it will be useful,
00012  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  GNU General Public License for more details.
00015 
00016  You should have received a copy of the GNU General Public License
00017  along with this program; if not, write to the Free Software
00018  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00019 *******************************************************************/
00020 
00021 #include <qclipboard.h>
00022 #include <qptrlist.h>
00023 #include <qdir.h>
00024 
00025 #include <kdebug.h>
00026 #include <kaction.h>
00027 #include <kxmlguifactory.h>
00028 #include <ksystemtray.h>
00029 #include <klocale.h>
00030 #include <kiconloader.h>
00031 #include <kstandarddirs.h>
00032 #include <kpopupmenu.h>
00033 #include <khelpmenu.h>
00034 #include <kkeydialog.h>
00035 #include <kglobalaccel.h>
00036 #include <kmessagebox.h>
00037 #include <ksimpleconfig.h>
00038 #include <kio/netaccess.h>
00039 #include <kwin.h>
00040 
00041 #include "libkcal/journal.h"
00042 #include "libkcal/icalformat.h"
00043 
00044 #include "knotesapp.h"
00045 #include "knote.h"
00046 #include "knoteconfigdlg.h"
00047 #include "knoteslegacy.h"
00048 #include "version.h"
00049 
00050 using namespace KCal;
00051 
00052 
00053 int KNotesApp::KNoteActionList::compareItems( QPtrCollection::Item s1, QPtrCollection::Item s2 )
00054 { 
00055     if ( ((KAction*)s1)->text() == ((KAction*)s2)->text() ) 
00056         return 0; 
00057     return ( ((KAction*)s1)->text() < ((KAction*)s2)->text() ? -1 : 1 ); 
00058 }
00059 
00060 
00061 KNotesApp::KNotesApp()
00062     : DCOPObject("KNotesIface"), QLabel( 0, 0, WType_TopLevel ),
00063       KXMLGUIBuilder( this )
00064 {
00065     m_noteActions.setAutoDelete( true );
00066     m_noteList.setAutoDelete( true );
00067 
00068     // create the dock widget...
00069     KWin::setSystemTrayWindowFor( winId(), qt_xrootwin() );
00070     setBackgroundMode( X11ParentRelative );
00071     setPixmap( KSystemTray::loadIcon( "knotes" ) );
00072 
00073     // create the GUI...
00074     new KAction( i18n("New Note"), "filenew", 0, 
00075         this, SLOT(slotNewNote()), actionCollection(), "new_note" );
00076     new KAction( i18n("New Note From Clipboard"), "editpaste", 0, 
00077         this, SLOT(slotNewNoteFromClipboard()), 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     factory = new KXMLGUIFactory( this, this, "guifactory" );
00086     factory->addClient( this );
00087 
00088     m_context_menu = static_cast<KPopupMenu*>(factory->container( "knotes_context", this ));
00089     m_note_menu = static_cast<KPopupMenu*>(factory->container( "notes_menu", this ));
00090 
00091     // create accels for global shortcuts
00092     globalAccel = new KGlobalAccel( this, "global accel" );
00093     globalAccel->insert( "global_new_note", i18n("New Note"), "",
00094                          ALT+SHIFT+Key_N, ALT+SHIFT+Key_N ,
00095                          this, SLOT(slotNewNote()), true, true );
00096     globalAccel->insert( "global_new_note_clipboard", i18n("New Note From Clipboard"), "",
00097                          ALT+SHIFT+Key_C, ALT+SHIFT+Key_C,
00098                          this, SLOT(slotNewNoteFromClipboard()), true, true );
00099 
00100     globalAccel->readSettings();
00101 
00102     KConfig *config = KGlobal::config();
00103     config->setGroup( "Global Keybindings" );
00104     globalAccel->setEnabled( config->readBoolEntry( "Enabled", true ) );
00105 
00106     updateGlobalAccels();
00107 
00108     // clean up old config files
00109     KNotesLegacy::cleanUp();
00110 
00111     // read the notes
00112     m_calendar.load( KGlobal::dirs()->saveLocation( "appdata" ) + "notes.ics" );
00113 
00114     // TODO
00115     // initialize the Calendar
00116     //m_calendar.setOwner(..);
00117     //m_calendar.setEmail(..);
00118 
00119     // read the old config files into m_calendar and convert them
00120     if ( KNotesLegacy::convert( &m_calendar ) )
00121         saveNotes();
00122 
00123     QDir noteDir( KGlobal::dirs()->saveLocation( "appdata", "notes/" ) );
00124     Journal::List notes = m_calendar.journals();
00125     Journal::List::ConstIterator it;
00126     for ( it = notes.begin(); it != notes.end(); ++it )
00127     {
00128         Journal *note = *it;
00129         // KOrganizers journals don't have attachments -> use default display config
00130         if ( note->attachments(CONFIG_MIME).isEmpty() )
00131         {
00132             // set the name of the config file...
00133             QString file = noteDir.absFilePath( note->uid() );
00134 
00135             // ...and "fill" it with the default config
00136             KIO::NetAccess::copy(
00137                     KURL( KGlobal::dirs()->findResource( "config", "knotesrc" ) ),
00138                     KURL( file )
00139             );
00140 
00141             note->addAttachment( new Attachment( file, CONFIG_MIME ) );
00142         }
00143 
00144         if ( note->summary().isNull() && note->dtStart().isValid() )
00145             note->setSummary( KGlobal::locale()->formatDateTime( note->dtStart() ) );
00146 
00147         KNote* newNote = new KNote( this, domDocument(), note );
00148         m_noteList.insert( note->uid(), newNote );
00149 
00150         connect( newNote, SIGNAL(sigNewNote()), this, SLOT(slotNewNote()) );
00151         connect( newNote, SIGNAL(sigKillNote( KCal::Journal* )),
00152                  this,    SLOT(slotNoteKilled( KCal::Journal* )) );
00153         connect( newNote, SIGNAL(sigNameChanged()), this, SLOT(updateNoteActions()) );
00154         connect( newNote, SIGNAL(sigSaveData()), this, SLOT(saveNotes()) );
00155     }
00156     updateNoteActions();
00157 
00158     connect( kapp, SIGNAL(lastWindowClosed()), kapp, SLOT(quit()) );
00159 
00160     kapp->installEventFilter( this );
00161 
00162     if ( m_noteList.count() == 0 && !kapp->isRestored() )
00163         newNote();
00164 }
00165 
00166 KNotesApp::~KNotesApp()
00167 {
00168     saveNotes();
00169 
00170     blockSignals( true );
00171     m_noteList.clear();
00172     blockSignals( false );
00173 
00174     delete factory;
00175 }
00176 
00177 bool KNotesApp::commitData( QSessionManager& )
00178 {
00179     saveConfig();
00180     return true;
00181 }
00182 
00183 // -------------------- public DCOP interface -------------------- //
00184 
00185 QString KNotesApp::newNote( const QString& name, const QString& text )
00186 {
00187     // create the new note
00188     Journal *note = new Journal();
00189 
00190     // set the name of the config file...
00191     QDir noteDir( KGlobal::dirs()->saveLocation( "appdata", "notes/" ) );
00192     QString file = noteDir.absFilePath( note->uid() );
00193 
00194     // ...and "fill" it with the default config
00195     KIO::NetAccess::copy( KURL( KGlobal::dirs()->findResource( "config", "knotesrc" ) ),
00196                           KURL( file ) );
00197 
00198     // new notes have the current date/time as title if none was given
00199     if ( !name.isNull() )
00200         note->setSummary( name );
00201     else
00202         note->setSummary( KGlobal::locale()->formatDateTime( QDateTime::currentDateTime() ) );
00203 
00204     note->setDescription( text );
00205     note->addAttachment( new Attachment( file, CONFIG_MIME ) );
00206     m_calendar.addJournal( note );
00207 
00208     KNote* newNote = new KNote( this, domDocument(), note );
00209     m_noteList.insert( newNote->noteId(), newNote );
00210 
00211     connect( newNote, SIGNAL(sigNewNote()), this, SLOT(slotNewNote()) );
00212     connect( newNote, SIGNAL(sigKillNote( KCal::Journal* )),
00213              this,    SLOT(slotNoteKilled( KCal::Journal* )) );
00214     connect( newNote, SIGNAL(sigNameChanged()), this, SLOT(updateNoteActions()) );
00215     connect( newNote, SIGNAL(sigSaveData()), this, SLOT(saveNotes()) );
00216 
00217     updateNoteActions();
00218     showNote( newNote );
00219 
00220     return newNote->noteId();
00221 }
00222 
00223 QString KNotesApp::newNoteFromClipboard( const QString& name )
00224 {
00225     const QString& text = KApplication::clipboard()->text();
00226     return newNote( name, text );
00227 }
00228 
00229 void KNotesApp::showNote( const QString& id ) const
00230 {
00231     KNote* note = m_noteList[id];
00232     if ( note )
00233         showNote( note );
00234     else
00235         kdWarning(5500) << "No note with id: " << id << endl;
00236 }
00237 
00238 void KNotesApp::hideNote( const QString& id ) const
00239 {
00240     KNote* note = m_noteList[id];
00241     if ( note )
00242         note->hide();
00243     else
00244         kdWarning(5500) << "No note with id: " << id << endl;
00245 }
00246 
00247 void KNotesApp::killNote( const QString& id, bool force ) 
00248 {
00249     KNote* note = m_noteList[id];
00250     if ( note )
00251         note->slotKill( force );
00252     else
00253         kdWarning(5500) << "No note with id: " << id << endl;
00254 }
00255 
00256 void KNotesApp::killNote( const QString& id ) // "bool force = false" doesn't work with dcop 
00257 {
00258     killNote( id, false );
00259 }
00260 
00261 QMap<QString,QString> KNotesApp::notes() const
00262 {
00263     QMap<QString,QString> notes;
00264     QDictIterator<KNote> it( m_noteList );
00265 
00266     for ( ; it.current(); ++it )
00267         notes.insert( it.current()->noteId(), it.current()->name() );
00268 
00269     return notes;
00270 }
00271 
00272 QString KNotesApp::name( const QString& id ) const
00273 {
00274     KNote* note = m_noteList[id];
00275     if ( note )
00276         return note->name();
00277     else
00278         return QString::null;
00279 }
00280 
00281 QString KNotesApp::text( const QString& id ) const
00282 {
00283     KNote* note = m_noteList[id];
00284     if ( note )
00285         return note->text();
00286     else
00287         return QString::null;
00288 }
00289 
00290 void KNotesApp::setName( const QString& id, const QString& newName )
00291 {
00292     KNote* note = m_noteList[id];
00293     if ( note )
00294         note->setName( newName );
00295     else
00296         kdWarning(5500) << "No note with id: " << id << endl;
00297 }
00298 
00299 void KNotesApp::setText( const QString& id, const QString& newText )
00300 {
00301     KNote* note = m_noteList[id];
00302     if ( note )
00303         note->setText( newText );
00304     else
00305         kdWarning(5500) << "No note with id: " << id << endl;
00306 }
00307 
00308 void KNotesApp::sync( const QString& app )
00309 {
00310     QDictIterator<KNote> it( m_noteList );
00311 
00312     for ( ; it.current(); ++it )
00313         it.current()->sync( app );
00314 }
00315 
00316 bool KNotesApp::isNew( const QString& app, const QString& id ) const
00317 {
00318     KNote* note = m_noteList[id];
00319     if ( note )
00320         return note->isNew( app );
00321     else
00322         return false;
00323 }
00324 
00325 bool KNotesApp::isModified( const QString& app, const QString& id ) const
00326 {
00327     KNote* note = m_noteList[id];
00328     if ( note )
00329         return note->isModified( app );
00330     else
00331         return false;
00332 }
00333 
00334 
00335 // ------------------- protected methods ------------------- //
00336 
00337 void KNotesApp::mousePressEvent( QMouseEvent* e )
00338 {
00339     if ( !rect().contains( e->pos() ) )
00340         return;
00341 
00342     switch ( e->button() )
00343     {
00344     case LeftButton:
00345         if ( m_noteList.count() == 1 )
00346         {
00347             QDictIterator<KNote> it( m_noteList );
00348             showNote( it.toFirst() );
00349         }
00350         else if ( m_note_menu->count() > 0 )
00351             m_note_menu->popup( e->globalPos() );
00352         break;
00353     case MidButton:
00354         newNote();
00355         break;
00356     case RightButton:
00357         m_context_menu->popup( e->globalPos() );
00358     default: break;
00359     }
00360 }
00361 
00362 bool KNotesApp::eventFilter( QObject* o, QEvent* ev )
00363 {
00364     if ( ev->type() == QEvent::KeyPress )
00365     {
00366         QKeyEvent* ke = (QKeyEvent*)ev;
00367 
00368         if ( ke->key() == Key_BackTab )         // Shift+Tab
00369         {
00370             // show next note
00371             QDictIterator<KNote> it( m_noteList );
00372             KNote* first = it.toFirst();
00373             for ( ; it.current(); ++it )
00374                 if ( it.current()->hasFocus() )
00375                 {
00376                     if ( ++it )
00377                         showNote( it.current() );
00378                     else
00379                         showNote( first );
00380                     break;
00381                 }
00382 
00383             ke->accept();
00384             return true;
00385         }
00386         else
00387             ke->ignore();
00388     }
00389 
00390     return QLabel::eventFilter( o, ev );
00391 }
00392 
00393 
00394 // -------------------- protected slots -------------------- //
00395 
00396 void KNotesApp::slotNewNote()
00397 {
00398     newNote();
00399 }
00400 
00401 void KNotesApp::slotNewNoteFromClipboard()
00402 {
00403     newNoteFromClipboard();
00404 }
00405 
00406 void KNotesApp::slotShowNote()
00407 {
00408     // tell the WM to give this note focus
00409     QString name = QString::fromUtf8( sender()->name() );
00410     showNote( name );
00411 }
00412 
00413 void KNotesApp::slotNoteKilled( Journal *journal )
00414 {
00415     // this kills the KNote object
00416     m_noteList.remove( journal->uid() );
00417 
00418     QString configFile = journal->attachments( CONFIG_MIME ).first()->uri();
00419     if ( !QDir::home().remove( configFile ) )
00420         kdError(5500) << "Can't remove the note config: " << configFile << endl;
00421 
00422     m_calendar.deleteJournal( journal );
00423 
00424     updateNoteActions();
00425 }
00426 
00427 void KNotesApp::slotPreferences() const
00428 {
00429     // launch preferences dialog...
00430     KNoteConfigDlg config( "knotesrc", i18n("KNotes Defaults"), true );
00431     config.exec();
00432 }
00433 
00434 void KNotesApp::slotConfigureAccels()
00435 {
00436     KKeyDialog::configure( globalAccel, this, false );
00437     globalAccel->writeSettings();
00438     updateGlobalAccels();
00439 }
00440 
00441 void KNotesApp::slotQuit()
00442 {
00443     saveConfig();
00444     kapp->quit();
00445 }
00446 
00447 
00448 // -------------------- private methods -------------------- //
00449 
00450 void KNotesApp::showNote( KNote* note ) const
00451 {
00452     if ( !note->isHidden() )
00453     {
00454         // if it's already showing, we need to change to its desktop
00455         // and give it focus
00456         KWin::setCurrentDesktop( KWin::info( note->winId() ).desktop );
00457         KWin::setActiveWindow( note->winId() );
00458         note->setFocus();
00459     }
00460     else
00461     {
00462         WId id = note->winId();
00463 
00464         // if not, show note on the current desktop
00465         note->show();
00466         note->toDesktop( KWin::currentDesktop() );
00467         if ( note->m_alwaysOnTop->isChecked() )
00468             KWin::setState( id, KWin::info( id ).state | NET::StaysOnTop );
00469         KWin::setActiveWindow( id );
00470         note->setFocus();
00471     }
00472 }
00473 
00474 void KNotesApp::saveConfig()
00475 {
00476     QDictIterator<KNote> it( m_noteList );
00477     for ( ; it.current(); ++it )
00478         it.current()->saveConfig();
00479 }
00480 
00481 void KNotesApp::saveNotes()
00482 {
00483     QString file = KGlobal::dirs()->saveLocation( "appdata" ) + "notes.ics";
00484     QString backup = file + "~";
00485 
00486     // if the backup fails don't even try to save the current notes
00487     // (might just destroy the file that's already there)
00488 
00489     if ( KIO::NetAccess::exists( KURL( file ) ) && !KIO::NetAccess::file_copy( KURL( file ), KURL( backup ), -1, true) )
00490         KMessageBox::error(0, i18n("<qt>Unable to save the notes backup to <b>%1</b>! Check that there is sufficient disk space.</qt>")
00491                                   .arg( backup ) );
00492     else if ( !m_calendar.save( file, new ICalFormat() ) )
00493         KMessageBox::error(0, i18n("<qt>Unable to save the notes to <b>%1</b>! Check that there is sufficient disk space.<br>"
00494                                    "There should be a backup in <b>%2</b> though.</qt>")
00495                                   .arg( file ).arg( backup ) );
00496 }
00497 
00498 void KNotesApp::updateNoteActions()
00499 {
00500     unplugActionList( "notes" );
00501     m_noteActions.clear();
00502 
00503     for ( QDictIterator<KNote> it( m_noteList ); it.current(); ++it )
00504     {
00505         KAction *action = new KAction( it.current()->name().replace( "&", "&&"), KShortcut(),
00506                                        this, SLOT(slotShowNote()),
00507                                        (QObject*)0, it.current()->noteId().utf8() );
00508         QPixmap pix( 16, 16 );
00509         pix.fill( it.current()->paletteBackgroundColor() );
00510         action->setIconSet( pix );
00511         m_noteActions.append( action );
00512     }
00513 
00514     m_noteActions.sort();
00515 
00516     if ( m_noteActions.isEmpty() )
00517     {
00518         KAction *action = new KAction( i18n("No Notes") );
00519         m_noteActions.append( action );
00520     }
00521 
00522     plugActionList( "notes", m_noteActions );
00523 }
00524 
00525 void KNotesApp::updateGlobalAccels()
00526 {
00527     if ( globalAccel->isEnabled() )
00528     {
00529         KAction *action = actionCollection()->action( "new_note" );
00530         if ( action )
00531             action->setShortcut( globalAccel->shortcut( "global_new_note" ) );
00532         action = actionCollection()->action( "new_note_clipboard" );
00533         if ( action )
00534             action->setShortcut( globalAccel->shortcut( "global_new_note_clipboard" ) );
00535 
00536         globalAccel->updateConnections();
00537     }
00538     else
00539     {
00540         KAction *action = actionCollection()->action( "new_note" );
00541         if ( action )
00542             action->setShortcut( 0 );
00543         action = actionCollection()->action( "new_note_clipboard" );
00544         if ( action )
00545             action->setShortcut( 0 );
00546     }
00547 }
00548 
00549 #include "knotesapp.moc"
KDE Logo
This file is part of the documentation for knotes Library Version 3.2.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Mar 6 17:18:05 2004 by doxygen 1.3.6-20040222 written by Dimitri van Heesch, © 1997-2003