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