• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdepim
  • Sitemap
  • Contact Us
 

knotes

knotesapp.cpp

Go to the documentation of this file.
00001 /*******************************************************************
00002  KNotes -- Notes for the KDE project
00003 
00004  Copyright (c) 1997-2006, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019 *******************************************************************/
00020 
00021 
00022 #include <QPixmap>
00023 
00024 #include <QClipboard>
00025 #include <QTcpServer>
00026 
00027 #include <kaction.h>
00028 #include <kactioncollection.h>
00029 #include <kconfig.h>
00030 #include <kdebug.h>
00031 #include <kfind.h>
00032 #include <kfinddialog.h>
00033 #include <khelpmenu.h>
00034 #include <kicon.h>
00035 #include <kiconeffect.h>
00036 #include <klocale.h>
00037 #include <kmenu.h>
00038 #include <kshortcutsdialog.h>
00039 #include <ksocketfactory.h>
00040 #include <kstandardaction.h>
00041 #include <kstandarddirs.h>
00042 #include <ksystemtrayicon.h>
00043 #include <kwindowsystem.h>
00044 #include <kxmlguibuilder.h>
00045 #include <kxmlguifactory.h>
00046 
00047 #include <kcal/calendarlocal.h>
00048 #include <kcal/journal.h>
00049 #include <kiconloader.h>
00050 
00051 #include "knote.h"
00052 #include "knoteconfigdlg.h"
00053 #include "knotes/resourcemanager.h"
00054 #include "knotesadaptor.h"
00055 #include "knotesalarm.h"
00056 #include "knotesapp.h"
00057 #include "knotesglobalconfig.h"
00058 #include "knoteslegacy.h"
00059 #include "knotesnetrecv.h"
00060 
00061 class KNotesKeyDialog
00062   : public KDialog
00063 {
00064   public:
00065     KNotesKeyDialog( KActionCollection *globals, QWidget *parent )
00066       : KDialog( parent )
00067     {
00068       setCaption( i18n( "Configure Shortcuts" ) );
00069       setButtons( Default | Ok | Cancel );
00070       
00071       m_keyChooser = new KShortcutsEditor( globals, this );
00072       setMainWidget( m_keyChooser );
00073       connect( this, SIGNAL( defaultClicked() ),
00074                m_keyChooser, SLOT( allDefault() ) );
00075     }
00076     
00077     void insert( KActionCollection *actions )
00078     {
00079         m_keyChooser->addCollection( actions, i18n( "Note Actions" ) );
00080     }
00081     
00082     void configure()
00083     {
00084         if ( exec() == Accepted ) {
00085             m_keyChooser->save();
00086         }
00087     }
00088     
00089   private:
00090     KShortcutsEditor *m_keyChooser;
00091 };
00092 
00093 
00094 static bool qActionLessThan( const QAction *a1, const QAction *a2 )
00095 {
00096   return ( a1->text() < a2->text() );
00097 }
00098 
00099 
00100 KNotesApp::KNotesApp()
00101   : QWidget(), m_alarm( 0 ), m_listener( 0 ), m_find( 0 ), m_findPos( 0 )
00102 {
00103   new KNotesAdaptor( this );
00104   QDBusConnection::sessionBus().registerObject( "/KNotes" , this );
00105   connect( kapp, SIGNAL( lastWindowClosed() ), kapp, SLOT( quit() ) );
00106   
00107   // create the dock widget...
00108   m_tray = new KSystemTrayIcon();
00109   
00110   m_tray->setToolTip( i18n( "KNotes: Sticky notes for KDE" ) );
00111   m_tray->setIcon( KSystemTrayIcon::loadIcon( "knotes" ) );
00112   connect( m_tray, SIGNAL( activated( QSystemTrayIcon::ActivationReason ) ),
00113            SLOT( slotActivated( QSystemTrayIcon::ActivationReason ) ) );
00114   
00115   // set the initial style
00116 #ifdef __GNUC__
00117 #warning FIXME
00118 #endif
00119   //    KNote::setStyle( KNotesGlobalConfig::style() );
00120   
00121   // create the GUI...
00122   KAction *action  = new KAction( KIcon( "document-new" ),
00123                                   i18n( "New Note" ), this );
00124   action->setGlobalShortcut( KShortcut( Qt::ALT + Qt::SHIFT + Qt::Key_N ),
00125                              KAction::DefaultShortcut );
00126   actionCollection()->addAction( "new_note", action );
00127   connect( action, SIGNAL( triggered() ), SLOT( newNote() ) );
00128   
00129   action  = new KAction( KIcon( "edit-paste" ),
00130                          i18n( "New Note From Clipboard" ), this );
00131   action->setGlobalShortcut( KShortcut( Qt::ALT + Qt::SHIFT + Qt::Key_C ),
00132                              KAction::DefaultShortcut );
00133   actionCollection()->addAction( "new_note_clipboard", action );
00134   connect( action, SIGNAL( triggered() ), SLOT( newNoteFromClipboard() ) );
00135   
00136   action  = new KAction( KIcon( "knotes" ), i18n( "Show All Notes" ), this );
00137   action->setGlobalShortcut( KShortcut( Qt::ALT + Qt::SHIFT + Qt::Key_S ),
00138                              KAction::DefaultShortcut );
00139   actionCollection()->addAction( "show_all_notes", action );
00140   connect( action, SIGNAL( triggered() ), SLOT( showAllNotes() ) );
00141   
00142   action  = new KAction( KIcon( "window-close" ),
00143                          i18n( "Hide All Notes" ), this );
00144   action->setGlobalShortcut( KShortcut( Qt::ALT + Qt::SHIFT + Qt::Key_H ),
00145                              KAction::DefaultShortcut );
00146   actionCollection()->addAction( "hide_all_notes", action );
00147   connect( action, SIGNAL( triggered() ), SLOT( hideAllNotes() ) );
00148   
00149   new KHelpMenu( this, KGlobal::mainComponent().aboutData(), false,
00150                  actionCollection() );
00151   
00152   KStandardAction::find( this, SLOT( slotOpenFindDialog() ),
00153                          actionCollection() );
00154   KStandardAction::preferences( this, SLOT( slotPreferences() ),
00155                          actionCollection() );
00156   KStandardAction::keyBindings( this, SLOT( slotConfigureAccels() ),
00157                          actionCollection() );
00158   //FIXME: no shortcut removing!?
00159   KStandardAction::quit( this, SLOT( slotQuit() ),
00160                          actionCollection() )->setShortcut( 0 );
00161   
00162   setXMLFile( componentData().componentName() + "appui.rc" );
00163   
00164   m_guiBuilder = new KXMLGUIBuilder( this );
00165   m_guiFactory = new KXMLGUIFactory( m_guiBuilder, this );
00166   m_guiFactory->addClient( this );
00167   
00168   m_contextMenu = static_cast<KMenu *>( m_guiFactory->container(
00169                                         "knotes_context",
00170                                         this ) );
00171   m_noteMenu = static_cast<KMenu *>( m_guiFactory->container(
00172                                       "notes_menu", this ) );
00173   m_tray->setContextMenu( m_contextMenu );
00174   // get the most recent XML UI file
00175   QString xmlFileName = componentData().componentName() + "ui.rc";
00176   QString filter = componentData().componentName() + '/' + xmlFileName;
00177   QStringList fileList =
00178       componentData().dirs()->findAllResources( "data", filter ) +
00179       componentData().dirs()->findAllResources( "data", xmlFileName );
00180   
00181   QString doc;
00182   KXMLGUIClient::findMostRecentXMLFile( fileList, doc );
00183   m_noteGUI.setContent( doc );
00184   
00185   KConfigGroup config( KGlobal::config(), "Global Keybindings" );
00186   
00187   // clean up old config files
00188   KNotesLegacy::cleanUp();
00189   
00190   // create the resource manager
00191   m_manager = new KNotesResourceManager();
00192   connect( m_manager, SIGNAL( sigRegisteredNote( KCal::Journal * ) ),
00193            this,      SLOT( createNote( KCal::Journal * ) ) );
00194   connect( m_manager, SIGNAL( sigDeregisteredNote( KCal::Journal * ) ),
00195            this,      SLOT( killNote( KCal::Journal * ) ) );
00196   
00197   // read the notes
00198   m_manager->load();
00199   
00200   // read the old config files, convert and add them
00201   KCal::CalendarLocal calendar( QString::fromLatin1( "UTC" ) );
00202   if ( KNotesLegacy::convert( &calendar ) ) {
00203     KCal::Journal::List notes = calendar.journals();
00204     KCal::Journal::List::ConstIterator it;
00205     for ( it = notes.begin(); it != notes.end(); ++it ) {
00206       m_manager->addNewNote( *it );
00207     }
00208     
00209     m_manager->save();
00210   }
00211   
00212   // set up the alarm reminder - do it after loading the notes because this
00213   // is used as a check if updateNoteActions has to be called for a new note
00214   m_alarm = new KNotesAlarm( m_manager, this );
00215   
00216    updateNetworkListener();
00217   
00218   if ( m_notes.size() == 0 && !kapp->isSessionRestored() ) {
00219       newNote();
00220   }
00221   
00222   updateNoteActions();
00223   m_tray->show();
00224 }
00225 
00226 KNotesApp::~KNotesApp()
00227 {
00228   saveNotes();
00229   
00230   blockSignals( true );
00231   qDeleteAll( m_notes );
00232   m_notes.clear();
00233   qDeleteAll( m_noteActions );
00234   m_noteActions.clear();
00235   blockSignals( false );
00236   
00237   //delete m_listener;
00238   delete m_manager;
00239   delete m_guiBuilder;
00240   delete m_tray;
00241 }
00242 
00243 bool KNotesApp::commitData( QSessionManager & )
00244 {
00245   saveConfigs();
00246   return true;
00247 }
00248 
00249 // -------------------- public D-Bus interface -------------------- //
00250 
00251 QString KNotesApp::newNote( const QString &name, const QString &text )
00252 {
00253   // create the new note
00254   KCal::Journal *journal = new KCal::Journal();
00255   
00256   // new notes have the current date/time as title if none was given
00257   if ( !name.isEmpty() ) {
00258     journal->setSummary( name );
00259   } else {
00260     journal->setSummary( KGlobal::locale()->formatDateTime(
00261                                                QDateTime::currentDateTime() ) );
00262   }
00263   
00264   // the body of the note
00265   journal->setDescription( text );
00266   
00267   m_manager->addNewNote( journal );
00268   
00269   showNote( journal->uid() );
00270   
00271   return journal->uid();
00272 }
00273 
00274 QString KNotesApp::newNoteFromClipboard( const QString &name )
00275 {
00276   const QString &text = KApplication::clipboard()->text();
00277   return newNote( name, text );
00278 }
00279 
00280 void KNotesApp::hideAllNotes() const
00281 {
00282   foreach ( KNote *note, m_notes ) {
00283     note->hide();
00284   }
00285 }
00286 
00287 void KNotesApp::showAllNotes() const
00288 {
00289   foreach ( KNote *note, m_notes ) {
00290     // workaround to BUG 149116
00291     note->hide();
00292     
00293     note->show();
00294     note->setFocus();
00295   }
00296 }
00297 
00298 void KNotesApp::showNote( const QString &id ) const
00299 {
00300   KNote *note = m_notes.value( id );
00301   if ( note ) {
00302     showNote( note );
00303   } else {
00304     kWarning( 5500 ) << "showNote: no note with id:" << id;
00305   }
00306 }
00307 
00308 void KNotesApp::hideNote( const QString &id ) const
00309 {
00310   KNote *note = m_notes.value( id );
00311   if ( note ) {
00312     note->hide();
00313   } else {
00314     kWarning( 5500 ) << "hideNote: no note with id:" << id;
00315   }
00316 }
00317 
00318 void KNotesApp::killNote( const QString &id, bool force )
00319 {
00320   KNote *note = m_notes.value( id );
00321   if ( note ) {
00322     note->slotKill( force );
00323   } else {
00324     kWarning( 5500 ) << "killNote: no note with id:" << id;
00325   }
00326 }
00327 
00328 // "bool force = false" doesn't work with dcop
00329 void KNotesApp::killNote( const QString &id )
00330 {
00331   killNote( id, false );
00332 }
00333 
00334 QMap<QString, QString> KNotesApp::notes() const
00335 {
00336   QMap<QString, QString> notes;
00337   
00338   foreach ( KNote *note, m_notes ) {
00339     notes.insert( note->noteId(), note->name() );
00340   }
00341   
00342   return notes;
00343 }
00344 
00345 QString KNotesApp::name( const QString &id ) const
00346 {
00347   KNote *note = m_notes.value( id );
00348   if ( note ) {
00349     return note->name();
00350   } else {
00351     return QString();
00352   }
00353 }
00354 
00355 QString KNotesApp::text( const QString &id ) const
00356 {
00357   KNote *note = m_notes.value( id );
00358   if ( note ) {
00359     return note->text();
00360   } else {
00361     return QString();
00362   }
00363 }
00364 
00365 void KNotesApp::setName( const QString &id, const QString &newName )
00366 {
00367   KNote *note = m_notes.value( id );
00368   if ( note ) {
00369     note->setName( newName );
00370   } else {
00371     kWarning( 5500 ) << "setName: no note with id:" << id;
00372   }
00373 }
00374 
00375 void KNotesApp::setText( const QString &id, const QString &newText )
00376 {
00377   KNote *note = m_notes.value( id );
00378   if ( note ) {
00379     note->setText( newText );
00380   } else {
00381     kWarning( 5500 ) << "setText: no note with id:" << id;
00382   }
00383 }
00384 
00385 // -------------------- protected slots -------------------- //
00386 
00387 void KNotesApp::slotActivated( QSystemTrayIcon::ActivationReason r )
00388 {
00389   switch ( r ) {
00390 
00391     case QSystemTrayIcon::Trigger:
00392       if ( m_notes.size() == 1 ) {
00393         showNote( *m_notes.begin() );
00394       } else if ( m_notes.size() > 1 ) {
00395         m_noteMenu->popup( QCursor::pos () );
00396       }
00397       break;
00398 
00399     case QSystemTrayIcon::MiddleClick:
00400       newNote();
00401       break;
00402 
00403     default:
00404     break;
00405 
00406   }
00407 }
00408 
00409 void KNotesApp::slotShowNote()
00410 {
00411   // tell the WM to give this note focus
00412   showNote( sender()->objectName() );
00413 }
00414 
00415 void KNotesApp::slotWalkThroughNotes()
00416 {
00417   // show next note
00418   QMap<QString, KNote *>::const_iterator it = m_notes.begin();
00419   for ( ; it != m_notes.end(); ++it ) {
00420     if ( ( *it )->hasFocus() ) {
00421       if ( ++it != m_notes.end() ) {
00422         showNote( *it );
00423       } else {
00424         showNote( *m_notes.begin() );
00425       }
00426       break;
00427     }
00428   }
00429 }
00430 
00431 void KNotesApp::slotOpenFindDialog()
00432 {
00433   KFindDialog findDia( this );
00434   findDia.setObjectName( "find_dialog" );
00435   findDia.setHasSelection( false );
00436   findDia.setHasCursor( false );
00437   findDia.setSupportsBackwardsFind( false );
00438   
00439   if ( findDia.exec() != QDialog::Accepted ) {
00440     return;
00441   }
00442   
00443   delete m_findPos;
00444   m_findPos = new QMap<QString, KNote *>::iterator();
00445   *m_findPos = m_notes.begin();
00446   
00447   // this could be in an own method if searching without a dialog
00448   // should be possible
00449   delete m_find;
00450   m_find = new KFind( findDia.pattern(), findDia.options(), this );
00451   
00452   slotFindNext();
00453 }
00454 
00455 void KNotesApp::slotFindNext()
00456 {
00457   if ( *m_findPos != m_notes.end() ) {
00458     KNote *note = * ( *m_findPos++ );
00459     note->find( m_find->pattern(), m_find->options() );
00460   } else {
00461     m_find->displayFinalDialog();
00462     delete m_find;
00463     m_find = 0;
00464     delete m_findPos;
00465     m_findPos = 0;
00466   }
00467 }
00468 
00469 void KNotesApp::slotPreferences()
00470 {
00471   // reuse the dialog if possible
00472   if ( KNoteConfigDlg::showDialog( "KNotes Default Settings" ) ) {
00473     return;
00474   }
00475 
00476   // create a new preferences dialog...
00477   KNoteConfigDlg *dialog = new KNoteConfigDlg( 0, i18n( "Settings" ), this,
00478                                                "KNotes Settings" );
00479   connect( dialog, SIGNAL( settingsChanged( const QString & ) ),
00480            this,   SLOT( updateNetworkListener() ) );
00481   connect( dialog, SIGNAL( settingsChanged( const QString & ) ),
00482            this,   SLOT( updateStyle() ) );
00483   dialog->show();
00484 }
00485 
00486 void KNotesApp::slotConfigureAccels()
00487 {
00488   KNotesKeyDialog keys( actionCollection(), this );
00489   
00490   QMap<QString, KNote *>::const_iterator it = m_notes.begin();
00491   
00492   if ( !m_notes.isEmpty() ) {
00493     keys.insert( ( *it )->actionCollection() );
00494   }
00495   
00496   keys.configure();
00497   
00498   // update GUI doc for new notes
00499   m_noteGUI.setContent(
00500     KXMLGUIFactory::readConfigFile( componentData().componentName() + "ui.rc",
00501                                     componentData() )
00502                       );
00503   
00504   if ( m_notes.isEmpty() ) {
00505     return;
00506   }
00507   
00508   foreach ( QAction *action, ( *it )->actionCollection()->actions() ) {
00509     it = m_notes.begin();
00510     for ( ++it; it != m_notes.end(); ++it ) {
00511 /*
00512     // Not sure if this is what this message has in mind but since both
00513     // action->objectName() and KAction::action() are QStrings, this
00514     // might be fine.
00515     // Corrent me if I am wrong... ~ gamaral
00516 #ifdef __GNUC__
00517 #warning Port KAction::action() to QString
00518 #endif
00519 */
00520       QAction *toChange =
00521         ( *it )->actionCollection()->action( action->objectName() );
00522       
00523       if ( toChange ) {
00524         toChange->setShortcuts( action->shortcuts() );
00525       }
00526     }
00527   }
00528 }
00529 
00530 void KNotesApp::slotNoteKilled( KCal::Journal *journal )
00531 {
00532   m_manager->deleteNote( journal );
00533   saveNotes();
00534 }
00535 
00536 void KNotesApp::slotQuit()
00537 {
00538   foreach ( KNote *note, m_notes ) {
00539     if ( note->isModified() ) {
00540       note->saveData();
00541     }
00542   }
00543   
00544   saveConfigs();
00545   kapp->quit();
00546 }
00547 
00548 // -------------------- private methods -------------------- //
00549 
00550 void KNotesApp::showNote( KNote *note ) const
00551 {
00552   note->show();
00553 #ifdef Q_WS_X11
00554   KWindowSystem::setCurrentDesktop( KWindowSystem::windowInfo( note->winId(),
00555                                     NET::WMDesktop ).desktop() );
00556   KWindowSystem::forceActiveWindow( note->winId() );
00557 #endif
00558   note->setFocus();
00559 }
00560 
00561 void KNotesApp::createNote( KCal::Journal *journal )
00562 {
00563   KNote *newNote = new KNote( m_noteGUI, journal, 0 );
00564   m_notes.insert( newNote->noteId(), newNote );
00565   
00566   connect( newNote, SIGNAL( sigRequestNewNote() ),
00567            SLOT( newNote() ) );
00568   connect( newNote, SIGNAL( sigShowNextNote() ),
00569            SLOT( slotWalkThroughNotes() ) ) ;
00570   connect( newNote, SIGNAL( sigKillNote( KCal::Journal * ) ),
00571            SLOT( slotNoteKilled( KCal::Journal * ) ) );
00572   connect( newNote, SIGNAL( sigNameChanged() ),
00573            SLOT( updateNoteActions() ) );
00574   connect( newNote, SIGNAL( sigDataChanged() ),
00575            SLOT( saveNotes() ) );
00576   connect( newNote, SIGNAL( sigColorChanged() ),
00577            SLOT( updateNoteActions() ) );
00578   connect( newNote, SIGNAL( sigFindFinished() ),
00579            SLOT( slotFindNext() ) );
00580   
00581   // don't call this during startup for each and every loaded note
00582   if ( m_alarm ) {
00583     updateNoteActions();
00584   }
00585 }
00586 
00587 void KNotesApp::killNote( KCal::Journal *journal )
00588 {
00589   // this kills the KNote object
00590   delete m_notes.take( journal->uid() );
00591   updateNoteActions();
00592 }
00593 
00594 void KNotesApp::acceptConnection()
00595 {
00596   // Accept the connection and make KNotesNetworkReceiver do the job
00597   QTcpSocket *s = m_listener->nextPendingConnection();
00598   
00599   if ( s ) {
00600     KNotesNetworkReceiver *recv = new KNotesNetworkReceiver( s );
00601     connect( recv,
00602              SIGNAL( sigNoteReceived( const QString &, const QString & ) ),
00603              SLOT( newNote( const QString &, const QString & ) ) );
00604   }
00605 }
00606 
00607 void KNotesApp::saveNotes()
00608 {
00609   KNotesGlobalConfig::self()->writeConfig();
00610   m_manager->save();
00611 }
00612 
00613 void KNotesApp::saveConfigs()
00614 {
00615   foreach ( KNote *note, m_notes ) {
00616     note->saveConfig();
00617   }
00618 }
00619 
00620 void KNotesApp::updateNoteActions()
00621 {
00622   unplugActionList( "notes" );
00623   m_noteActions.clear();
00624 
00625   foreach ( KNote *note, m_notes ) {
00626     // what does this actually mean? ~gamaral
00627 #ifdef __GNUC__
00628 #warning utf8: use QString
00629 #endif
00630     KAction *action = new KAction( note->name().replace( "&", "&&" ), this );
00631         action->setObjectName( note->noteId() );
00632     connect( action, SIGNAL( triggered( bool ) ), SLOT( slotShowNote() ) );
00633     KIconEffect effect;
00634     QPixmap icon =
00635       effect.apply( qApp->windowIcon().pixmap( IconSize( KIconLoader::Small ),
00636                                                IconSize( KIconLoader::Small ) ),
00637                     KIconEffect::Colorize,
00638                     1,
00639                     note->palette().color( note->backgroundRole() ),
00640                     false );
00641     
00642     action->setIcon( icon );
00643     m_noteActions.append( action );
00644   }
00645   
00646     qSort( m_noteActions.begin(), m_noteActions.end(), qActionLessThan );
00647   
00648   if ( m_noteActions.isEmpty() ) {
00649     KAction *action = new KAction( i18n( "No Notes" ), this );
00650     m_noteActions.append( action );
00651   }
00652   
00653   plugActionList( "notes", m_noteActions );
00654 }
00655 
00656 void KNotesApp::updateNetworkListener()
00657 {
00658     delete m_listener;
00659     m_listener=0;
00660     
00661     if ( KNotesGlobalConfig::receiveNotes() ) {
00662         // create the socket and start listening for connections
00663         m_listener=KSocketFactory::listen( "knotes" , QHostAddress::Any,
00664                                            KNotesGlobalConfig::port() );
00665         connect( m_listener, SIGNAL( newConnection() ),
00666                  SLOT( acceptConnection() ) );
00667     }
00668 }
00669 
00670 void KNotesApp::updateStyle()
00671 {
00672 #ifdef __GNUC__
00673 #warning FIXME!
00674 #endif
00675   //    KNote::setStyle( KNotesGlobalConfig::style() );
00676   
00677   foreach ( KNote *note, m_notes ) {
00678     QApplication::postEvent( note, new QEvent( QEvent::LayoutRequest ) );
00679   }
00680 }
00681 
00682 #include "knotesapp.moc"

knotes

Skip menu "knotes"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members

kdepim

Skip menu "kdepim"
  • akonadi
  •   clients
  •   kabc
  •   kcal
  •   kcm
  • akregator
  • console
  •   kabcclient
  •   konsolekalendar
  • kaddressbook
  • kalarm
  •   lib
  • kdgantt
  • kdgantt1
  • kjots
  • kleopatra
  • kmail
  • kmobiletools
  • knode
  • knotes
  • kontact
  • kontactinterfaces
  • korganizer
  •   korgac
  • kpilot
  • ktimetracker
  •   doc
  • libkdepim
  • libkholidays
  • libkleo
  • libkpgp
  • maildir
Generated for kdepim by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal