kandy

mobilegui.cpp

00001 /*
00002     This file is part of Kandy.
00003 
00004     Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
00005 
00006     This program is free software; you can redistribute it and/or modify
00007     it under the terms of the GNU General Public License as published by
00008     the Free Software Foundation; either version 2 of the License, or
00009     (at your option) any later version.
00010 
00011     This program is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00014     GNU General Public License for more details.
00015 
00016     You should have received a copy of the GNU General Public License
00017     along with this program; if not, write to the Free Software
00018     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019 
00020     As a special exception, permission is given to link this program
00021     with any edition of Qt, and distribute the resulting executable,
00022     without including the source code for Qt in the source distribution.
00023 */
00024 
00025 #include <time.h>
00026 
00027 #include <qlabel.h>
00028 #include <qlistview.h>
00029 #include <qfile.h>
00030 #include <qtextstream.h>
00031 #include <qmessagebox.h>
00032 
00033 #include <qtextedit.h>
00034 #include <qgroupbox.h>
00035 #include <qpushbutton.h>
00036 
00037 #include <kdebug.h>
00038 #include <kfiledialog.h>
00039 #include <kmessagebox.h>
00040 #include <klocale.h>
00041 #include <kapplication.h>
00042 #include <kstatusbar.h>
00043 
00044 #include <kabc/stdaddressbook.h>
00045 
00046 #include "modem.h"
00047 #include "atcommand.h"
00048 #include "commandscheduler.h"
00049 
00050 #include "mobilegui.h"
00051 #include "mobilegui.moc"
00052 #include "mobilemain.h"
00053 
00054 
00055 class SyncEntry
00056 {
00057   public:
00058     SyncEntry()
00059     {
00060       mOn = true;
00061       mToBeUpdated = false;
00062       mToBeInserted = false;
00063     }
00064   
00065     bool mOn;
00066     bool mToBeUpdated;
00067     bool mToBeInserted;
00068 };
00069 
00070 
00071 class SyncEntryKab : public SyncEntry
00072 {
00073   public:
00074     SyncEntryKab( bool on, const QString &index, const QString &name,
00075                   const QString &phone )
00076     {
00077       mOn = on;
00078       
00079       mIndex = index;
00080       mName = name;
00081       mPhone = phone;
00082       
00083       mKABindex = -1;
00084       mPhoneNumberIndex = -1;
00085     }
00086   
00087     QString mIndex;
00088     QString mName;
00089     QString mPhone;
00090 
00091     KABC::Addressee mAddressee;
00092     int mKABindex;
00093     int mPhoneNumberIndex;
00094 };
00095 
00096 
00097 class SyncEntryMobile : public SyncEntry
00098 {
00099   public:
00100     SyncEntryMobile( bool on, const QString &index, const QString &phone,
00101                      const QString &name )
00102     {
00103       mOn = on;
00104       mToBeDeleted = false;
00105 
00106       mIndex = index;
00107       mName = name;
00108       mPhone = phone;
00109     }
00110     
00111     QString mIndex;
00112     QString mName;
00113     QString mPhone;
00114     
00115     bool mToBeDeleted;
00116 };
00117 
00118 
00119 class SyncEntryCommon : public SyncEntry
00120 {
00121   public:
00122     SyncEntryCommon( bool on, SyncEntryKab *kabEntry,
00123                      SyncEntryMobile *mobileEntry )
00124     {
00125       mOn = on;
00126       mKabEntry = kabEntry;
00127       mMobileEntry = mobileEntry;
00128     }
00129     
00130     SyncEntryKab *mKabEntry;
00131     SyncEntryMobile *mMobileEntry;
00132 };
00133 
00134 
00135 class AddressSyncer
00136 {
00137   public:
00138     AddressSyncer()
00139     {
00140       mKabEntries.setAutoDelete( true );
00141       mMobileEntries.setAutoDelete( true );
00142       mCommonEntries.setAutoDelete( true );
00143     }
00144   
00145     QPtrList<SyncEntryKab> mKabEntries;
00146     QPtrList<SyncEntryMobile> mMobileEntries;
00147     QPtrList<SyncEntryCommon> mCommonEntries; 
00148 };
00149 
00150 
00151 class PhoneBookItem : public QCheckListItem
00152 {
00153   public:
00154     PhoneBookItem( QListView *v ) :
00155       QCheckListItem( v, "", QCheckListItem::CheckBox )
00156     {
00157       mSyncEntry = 0;
00158     }
00159 
00160     PhoneBookItem( QListView *v, SyncEntry *syncEntry, const QString &name,
00161                    const QString &phone, const QString &index ) :
00162       QCheckListItem( v, index, QCheckListItem::CheckBox )
00163     {
00164       mSyncEntry = syncEntry;
00165       
00166       setText( 0, name );
00167       setText( 1, phone );
00168       setText( 2, index );
00169     }
00170 
00171     SyncEntry *syncEntry() { return mSyncEntry; }
00172 
00173   private:
00174     SyncEntry *mSyncEntry;
00175 };
00176 
00177 
00178 /* 
00179  *  Constructs a MobileGui which is a child of 'parent', with the 
00180  *  name 'name' and widget flags set to 'f' 
00181  *
00182  *  The dialog will by default be modeless, unless you set 'modal' to
00183  *  TRUE to construct a modal dialog.
00184  */
00185 MobileGui::MobileGui( CommandScheduler *scheduler, KandyPrefs *kprefs,
00186                       QWidget* parent, const char* name, WFlags fl ) :
00187   DCOPObject( "KandyIface" ), MobileGui_base( parent, name, fl )
00188 {
00189   // Setup links to related classes
00190   mScheduler = scheduler;
00191   mSyncer = new AddressSyncer;
00192   mPrefs = kprefs;
00193   mparent = parent;
00194 
00195   // Setup mobile phone specific data
00196   mMobManufacturer = "";
00197   mMobModel = "";
00198   mPBStartIndex = 0;
00199   mPBLength = 0;
00200   mPBNameLength = 0;
00201   mPBIndexOccupied.resize( 0, false );
00202   mMobHasFD = false;
00203   mMobHasLD = false;
00204   mMobHasME = false;
00205   mMobHasMT = false;
00206   mMobHasTA = false;
00207   mMobHasOW = false;
00208   mMobHasMC = false;
00209   mMobHasRC = false;
00210   
00211   // Setup status for asynchronous control flow
00212   mLastWriteId = "";
00213   mComingFromToggleConnection = false;
00214   mComingFromReadPhonebook = false;
00215   mComingFromSyncPhonebooks = false;
00216   mComingFromExit = false;
00217   
00218   // Setup initial state of phone books
00219   setKabState( UNLOADED );
00220   setMobState( UNLOADED );
00221 
00222   // Setup signal handlers
00223   connect( mScheduler, SIGNAL( commandProcessed( ATCommand * ) ),
00224            SLOT( processResult( ATCommand * ) ) );
00225   connect( mScheduler->modem(), SIGNAL( gotLine( const char * ) ),
00226            SLOT( termAddOutput( const char * ) ) );
00227 }
00228 
00229 
00230 MobileGui::~MobileGui()
00231 {
00232   delete mSyncer;
00233 }
00234 
00235 
00236 void MobileGui::exit()
00237 {
00238   warnKabState( UNLOADED );
00239   
00240   mComingFromExit = true;
00241   if ( !warnMobState( UNLOADED ) ) {
00242     mComingFromExit = false;
00243     kapp->quit();
00244   }
00245 }
00246 
00247 
00248 void MobileGui::readModelInformation()
00249 {
00250   // Read generic manufacturer and model information
00251   mScheduler->executeId( "+cgmi" );
00252   mScheduler->executeId( "+cgmm" );
00253   mScheduler->executeId( "+cgmr" );
00254   mScheduler->executeId( "+cgsn" );
00255   
00256   // Read information about additional phonebook memories
00257   ATCommand *cmd = new ATCommand( "+cpbs=?" );
00258   cmd->setAutoDelete( true );
00259   mScheduler->execute( cmd );
00260   
00261   // Select SIM phonebook by default
00262   cmd = new ATCommand( "+cpbs=" );
00263   cmd->setAutoDelete( true );
00264   cmd->addParameter( new ATParameter( "SM" ) );
00265   mScheduler->execute( cmd );
00266 
00267   // Read phonebook properties
00268   mScheduler->executeId( "+cpbr=?" );
00269   mScheduler->executeId( "+cpbs?" );
00270 
00271   // Set clock
00272   if ( (*mPrefs).autoSetClock() )
00273     setClock();
00274 }
00275 
00276 
00277 void MobileGui::readPhonebook()
00278 {
00279   if ( mMobState == LOADED )
00280     return;
00281 
00282   mComingFromReadPhonebook = true;
00283   if ( !warnMobState( LOADED ) ) {
00284     mComingFromReadPhonebook = false;
00285     QString tmp = "";
00286     
00287     ATCommand *cmd = new ATCommand( "+cpbr=" );
00288     cmd->setAutoDelete( true );
00289     cmd->addParameter( new ATParameter( tmp.setNum( mPBStartIndex ) ) );
00290     cmd->addParameter( new ATParameter( tmp.setNum( mPBStartIndex +
00291                                                     mPBLength - 1 ) ) );
00292     
00293     mScheduler->execute( cmd );
00294   
00295     emit statusMessage( i18n( "Reading mobile phonebook..." ) );
00296   }
00297 }
00298 
00299 
00300 void MobileGui::writePhonebook()
00301 {
00302   bool ModemCommandScheduled = false;
00303   
00304   
00305   if ( mMobState != MODIFIED )
00306     return;
00307 
00308   PushButton12->setEnabled( false );
00309 
00310 
00311   //
00312   // Remove all entries from data structures which are marked as
00313   // deleted but which are not found on the mobile phone
00314   //
00315   
00316   for ( uint i = 0; i < mSyncer->mMobileEntries.count(); i++ ) {
00317     SyncEntryMobile *entry = mSyncer->mMobileEntries.at( i );
00318     
00319     
00320     if ( entry->mToBeDeleted )
00321       if ( entry->mIndex.isEmpty() ) {
00322         // The current entry has to be deleted but doesn't come from
00323     // the mobile phone. Hence, it was inserted during phonebook
00324     // synchronisation or so.
00325     // => It is sufficient to remove it from mMobileEntries, no
00326     // ATCommand for deletion needs to be scheduled.
00327         mSyncer->mMobileEntries.remove( i );
00328         i--;
00329       } else {
00330         // The current entry has to be deleted and stems from the
00331     // mobile phone. First thing to do is to free its associated
00332     // index. This way, its index can be reused for entries which
00333     // have be newly inserted to the mobile phone and we can save
00334     // an explicit ATCommand for deletion and save time & battery
00335     // energy.
00336     uint theIndex = entry->mIndex.toUInt();
00337     mPBIndexOccupied[ theIndex - mPBStartIndex ] = false;
00338       }
00339   }
00340 
00341   
00342   //
00343   // Write all elements which need an update to the mobile phone
00344   //
00345   
00346   for ( uint i = 0; i < mSyncer->mMobileEntries.count(); i++ ) {
00347     SyncEntryMobile *entry = mSyncer->mMobileEntries.at( i );
00348     QString id;
00349 
00350 
00351     // Only process changed items of the mobile phonebook in
00352     // order to save time.
00353     if ( entry->mToBeUpdated || entry->mToBeInserted ) {
00354       QString tmp = "";
00355       
00356       
00357       if ( entry->mToBeUpdated ) {
00358         id = "+cpbw=" + entry->mIndex;
00359       } else {
00360         int index = firstFreeIndex();
00361     
00362     
00363     mPBIndexOccupied[ index ] = true;
00364         id = "+cpbw=" + tmp.setNum( index + mPBStartIndex );
00365       }
00366       mLastWriteId = id;
00367       entry->mToBeUpdated = false;
00368       entry->mToBeInserted = false;
00369 
00370       ATCommand *cmd = new ATCommand( id );
00371       cmd->setAutoDelete( true );
00372       cmd->addParameter( new ATParameter( quote( entry->mPhone ) ) );
00373 
00374       if ( entry->mPhone.left( 1 ) == "+" )
00375         cmd->addParameter( new ATParameter( "145" ) );
00376       else
00377         cmd->addParameter( new ATParameter( "129" ) );
00378 
00379       cmd->addParameter( new ATParameter(
00380                                quote( string2GSM( entry->mName ) ) ) );
00381     
00382       mScheduler->execute( cmd );
00383       ModemCommandScheduled = true;
00384     }
00385   }
00386   
00387   
00388   //
00389   // As a final step, we need to check again all entries which should be
00390   // deleted. If entries exist stemming from the mobile phone and whose
00391   // index-position was not reused for updating or inserting other entries in
00392   // the previous loop, we need to issue an explicit ATCommand for its deletion.
00393   //
00394   
00395   for ( uint i = 0; i < mSyncer->mMobileEntries.count(); i++ ) {
00396     SyncEntryMobile *entry = mSyncer->mMobileEntries.at( i );
00397     
00398     
00399     if ( entry->mToBeDeleted ) {
00400       uint theIndex = entry->mIndex.toUInt();
00401       
00402       
00403       if ( !mPBIndexOccupied[ theIndex - mPBStartIndex ] ) {
00404         // Index of item to be deleted still is 0, so that index position
00405     // wasn't reused. We must delete it explicitly.
00406     QString id = "+cpbw=" + entry->mIndex;
00407     
00408     
00409     mLastWriteId = id;
00410     ATCommand *cmd = new ATCommand( id );
00411     cmd->setAutoDelete( true );
00412     
00413     mScheduler->execute( cmd );
00414     ModemCommandScheduled = true;
00415       }
00416     
00417       // Remove entry from internal data structures
00418       mSyncer->mMobileEntries.remove( i );
00419       i--;
00420     }
00421   }
00422 
00423   if ( ModemCommandScheduled )
00424     emit statusMessage( i18n( "Writing mobile phonebook..." ) );
00425   else
00426     writePhonebookPostProcessing();
00427 }
00428 
00429 
00430 void MobileGui::writePhonebookPostProcessing()
00431 {
00432   mLastWriteId = "";
00433   emit transientStatusMessage( i18n( "Wrote mobile phonebook." ) );
00434   PushButton12->setEnabled( true );
00435   setMobState( LOADED );
00436   updateMobileBook();
00437 
00438   if ( mComingFromToggleConnection ) {
00439     mComingFromToggleConnection = false;
00440     disconnectGUI();
00441   } else
00442   if ( mComingFromReadPhonebook ) {
00443     mComingFromReadPhonebook = false;
00444     QString tmp = "";
00445     
00446     ATCommand *cmd = new ATCommand( "+cpbr=" );
00447     cmd->setAutoDelete( true );
00448     cmd->addParameter( new ATParameter( tmp.setNum( mPBStartIndex ) ) );
00449     cmd->addParameter( new ATParameter( tmp.setNum( mPBStartIndex +
00450                                                     mPBLength - 1 ) ) );
00451     
00452     mScheduler->execute( cmd );
00453 
00454     emit statusMessage( i18n( "Reading mobile phonebook..." ) );
00455   } else
00456   if ( mComingFromExit ) {
00457     mComingFromExit = false;
00458     kapp->quit();
00459   }
00460 }
00461 
00462 
00463 void MobileGui::setClock()
00464 {
00465   char *timeStr = new char[50];
00466   QString id = "+cclk=";
00467   ATCommand *cmd = new ATCommand( id );
00468 
00469 
00470   cmd->setAutoDelete( true );
00471   
00472   time_t tloc;
00473   time( &tloc );
00474   struct tm *theTime = localtime( &tloc );
00475   strftime( timeStr, 50, "%y/%m/%d,%T+00", theTime );
00476 
00477   QString Time = timeStr;
00478   cmd->addParameter( new ATParameter( quote( Time ) ) );
00479   
00480   mScheduler->execute( cmd );
00481   
00482   delete[] timeStr;
00483 }
00484 
00485 
00486 void MobileGui::readKabc()
00487 {
00488   if ( mKabState == LOADED )
00489     return;
00490 
00491   warnKabState( LOADED );
00492    
00493   emit statusMessage( i18n( "Reading KDE address book..." ) );
00494 
00495   mSyncer->mKabEntries.clear();
00496 
00497   KABC::AddressBook *addressBook = KABC::StdAddressBook::self( true );
00498   KABC::AddressBook::Iterator it;
00499   int kabIndex = 0;
00500 
00501   for ( it = addressBook->begin(); it != addressBook->end();
00502         it++, kabIndex++ ) {
00503     QString index, name;
00504     KABC::PhoneNumber phoneNumber;
00505     KABC::PhoneNumber::List phoneNumbers = (*it).phoneNumbers();
00506     KABC::PhoneNumber::List::Iterator it2;
00507     int phoneNumberIndex = 0;
00508 
00509 
00510     // Scan all numbers associated with a KAB entry
00511     for ( it2 = phoneNumbers.begin(); it2 != phoneNumbers.end();
00512           it2++, phoneNumberIndex++ ) {
00513       bool excludeNumber = false;
00514       phoneNumber = (*it2);
00515       QString phone = phoneNumber.number();
00516 
00517     
00518       if ( (*mPrefs).excludeHome() &&
00519            ( phoneNumber.type() & KABC::PhoneNumber::Home ) )
00520     excludeNumber = true;
00521       if ( (*mPrefs).excludeWork() &&
00522            ( phoneNumber.type() & KABC::PhoneNumber::Work ) )
00523     excludeNumber = true;
00524       if ( (*mPrefs).excludeMessaging() &&
00525            ( phoneNumber.type() & KABC::PhoneNumber::Msg ) )
00526     excludeNumber = true;
00527       if ( (*mPrefs).excludeFax() &&
00528            ( phoneNumber.type() & KABC::PhoneNumber::Fax ) )
00529     excludeNumber = true;
00530       if ( (*mPrefs).excludeCell() &&
00531            ( phoneNumber.type() & KABC::PhoneNumber::Cell ) )
00532     excludeNumber = true;
00533       if ( (*mPrefs).excludeVideo() &&
00534            ( phoneNumber.type() & KABC::PhoneNumber::Video ) )
00535     excludeNumber = true;
00536       if ( (*mPrefs).excludeMailbox() &&
00537            ( phoneNumber.type() & KABC::PhoneNumber::Bbs ) )
00538     excludeNumber = true;
00539       if ( (*mPrefs).excludeModem() &&
00540            ( phoneNumber.type() & KABC::PhoneNumber::Modem ) )
00541     excludeNumber = true;
00542       if ( (*mPrefs).excludeCar() &&
00543            ( phoneNumber.type() & KABC::PhoneNumber::Car ) )
00544     excludeNumber = true;
00545       if ( (*mPrefs).excludeISDN() &&
00546            ( phoneNumber.type() & KABC::PhoneNumber::Isdn ) )
00547     excludeNumber = true;
00548       if ( (*mPrefs).excludePager() &&
00549            ( phoneNumber.type() & KABC::PhoneNumber::Pager ) )
00550     excludeNumber = true;
00551     
00552       if ( excludeNumber == false ) {
00553     SyncEntryKab *kabEntry;
00554       
00555       
00556     index = "";
00557         name = (*it).familyName();
00558         
00559     KABC::AddressBook::Iterator it3;
00560     KABC::Addressee::List tmp;
00561     bool firstCharIsUnique = true;
00562     for ( it3 = addressBook->begin(); it3 != addressBook->end(); ++it3 )
00563       if ( ( (*it3).familyName() == name ) && ( it3 != it ) ) {
00564         tmp.append( (*it3) );
00565         if ( (*it3).givenName()[0] == (*it).givenName()[0] )
00566           firstCharIsUnique = false;
00567       }
00568 
00569     // There are several KAB entries with the same family name.
00570     // So, we need to append the given name in order to
00571     // distinguish them.
00572     if ( ( tmp.size() > 0 ) && !(*it).givenName().isEmpty() ) {
00573       name += ", ";
00574           
00575       if ( firstCharIsUnique )
00576         name += (*it).givenName()[0] + ".";
00577       else
00578         name += (*it).givenName();
00579     }
00580           
00581     // Truncate name field if it's too long for mobile phone
00582     if ( name.length() > mPBNameLength )
00583       name = name.remove( mPBNameLength, name.length() - mPBNameLength );
00584         
00585     // Append Suffix to name if specified in preferences
00586     if ( (*mPrefs).useHomeSuff() &&
00587          ( phoneNumber.type() & KABC::PhoneNumber::Home ) )
00588       formatPBName( &name, (*mPrefs).homeSuff() );
00589     else
00590     if ( (*mPrefs).useWorkSuff() &&
00591          ( phoneNumber.type() & KABC::PhoneNumber::Work ) )
00592       formatPBName( &name, (*mPrefs).workSuff() );
00593     else
00594     if ( (*mPrefs).useMessagingSuff() &&
00595          ( phoneNumber.type() & KABC::PhoneNumber::Msg ) )
00596       formatPBName( &name, (*mPrefs).messagingSuff() );
00597     else
00598     if ( (*mPrefs).useFaxSuff() &&
00599          ( phoneNumber.type() & KABC::PhoneNumber::Fax ) )
00600       formatPBName( &name, (*mPrefs).faxSuff() );
00601     else
00602     if ( (*mPrefs).useCellSuff() &&
00603          ( phoneNumber.type() & KABC::PhoneNumber::Cell ) )
00604       formatPBName( &name, (*mPrefs).cellSuff() );
00605     else
00606     if ( (*mPrefs).useVideoSuff() &&
00607          ( phoneNumber.type() & KABC::PhoneNumber::Video ) )
00608       formatPBName( &name, (*mPrefs).videoSuff() );
00609     else
00610     if ( (*mPrefs).useMailboxSuff() &&
00611          ( phoneNumber.type() & KABC::PhoneNumber::Bbs ) )
00612       formatPBName( &name, (*mPrefs).mailboxSuff() );
00613     else
00614     if ( (*mPrefs).useModemSuff() &&
00615          ( phoneNumber.type() & KABC::PhoneNumber::Modem ) )
00616       formatPBName( &name, (*mPrefs).modemSuff() );
00617     else
00618     if ( (*mPrefs).useCarSuff() &&
00619          ( phoneNumber.type() & KABC::PhoneNumber::Car ) )
00620       formatPBName( &name, (*mPrefs).carSuff() );
00621     else
00622     if ( (*mPrefs).useISDNSuff() &&
00623          ( phoneNumber.type() & KABC::PhoneNumber::Isdn ) )
00624       formatPBName( &name, (*mPrefs).iSDNSuff() );
00625     else
00626     if ( (*mPrefs).usePagerSuff() &&
00627          ( phoneNumber.type() & KABC::PhoneNumber::Pager ) )
00628       formatPBName( &name, (*mPrefs).pagerSuff() );
00629         
00630     kabEntry = new SyncEntryKab( true, index, name, phone );
00631     kabEntry->mKABindex = kabIndex;
00632     kabEntry->mPhoneNumberIndex = phoneNumberIndex;
00633     
00634     kabEntry->mAddressee = (*it);
00635         mSyncer->mKabEntries.append( kabEntry );
00636       }
00637     }
00638   }
00639 
00640   // Display KAB entries
00641   updateKabBook();
00642   
00643   emit transientStatusMessage( i18n( "Read KDE address book." ) );
00644   
00645   setKabState( LOADED );
00646 }
00647 
00648 
00649 QString MobileGui::decodeSuffix( const QString &suffix )
00650 {
00651   QString theSuffix = suffix;
00652   
00653   
00654   // Check whether suffix is quoted. If so, it should be interpreted
00655   // as Hex-Number of a special GSM character.
00656   if ( ( theSuffix.left( 1 ) == "\"" ) && ( theSuffix.right( 1 ) == "\"" ) ) {
00657     QString tmp = "";
00658     char suffixNumber = (char) dequote( suffix ).toUInt( 0, 16 );
00659     tmp += suffixNumber;
00660 
00661     theSuffix = GSM2String( tmp );
00662   }
00663   
00664   return theSuffix;
00665 }
00666 
00667 
00668 void MobileGui::formatPBName( QString *name, QString suffix )
00669 {
00670   QString theSuffix = decodeSuffix( suffix );
00671 
00672   
00673   if ( name->length() + theSuffix.length() > mPBNameLength ) {
00674     // Truncate name field if it's too long for mobile phone
00675     unsigned int toolong = name->length() + theSuffix.length() - mPBNameLength;
00676     (*name) = name->remove( name->length() - toolong, toolong );
00677   } else
00678   if ( name->length() + theSuffix.length() < mPBNameLength )
00679     // Add white spaces so that suffix is right justified
00680     while ( name->length() + theSuffix.length() != mPBNameLength )
00681       (*name) += ' ';
00682 
00683   (*name) += theSuffix;
00684 }
00685 
00686 
00687 QString MobileGui::stripWhiteSpaces( const QString &theString )
00688 {
00689   int pos = 0;
00690   int len = theString.length();
00691 
00692 
00693   for ( unsigned int i = 0; i < theString.length(); i++ )
00694     if ( theString[ i ].latin1() == ' ' ) {
00695       pos++;
00696       len--;
00697     } else
00698       break;
00699 
00700   if ( len == 0 )
00701     return "";
00702 
00703   for ( int i = theString.length() - 1; i >= 0; i-- )
00704     if ( theString[ i ].latin1() == ' ' )
00705       len--;
00706     else
00707       break;
00708   
00709   return theString.mid( pos, len );
00710 }
00711 
00712 
00713 void MobileGui::writeKabc()
00714 {
00715   if ( mKabState != MODIFIED )
00716     return;
00717 
00718   KABC::AddressBook *addressBook = KABC::StdAddressBook::self( true );
00719   KABC::Ticket *ticket = addressBook->requestSaveTicket();
00720 
00721   if ( !ticket ) {
00722     kdDebug() << "Error! No ticket to save." << endl;
00723     return;
00724   }
00725 
00726 
00727   for ( uint i = 0; i < mSyncer->mKabEntries.count(); i++ ) {
00728     SyncEntryKab *kabEntry = mSyncer->mKabEntries.at( i );
00729     QString phoneNumber = kabEntry->mPhone;
00730     
00731     
00732     if ( kabEntry->mToBeUpdated ) {
00733       // Find the entry in the KAB which has to be updated
00734       KABC::AddressBook::Iterator it = addressBook->begin();
00735       for ( int KABindex = 0; KABindex != kabEntry->mKABindex;
00736             it++, KABindex++ ) ;
00737     
00738       // Find the correct phonenumber of the phonebook entry
00739       KABC::PhoneNumber::List phoneNumbers = (*it).phoneNumbers();
00740       KABC::PhoneNumber::List::Iterator it2 = phoneNumbers.begin();
00741       for ( int phoneNumberIndex = 0;
00742             phoneNumberIndex != kabEntry->mPhoneNumberIndex;
00743         it2++, phoneNumberIndex++ ) ;
00744       
00745       (*it2).setNumber( phoneNumber ); 
00746       (*it).insertPhoneNumber( (*it2) );
00747     } else
00748 
00749     if ( kabEntry->mToBeInserted ) {
00750       int phoneType = 0;
00751       bool goon = true;
00752       KABC::AddressBook::Iterator it;
00753       bool equivalentEntryFound = false;
00754       QString name = kabEntry->mName;
00755 
00756 
00757       //
00758       // Identify Type of Phonenumber using possibly appended suffixes.
00759       // If a suffix is found, remove it from the name.
00760       //
00761       if ( goon && (*mPrefs).useHomeSuff() ) {
00762         QString theSuffix = decodeSuffix( (*mPrefs).homeSuff() );
00763     if ( name.right( theSuffix.length() ) == theSuffix ) {
00764       phoneType = KABC::PhoneNumber::Home;
00765       name = stripWhiteSpaces(
00766                name.left( name.length() - theSuffix.length() ) );
00767       goon = false;
00768     }
00769       }
00770       if ( goon && (*mPrefs).useWorkSuff() ) {
00771         QString theSuffix = decodeSuffix( (*mPrefs).workSuff() );
00772     if ( name.right( theSuffix.length() ) == theSuffix ) {
00773       phoneType = KABC::PhoneNumber::Work;
00774       name = stripWhiteSpaces(
00775                name.left( name.length() - theSuffix.length() ) );
00776       goon = false;
00777     }
00778       }
00779       if ( goon && (*mPrefs).useMessagingSuff() ) {
00780         QString theSuffix = decodeSuffix( (*mPrefs).messagingSuff() );
00781     if ( name.right( theSuffix.length() ) == theSuffix ) {
00782       phoneType = KABC::PhoneNumber::Msg;
00783       name = stripWhiteSpaces(
00784                name.left( name.length() - theSuffix.length() ) );
00785       goon = false;
00786     }
00787       }
00788       if ( goon && (*mPrefs).useFaxSuff() ) {
00789         QString theSuffix = decodeSuffix( (*mPrefs).faxSuff() );
00790     if ( name.right( theSuffix.length() ) == theSuffix ) {
00791       phoneType = KABC::PhoneNumber::Fax;
00792       name = stripWhiteSpaces(
00793                name.left( name.length() - theSuffix.length() ) );
00794       goon = false;
00795     }
00796       }
00797       if ( goon && (*mPrefs).useCellSuff() ) {
00798         QString theSuffix = decodeSuffix( (*mPrefs).cellSuff() );
00799     if ( name.right( theSuffix.length() ) == theSuffix ) {
00800       phoneType = KABC::PhoneNumber::Cell;
00801       name = stripWhiteSpaces(
00802                name.left( name.length() - theSuffix.length() ) );
00803       goon = false;
00804     }
00805       }
00806       if ( goon && (*mPrefs).useVideoSuff() ) {
00807         QString theSuffix = decodeSuffix( (*mPrefs).videoSuff() );
00808     if ( name.right( theSuffix.length() ) == theSuffix ) {
00809       phoneType = KABC::PhoneNumber::Video;
00810       name = stripWhiteSpaces(
00811                name.left( name.length() - theSuffix.length() ) );
00812       goon = false;
00813     }
00814       }
00815       if ( goon && (*mPrefs).useMailboxSuff() ) {
00816         QString theSuffix = decodeSuffix( (*mPrefs).mailboxSuff() );
00817     if ( name.right( theSuffix.length() ) == theSuffix ) {
00818       phoneType = KABC::PhoneNumber::Bbs;
00819       name = stripWhiteSpaces(
00820                name.left( name.length() - theSuffix.length() ) );
00821       goon = false;
00822     }
00823       }
00824       if ( goon && (*mPrefs).useModemSuff() ) {
00825         QString theSuffix = decodeSuffix( (*mPrefs).modemSuff() );
00826     if ( name.right( theSuffix.length() ) == theSuffix ) {
00827       phoneType = KABC::PhoneNumber::Modem;
00828       name = stripWhiteSpaces(
00829                name.left( name.length() - theSuffix.length() ) );
00830       goon = false;
00831     }
00832       }
00833       if ( goon && (*mPrefs).useCarSuff() ) {
00834         QString theSuffix = decodeSuffix( (*mPrefs).carSuff() );
00835     if ( name.right( theSuffix.length() ) == theSuffix ) {
00836       phoneType = KABC::PhoneNumber::Car;
00837       name = stripWhiteSpaces(
00838                name.left( name.length() - theSuffix.length() ) );
00839       goon = false;
00840     }
00841       }
00842       if ( goon && (*mPrefs).useISDNSuff() ) {
00843         QString theSuffix = decodeSuffix( (*mPrefs).iSDNSuff() );
00844     if ( name.right( theSuffix.length() ) == theSuffix ) {
00845       phoneType = KABC::PhoneNumber::Isdn;
00846       name = stripWhiteSpaces(
00847                name.left( name.length() - theSuffix.length() ) );
00848       goon = false;
00849     }
00850       }
00851       if ( goon && (*mPrefs).usePagerSuff() ) {
00852         QString theSuffix = decodeSuffix( (*mPrefs).pagerSuff() );
00853     if ( name.right( theSuffix.length() ) == theSuffix ) {
00854       phoneType = KABC::PhoneNumber::Pager;
00855       name = stripWhiteSpaces(
00856                name.left( name.length() - theSuffix.length() ) );
00857       goon = false;
00858     }
00859       }
00860 
00861 
00862       //
00863       // Search for a KAB entry whose name, if formatted in exactly the
00864       // same way as was done in readKabc, is equal to the actual name.
00865       //
00866       
00867       for ( it = addressBook->begin(); it != addressBook->end(); it++ ) {
00868         QString kabName = (*it).familyName();
00869     KABC::AddressBook::Iterator it3;
00870     KABC::Addressee::List tmp;
00871     bool firstCharIsUnique = true;
00872     unsigned int minLength;
00873 
00874 
00875     for ( it3 = addressBook->begin(); it3 != addressBook->end(); it3++ )
00876       if ( ( (*it3).familyName() == kabName ) && ( it3 != it ) ) {
00877         tmp.append( (*it3) );
00878         if ( (*it3).givenName()[0] == (*it).givenName()[0] )
00879           firstCharIsUnique = false;
00880       }
00881 
00882     // There are several KAB entries with the same family name.
00883     // So, we need to append the given name in order to
00884     // distinguish them.
00885     if ( ( tmp.size() > 0 ) && !(*it).givenName().isEmpty() ) {
00886       kabName += ", ";
00887           
00888       if ( firstCharIsUnique )
00889         kabName += (*it).givenName()[0] + ".";
00890       else
00891         kabName += (*it).givenName();
00892     }
00893           
00894     // Truncate name field if it's too long for mobile phone
00895     if ( kabName.length() > mPBNameLength )
00896       kabName = kabName.remove( mPBNameLength,
00897                                 kabName.length() - mPBNameLength );
00898 
00899         minLength = kabName.length();
00900     if ( name.length() < minLength )
00901       minLength = name.length();
00902       
00903     if ( name.left( minLength ) == kabName.left( minLength ) ) {
00904       (*it).insertPhoneNumber( KABC::PhoneNumber( phoneNumber,
00905                                                   phoneType ) );
00906       
00907       equivalentEntryFound = true;
00908       break;
00909     }
00910       }
00911       
00912       //
00913       // If no equivalent entry was found in KAB, we need to generate
00914       // a complete new entry.
00915       //
00916       
00917       if ( !equivalentEntryFound ) {
00918         KABC::Addressee entry;
00919         QStringList *fields = new QStringList;
00920 
00921   
00922         *fields = QStringList::split( ',', name );
00923     
00924     if ( fields->count() > 1 ) {
00925       // Name string contains comma separated entry so that we
00926       // need to build family and given names out of them.
00927       QString givenName = "";
00928       
00929 
00930       entry.setFamilyName( stripWhiteSpaces( (*fields)[ 0 ] ) );
00931       
00932       for ( unsigned int i = 1; i < fields->count(); i++ )
00933         givenName += stripWhiteSpaces( (*fields)[ i ] ) + " ";
00934       entry.setGivenName( stripWhiteSpaces( givenName ) );
00935     } else
00936       // Name string contains only one string without comma.
00937       entry.setFamilyName( stripWhiteSpaces( name ) );
00938 
00939         entry.insertPhoneNumber( KABC::PhoneNumber( phoneNumber, phoneType ) );
00940 
00941         addressBook->insertAddressee( entry );
00942       }
00943     }
00944 
00945     kabEntry->mToBeUpdated = false;
00946     kabEntry->mToBeInserted = false;
00947   }
00948   
00949   addressBook->save( ticket );
00950   
00951   emit transientStatusMessage( i18n( "Wrote KDE address book." ) );
00952   
00953   setKabState( LOADED );
00954 }
00955 
00956 
00957 void MobileGui::refreshStatus()
00958 {
00959   mScheduler->executeId( "+cbc" );
00960   mScheduler->executeId( "+csq" );
00961 }
00962 
00963 
00964 void MobileGui::processResult( ATCommand *command )
00965 {
00966   if ( command->id() == "+cbc" )
00967     mBatteryChargeLabel->setText( command->resultField( 1 ) + " %" );
00968   else
00969   if ( command->id() == "+csq" )
00970     mSignalQualityLabel->setText( command->resultField( 0 ) );
00971   else
00972   if ( command->id() == "+cgmi" ) {
00973     mMobManufacturer = command->resultField( 0 );
00974     mManufacturerLabel->setText( mMobManufacturer );
00975   } else
00976   if ( command->id() == "+cgmm" ) {
00977     mMobModel = command->resultField( 0 );
00978     mModelLabel->setText( mMobModel );
00979   } else
00980   if ( command->id() == "+cgmr" )
00981     mGSMVersionLabel->setText( command->resultField( 0 ) );
00982   else
00983   if ( command->id() == "+cgsn" )
00984     mSerialNumberLabel->setText( command->resultField( 0 ) );
00985   else
00986   if ( command->id() == "+cpbr=?" )
00987   {
00988     QStringList tmpList = QStringList::split( "-", command->resultField( 0 ) );
00989     QString tmpString = tmpList.first().right( tmpList.first().length() - 1 );
00990     mPBStartIndex = tmpString.toUInt();
00991     mPBNameLength = command->resultField( 2 ).toUInt();
00992   } else
00993   if ( command->id() == "+cpbs?" ) {
00994     mPBLength = command->resultField( 2 ).toUInt();
00995 
00996     // Allocate and initialize memory for the buckets of indices
00997     mPBIndexOccupied.resize( mPBLength, false );
00998     for ( unsigned int i = 0; i < mPBLength; i++ )
00999       mPBIndexOccupied[ i ] = false;
01000   } else
01001   if ( command->id() == "+cpbr=" ) {
01002     fillPhonebook( command );
01003     
01004     if ( mComingFromSyncPhonebooks ) {
01005       mComingFromSyncPhonebooks = false;
01006       mergePhonebooks();
01007     }
01008   } else
01009   if ( command->id() == mLastWriteId )
01010     writePhonebookPostProcessing();
01011   else
01012   if ( command->id() == "+cpbs=?" ) {
01013     QPtrList<QStringList> *list = command->resultFields();
01014     QStringList *fields = list->first();
01015 
01016 
01017     while( fields ) {
01018       for ( unsigned int i = 0; i < fields->count(); i++ ) {
01019         QString memory = dequote( (*fields)[ i ] );
01020 
01021 
01022     if ( memory == "FD" )
01023       mMobHasFD = true;
01024         else
01025     if ( memory == "LD" )
01026       mMobHasLD = true;
01027     else
01028     if ( memory == "ME" )
01029       mMobHasME = true;
01030     else
01031     if ( memory == "MT" )
01032       mMobHasMT = true;
01033     else
01034     if ( memory == "TA" )
01035       mMobHasTA = true;
01036     else
01037     if ( ( memory == "OW" ) ||
01038          ( ( memory == "ON" ) && ( mMobManufacturer == "SIEMENS" ) ) )
01039       mMobHasOW = true;
01040     else
01041     if ( ( mMobManufacturer == "SIEMENS" ) && ( memory == "MC" ) )
01042       mMobHasMC = true;
01043     else
01044     if ( ( mMobManufacturer == "SIEMENS" ) && ( memory == "RC" ) )
01045       mMobHasRC = true;
01046       }
01047       
01048       fields = list->next();
01049     }
01050   }
01051 }
01052 
01053 
01054 QString MobileGui::noSpaces( const QString &theString )
01055 {
01056   QString result = "";
01057   
01058   
01059   for ( unsigned int i = 0; i < theString.length(); i++ )
01060     if ( theString[ i ].latin1() != ' ' )
01061       result += theString[ i ];
01062   
01063   return result;
01064 }
01065 
01066 
01067 int MobileGui::firstFreeIndex()
01068 {
01069   unsigned int i;
01070   
01071   
01072   if ( mPBIndexOccupied.capacity() == 0 )
01073     return 0;
01074 
01075   for ( i = 1; i < mPBLength; i++ )
01076     if ( !mPBIndexOccupied[ i ] )
01077       break;
01078 
01079   if ( i < mPBLength )
01080     return i;
01081 
01082   return 0;
01083 }
01084 
01085 
01086 QString MobileGui::string2GSM( const QString &theString )
01087 {
01088   QString result = "";
01089 
01090 
01091   for ( unsigned int i = 0; i < theString.length(); i++ )
01092     switch ( theString[ i ].latin1() ) {
01093       case 'Ä': result += '['; break;
01094       case 'ä': result += '{'; break;
01095       case 'Ö': result += 92; break;
01096       case 'ö': result += '|'; break;
01097       case 'Ü': result += '^'; break;
01098       case 'ü': result += '~'; break;
01099       case 'ß': result += 30; break;
01100       case 'è': result += 4; break;
01101       case 'é': result += 5; break;
01102       
01103       default: result += theString[ i ];
01104     }
01105   
01106   return result;
01107 }
01108 
01109 
01110 QString MobileGui::GSM2String( const QString &theString )
01111 {
01112   QString result = "";
01113 
01114 
01115   for ( unsigned int i = 0; i < theString.length(); i++ )
01116     switch ( theString[ i ].latin1() ) {
01117       case '[': result += 'Ä'; break;
01118       case '{': result += 'ä'; break;
01119       case 92:  result += 'Ö'; break;
01120       case '|': result += 'ö'; break;
01121       case '^': result += 'Ü'; break;
01122       case '~': result += 'ü'; break;
01123       case 30:  result += 'ß'; break;
01124       case 4:   result += 'è'; break;
01125       case 5:   result += 'é'; break;
01126 
01127       default: result += theString[ i ];
01128     }
01129 
01130   return result;
01131 }
01132 
01133 
01134 void MobileGui::fillPhonebook( ATCommand *cmd )
01135 {
01136   mSyncer->mMobileEntries.clear();
01137     
01138   QPtrList<QStringList> *list = cmd->resultFields();
01139   QStringList *fields = list->first();
01140 
01141   while( fields ) {
01142     if ( fields->count() != 4 )
01143       kdDebug() << "Error! Unexpected number of address fields." << endl;
01144     else {
01145       QString index = (*fields)[0];
01146       QString phone = (*fields)[1];
01147       QString type = (*fields)[2];
01148       QString name = GSM2String( (*fields)[3] );
01149 
01150       SyncEntryMobile *phoneEntry = new SyncEntryMobile( true, dequote( index ),
01151                                                          dequote( phone ),
01152                              dequote( name ) );
01153       mPBIndexOccupied[ index.toUInt() - mPBStartIndex ] = true;
01154       mSyncer->mMobileEntries.append( phoneEntry );
01155     }
01156     fields = list->next();
01157   }
01158 
01159   // Display mobile entries
01160   updateMobileBook();
01161 
01162   emit transientStatusMessage(i18n("Read mobile phonebook."));
01163   emit phonebookRead();
01164   
01165   setMobState( LOADED );
01166 }
01167 
01168 
01169 QString MobileGui::quote( const QString &str )
01170 {
01171   if ( ( str.left(1) == "\"" ) && ( str.right(1) == "\"" ) )
01172     return str;
01173   
01174   return "\"" + str + "\"";
01175 }
01176 
01177 
01178 QString MobileGui::dequote( const QString &str )
01179 {
01180   int pos = 0;
01181   int len = str.length();
01182 
01183 
01184   if ( str.left(1) == "\"" ) {
01185     pos = 1;
01186     len --;
01187   } 
01188   
01189   if ( str.right(1) == "\"" )
01190     len--;
01191   
01192   return str.mid( pos, len );
01193 }
01194 
01195 
01196 void MobileGui::savePhonebook()
01197 {
01198   if ( mMobState == UNLOADED )
01199     return;
01200     
01201   QString fileName = KFileDialog::getSaveFileName( "phonebook.csv" );
01202   QFile outFile( fileName );
01203 
01204   if ( outFile.open( IO_WriteOnly ) ) {
01205     QTextStream t( &outFile );        // use a text stream
01206 
01207     for( uint i = 0; i < mSyncer->mMobileEntries.count(); i++) {
01208       SyncEntryMobile *e = mSyncer->mMobileEntries.at( i );
01209       
01210       
01211       if ( !e->mToBeDeleted )
01212         t << e->mIndex << "," << e->mPhone << "," << e->mName << endl;
01213     }
01214 
01215     outFile.close();
01216   }
01217 }
01218 
01219 
01220 void MobileGui::deleteMobPhonebook()
01221 {
01222 
01223   //
01224   // Process all elements selected in the GUI
01225   //
01226   
01227   PhoneBookItem *item = (PhoneBookItem *) mMobileBook->firstChild();
01228   while ( item ) {
01229     if ( item->isOn() ) {
01230       SyncEntryMobile *mobileItem = (SyncEntryMobile *) item->syncEntry();
01231 
01232 
01233       // Deselect current item
01234       item->setOn( false );
01235       mobileItem->mOn = false;
01236       
01237       // Mark current item as deleted
01238       mobileItem->mToBeDeleted = true;
01239     }
01240     
01241     item = (PhoneBookItem *) item->nextSibling();
01242   }
01243       
01244   // Update GUI
01245   updateMobileBook();
01246   setMobState( MODIFIED );
01247 }
01248 
01249 
01250 void MobileGui::mergePhonebooks()
01251 {
01252   uint i;
01253   
01254   
01255   //
01256   // Transfer current Selection State from GUI to mSyncer
01257   //
01258 
01259   PhoneBookItem *item = (PhoneBookItem *) mKabBook->firstChild();
01260   while ( item ) {
01261     item->syncEntry()->mOn = item->isOn();
01262     item = (PhoneBookItem *) item->nextSibling();
01263   }
01264 
01265   item = (PhoneBookItem *) mMobileBook->firstChild();
01266   while ( item ) {
01267     item->syncEntry()->mOn = item->isOn();
01268     item = (PhoneBookItem *) item->nextSibling();
01269   }
01270   
01271   mSyncer->mCommonEntries.clear();
01272 
01273 
01274   //
01275   // Put KDE Address Book list into Common List
01276   //
01277 
01278   for ( i = 0; i < mSyncer->mKabEntries.count(); i++ )
01279     if ( mSyncer->mKabEntries.at( i )->mOn ) {
01280       mSyncer->mCommonEntries.append(
01281         new SyncEntryCommon( true, mSyncer->mKabEntries.at( i ), 0 ) );
01282       mSyncer->mKabEntries.at( i )->mOn = false;
01283     }
01284 
01285 
01286   //
01287   // Put Mobile Address Book list into Common List; Merge equivalent entries
01288   //
01289   
01290   for ( i = 0; i < mSyncer->mMobileEntries.count(); i++ ) {
01291     SyncEntryMobile *mobileEntry = mSyncer->mMobileEntries.at( i );
01292     bool equivalentEntryFound = false;
01293     uint j;
01294     
01295     
01296     if( !mobileEntry->mToBeDeleted )
01297       for ( j = 0; j < mSyncer->mCommonEntries.count(); j++ ) {
01298         SyncEntryCommon *theCommonEntry = mSyncer->mCommonEntries.at( j );
01299       
01300       
01301         if ( theCommonEntry->mKabEntry &&
01302          ( theCommonEntry->mKabEntry->mName == mobileEntry->mName ) ) {
01303           theCommonEntry->mMobileEntry = mobileEntry;
01304       equivalentEntryFound = true;
01305     
01306           if ( noSpaces( theCommonEntry->mKabEntry->mPhone ) ==
01307            mobileEntry->mPhone ) {
01308         mobileEntry->mOn = false;
01309         break;
01310           } else {
01311         // Conflict: 2 Entries have same name but different numbers.
01312         // Prompt user.
01313             QString text = "<qt><b>" + i18n( "Kab Entry:" ) + "</b><br>";
01314             text += "  " + theCommonEntry->mKabEntry->mName + " " +
01315                        theCommonEntry->mKabEntry->mPhone + "<br>";
01316             text += "<b>" + i18n( "Mobile Entry:" ) + "</b><br>";
01317             text += "  " + mobileEntry->mName + " " + mobileEntry->mPhone;
01318             text += "</qt>";
01319       
01320             QMessageBox *msg =
01321           new QMessageBox( i18n( "Conflicting Entries" ), text,
01322                            QMessageBox::Warning, 1, 2, 0, this );
01323             msg->setButtonText( 1, i18n( "Use Kab Entry" ) );
01324             msg->setButtonText( 2, i18n( "Use Mobile Entry" ) );
01325       
01326         switch ( msg->exec() ) {
01327           case 1:
01328             // Use KDE Address Book Entry
01329             mobileEntry->mPhone = theCommonEntry->mKabEntry->mPhone;
01330             mobileEntry->mName = theCommonEntry->mKabEntry->mName;
01331             mobileEntry->mOn = true;
01332             mobileEntry->mToBeUpdated = true;
01333           
01334             setMobState( MODIFIED );
01335             break;
01336           
01337           case 2:
01338             // Use Mobile Address Book Entry
01339             theCommonEntry->mKabEntry->mPhone = mobileEntry->mPhone;
01340             theCommonEntry->mKabEntry->mName = mobileEntry->mName;
01341             theCommonEntry->mKabEntry->mOn = true;
01342         theCommonEntry->mKabEntry->mToBeUpdated = true;
01343         
01344         mobileEntry->mOn = false;
01345           
01346             setKabState( MODIFIED );
01347             break;
01348         }
01349       }
01350         }
01351       }
01352 
01353     if ( !equivalentEntryFound && mobileEntry->mOn ) {
01354       // No equivalent entry exists; generate a new one.
01355       mSyncer->mCommonEntries.append(
01356         new SyncEntryCommon( true, 0, mobileEntry ) );
01357       mobileEntry->mOn = false;
01358     }
01359   }
01360 
01361 
01362   //
01363   // Create new KAB and Mobile Entries
01364   //
01365   
01366   for ( i = 0; i < mSyncer->mCommonEntries.count(); i++ ) {
01367     SyncEntryCommon *entry = mSyncer->mCommonEntries.at( i );
01368     SyncEntryKab *kabEntry = entry->mKabEntry;
01369     SyncEntryMobile *mobileEntry = entry->mMobileEntry;
01370 
01371 
01372     if ( kabEntry && !mobileEntry ) {
01373       // Create Mobile Entry
01374       entry->mMobileEntry = new SyncEntryMobile( true, "", kabEntry->mPhone,
01375                                                  kabEntry->mName );
01376       entry->mMobileEntry->mToBeInserted = true;
01377       mSyncer->mMobileEntries.append( entry->mMobileEntry );
01378 
01379       setMobState( MODIFIED );
01380     } else
01381     if ( mobileEntry && !kabEntry ) {
01382       // Create KAB Entry
01383       entry->mKabEntry = new SyncEntryKab( true, mobileEntry->mIndex,
01384                                            mobileEntry->mName,
01385                        mobileEntry->mPhone );
01386       entry->mKabEntry->mToBeInserted = true;
01387       mSyncer->mKabEntries.append( entry->mKabEntry );
01388 
01389       setKabState( MODIFIED );
01390     }
01391   }
01392 
01393 
01394   //
01395   // Update GUI
01396   //
01397 
01398   updateKabBook();
01399   updateMobileBook();
01400 
01401   emit transientStatusMessage( i18n( "Synced phonebooks." ) );
01402   PushButton8_3->setEnabled( true );
01403 }
01404 
01405 
01406 void MobileGui::syncPhonebooks()
01407 {
01408   PushButton8_3->setEnabled( false );
01409 
01410   if ( mKabState == UNLOADED )
01411     readKabc();
01412   if ( mMobState == UNLOADED ) {
01413     mComingFromSyncPhonebooks = true;
01414     readPhonebook();
01415   } else
01416     mergePhonebooks();
01417 }
01418 
01419 
01420 void MobileGui::updateKabBook()
01421 {
01422   mKabBook->clear();
01423   
01424   for ( uint i = 0; i < mSyncer->mKabEntries.count(); i++ ) {
01425     SyncEntryKab *kabEntry = mSyncer->mKabEntries.at( i );
01426     PhoneBookItem *item = new PhoneBookItem( mKabBook, kabEntry,
01427                                              kabEntry->mName, kabEntry->mPhone,
01428                          kabEntry->mIndex );
01429     item->setOn( kabEntry->mOn );
01430   }
01431 }
01432 
01433 
01434 void MobileGui::updateMobileBook()
01435 {
01436   mMobileBook->clear();
01437   
01438   for ( uint i = 0; i < mSyncer->mMobileEntries.count(); i++ ) {
01439     SyncEntryMobile *entry = mSyncer->mMobileEntries.at( i );
01440     
01441     if ( !entry->mToBeDeleted ) {
01442       PhoneBookItem *item = new PhoneBookItem( mMobileBook, entry, entry->mName,
01443                                                entry->mPhone, entry->mIndex );
01444       item->setOn( entry->mOn );
01445     }
01446   }
01447 }
01448 
01449 
01450 void MobileGui::toggleConnection()
01451 {
01452   if ( mConnectButton->text() == i18n( "Connect" ) ) {
01453     emit connectModem();
01454     
01455     readModelInformation();
01456     refreshStatus();
01457     
01458     mConnectButton->setText( tr2i18n( "Disconnect" ) );
01459     PushButton1->setEnabled( true );
01460     PushButton5_3->setEnabled( true );
01461 
01462     mABTab->setEnabled( true );
01463     setKabState( UNLOADED );
01464     setMobState( UNLOADED );
01465 
01466     ((MobileMain *) mparent)->statusBar()->changeItem( i18n(" Connected "), 1 );
01467   } else {
01468     warnKabState( UNLOADED );
01469 
01470     mComingFromToggleConnection = true;
01471     if ( !warnMobState( UNLOADED ) ) {
01472       mComingFromToggleConnection = false;
01473       disconnectGUI();
01474     }
01475   }
01476 }
01477 
01478 
01479 void MobileGui::disconnectGUI()
01480 {
01481   emit disconnectModem();
01482     
01483   mManufacturerLabel->setText( "x" );
01484   mModelLabel->setText( "x" );
01485   mGSMVersionLabel->setText( "x" );
01486   mSerialNumberLabel->setText( "x" );
01487 
01488   mBatteryChargeLabel->setText( "xx %" );
01489   mSignalQualityLabel->setText( "x" );
01490 
01491   mConnectButton->setText( tr2i18n( "Connect" ) );
01492   PushButton1->setEnabled( false );
01493   PushButton5_3->setEnabled( false );
01494     
01495   mKabBook->clear();
01496   mMobileBook->clear();
01497   setKabState( UNLOADED );
01498   setMobState( UNLOADED );
01499 
01500   mABTab->setEnabled( false );
01501   
01502   mMobHasFD = false;
01503   mMobHasLD = false;
01504   mMobHasME = false;
01505   mMobHasMT = false;
01506   mMobHasTA = false;
01507   mMobHasOW = false;
01508   mMobHasMC = false;
01509   mMobHasRC = false;
01510   
01511   mPBIndexOccupied.resize( 0, false );
01512 
01513   ((MobileMain *) mparent)->statusBar()->changeItem( i18n(" Disconnected "),
01514                                                      1 );
01515 }
01516 
01517 
01518 void MobileGui::termAddOutput( const char *line )
01519 {
01520   mTermIO->append( line );
01521   mTermIO->setCursorPosition( mTermIO->paragraphs() - 1, 0 );
01522 }
01523 
01524 
01525 void MobileGui::setKabState( ABState newState )
01526 {
01527   switch ( mKabState ) {
01528     case UNLOADED:
01529       groupBox3->setTitle( tr2i18n( "KDE Address Book" ) );
01530       mReadKabButton->setEnabled( true );
01531       PushButton8->setEnabled( false );
01532       break;
01533       
01534     case LOADED:
01535       if ( newState == MODIFIED ) {
01536         groupBox3->setTitle( tr2i18n( "KDE Address Book (modified)" ) );
01537     mReadKabButton->setEnabled( true );
01538     PushButton8->setEnabled( true );
01539       } else
01540       if ( newState == UNLOADED ) {
01541         groupBox3->setTitle( tr2i18n( "KDE Address Book" ) );
01542     mReadKabButton->setEnabled( true );
01543     PushButton8->setEnabled( false );
01544       }
01545       break;
01546 
01547     case MODIFIED:
01548       if ( newState != MODIFIED ) {
01549         groupBox3->setTitle( tr2i18n( "KDE Address Book" ) );
01550     mReadKabButton->setEnabled( true );
01551     PushButton8->setEnabled( false );
01552       }
01553       break;
01554   }
01555   
01556   mKabState = newState;
01557 }
01558 
01559 
01560 void MobileGui::warnKabState( ABState newState )
01561 {
01562   if ( ( mKabState == MODIFIED ) && ( newState != MODIFIED ) ) {
01563     QString text = "<qt><b>" + i18n( "Warning" ) + "</b><br>";
01564     text += i18n( "The KDE address book contains unsaved changes." ) +
01565             "<br></qt>";
01566       
01567     QMessageBox *msg = new QMessageBox( i18n( "Unsaved Changes" ), text,
01568                                         QMessageBox::Critical, 1, 2, 0, this );
01569     msg->setButtonText( 1, i18n( "Save" ) );
01570     msg->setButtonText( 2, i18n( "Discard" ) );
01571       
01572     switch ( msg->exec() ) {
01573       case 1:
01574         // Save Changes first
01575     writeKabc();
01576     break;
01577           
01578       case 2:
01579     break;
01580     }
01581   }
01582 }
01583 
01584 
01585 void MobileGui::setMobState( ABState newState )
01586 {
01587   switch ( mMobState ) {
01588     case UNLOADED:
01589       if ( newState == UNLOADED ) {
01590         groupBox4->setTitle( tr2i18n( "Mobile Phone Book" ) );
01591         PushButton3->setEnabled( true );
01592         PushButton12->setEnabled( false );
01593         PushButton4_2->setEnabled( false );
01594     MobDeleteButton->setEnabled( false );
01595       } else
01596       if ( newState == LOADED ) {
01597         groupBox4->setTitle( tr2i18n( "Mobile Phone Book" ) );
01598         PushButton3->setEnabled( true );
01599         PushButton12->setEnabled( false );
01600         PushButton4_2->setEnabled( true );
01601     MobDeleteButton->setEnabled( true );
01602       }
01603       break;
01604       
01605     case LOADED:
01606       if ( newState == MODIFIED ) {
01607         groupBox4->setTitle( tr2i18n( "Mobile Phone Book (modified)" ) );
01608     PushButton3->setEnabled( true );
01609     PushButton12->setEnabled( true );
01610     PushButton4_2->setEnabled( true );
01611     MobDeleteButton->setEnabled( true );
01612       } else
01613       if ( newState == UNLOADED ) {
01614         groupBox4->setTitle( tr2i18n( "Mobile Phone Book" ) );
01615     PushButton3->setEnabled( true );
01616     PushButton12->setEnabled( false );
01617     PushButton4_2->setEnabled( false );
01618     MobDeleteButton->setEnabled( false );
01619       }
01620       break;
01621 
01622     case MODIFIED:
01623       if ( newState == UNLOADED ) {
01624         groupBox4->setTitle( tr2i18n( "Mobile Phone Book" ) );
01625     PushButton3->setEnabled( true );
01626     PushButton12->setEnabled( false );
01627     PushButton4_2->setEnabled( false );
01628     MobDeleteButton->setEnabled( false );
01629       } else
01630       if ( newState == LOADED ) {
01631         groupBox4->setTitle( tr2i18n( "Mobile Phone Book" ) );
01632     PushButton3->setEnabled( true );
01633     PushButton12->setEnabled( false );
01634     PushButton4_2->setEnabled( true );
01635     MobDeleteButton->setEnabled( true );
01636       }
01637       break;
01638   }
01639   
01640   mMobState = newState;
01641 }
01642 
01643 
01644 bool MobileGui::warnMobState( ABState newState )
01645 {
01646   if ( ( mMobState == MODIFIED ) && ( newState != MODIFIED ) )
01647   {
01648     QString text = "<qt><b>" + i18n( "Warning" ) + "</b><br>";
01649     text += i18n( "The mobile phone book contains unsaved changes." ) +
01650             "<br></qt>";
01651       
01652     QMessageBox *msg = new QMessageBox( i18n( "Unsaved Changes" ), text,
01653                                         QMessageBox::Critical, 1, 2, 0, this );
01654     msg->setButtonText( 1, i18n( "Save" ) );
01655     msg->setButtonText( 2, i18n( "Discard" ) );
01656       
01657     switch ( msg->exec() ) {
01658       case 1:
01659         // Save Changes first
01660     writePhonebook();
01661     return true;
01662     break;
01663           
01664       case 2:
01665         return false;
01666     break;
01667     }
01668   }
01669   
01670   return false;
01671 }
KDE Home | KDE Accessibility Home | Description of Access Keys