kaddressbook

kabcore.cpp

00001 /*
00002     This file is part of KAddressbook.
00003     Copyright (c) 2003 - 2004 Tobias Koenig <tokoe@kde.org>
00004 
00005     This program is free software; you can redistribute it and/or modify
00006     it under the terms of the GNU General Public License as published by
00007     the Free Software Foundation; either version 2 of the License, or
00008     (at your option) any later version.
00009 
00010     This program is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00013     GNU General Public License for more details.
00014 
00015     You should have received a copy of the GNU General Public License
00016     along with this program; if not, write to the Free Software
00017     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00018 
00019     As a special exception, permission is given to link this program
00020     with any edition of Qt, and distribute the resulting executable,
00021     without including the source code for Qt in the source distribution.
00022 */
00023 
00024 // Needed for ugly hack, to be removed in 4.0
00025 #include <unistd.h> // for usleep
00026 #include <qeventloop.h>
00027 
00028 #include <qclipboard.h>
00029 #include <qdir.h>
00030 #include <qfile.h>
00031 #include <qlabel.h>
00032 #include <qlayout.h>
00033 #include <qptrlist.h>
00034 #include <qwidgetstack.h>
00035 #include <qregexp.h>
00036 #include <qvbox.h>
00037 
00038 #include <kabc/addresseelist.h>
00039 #include <kabc/errorhandler.h>
00040 #include <kabc/resource.h>
00041 #include <kabc/stdaddressbook.h>
00042 #include <kabc/vcardconverter.h>
00043 #include <kabc/resourcefile.h>
00044 #include <kaboutdata.h>
00045 #include <kaccelmanager.h>
00046 #include <kapplication.h>
00047 #include <dcopclient.h>
00048 #include <kactionclasses.h>
00049 #include <kcmdlineargs.h>
00050 #include <kcmultidialog.h>
00051 #include <kdebug.h>
00052 #include <kdeversion.h>
00053 #include <kimproxy.h>
00054 #include <klocale.h>
00055 #include <kmessagebox.h>
00056 #include <kprinter.h>
00057 #include <kprotocolinfo.h>
00058 #include <kpushbutton.h>
00059 #include <kresources/selectdialog.h>
00060 #include <kstandarddirs.h>
00061 #include <kstatusbar.h>
00062 #include <kstdguiitem.h>
00063 #include <kxmlguiclient.h>
00064 #include <ktoolbar.h>
00065 #include <libkdepim/addresseeview.h>
00066 #include <libkdepim/categoryeditdialog.h>
00067 #include <libkdepim/categoryselectdialog.h>
00068 #include <libkdepim/resourceabc.h>
00069 #include "distributionlisteditor.h"
00070 
00071 #include "addresseeutil.h"
00072 #include "addresseeeditordialog.h"
00073 #include "distributionlistentryview.h"
00074 #include "extensionmanager.h"
00075 #include "filterselectionwidget.h"
00076 #include "incsearchwidget.h"
00077 #include "jumpbuttonbar.h"
00078 #include "kablock.h"
00079 #include "kabprefs.h"
00080 #include "kabtools.h"
00081 #include "kaddressbookservice.h"
00082 #include "kaddressbookiface.h"
00083 #include "ldapsearchdialog.h"
00084 #include "locationmap.h"
00085 #include "printing/printingwizard.h"
00086 #include "searchmanager.h"
00087 #include "undocmds.h"
00088 #include "viewmanager.h"
00089 #include "xxportmanager.h"
00090 
00091 #include "kabcore.h"
00092 
00093 KABCore::KABCore( KXMLGUIClient *client, bool readWrite, QWidget *parent,
00094                   const QString &file, const char *name )
00095   : KAB::Core( client, parent, name ), mStatusBar( 0 ), mViewManager( 0 ),
00096     mExtensionManager( 0 ), mJumpButtonBar( 0 ), mCategorySelectDialog( 0 ),
00097     mCategoryEditDialog( 0 ), mLdapSearchDialog( 0 ), mReadWrite( readWrite ),
00098     mModified( false )
00099 {
00100   mWidget = new QWidget( parent, name );
00101 
00102   mIsPart = !parent->isA( "KAddressBookMain" );
00103 
00104   mAddressBookChangedTimer = new QTimer( this );
00105   connect( mAddressBookChangedTimer, SIGNAL( timeout() ),
00106            this, SLOT( addressBookChanged() ) );
00107 
00108   if ( file.isEmpty() ) {
00109     mAddressBook = KABC::StdAddressBook::self( true );
00110   } else {
00111     kdDebug(5720) << "KABCore(): document '" << file << "'" << endl;
00112     mAddressBook = new KABC::AddressBook;
00113     mAddressBook->addResource( new KABC::ResourceFile( file ) );
00114     if ( !mAddressBook->load() ) {
00115       KMessageBox::error( parent, i18n("Unable to load '%1'.").arg( file ) );
00116     }
00117   }
00118   mAddressBook->setErrorHandler( new KABC::GuiErrorHandler( mWidget ) );
00119 
00120 #if ! KDE_IS_VERSION(3,5,8)
00121   mAddressBook->addCustomField( i18n( "Department" ), KABC::Field::Organization,
00122                                 "X-Department", "KADDRESSBOOK" );
00123 #endif
00124   mAddressBook->addCustomField( i18n( "Profession" ), KABC::Field::Organization,
00125                                 "X-Profession", "KADDRESSBOOK" );
00126   mAddressBook->addCustomField( i18n( "Assistant's Name" ), KABC::Field::Organization,
00127                                 "X-AssistantsName", "KADDRESSBOOK" );
00128   mAddressBook->addCustomField( i18n( "Manager's Name" ), KABC::Field::Organization,
00129                                 "X-ManagersName", "KADDRESSBOOK" );
00130   mAddressBook->addCustomField( i18n( "Partner's Name" ), KABC::Field::Personal,
00131                                 "X-SpousesName", "KADDRESSBOOK" );
00132   mAddressBook->addCustomField( i18n( "Office" ), KABC::Field::Personal,
00133                                 "X-Office", "KADDRESSBOOK" );
00134   mAddressBook->addCustomField( i18n( "IM Address" ), KABC::Field::Personal,
00135                                 "X-IMAddress", "KADDRESSBOOK" );
00136   mAddressBook->addCustomField( i18n( "Anniversary" ), KABC::Field::Personal,
00137                                 "X-Anniversary", "KADDRESSBOOK" );
00138   mAddressBook->addCustomField( i18n( "Blog" ), KABC::Field::Personal,
00139                                 "BlogFeed", "KADDRESSBOOK" );
00140 
00141   mSearchManager = new KAB::SearchManager( mAddressBook, parent );
00142 
00143   connect( mSearchManager, SIGNAL( contactsUpdated() ),
00144            this, SLOT( slotContactsUpdated() ) );
00145 
00146   initGUI();
00147 
00148   connect( mAddressBook, SIGNAL( addressBookChanged( AddressBook* ) ),
00149            SLOT( delayedAddressBookChanged() ) );
00150   connect( mAddressBook, SIGNAL( loadingFinished( Resource* ) ),
00151            SLOT( delayedAddressBookChanged() ) );
00152 
00153   mIncSearchWidget->setFocus();
00154 
00155   connect( mViewManager, SIGNAL( selected( const QString& ) ),
00156            SLOT( setContactSelected( const QString& ) ) );
00157   connect( mViewManager, SIGNAL( executed( const QString& ) ),
00158            SLOT( editContact( const QString& ) ) );
00159   connect( mViewManager, SIGNAL( modified() ),
00160            SLOT( setModified() ) );
00161   connect( mViewManager, SIGNAL( urlDropped( const KURL& ) ),
00162            mXXPortManager, SLOT( importVCard( const KURL& ) ) );
00163   connect( mViewManager, SIGNAL( viewFieldsChanged() ),
00164            SLOT( updateIncSearchWidget() ) );
00165   connect( mExtensionManager, SIGNAL( modified( const KABC::Addressee::List& ) ),
00166            this, SLOT( extensionModified( const KABC::Addressee::List& ) ) );
00167   connect( mExtensionManager, SIGNAL( deleted( const QStringList& ) ),
00168            this, SLOT( extensionDeleted( const QStringList& ) ) );
00169 
00170   connect( mXXPortManager, SIGNAL( modified() ),
00171            SLOT( setModified() ) );
00172 
00173   connect( mDetailsViewer, SIGNAL( highlightedMessage( const QString& ) ),
00174            SLOT( detailsHighlighted( const QString& ) ) );
00175 
00176   connect( mIncSearchWidget, SIGNAL( scrollUp() ),
00177            mViewManager, SLOT( scrollUp() ) );
00178   connect( mIncSearchWidget, SIGNAL( scrollDown() ),
00179            mViewManager, SLOT( scrollDown() ) );
00180 
00181   mAddressBookService = new KAddressBookService( this );
00182 
00183   mCommandHistory = new KCommandHistory( actionCollection(), true );
00184   connect( mCommandHistory, SIGNAL( commandExecuted() ),
00185            mSearchManager, SLOT( reload() ) );
00186 
00187   mSearchManager->reload();
00188 
00189   setModified( false );
00190 
00191   KAcceleratorManager::manage( mWidget );
00192 
00193   mKIMProxy = ::KIMProxy::instance( kapp->dcopClient() );
00194 }
00195 
00196 KABCore::~KABCore()
00197 {
00198   mAddressBook->disconnect();
00199 
00200   mAddressBook = 0;
00201   KABC::StdAddressBook::close();
00202   mKIMProxy = 0;
00203 }
00204 
00205 void KABCore::restoreSettings()
00206 {
00207   bool state = KABPrefs::instance()->jumpButtonBarVisible();
00208   mActionJumpBar->setChecked( state );
00209   setJumpButtonBarVisible( state );
00210 
00211   state = KABPrefs::instance()->detailsPageVisible();
00212   mActionDetails->setChecked( state );
00213   setDetailsVisible( state );
00214 
00215   mViewManager->restoreSettings();
00216   mExtensionManager->restoreSettings();
00217 
00218   updateIncSearchWidget();
00219   mIncSearchWidget->setCurrentItem( KABPrefs::instance()->currentIncSearchField() );
00220 
00221   QValueList<int> splitterSize = KABPrefs::instance()->detailsSplitter();
00222   if ( splitterSize.count() == 0 ) {
00223     splitterSize.append( 360 );
00224     splitterSize.append( 260 );
00225   }
00226   mDetailsSplitter->setSizes( splitterSize );
00227 
00228   const QValueList<int> leftSplitterSizes = KABPrefs::instance()->leftSplitter();
00229   if ( !leftSplitterSizes.isEmpty() )
00230       mLeftSplitter->setSizes( leftSplitterSizes );
00231 }
00232 
00233 void KABCore::saveSettings()
00234 {
00235   KABPrefs::instance()->setJumpButtonBarVisible( mActionJumpBar->isChecked() );
00236   KABPrefs::instance()->setDetailsPageVisible( mActionDetails->isChecked() );
00237   KABPrefs::instance()->setDetailsSplitter( mDetailsSplitter->sizes() );
00238   KABPrefs::instance()->setLeftSplitter( mLeftSplitter->sizes() );
00239 
00240   mExtensionManager->saveSettings();
00241   mViewManager->saveSettings();
00242 
00243   KABPrefs::instance()->setCurrentIncSearchField( mIncSearchWidget->currentItem() );
00244 }
00245 
00246 KABC::AddressBook *KABCore::addressBook() const
00247 {
00248   return mAddressBook;
00249 }
00250 
00251 KConfig *KABCore::config() const
00252 {
00253   return KABPrefs::instance()->config();
00254 }
00255 
00256 KActionCollection *KABCore::actionCollection() const
00257 {
00258   return guiClient()->actionCollection();
00259 }
00260 
00261 KABC::Field *KABCore::currentSortField() const
00262 {
00263   return mViewManager->currentSortField();
00264 }
00265 
00266 QStringList KABCore::selectedUIDs() const
00267 {
00268   return mViewManager->selectedUids();
00269 }
00270 
00271 KABC::Resource *KABCore::requestResource( QWidget *parent )
00272 {
00273   QPtrList<KABC::Resource> kabcResources = addressBook()->resources();
00274 
00275   QPtrList<KRES::Resource> kresResources;
00276   QPtrListIterator<KABC::Resource> resIt( kabcResources );
00277   KABC::Resource *resource;
00278   while ( ( resource = resIt.current() ) != 0 ) {
00279     ++resIt;
00280     if ( !resource->readOnly() ) {
00281       KRES::Resource *res = resource; // downcast
00282       kresResources.append( res );
00283     }
00284   }
00285 
00286   KRES::Resource *res = KRES::SelectDialog::getResource( kresResources, parent );
00287   return static_cast<KABC::Resource*>( res ); // upcast
00288 }
00289 
00290 QWidget *KABCore::widget() const
00291 {
00292   return mWidget;
00293 }
00294 
00295 KAboutData *KABCore::createAboutData()
00296 {
00297   KAboutData *about = new KAboutData( "kaddressbook", I18N_NOOP( "KAddressBook" ),
00298                                       "3.5.10", I18N_NOOP( "The KDE Address Book" ),
00299                                       KAboutData::License_GPL_V2,
00300                                       I18N_NOOP( "(c) 1997-2005, The KDE PIM Team" ) );
00301   about->addAuthor( "Tobias Koenig", I18N_NOOP( "Current maintainer" ), "tokoe@kde.org" );
00302   about->addAuthor( "Don Sanders", I18N_NOOP( "Original author" ) );
00303   about->addAuthor( "Cornelius Schumacher",
00304                     I18N_NOOP( "Co-maintainer, libkabc port, CSV import/export" ),
00305                     "schumacher@kde.org" );
00306   about->addAuthor( "Mike Pilone", I18N_NOOP( "GUI and framework redesign" ),
00307                     "mpilone@slac.com" );
00308   about->addAuthor( "Greg Stern", I18N_NOOP( "DCOP interface" ) );
00309   about->addAuthor( "Mark Westcott", I18N_NOOP( "Contact pinning" ) );
00310   about->addAuthor( "Mischel Boyer de la Giroday", I18N_NOOP( "LDAP Lookup" ),
00311                     "michel@klaralvdalens-datakonsult.se" );
00312   about->addAuthor( "Steffen Hansen", I18N_NOOP( "LDAP Lookup" ),
00313                     "hansen@kde.org" );
00314 
00315   return about;
00316 }
00317 
00318 void KABCore::setStatusBar( KStatusBar *statusBar )
00319 {
00320   mStatusBar = statusBar;
00321 }
00322 
00323 KStatusBar *KABCore::statusBar() const
00324 {
00325   return mStatusBar;
00326 }
00327 
00328 void KABCore::setContactSelected( const QString &uid )
00329 {
00330   KABC::Addressee addr = mAddressBook->findByUid( uid );
00331   if ( !mDetailsViewer->isHidden() )
00332     mDetailsViewer->setAddressee( addr );
00333 #ifdef KDEPIM_NEW_DISTRLISTS
00334   if ( !mSelectedDistributionList.isNull() && mDistListEntryView->isShown() ) {
00335       showDistributionListEntry( uid );
00336   }
00337 #endif
00338   mExtensionManager->setSelectionChanged();
00339 
00340   KABC::Addressee::List list = mViewManager->selectedAddressees();
00341   const bool someSelected = list.size() > 0;
00342   const bool singleSelected = list.size() == 1;
00343   bool writable = mReadWrite;
00344 
00345   if ( writable ) {
00346     //check if every single (sub)resource is writable
00347     //### We have a performance problem here - everytime *one* item is added or
00348     //    removed we re-check *all* items. If this turns out to be a bottleneck
00349     //    we need to keep some state and check new items only.
00350     KABC::Addressee::List::ConstIterator addrIt = list.constBegin();
00351     for ( ; addrIt != list.constEnd(); ++addrIt ) {
00352       KABC::Resource *res = ( *addrIt ).resource();
00353       if ( !res ) {
00354         kdDebug() << "KABCore::setContactSelected: this addressee has no resource!" << endl;
00355         writable = false;
00356         break;
00357       }
00358       if ( res->readOnly() ) {
00359         writable = false;
00360         break;
00361       }
00362       //HACK: manual polymorphism
00363       if ( res->inherits( "KPIM::ResourceABC" ) ) {
00364         KPIM::ResourceABC *resAbc = static_cast<KPIM::ResourceABC *>( res );
00365 
00366         QString subresource = resAbc->uidToResourceMap()[ ( *addrIt ).uid() ];
00367         if ( !subresource.isEmpty() && !resAbc->subresourceWritable( subresource ) ) {
00368           writable = false;
00369           break;
00370         }
00371       }
00372     }
00373   }
00374 
00375   bool moreThanOneResource = mAddressBook->resources().count() > 1;
00376   if ( !moreThanOneResource && !mAddressBook->resources().isEmpty() ) {
00377       KABC::Resource *res = mAddressBook->resources().first();
00378       if ( res->inherits( "KPIM::ResourceABC" ) ) {
00379         KPIM::ResourceABC *resAbc = static_cast<KPIM::ResourceABC *>( res );
00380         const QStringList subresources = resAbc->subresources();
00381         int writeables = 0;
00382         for ( QStringList::ConstIterator it = subresources.begin(); it != subresources.end(); ++it ) {
00383             if ( resAbc->subresourceActive(*it) && resAbc->subresourceWritable(*it) ) {
00384                 writeables++;
00385             }
00386         }
00387         moreThanOneResource = ( writeables >= 2 );
00388       }
00389   }
00390 
00391   // update the actions
00392 
00393   mActionCopy->setEnabled( someSelected );
00394   mActionCut->setEnabled( someSelected && writable );
00395   mActionDelete->setEnabled( someSelected && writable );
00396   // the "edit" dialog doubles as the details dialog and it knows when the addressee is read-only
00397   // (### this does not make much sense from the user perspective!)
00398   mActionEditAddressee->setEnabled( singleSelected && !mExtensionManager->isQuickEditVisible());
00399   mActionCopyAddresseeTo->setEnabled( someSelected && moreThanOneResource );
00400   mActionMoveAddresseeTo->setEnabled( someSelected && moreThanOneResource && writable );
00401   mActionMail->setEnabled( someSelected );
00402   mActionMailVCard->setEnabled( someSelected );
00403   mActionChat->setEnabled( singleSelected && mKIMProxy && mKIMProxy->initialize() );
00404   mActionWhoAmI->setEnabled( singleSelected );
00405   mActionCategories->setEnabled( someSelected && writable );
00406   mActionMerge->setEnabled( ( list.size() == 2 ) && writable );
00407 
00408   if ( mReadWrite ) {
00409     QClipboard *cb = QApplication::clipboard();
00410     list = AddresseeUtil::clipboardToAddressees( cb->text() );
00411     mActionPaste->setEnabled( !list.isEmpty() );
00412   }
00413 }
00414 
00415 void KABCore::sendMail()
00416 {
00417   //FIXME: breaks with email addresses containing ","
00418   sendMail( mViewManager->selectedEmails().join( ", " ) );
00419 }
00420 
00421 void KABCore::sendMail( const QString& email )
00422 {
00423   kapp->invokeMailer( email, "" );
00424 }
00425 
00426 void KABCore::mailVCard()
00427 {
00428   QStringList uids = mViewManager->selectedUids();
00429   if ( !uids.isEmpty() )
00430     mailVCard( uids );
00431 }
00432 
00433 void KABCore::mailVCard( const QStringList &uids )
00434 {
00435   KABTools::mailVCards( uids, mAddressBook );
00436 }
00437 
00438 void KABCore::startChat()
00439 {
00440   QStringList uids = mViewManager->selectedUids();
00441   if ( !uids.isEmpty() )
00442     mKIMProxy->chatWithContact( uids.first() );
00443 }
00444 
00445 void KABCore::browse( const QString& url )
00446 {
00447   kapp->invokeBrowser( url );
00448 }
00449 
00450 void KABCore::selectAllContacts()
00451 {
00452   mViewManager->setSelected( QString::null, true );
00453 }
00454 
00455 void KABCore::deleteContacts()
00456 {
00457   QStringList uidList = mViewManager->selectedUids();
00458 
00459   deleteContacts( uidList );
00460 }
00461 
00462 void KABCore::deleteDistributionLists( const QStringList & names )
00463 {
00464   if ( names.isEmpty() )
00465       return;
00466   if ( KMessageBox::warningContinueCancelList( mWidget, i18n( "Do you really want to delete this distribution list?",
00467                                                  "Do you really want to delete these %n distribution lists?", names.count() ),
00468                                                  names, QString::null, KStdGuiItem::del() ) == KMessageBox::Cancel )
00469    return;
00470 
00471   QStringList uids;
00472   for ( QStringList::ConstIterator it = names.begin(); it != names.end(); ++it ) {
00473       uids.append( KPIM::DistributionList::findByName( mAddressBook, *it ).uid() );
00474   }
00475   DeleteCommand *command = new DeleteCommand( mAddressBook, uids );
00476   mCommandHistory->addCommand( command );
00477   setModified( true );
00478 }
00479 
00480 void KABCore::deleteContacts( const QStringList &uids )
00481 {
00482   if ( uids.count() > 0 ) {
00483     QStringList names;
00484     QStringList::ConstIterator it = uids.begin();
00485     const QStringList::ConstIterator endIt( uids.end() );
00486     while ( it != endIt ) {
00487       KABC::Addressee addr = mAddressBook->findByUid( *it );
00488       names.append( addr.realName().isEmpty() ? addr.preferredEmail() : addr.realName() );
00489       ++it;
00490     }
00491 
00492     if ( KMessageBox::warningContinueCancelList( mWidget, i18n( "Do you really want to delete this contact?",
00493                                                  "Do you really want to delete these %n contacts?", uids.count() ),
00494                                                  names, QString::null, KStdGuiItem::del() ) == KMessageBox::Cancel )
00495       return;
00496 
00497     DeleteCommand *command = new DeleteCommand( mAddressBook, uids );
00498     mCommandHistory->addCommand( command );
00499 
00500     // now if we deleted anything, refresh
00501     setContactSelected( QString::null );
00502     setModified( true );
00503   }
00504 }
00505 
00506 void KABCore::copyContacts()
00507 {
00508   KABC::Addressee::List addrList = mViewManager->selectedAddressees();
00509 
00510   QString clipText = AddresseeUtil::addresseesToClipboard( addrList );
00511 
00512   kdDebug(5720) << "KABCore::copyContacts: " << clipText << endl;
00513 
00514   QClipboard *cb = QApplication::clipboard();
00515   cb->setText( clipText );
00516 }
00517 
00518 void KABCore::cutContacts()
00519 {
00520   QStringList uidList = mViewManager->selectedUids();
00521 
00522   if ( uidList.size() > 0 ) {
00523     CutCommand *command = new CutCommand( mAddressBook, uidList );
00524     mCommandHistory->addCommand( command );
00525 
00526     setModified( true );
00527   }
00528 }
00529 
00530 void KABCore::pasteContacts()
00531 {
00532   QClipboard *cb = QApplication::clipboard();
00533 
00534   KABC::Addressee::List list = AddresseeUtil::clipboardToAddressees( cb->text() );
00535 
00536   pasteContacts( list );
00537 }
00538 
00539 void KABCore::pasteContacts( KABC::Addressee::List &list )
00540 {
00541   KABC::Resource *resource = requestResource( mWidget );
00542   if ( !resource )
00543     return;
00544 
00545   KABC::Addressee::List::Iterator it;
00546   const KABC::Addressee::List::Iterator endIt( list.end() );
00547   for ( it = list.begin(); it != endIt; ++it )
00548     (*it).setResource( resource );
00549 
00550   PasteCommand *command = new PasteCommand( this, list );
00551   mCommandHistory->addCommand( command );
00552 
00553   setModified( true );
00554 }
00555 
00556 void KABCore::mergeContacts()
00557 {
00558   KABC::Addressee::List list = mViewManager->selectedAddressees();
00559   if ( list.count() < 2 )
00560     return;
00561 
00562   KABC::Addressee addr = KABTools::mergeContacts( list );
00563 
00564   KABC::Addressee::List::Iterator it = list.begin();
00565   const KABC::Addressee::List::Iterator endIt( list.end() );
00566   KABC::Addressee origAddr = *it;
00567   QStringList uids;
00568   ++it;
00569   while ( it != endIt ) {
00570     uids.append( (*it).uid() );
00571     ++it;
00572   }
00573 
00574   DeleteCommand *command = new DeleteCommand( mAddressBook, uids );
00575   mCommandHistory->addCommand( command );
00576 
00577   EditCommand *editCommand = new EditCommand( mAddressBook, origAddr, addr );
00578   mCommandHistory->addCommand( editCommand );
00579 
00580   mSearchManager->reload();
00581 }
00582 
00583 void KABCore::setWhoAmI()
00584 {
00585   KABC::Addressee::List addrList = mViewManager->selectedAddressees();
00586 
00587   if ( addrList.count() > 1 ) {
00588     // can probably be removed because we now check the selection in setContactSelected().
00589     KMessageBox::sorry( mWidget, i18n( "Please select only one contact." ) );
00590     return;
00591   }
00592 
00593   QString text( i18n( "<qt>Do you really want to use <b>%1</b> as your new personal contact?</qt>" ) );
00594   if ( KMessageBox::questionYesNo( mWidget, text.arg( addrList[ 0 ].assembledName() ), QString::null, i18n("Use"), i18n("Do Not Use") ) == KMessageBox::Yes )
00595     static_cast<KABC::StdAddressBook*>( KABC::StdAddressBook::self( true ) )->setWhoAmI( addrList[ 0 ] );
00596 }
00597 
00598 void KABCore::incrementalTextSearch( const QString& text )
00599 {
00600   setContactSelected( QString::null );
00601   mSearchManager->search( text, mIncSearchWidget->currentFields() );
00602 }
00603 
00604 void KABCore::incrementalJumpButtonSearch( const QString& character )
00605 {
00606   mViewManager->setSelected( QString::null, false );
00607 
00608   KABC::AddresseeList list = mSearchManager->contacts();
00609   KABC::Field *field = mViewManager->currentSortField();
00610   if ( field ) {
00611     list.sortByField( field );
00612     KABC::AddresseeList::ConstIterator it;
00613     const KABC::AddresseeList::ConstIterator endIt( list.end() );
00614     for ( it = list.begin(); it != endIt; ++it ) {
00615       if ( field->value( *it ).startsWith( character, false ) ) {
00616         mViewManager->setSelected( (*it).uid(), true );
00617         return;
00618       }
00619     }
00620   }
00621 }
00622 
00623 void KABCore::setModified()
00624 {
00625   setModified( true );
00626 }
00627 
00628 void KABCore::setModified( bool modified )
00629 {
00630   mModified = modified;
00631   mActionSave->setEnabled( mModified );
00632 
00633   mSearchManager->reload();
00634 }
00635 
00636 bool KABCore::modified() const
00637 {
00638   return mModified;
00639 }
00640 
00641 void KABCore::contactModified( const KABC::Addressee &addr )
00642 {
00643   Command *command = 0;
00644 
00645   // check if it exists already
00646   KABC::Addressee origAddr = mAddressBook->findByUid( addr.uid() );
00647   if ( origAddr.isEmpty() ) {
00648     KABC::Addressee::List addressees;
00649     addressees.append( addr );
00650     command = new NewCommand( mAddressBook, addressees );
00651   } else {
00652     command = new EditCommand( mAddressBook, origAddr, addr );
00653   }
00654 
00655   mCommandHistory->addCommand( command );
00656 
00657   setContactSelected( addr.uid() );
00658   setModified( true );
00659 }
00660 
00661 void KABCore::newDistributionList()
00662 {
00663 #ifdef KDEPIM_NEW_DISTRLISTS
00664   KABC::Resource *resource = requestResource( mWidget );
00665   if ( !resource )
00666     return;
00667 
00668   QString name = i18n( "New Distribution List" );
00669   const KPIM::DistributionList distList = KPIM::DistributionList::findByName( addressBook(), name );
00670   if ( !distList.isEmpty() ) {
00671     bool foundUnused = false;
00672     int i = 1;
00673     while ( !foundUnused ) {
00674       name = i18n( "New Distribution List (%1)" ).arg( i++ );
00675       foundUnused = KPIM::DistributionList::findByName( addressBook(), name ).isEmpty();
00676     }
00677   }
00678   KPIM::DistributionList list;
00679   list.setUid( KApplication::randomString( 10 ) );
00680   list.setName( name );
00681   list.setResource( resource );
00682   editDistributionList( list );
00683 #endif
00684 }
00685 
00686 void KABCore::newContact()
00687 {
00688   AddresseeEditorDialog *dialog = 0;
00689 
00690   KABC::Resource* resource = requestResource( mWidget );
00691 
00692   if ( resource ) {
00693     KABC::Addressee addr;
00694     addr.setResource( resource );
00695 
00696     if ( !KABLock::self( mAddressBook )->lock( addr.resource() ) )
00697       return;
00698 
00699     dialog = createAddresseeEditorDialog( mWidget );
00700     dialog->setAddressee( addr );
00701   } else
00702     return;
00703 
00704   mEditorDict.insert( dialog->addressee().uid(), dialog );
00705 
00706   dialog->show();
00707 }
00708 
00709 void KABCore::addEmail( const QString &aStr )
00710 {
00711   QString fullName, email;
00712 
00713   KABC::Addressee::parseEmailAddress( aStr, fullName, email );
00714 
00715 #if KDE_IS_VERSION(3,4,89)
00716   // This ugly hack will be removed in 4.0
00717   // addressbook may not be reloaded yet, as done asynchronously sometimes, so wait
00718   while ( !mAddressBook->loadingHasFinished() ) {
00719     QApplication::eventLoop()->processEvents( QEventLoop::ExcludeUserInput );
00720     // use sleep here to reduce cpu usage
00721     usleep( 100 );
00722   }
00723 #endif
00724 
00725   // Try to lookup the addressee matching the email address
00726   bool found = false;
00727   QStringList emailList;
00728   KABC::AddressBook::Iterator it;
00729   const KABC::AddressBook::Iterator endIt( mAddressBook->end() );
00730   for ( it = mAddressBook->begin(); !found && (it != endIt); ++it ) {
00731     emailList = (*it).emails();
00732     if ( emailList.contains( email ) > 0 ) {
00733       found = true;
00734       (*it).setNameFromString( fullName );
00735       editContact( (*it).uid() );
00736     }
00737   }
00738 
00739   if ( !found ) {
00740     KABC::Addressee addr;
00741     addr.setNameFromString( fullName );
00742     addr.insertEmail( email, true );
00743 
00744     mAddressBook->insertAddressee( addr );
00745     mViewManager->refreshView( addr.uid() );
00746     editContact( addr.uid() );
00747   }
00748 }
00749 
00750 void KABCore::importVCard( const KURL &url )
00751 {
00752   mXXPortManager->importVCard( url );
00753 }
00754 
00755 void KABCore::importVCardFromData( const QString &vCard )
00756 {
00757   mXXPortManager->importVCardFromData( vCard );
00758 }
00759 
00760 void KABCore::editContact( const QString &uid )
00761 {
00762   if ( mExtensionManager->isQuickEditVisible() )
00763     return;
00764 
00765   // First, locate the contact entry
00766   QString localUID = uid;
00767   if ( localUID.isNull() ) {
00768     QStringList uidList = mViewManager->selectedUids();
00769     if ( uidList.count() > 0 )
00770       localUID = *( uidList.at( 0 ) );
00771   }
00772 #if KDE_IS_VERSION(3,4,89)
00773   // This ugly hack will be removed in 4.0
00774   // for calls with given uid, as done from commandline and DCOP
00775   // addressbook may not be reloaded yet, as done asynchronously, so wait
00776   else while ( !mAddressBook->loadingHasFinished() ) {
00777     QApplication::eventLoop()->processEvents( QEventLoop::ExcludeUserInput );
00778     // use sleep here to reduce cpu usage
00779     usleep( 100 );
00780   }
00781 #endif
00782 
00783   KABC::Addressee addr = mAddressBook->findByUid( localUID );
00784   if ( !addr.isEmpty() ) {
00785     AddresseeEditorDialog *dialog = mEditorDict.find( addr.uid() );
00786     if ( !dialog ) {
00787 
00788       if ( !addr.resource()->readOnly() )
00789         if ( !KABLock::self( mAddressBook )->lock( addr.resource() ) ) {
00790           return;
00791         }
00792 
00793       dialog = createAddresseeEditorDialog( mWidget );
00794 
00795       mEditorDict.insert( addr.uid(), dialog );
00796 
00797       dialog->setAddressee( addr );
00798     }
00799 
00800     dialog->raise();
00801     dialog->show();
00802   }
00803 }
00804 
00805 
00806 void KABCore::copySelectedContactToResource()
00807 {
00808     storeContactIn( QString(), true /*copy*/);
00809 }
00810 
00811 void KABCore::moveSelectedContactToResource()
00812 {
00813     storeContactIn( QString(), false /*copy*/);
00814 }
00815 
00816 void KABCore::storeContactIn( const QString &uid, bool copy /*false*/ )
00817 {
00818   // First, locate the contact entry
00819   QStringList uidList;
00820   if ( uid.isNull() ) {
00821     uidList = mViewManager->selectedUids();
00822   } else {
00823     uidList << uid;
00824   }
00825   KABC::Resource *resource = requestResource( mWidget );
00826   if ( !resource )
00827     return;
00828 
00829   if ( copy ) {
00830     CopyToCommand *command = new CopyToCommand( mAddressBook, uidList, resource );
00831     mCommandHistory->addCommand( command );
00832   }
00833   else {
00834     MoveToCommand *command = new MoveToCommand( this, uidList, resource );
00835     mCommandHistory->addCommand( command );
00836   }
00837 
00838   addressBookChanged();
00839   setModified( true );
00840 }
00841 
00842 void KABCore::save()
00843 {
00844   QPtrList<KABC::Resource> resources = mAddressBook->resources();
00845   QPtrListIterator<KABC::Resource> it( resources );
00846   while ( it.current() && !it.current()->readOnly() ) {
00847     KABC::Ticket *ticket = mAddressBook->requestSaveTicket( it.current() );
00848     if ( ticket ) {
00849       if ( !mAddressBook->save( ticket ) ) {
00850         KMessageBox::error( mWidget,
00851                             i18n( "<qt>Unable to save address book <b>%1</b>.</qt>" ).arg( it.current()->resourceName() ) );
00852         mAddressBook->releaseSaveTicket( ticket );
00853       } else {
00854         setModified( false );
00855       }
00856     } else {
00857       KMessageBox::error( mWidget,
00858                           i18n( "<qt>Unable to get access for saving the address book <b>%1</b>.</qt>" )
00859                           .arg( it.current()->resourceName() ) );
00860     }
00861 
00862     ++it;
00863   }
00864 }
00865 
00866 void KABCore::setJumpButtonBarVisible( bool visible )
00867 {
00868   if ( visible ) {
00869     if ( !mJumpButtonBar )
00870       createJumpButtonBar();
00871     mJumpButtonBar->show();
00872   } else
00873     if ( mJumpButtonBar )
00874       mJumpButtonBar->hide();
00875 }
00876 
00877 void KABCore::setDetailsVisible( bool visible )
00878 {
00879   if ( visible )
00880     mDetailsPage->show();
00881   else
00882     mDetailsPage->hide();
00883 }
00884 
00885 void KABCore::extensionModified( const KABC::Addressee::List &list )
00886 {
00887   if ( list.count() != 0 ) {
00888     KABC::Addressee::List::ConstIterator it;
00889     const KABC::Addressee::List::ConstIterator endIt( list.end() );
00890     for ( it = list.begin(); it != endIt; ++it ) {
00891       Command *command = 0;
00892 
00893       // check if it exists already
00894       KABC::Addressee origAddr = mAddressBook->findByUid( (*it).uid() );
00895       if ( origAddr.isEmpty() ) {
00896         KABC::Addressee::List addressees;
00897         addressees.append( *it );
00898         command = new NewCommand( mAddressBook, addressees );
00899       } else
00900         command = new EditCommand( mAddressBook, origAddr, *it );
00901 
00902       mCommandHistory->blockSignals( true );
00903       mCommandHistory->addCommand( command );
00904       mCommandHistory->blockSignals( false );
00905     }
00906 
00907     setModified(true);
00908   }
00909 }
00910 
00911 void KABCore::extensionDeleted( const QStringList &uidList )
00912 {
00913   DeleteCommand *command = new DeleteCommand( mAddressBook, uidList );
00914   mCommandHistory->addCommand( command );
00915 
00916   // now if we deleted anything, refresh
00917   setContactSelected( QString::null );
00918   setModified( true );
00919 }
00920 
00921 QString KABCore::getNameByPhone( const QString &phone )
00922 {
00923 #if KDE_IS_VERSION(3,4,89)
00924   // This ugly hack will be removed in 4.0
00925   // addressbook may not be reloaded yet, as done asynchronously, so wait
00926   while ( !mAddressBook->loadingHasFinished() ) {
00927     QApplication::eventLoop()->processEvents( QEventLoop::ExcludeUserInput );
00928     // use sleep here to reduce cpu usage
00929     usleep( 100 );
00930   }
00931 #endif
00932 
00933   QRegExp r( "[/*/-/ ]" );
00934   QString localPhone( phone );
00935 
00936   bool found = false;
00937   QString ownerName = "";
00938   KABC::PhoneNumber::List phoneList;
00939 
00940   KABC::AddressBook::ConstIterator iter;
00941   const KABC::AddressBook::ConstIterator endIter( mAddressBook->end() );
00942 
00943   for ( iter = mAddressBook->begin(); !found && ( iter != endIter ); ++iter ) {
00944     phoneList = (*iter).phoneNumbers();
00945     KABC::PhoneNumber::List::Iterator phoneIter( phoneList.begin() );
00946     const KABC::PhoneNumber::List::Iterator phoneEndIter( phoneList.end() );
00947     for ( ; !found && ( phoneIter != phoneEndIter ); ++phoneIter) {
00948       // Get rid of separator chars so just the numbers are compared.
00949       if ( (*phoneIter).number().replace( r, "" ) == localPhone.replace( r, "" ) ) {
00950         ownerName = (*iter).realName();
00951         found = true;
00952       }
00953     }
00954   }
00955 
00956   return ownerName;
00957 }
00958 
00959 void KABCore::openLDAPDialog()
00960 {
00961   if ( !KProtocolInfo::isKnownProtocol( KURL( "ldap://localhost" ) ) ) {
00962     KMessageBox::error( mWidget, i18n( "Your KDE installation is missing LDAP "
00963                                        "support, please ask your administrator or distributor for more information." ),
00964                         i18n( "No LDAP IO Slave Available" ) );
00965     return;
00966   }
00967 
00968   if ( !mLdapSearchDialog ) {
00969     mLdapSearchDialog = new LDAPSearchDialog( mAddressBook, this, mWidget );
00970     connect( mLdapSearchDialog, SIGNAL( addresseesAdded() ),
00971             SLOT( addressBookChanged() ) );
00972     connect( mLdapSearchDialog, SIGNAL( addresseesAdded() ),
00973             SLOT( setModified() ) );
00974   } else
00975     mLdapSearchDialog->restoreSettings();
00976 
00977   if ( mLdapSearchDialog->isOK() )
00978     mLdapSearchDialog->exec();
00979 }
00980 
00981 void KABCore::configure()
00982 {
00983   // Save the current config so we do not loose anything if the user accepts
00984   saveSettings();
00985 
00986   KCMultiDialog dlg( mWidget, "", true );
00987   connect( &dlg, SIGNAL( configCommitted() ),
00988            this, SLOT( configurationChanged() ) );
00989 
00990   dlg.addModule( "kabconfig.desktop" );
00991   dlg.addModule( "kabldapconfig.desktop" );
00992   dlg.addModule( "kabcustomfields.desktop" );
00993 
00994   dlg.exec();
00995 }
00996 
00997 void KABCore::print()
00998 {
00999   KPrinter printer;
01000   printer.setDocName( i18n( "Address Book" ) );
01001   printer.setDocFileName( "addressbook" );
01002 
01003   if ( !printer.setup( mWidget, i18n("Print Addresses") ) )
01004     return;
01005 
01006   KABPrinting::PrintingWizard wizard( &printer, mAddressBook,
01007                                       mViewManager->selectedUids(), mWidget );
01008 
01009   wizard.exec();
01010 }
01011 
01012 void KABCore::detailsHighlighted( const QString &msg )
01013 {
01014   if ( mStatusBar ) {
01015     if ( !mStatusBar->hasItem( 2 ) )
01016       mStatusBar->insertItem( msg, 2 );
01017     else
01018       mStatusBar->changeItem( msg, 2 );
01019   }
01020 }
01021 
01022 void KABCore::showContactsAddress( const QString &addrUid )
01023 {
01024   QStringList uidList = mViewManager->selectedUids();
01025   if ( uidList.isEmpty() )
01026     return;
01027 
01028   KABC::Addressee addr = mAddressBook->findByUid( uidList.first() );
01029   if ( addr.isEmpty() )
01030     return;
01031 
01032   const KABC::Address::List list = addr.addresses();
01033   KABC::Address::List::ConstIterator it;
01034   const KABC::Address::List::ConstIterator endIt( list.end() );
01035   for ( it = list.begin(); it != endIt; ++it )
01036     if ( (*it).id() == addrUid ) {
01037       LocationMap::instance()->showAddress( *it );
01038       break;
01039     }
01040 }
01041 
01042 void KABCore::configurationChanged()
01043 {
01044   mExtensionManager->reconfigure();
01045   mViewManager->refreshView();
01046 }
01047 
01048 bool KABCore::queryClose()
01049 {
01050   saveSettings();
01051   KABPrefs::instance()->writeConfig();
01052 
01053   QPtrList<KABC::Resource> resources = mAddressBook->resources();
01054   QPtrListIterator<KABC::Resource> it( resources );
01055   while ( it.current() ) {
01056     it.current()->close();
01057     ++it;
01058   }
01059 
01060   return true;
01061 }
01062 
01063 void KABCore::reinitXMLGUI()
01064 {
01065   mExtensionManager->createActions();
01066 }
01067 void KABCore::delayedAddressBookChanged()
01068 {
01069   mAddressBookChangedTimer->start( 1000 );
01070 }
01071 
01072 void KABCore::addressBookChanged()
01073 {
01074   const QStringList selectedUids = mViewManager->selectedUids();
01075 
01076   mAddressBookChangedTimer->stop();
01077 
01078   if ( mJumpButtonBar )
01079     mJumpButtonBar->updateButtons();
01080 
01081   mSearchManager->reload();
01082 
01083   mViewManager->setSelected( QString::null, false );
01084 
01085   QString uid = QString::null;
01086   if ( !selectedUids.isEmpty() ) {
01087     uid = selectedUids.first();
01088     mViewManager->setSelected( uid, true );
01089   }
01090 
01091   setContactSelected( uid );
01092 
01093   updateCategories();
01094 }
01095 
01096 AddresseeEditorDialog *KABCore::createAddresseeEditorDialog( QWidget *parent,
01097                                                              const char *name )
01098 {
01099   AddresseeEditorDialog *dialog = new AddresseeEditorDialog( this, parent,
01100                                                  name ? name : "editorDialog" );
01101   connect( dialog, SIGNAL( contactModified( const KABC::Addressee& ) ),
01102            SLOT( contactModified( const KABC::Addressee& ) ) );
01103   connect( dialog, SIGNAL( editorDestroyed( const QString& ) ),
01104            SLOT( slotEditorDestroyed( const QString& ) ) );
01105 
01106   return dialog;
01107 }
01108 
01109 void KABCore::activateDetailsWidget( QWidget *widget )
01110 {
01111   if ( mDetailsStack->visibleWidget() == widget )
01112     return;
01113   mDetailsStack->raiseWidget( widget );
01114 }
01115 
01116 void KABCore::deactivateDetailsWidget( QWidget *widget )
01117 {
01118   if ( mDetailsStack->visibleWidget() != widget )
01119     return;
01120   mDetailsStack->raiseWidget( mDetailsWidget );
01121 }
01122 
01123 void KABCore::slotEditorDestroyed( const QString &uid )
01124 {
01125   AddresseeEditorDialog *dialog = mEditorDict.take( uid );
01126 
01127   KABC::Addressee addr = dialog->addressee();
01128 
01129   if ( !addr.resource()->readOnly() ) {
01130     QApplication::setOverrideCursor( Qt::waitCursor );
01131     KABLock::self( mAddressBook )->unlock( addr.resource() );
01132     QApplication::restoreOverrideCursor();
01133   }
01134 }
01135 
01136 void KABCore::initGUI()
01137 {
01138   QVBoxLayout *topLayout = new QVBoxLayout( mWidget, 0, 0 );
01139   KToolBar* searchTB = new KToolBar( mWidget, "search toolbar");
01140   searchTB->boxLayout()->setSpacing( KDialog::spacingHint() );
01141   mIncSearchWidget = new IncSearchWidget( searchTB, "kde toolbar widget");
01142   searchTB->setStretchableWidget( mIncSearchWidget );
01143   connect( mIncSearchWidget, SIGNAL( doSearch( const QString& ) ),
01144            SLOT( incrementalTextSearch( const QString& ) ) );
01145 
01146   mDetailsSplitter = new QSplitter( mWidget );
01147 
01148   mLeftSplitter = new QSplitter( mDetailsSplitter );
01149   mLeftSplitter->setOrientation( KABPrefs::instance()->contactListAboveExtensions() ? Qt::Vertical : Qt::Horizontal );
01150 
01151   topLayout->addWidget( searchTB );
01152   topLayout->addWidget( mDetailsSplitter );
01153 
01154   mDetailsStack = new QWidgetStack( mDetailsSplitter );
01155   mExtensionManager = new ExtensionManager( new QWidget( mLeftSplitter ), mDetailsStack, this, this );
01156   connect( mExtensionManager, SIGNAL( detailsWidgetDeactivated( QWidget* ) ),
01157            this, SLOT( deactivateDetailsWidget( QWidget* ) ) );
01158   connect( mExtensionManager, SIGNAL( detailsWidgetActivated( QWidget* ) ),
01159            this, SLOT( activateDetailsWidget( QWidget* ) ) );
01160 
01161   QWidget *viewWidget = new QWidget( mLeftSplitter );
01162   if ( KABPrefs::instance()->contactListAboveExtensions() )
01163     mLeftSplitter->moveToFirst( viewWidget );
01164   QVBoxLayout *viewLayout = new QVBoxLayout( viewWidget );
01165   viewLayout->setSpacing( KDialog::spacingHint() );
01166 
01167   mViewHeaderLabel = new QLabel( viewWidget );
01168 //  mViewHeaderLabel->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed );
01169   mViewHeaderLabel->setText( i18n( "Contacts" ) );
01170   viewLayout->addWidget( mViewHeaderLabel );
01171   mViewManager = new ViewManager( this, viewWidget );
01172   viewLayout->addWidget( mViewManager, 1 );
01173 
01174 #ifdef KDEPIM_NEW_DISTRLISTS
01175   mDistListButtonWidget = new QWidget( viewWidget );
01176   QHBoxLayout *buttonLayout = new QHBoxLayout( mDistListButtonWidget );
01177   buttonLayout->setSpacing( KDialog::spacingHint() );
01178   buttonLayout->addStretch( 1 );
01179 
01180   KPushButton *addDistListButton = new KPushButton( mDistListButtonWidget );
01181   addDistListButton->setText( i18n( "Add" ) );
01182   connect( addDistListButton, SIGNAL( clicked() ),
01183            this, SLOT( editSelectedDistributionList() ) );
01184   buttonLayout->addWidget( addDistListButton );
01185   mDistListButtonWidget->setShown( false );
01186   viewLayout->addWidget( mDistListButtonWidget );
01187 
01188   KPushButton *removeDistListButton = new KPushButton( mDistListButtonWidget );
01189   removeDistListButton->setText( i18n( "Remove" ) );
01190   connect( removeDistListButton, SIGNAL( clicked() ),
01191            this, SLOT( removeSelectedContactsFromDistList() ) );
01192   buttonLayout->addWidget( removeDistListButton );
01193 #endif
01194 
01195   mFilterSelectionWidget = new FilterSelectionWidget( searchTB , "kde toolbar widget" );
01196   mViewManager->setFilterSelectionWidget( mFilterSelectionWidget );
01197 
01198   connect( mFilterSelectionWidget, SIGNAL( filterActivated( int ) ),
01199            mViewManager, SLOT( setActiveFilter( int ) ) );
01200 
01201   mDetailsWidget = new QWidget( mDetailsSplitter );
01202   mDetailsLayout = new QHBoxLayout( mDetailsWidget );
01203 
01204   mDetailsPage = new QWidget( mDetailsWidget );
01205   mDetailsLayout->addWidget( mDetailsPage );
01206 
01207   QHBoxLayout *detailsPageLayout = new QHBoxLayout( mDetailsPage, 0, 0 );
01208   mDetailsViewer = new KPIM::AddresseeView( mDetailsPage );
01209   mDetailsViewer->setVScrollBarMode( QScrollView::Auto );
01210   detailsPageLayout->addWidget( mDetailsViewer );
01211 
01212   mDistListEntryView = new KAB::DistributionListEntryView( this, mWidget );
01213   connect( mDistListEntryView, SIGNAL( distributionListClicked( const QString& ) ),
01214            this, SLOT( sendMailToDistributionList( const QString& ) ) );
01215   mDetailsStack->addWidget( mDistListEntryView );
01216   mDetailsStack->addWidget( mDetailsWidget );
01217   mDetailsStack->raiseWidget( mDetailsWidget );
01218   mDetailsSplitter->moveToLast( mDetailsStack );
01219 
01220   connect( mDetailsViewer, SIGNAL( addressClicked( const QString&) ),
01221            this, SLOT( showContactsAddress( const QString& ) ) );
01222 
01223   topLayout->setStretchFactor( mDetailsSplitter, 1 );
01224 
01225   mXXPortManager = new XXPortManager( this, mWidget );
01226 
01227   initActions();
01228 }
01229 
01230 void KABCore::createJumpButtonBar()
01231 {
01232   mJumpButtonBar = new JumpButtonBar( this, mDetailsWidget );
01233   mDetailsLayout->addWidget( mJumpButtonBar );
01234   mDetailsLayout->setStretchFactor( mJumpButtonBar, 1 );
01235 
01236   connect( mJumpButtonBar, SIGNAL( jumpToLetter( const QString& ) ),
01237            SLOT( incrementalJumpButtonSearch( const QString& ) ) );
01238   connect( mViewManager, SIGNAL( sortFieldChanged() ),
01239            mJumpButtonBar, SLOT( updateButtons() ) );
01240 }
01241 
01242 void KABCore::initActions()
01243 {
01244   connect( QApplication::clipboard(), SIGNAL( dataChanged() ),
01245            SLOT( clipboardDataChanged() ) );
01246 
01247   KAction *action;
01248 
01249   // file menu
01250   mActionMail = new KAction( i18n( "&Send Email to Contact..." ), "mail_send", 0,
01251                              this, SLOT( sendMail() ), actionCollection(), "file_mail" );
01252   action = KStdAction::print( this, SLOT( print() ), actionCollection() );
01253   mActionMail->setWhatsThis( i18n( "Send a mail to all selected contacts." ) );
01254   action->setWhatsThis( i18n( "Print a special number of contacts." ) );
01255 
01256   mActionSave = KStdAction::save( this,
01257                              SLOT( save() ), actionCollection(), "file_sync" );
01258   mActionSave->setWhatsThis( i18n( "Save all changes of the address book to the storage backend." ) );
01259 
01260   action = new KAction( i18n( "&New Contact..." ), "identity", CTRL+Key_N, this,
01261                SLOT( newContact() ), actionCollection(), "file_new_contact" );
01262   action->setWhatsThis( i18n( "Create a new contact<p>You will be presented with a dialog where you can add all data about a person, including addresses and phone numbers." ) );
01263 
01264   action = new KAction( i18n( "&New Distribution List..." ), "kontact_contacts", 0, this,
01265                SLOT( newDistributionList() ), actionCollection(), "file_new_distributionlist" );
01266   action->setWhatsThis( i18n( "Create a new distribution list<p>You will be presented with a dialog where you can create a new distribution list." ) );
01267 
01268   mActionMailVCard = new KAction( i18n("Send &Contact..."), "mail_post_to", 0,
01269                                   this, SLOT( mailVCard() ),
01270                                   actionCollection(), "file_mail_vcard" );
01271   mActionMailVCard->setWhatsThis( i18n( "Send a mail with the selected contact as attachment." ) );
01272 
01273   mActionChat = new KAction( i18n("Chat &With..."), 0,
01274                                   this, SLOT( startChat() ),
01275                                   actionCollection(), "file_chat" );
01276   mActionChat->setWhatsThis( i18n( "Start a chat with the selected contact." ) );
01277 
01278   mActionEditAddressee = new KAction( i18n( "&Edit Contact..." ), "edit", 0,
01279                                       this, SLOT( editContact() ),
01280                                       actionCollection(), "file_properties" );
01281   mActionEditAddressee->setWhatsThis( i18n( "Edit a contact<p>You will be presented with a dialog where you can change all data about a person, including addresses and phone numbers." ) );
01282 
01283   mActionMerge = new KAction( i18n( "&Merge Contacts" ), "", 0,
01284                               this, SLOT( mergeContacts() ),
01285                               actionCollection(), "edit_merge" );
01286 
01287   // edit menu
01288   mActionCopy = KStdAction::copy( this, SLOT( copyContacts() ), actionCollection() );
01289   mActionCut = KStdAction::cut( this, SLOT( cutContacts() ), actionCollection() );
01290   mActionPaste = KStdAction::paste( this, SLOT( pasteContacts() ), actionCollection() );
01291   action = KStdAction::selectAll( this, SLOT( selectAllContacts() ), actionCollection() );
01292   mActionCopy->setWhatsThis( i18n( "Copy the currently selected contact(s) to system clipboard in vCard format." ) );
01293   mActionCut->setWhatsThis( i18n( "Cuts the currently selected contact(s) to system clipboard in vCard format." ) );
01294   mActionPaste->setWhatsThis( i18n( "Paste the previously cut or copied contacts from clipboard." ) );
01295   action->setWhatsThis( i18n( "Selects all visible contacts from current view." ) );
01296 //  mActionUndo->setWhatsThis( i18n( "Undoes the last <b>Cut</b>, <b>Copy</b> or <b>Paste</b>." ) );
01297 //  mActionRedo->setWhatsThis( i18n( "Redoes the last <b>Cut</b>, <b>Copy</b> or <b>Paste</b>." ) );
01298 
01299   mActionDelete = new KAction( i18n( "&Delete Contact" ), "editdelete",
01300                                Key_Delete, this, SLOT( deleteContacts() ),
01301                                actionCollection(), "edit_delete" );
01302   mActionDelete->setWhatsThis( i18n( "Delete all selected contacts." ) );
01303 
01304 
01305   mActionCopyAddresseeTo = new KAction( i18n( "&Copy Contact To..." ), "", 0,
01306                                       this, SLOT( copySelectedContactToResource() ),
01307                                       actionCollection(), "copy_contact_to" );
01308   const QString copyMoveWhatsThis = i18n( "Store a contact in a different Addressbook<p>You will be presented with a dialog where you can select a new storage place for this contact." );
01309   mActionCopyAddresseeTo->setWhatsThis( copyMoveWhatsThis );
01310 
01311   mActionMoveAddresseeTo = new KAction( i18n( "M&ove Contact To..." ), "", 0,
01312                                       this, SLOT( moveSelectedContactToResource() ),
01313                                       actionCollection(), "move_contact_to" );
01314   mActionMoveAddresseeTo->setWhatsThis( copyMoveWhatsThis );
01315 
01316   // settings menu
01317   mActionJumpBar = new KToggleAction( i18n( "Show Jump Bar" ), "next", 0,
01318                                       actionCollection(), "options_show_jump_bar" );
01319   mActionJumpBar->setWhatsThis( i18n( "Toggle whether the jump button bar shall be visible." ) );
01320   mActionJumpBar->setCheckedState( i18n( "Hide Jump Bar") );
01321   connect( mActionJumpBar, SIGNAL( toggled( bool ) ), SLOT( setJumpButtonBarVisible( bool ) ) );
01322 
01323   mActionDetails = new KToggleAction( i18n( "Show Details" ), 0, 0,
01324                                       actionCollection(), "options_show_details" );
01325   mActionDetails->setWhatsThis( i18n( "Toggle whether the details page shall be visible." ) );
01326   mActionDetails->setCheckedState( i18n( "Hide Details") );
01327   connect( mActionDetails, SIGNAL( toggled( bool ) ), SLOT( setDetailsVisible( bool ) ) );
01328 
01329   if ( mIsPart )
01330     action = new KAction( i18n( "&Configure Address Book..." ), "configure", 0,
01331                           this, SLOT( configure() ), actionCollection(),
01332                           "kaddressbook_configure" );
01333   else
01334     action = KStdAction::preferences( this, SLOT( configure() ), actionCollection() );
01335 
01336   action->setWhatsThis( i18n( "You will be presented with a dialog, that offers you all possibilities to configure KAddressBook." ) );
01337 
01338   // misc
01339   action = new KAction( i18n( "&Lookup Addresses in LDAP Directory..." ), "find", 0,
01340                         this, SLOT( openLDAPDialog() ), actionCollection(), "ldap_lookup" );
01341   action->setWhatsThis( i18n( "Search for contacts on a LDAP server<p>You will be presented with a dialog, where you can search for contacts and select the ones you want to add to your local address book." ) );
01342 
01343   mActionWhoAmI = new KAction( i18n( "Set as Personal Contact Data" ), "personal", 0, this,
01344                                SLOT( setWhoAmI() ), actionCollection(),
01345                                "edit_set_personal" );
01346   mActionWhoAmI->setWhatsThis( i18n( "Set the personal contact<p>The data of this contact will be used in many other KDE applications, so you do not have to input your personal data several times." ) );
01347 
01348   mActionCategories = new KAction( i18n( "Select Categories..." ), 0, this,
01349                                    SLOT( setCategories() ), actionCollection(),
01350                                    "edit_set_categories" );
01351   mActionCategories->setWhatsThis( i18n( "Set the categories for all selected contacts." ) );
01352 
01353   KAction *clearLocation = new KAction( i18n( "Clear Search Bar" ),
01354                     QApplication::reverseLayout() ? "clear_left" : "locationbar_erase",
01355                     CTRL+Key_L, this, SLOT( slotClearSearchBar() ), actionCollection(), "clear_search" );
01356   clearLocation->setWhatsThis( i18n( "Clear Search Bar<p>"
01357                      "Clears the content of the quick search bar." ) );
01358 
01359   clipboardDataChanged();
01360 }
01361 
01362 void KABCore::clipboardDataChanged()
01363 {
01364   if ( mReadWrite )
01365     mActionPaste->setEnabled( !QApplication::clipboard()->text().isEmpty() );
01366 }
01367 
01368 void KABCore::updateIncSearchWidget()
01369 {
01370   mIncSearchWidget->setViewFields( mViewManager->viewFields() );
01371 }
01372 
01373 void KABCore::updateCategories()
01374 {
01375   QStringList categories( allCategories() );
01376   categories.sort();
01377 
01378   const QStringList customCategories( KABPrefs::instance()->customCategories() );
01379   QStringList::ConstIterator it;
01380   const QStringList::ConstIterator endIt( customCategories.end() );
01381   for ( it = customCategories.begin(); it != endIt; ++it ) {
01382     if ( categories.find( *it ) == categories.end() ) {
01383       categories.append( *it );
01384     }
01385   }
01386 
01387   KABPrefs::instance()->mCustomCategories = categories;
01388   KABPrefs::instance()->writeConfig();
01389 
01390   if ( mCategoryEditDialog )
01391     mCategoryEditDialog->reload();
01392 }
01393 
01394 QStringList KABCore::allCategories() const
01395 {
01396   QStringList categories, allCategories;
01397   QStringList::ConstIterator catIt;
01398 
01399   KABC::AddressBook::ConstIterator it;
01400   const KABC::AddressBook::ConstIterator endIt( mAddressBook->end() );
01401   for ( it = mAddressBook->begin(); it != endIt; ++it ) {
01402     categories = (*it).categories();
01403     const QStringList::ConstIterator catEndIt( categories.end() );
01404     for ( catIt = categories.begin(); catIt != catEndIt; ++catIt ) {
01405       if ( !allCategories.contains( *catIt ) )
01406         allCategories.append( *catIt );
01407     }
01408   }
01409 
01410   return allCategories;
01411 }
01412 
01413 void KABCore::setCategories()
01414 {
01415   // Show the category dialog
01416   if ( mCategorySelectDialog == 0 ) {
01417     mCategorySelectDialog = new KPIM::CategorySelectDialog( KABPrefs::instance(), mWidget );
01418     connect( mCategorySelectDialog, SIGNAL( categoriesSelected( const QStringList& ) ),
01419              SLOT( categoriesSelected( const QStringList& ) ) );
01420     connect( mCategorySelectDialog, SIGNAL( editCategories() ), SLOT( editCategories() ) );
01421   }
01422 
01423   mCategorySelectDialog->show();
01424   mCategorySelectDialog->raise();
01425 }
01426 
01427 void KABCore::categoriesSelected( const QStringList &categories )
01428 {
01429   bool merge = false;
01430   QString msg = i18n( "Merge with existing categories?" );
01431   if ( KMessageBox::questionYesNo( mWidget, msg, QString::null, i18n( "Merge" ), i18n( "Do Not Merge" ) ) == KMessageBox::Yes )
01432     merge = true;
01433 
01434   QStringList uids = mViewManager->selectedUids();
01435   QStringList::ConstIterator it;
01436   const QStringList::ConstIterator endIt( uids.end() );
01437   for ( it = uids.begin(); it != endIt; ++it ) {
01438     KABC::Addressee addr = mAddressBook->findByUid( *it );
01439     if ( !addr.isEmpty() ) {
01440       if ( !merge )
01441         addr.setCategories( categories );
01442       else {
01443         QStringList addrCategories = addr.categories();
01444         QStringList::ConstIterator catIt;
01445         const QStringList::ConstIterator catEndIt( categories.end() );
01446         for ( catIt = categories.begin(); catIt != catEndIt; ++catIt ) {
01447           if ( !addrCategories.contains( *catIt ) )
01448             addrCategories.append( *catIt );
01449         }
01450         addr.setCategories( addrCategories );
01451       }
01452 
01453       mAddressBook->insertAddressee( addr );
01454     }
01455   }
01456 
01457   if ( uids.count() > 0 )
01458     setModified( true );
01459 }
01460 
01461 void KABCore::editCategories()
01462 {
01463   if ( mCategoryEditDialog == 0 ) {
01464     mCategoryEditDialog = new KPIM::CategoryEditDialog( KABPrefs::instance(), mWidget );
01465     connect( mCategoryEditDialog, SIGNAL( categoryConfigChanged() ),
01466              mCategorySelectDialog, SLOT( updateCategoryConfig() ) );
01467   }
01468 
01469   mCategoryEditDialog->show();
01470   mCategoryEditDialog->raise();
01471 }
01472 
01473 void KABCore::slotClearSearchBar()
01474 {
01475   mIncSearchWidget->clear();
01476   mIncSearchWidget->setFocus();
01477 }
01478 
01479 void KABCore::slotContactsUpdated()
01480 {
01481   if ( mStatusBar ) {
01482     QString msg( i18n( "%n contact matches", "%n contacts matching", mSearchManager->contacts().count() ) );
01483     if ( !mStatusBar->hasItem( 1 ) )
01484       mStatusBar->insertItem( msg, 1 );
01485     else
01486       mStatusBar->changeItem( msg, 1 );
01487   }
01488 
01489   emit contactsUpdated();
01490 }
01491 
01492 bool KABCore::handleCommandLine( KAddressBookIface* iface )
01493 {
01494   KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
01495   QCString addrStr = args->getOption( "addr" );
01496   QCString uidStr = args->getOption( "uid" );
01497 
01498   QString addr, uid, vcard;
01499   if ( !addrStr.isEmpty() )
01500     addr = QString::fromLocal8Bit( addrStr );
01501   if ( !uidStr.isEmpty() )
01502     uid = QString::fromLocal8Bit( uidStr );
01503 
01504   bool doneSomething = false;
01505 
01506   // Can not see why anyone would pass both a uid and an email address, so I'll leave it that two contact editors will show if they do
01507   if ( !addr.isEmpty() ) {
01508     iface->addEmail( addr );
01509     doneSomething = true;
01510   }
01511 
01512   if ( !uid.isEmpty() ) {
01513     iface->showContactEditor( uid );
01514     doneSomething = true;
01515   }
01516 
01517   if ( args->isSet( "new-contact" ) ) {
01518     iface->newContact();
01519     doneSomething = true;
01520   }
01521 
01522   if ( args->count() >= 1 ) {
01523     for ( int i = 0; i < args->count(); ++i )
01524       iface->importVCard( args->url( i ).url() );
01525     doneSomething = true;
01526   }
01527   return doneSomething;
01528 }
01529 
01530 void KABCore::removeSelectedContactsFromDistList()
01531 {
01532 #ifdef KDEPIM_NEW_DISTRLISTS
01533 
01534   KPIM::DistributionList dist = KPIM::DistributionList::findByName( addressBook(), mSelectedDistributionList );
01535   if ( dist.isEmpty() )
01536     return;
01537   const QStringList uids = selectedUIDs();
01538   if ( uids.isEmpty() )
01539       return;
01540   for ( QStringList::ConstIterator uidIt = uids.begin(); uidIt != uids.end(); ++uidIt ) {
01541     typedef KPIM::DistributionList::Entry::List EntryList;
01542     const EntryList entries = dist.entries( addressBook() );
01543     for ( EntryList::ConstIterator it = entries.begin(); it != entries.end(); ++it ) {
01544       if ( (*it).addressee.uid() == (*uidIt) ) {
01545         dist.removeEntry( (*it).addressee, (*it).email );
01546         break;
01547       }
01548     }
01549   }
01550   addressBook()->insertAddressee( dist );
01551   setModified();
01552 #endif
01553 }
01554 
01555 void KABCore::sendMailToDistributionList( const QString &name )
01556 {
01557 #ifdef KDEPIM_NEW_DISTRLISTS
01558   KPIM::DistributionList dist = KPIM::DistributionList::findByName( addressBook(), name );
01559   if ( dist.isEmpty() )
01560     return;
01561   typedef KPIM::DistributionList::Entry::List EntryList;
01562   QStringList mails;
01563   const EntryList entries = dist.entries( addressBook() );
01564   for ( EntryList::ConstIterator it = entries.begin(); it != entries.end(); ++it )
01565     mails += (*it).addressee.fullEmail( (*it).email );
01566   sendMail( mails.join( ", " ) );
01567 #endif
01568 }
01569 
01570 void KABCore::editSelectedDistributionList()
01571 {
01572 #ifdef KDEPIM_NEW_DISTRLISTS
01573   editDistributionList( KPIM::DistributionList::findByName( addressBook(), mSelectedDistributionList ) );
01574 #endif
01575 }
01576 
01577 
01578 void KABCore::editDistributionList( const QString &name )
01579 {
01580 #ifdef KDEPIM_NEW_DISTRLISTS
01581   editDistributionList( KPIM::DistributionList::findByName( addressBook(), name ) );
01582 #endif
01583 }
01584 
01585 #ifdef KDEPIM_NEW_DISTRLISTS
01586 
01587 void KABCore::showDistributionListEntry( const QString& uid )
01588 {
01589   KPIM::DistributionList dist = KPIM::DistributionList::findByName( addressBook(), mSelectedDistributionList );
01590   if ( !dist.isEmpty() ) {
01591     mDistListEntryView->clear();
01592     typedef KPIM::DistributionList::Entry::List EntryList;
01593     const EntryList entries = dist.entries( addressBook() );
01594     for (EntryList::ConstIterator it = entries.begin(); it != entries.end(); ++it ) {
01595       if ( (*it).addressee.uid() == uid ) {
01596         mDistListEntryView->setEntry( dist, *it );
01597         break;
01598       }
01599     }
01600   }
01601 }
01602 
01603 void KABCore::editDistributionList( const KPIM::DistributionList &dist )
01604 {
01605   if ( dist.isEmpty() )
01606     return;
01607   QGuardedPtr<KPIM::DistributionListEditor::EditorWidget> dlg = new KPIM::DistributionListEditor::EditorWidget( addressBook(), widget() );
01608   dlg->setDistributionList( dist );
01609   if ( dlg->exec() == QDialog::Accepted && dlg ) {
01610     const KPIM::DistributionList newDist = dlg->distributionList();
01611     if ( newDist != dist ) {
01612       addressBook()->insertAddressee( newDist );
01613       setModified();
01614     }
01615   }
01616   delete dlg;
01617 }
01618 
01619 
01620 KPIM::DistributionList::List KABCore::distributionLists() const
01621 {
01622   return mSearchManager->distributionLists();
01623 }
01624 
01625 void KABCore::setSelectedDistributionList( const QString &name )
01626 {
01627   mSelectedDistributionList = name;
01628   mSearchManager->setSelectedDistributionList( name );
01629   mViewHeaderLabel->setText( name.isNull() ? i18n( "Contacts" ) : i18n( "Distribution List: %1" ).arg( name ) );
01630   mDistListButtonWidget->setShown( !mSelectedDistributionList.isNull() );
01631   if ( !name.isNull() ) {
01632     mDetailsStack->raiseWidget( mDistListEntryView );
01633     const QStringList selectedUids = selectedUIDs();
01634     showDistributionListEntry( selectedUids.isEmpty() ? QString() : selectedUids.first() );
01635   }
01636   else
01637     mDetailsStack->raiseWidget( mExtensionManager->activeDetailsWidget() ? mExtensionManager->activeDetailsWidget() : mDetailsWidget );
01638 }
01639 
01640 QStringList KABCore::distributionListNames() const
01641 {
01642   return mSearchManager->distributionListNames();
01643 }
01644 #endif
01645 
01646 #include "kabcore.moc"