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 = (char *) malloc( 50 * sizeof( char ) );
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   delete theTime;
00484 }
00485 
00486 
00487 void MobileGui::readKabc()
00488 {
00489   if ( mKabState == LOADED )
00490     return;
00491 
00492   warnKabState( LOADED );
00493    
00494   emit statusMessage( i18n( "Reading KDE address book..." ) );
00495 
00496   mSyncer->mKabEntries.clear();
00497 
00498   KABC::AddressBook *addressBook = KABC::StdAddressBook::self( true );
00499   KABC::AddressBook::Iterator it;
00500   int kabIndex = 0;
00501 
00502   for ( it = addressBook->begin(); it != addressBook->end();
00503         it++, kabIndex++ ) {
00504     QString index, name;
00505     KABC::PhoneNumber phoneNumber;
00506     KABC::PhoneNumber::List phoneNumbers = (*it).phoneNumbers();
00507     KABC::PhoneNumber::List::Iterator it2;
00508     int phoneNumberIndex = 0;
00509 
00510 
00511     // Scan all numbers associated with a KAB entry
00512     for ( it2 = phoneNumbers.begin(); it2 != phoneNumbers.end();
00513           it2++, phoneNumberIndex++ ) {
00514       bool excludeNumber = false;
00515       phoneNumber = (*it2);
00516       QString phone = phoneNumber.number();
00517 
00518     
00519       if ( (*mPrefs).excludeHome() &&
00520            ( phoneNumber.type() & KABC::PhoneNumber::Home ) )
00521     excludeNumber = true;
00522       if ( (*mPrefs).excludeWork() &&
00523            ( phoneNumber.type() & KABC::PhoneNumber::Work ) )
00524     excludeNumber = true;
00525       if ( (*mPrefs).excludeMessaging() &&
00526            ( phoneNumber.type() & KABC::PhoneNumber::Msg ) )
00527     excludeNumber = true;
00528       if ( (*mPrefs).excludeFax() &&
00529            ( phoneNumber.type() & KABC::PhoneNumber::Fax ) )
00530     excludeNumber = true;
00531       if ( (*mPrefs).excludeCell() &&
00532            ( phoneNumber.type() & KABC::PhoneNumber::Cell ) )
00533     excludeNumber = true;
00534       if ( (*mPrefs).excludeVideo() &&
00535            ( phoneNumber.type() & KABC::PhoneNumber::Video ) )
00536     excludeNumber = true;
00537       if ( (*mPrefs).excludeMailbox() &&
00538            ( phoneNumber.type() & KABC::PhoneNumber::Bbs ) )
00539     excludeNumber = true;
00540       if ( (*mPrefs).excludeModem() &&
00541            ( phoneNumber.type() & KABC::PhoneNumber::Modem ) )
00542     excludeNumber = true;
00543       if ( (*mPrefs).excludeCar() &&
00544            ( phoneNumber.type() & KABC::PhoneNumber::Car ) )
00545     excludeNumber = true;
00546       if ( (*mPrefs).excludeISDN() &&
00547            ( phoneNumber.type() & KABC::PhoneNumber::Isdn ) )
00548     excludeNumber = true;
00549       if ( (*mPrefs).excludePager() &&
00550            ( phoneNumber.type() & KABC::PhoneNumber::Pager ) )
00551     excludeNumber = true;
00552     
00553       if ( excludeNumber == false ) {
00554     SyncEntryKab *kabEntry;
00555       
00556       
00557     index = "";
00558         name = (*it).familyName();
00559         
00560     KABC::AddressBook::Iterator it3;
00561     KABC::Addressee::List tmp;
00562     bool firstCharIsUnique = true;
00563     for ( it3 = addressBook->begin(); it3 != addressBook->end(); ++it3 )
00564       if ( ( (*it3).familyName() == name ) && ( it3 != it ) ) {
00565         tmp.append( (*it3) );
00566         if ( (*it3).givenName()[0] == (*it).givenName()[0] )
00567           firstCharIsUnique = false;
00568       }
00569 
00570     // There are several KAB entries with the same family name.
00571     // So, we need to append the given name in order to
00572     // distinguish them.
00573     if ( ( tmp.size() > 0 ) && !(*it).givenName().isEmpty() ) {
00574       name += ", ";
00575           
00576       if ( firstCharIsUnique )
00577         name += (*it).givenName()[0] + ".";
00578       else
00579         name += (*it).givenName();
00580     }
00581           
00582     // Truncate name field if it's too long for mobile phone
00583     if ( name.length() > mPBNameLength )
00584       name = name.remove( mPBNameLength, name.length() - mPBNameLength );
00585         
00586     // Append Suffix to name if specified in preferences
00587     if ( (*mPrefs).useHomeSuff() &&
00588          ( phoneNumber.type() & KABC::PhoneNumber::Home ) )
00589       formatPBName( &name, (*mPrefs).homeSuff() );
00590     else
00591     if ( (*mPrefs).useWorkSuff() &&
00592          ( phoneNumber.type() & KABC::PhoneNumber::Work ) )
00593       formatPBName( &name, (*mPrefs).workSuff() );
00594     else
00595     if ( (*mPrefs).useMessagingSuff() &&
00596          ( phoneNumber.type() & KABC::PhoneNumber::Msg ) )
00597       formatPBName( &name, (*mPrefs).messagingSuff() );
00598     else
00599     if ( (*mPrefs).useFaxSuff() &&
00600          ( phoneNumber.type() & KABC::PhoneNumber::Fax ) )
00601       formatPBName( &name, (*mPrefs).faxSuff() );
00602     else
00603     if ( (*mPrefs).useCellSuff() &&
00604          ( phoneNumber.type() & KABC::PhoneNumber::Cell ) )
00605       formatPBName( &name, (*mPrefs).cellSuff() );
00606     else
00607     if ( (*mPrefs).useVideoSuff() &&
00608          ( phoneNumber.type() & KABC::PhoneNumber::Video ) )
00609       formatPBName( &name, (*mPrefs).videoSuff() );
00610     else
00611     if ( (*mPrefs).useMailboxSuff() &&
00612          ( phoneNumber.type() & KABC::PhoneNumber::Bbs ) )
00613       formatPBName( &name, (*mPrefs).mailboxSuff() );
00614     else
00615     if ( (*mPrefs).useModemSuff() &&
00616          ( phoneNumber.type() & KABC::PhoneNumber::Modem ) )
00617       formatPBName( &name, (*mPrefs).modemSuff() );
00618     else
00619     if ( (*mPrefs).useCarSuff() &&
00620          ( phoneNumber.type() & KABC::PhoneNumber::Car ) )
00621       formatPBName( &name, (*mPrefs).carSuff() );
00622     else
00623     if ( (*mPrefs).useISDNSuff() &&
00624          ( phoneNumber.type() & KABC::PhoneNumber::Isdn ) )
00625       formatPBName( &name, (*mPrefs).iSDNSuff() );
00626     else
00627     if ( (*mPrefs).usePagerSuff() &&
00628          ( phoneNumber.type() & KABC::PhoneNumber::Pager ) )
00629       formatPBName( &name, (*mPrefs).pagerSuff() );
00630         
00631     kabEntry = new SyncEntryKab( true, index, name, phone );
00632     kabEntry->mKABindex = kabIndex;
00633     kabEntry->mPhoneNumberIndex = phoneNumberIndex;
00634     
00635     kabEntry->mAddressee = (*it);
00636         mSyncer->mKabEntries.append( kabEntry );
00637       }
00638     }
00639   }
00640 
00641   // Display KAB entries
00642   updateKabBook();
00643   
00644   emit transientStatusMessage( i18n( "Read KDE address book." ) );
00645   
00646   setKabState( LOADED );
00647 }
00648 
00649 
00650 QString MobileGui::decodeSuffix( const QString &suffix )
00651 {
00652   QString theSuffix = suffix;
00653   
00654   
00655   // Check whether suffix is quoted. If so, it should be interpreted
00656   // as Hex-Number of a special GSM character.
00657   if ( ( theSuffix.left( 1 ) == "\"" ) && ( theSuffix.right( 1 ) == "\"" ) ) {
00658     QString tmp = "";
00659     char suffixNumber = (char) dequote( suffix ).toUInt( 0, 16 );
00660     tmp += suffixNumber;
00661 
00662     theSuffix = GSM2String( tmp );
00663   }
00664   
00665   return theSuffix;
00666 }
00667 
00668 
00669 void MobileGui::formatPBName( QString *name, QString suffix )
00670 {
00671   QString theSuffix = decodeSuffix( suffix );
00672 
00673   
00674   if ( name->length() + theSuffix.length() > mPBNameLength ) {
00675     // Truncate name field if it's too long for mobile phone
00676     unsigned int toolong = name->length() + theSuffix.length() - mPBNameLength;
00677     (*name) = name->remove( name->length() - toolong, toolong );
00678   } else
00679   if ( name->length() + theSuffix.length() < mPBNameLength )
00680     // Add white spaces so that suffix is right justified
00681     while ( name->length() + theSuffix.length() != mPBNameLength )
00682       (*name) += ' ';
00683 
00684   (*name) += theSuffix;
00685 }
00686 
00687 
00688 QString MobileGui::stripWhiteSpaces( const QString &theString )
00689 {
00690   int pos = 0;
00691   int len = theString.length();
00692 
00693 
00694   for ( unsigned int i = 0; i < theString.length(); i++ )
00695     if ( theString[ i ].latin1() == ' ' ) {
00696       pos++;
00697       len--;
00698     } else
00699       break;
00700 
00701   if ( len == 0 )
00702     return "";
00703 
00704   for ( int i = theString.length() - 1; i >= 0; i-- )
00705     if ( theString[ i ].latin1() == ' ' )
00706       len--;
00707     else
00708       break;
00709   
00710   return theString.mid( pos, len );
00711 }
00712 
00713 
00714 void MobileGui::writeKabc()
00715 {
00716   if ( mKabState != MODIFIED )
00717     return;
00718 
00719   KABC::AddressBook *addressBook = KABC::StdAddressBook::self( true );
00720   KABC::Ticket *ticket = addressBook->requestSaveTicket();
00721 
00722   if ( !ticket ) {
00723     kdDebug() << "Error! No ticket to save." << endl;
00724     return;
00725   }
00726 
00727 
00728   for ( uint i = 0; i < mSyncer->mKabEntries.count(); i++ ) {
00729     SyncEntryKab *kabEntry = mSyncer->mKabEntries.at( i );
00730     QString phoneNumber = kabEntry->mPhone;
00731     
00732     
00733     if ( kabEntry->mToBeUpdated ) {
00734       // Find the entry in the KAB which has to be updated
00735       KABC::AddressBook::Iterator it = addressBook->begin();
00736       for ( int KABindex = 0; KABindex != kabEntry->mKABindex;
00737             it++, KABindex++ ) ;
00738     
00739       // Find the correct phonenumber of the phonebook entry
00740       KABC::PhoneNumber::List phoneNumbers = (*it).phoneNumbers();
00741       KABC::PhoneNumber::List::Iterator it2 = phoneNumbers.begin();
00742       for ( int phoneNumberIndex = 0;
00743             phoneNumberIndex != kabEntry->mPhoneNumberIndex;
00744         it2++, phoneNumberIndex++ ) ;
00745       
00746       (*it2).setNumber( phoneNumber ); 
00747       (*it).insertPhoneNumber( (*it2) );
00748     } else
00749 
00750     if ( kabEntry->mToBeInserted ) {
00751       int phoneType = 0;
00752       bool goon = true;
00753       KABC::AddressBook::Iterator it;
00754       bool equivalentEntryFound = false;
00755       QString name = kabEntry->mName;
00756 
00757 
00758       //
00759       // Identify Type of Phonenumber using possibly appended suffixes.
00760       // If a suffix is found, remove it from the name.
00761       //
00762       if ( goon && (*mPrefs).useHomeSuff() ) {
00763         QString theSuffix = decodeSuffix( (*mPrefs).homeSuff() );
00764     if ( name.right( theSuffix.length() ) == theSuffix ) {
00765       phoneType = KABC::PhoneNumber::Home;
00766       name = stripWhiteSpaces(
00767                name.left( name.length() - theSuffix.length() ) );
00768       goon = false;
00769     }
00770       }
00771       if ( goon && (*mPrefs).useWorkSuff() ) {
00772         QString theSuffix = decodeSuffix( (*mPrefs).workSuff() );
00773     if ( name.right( theSuffix.length() ) == theSuffix ) {
00774       phoneType = KABC::PhoneNumber::Work;
00775       name = stripWhiteSpaces(
00776                name.left( name.length() - theSuffix.length() ) );
00777       goon = false;
00778     }
00779       }
00780       if ( goon && (*mPrefs).useMessagingSuff() ) {
00781         QString theSuffix = decodeSuffix( (*mPrefs).messagingSuff() );
00782     if ( name.right( theSuffix.length() ) == theSuffix ) {
00783       phoneType = KABC::PhoneNumber::Msg;
00784       name = stripWhiteSpaces(
00785                name.left( name.length() - theSuffix.length() ) );
00786       goon = false;
00787     }
00788       }
00789       if ( goon && (*mPrefs).useFaxSuff() ) {
00790         QString theSuffix = decodeSuffix( (*mPrefs).faxSuff() );
00791     if ( name.right( theSuffix.length() ) == theSuffix ) {
00792       phoneType = KABC::PhoneNumber::Fax;
00793       name = stripWhiteSpaces(
00794                name.left( name.length() - theSuffix.length() ) );
00795       goon = false;
00796     }
00797       }
00798       if ( goon && (*mPrefs).useCellSuff() ) {
00799         QString theSuffix = decodeSuffix( (*mPrefs).cellSuff() );
00800     if ( name.right( theSuffix.length() ) == theSuffix ) {
00801       phoneType = KABC::PhoneNumber::Cell;
00802       name = stripWhiteSpaces(
00803                name.left( name.length() - theSuffix.length() ) );
00804       goon = false;
00805     }
00806       }
00807       if ( goon && (*mPrefs).useVideoSuff() ) {
00808         QString theSuffix = decodeSuffix( (*mPrefs).videoSuff() );
00809     if ( name.right( theSuffix.length() ) == theSuffix ) {
00810       phoneType = KABC::PhoneNumber::Video;
00811       name = stripWhiteSpaces(
00812                name.left( name.length() - theSuffix.length() ) );
00813       goon = false;
00814     }
00815       }
00816       if ( goon && (*mPrefs).useMailboxSuff() ) {
00817         QString theSuffix = decodeSuffix( (*mPrefs).mailboxSuff() );
00818     if ( name.right( theSuffix.length() ) == theSuffix ) {
00819       phoneType = KABC::PhoneNumber::Bbs;
00820       name = stripWhiteSpaces(
00821                name.left( name.length() - theSuffix.length() ) );
00822       goon = false;
00823     }
00824       }
00825       if ( goon && (*mPrefs).useModemSuff() ) {
00826         QString theSuffix = decodeSuffix( (*mPrefs).modemSuff() );
00827     if ( name.right( theSuffix.length() ) == theSuffix ) {
00828       phoneType = KABC::PhoneNumber::Modem;
00829       name = stripWhiteSpaces(
00830                name.left( name.length() - theSuffix.length() ) );
00831       goon = false;
00832     }
00833       }
00834       if ( goon && (*mPrefs).useCarSuff() ) {
00835         QString theSuffix = decodeSuffix( (*mPrefs).carSuff() );
00836     if ( name.right( theSuffix.length() ) == theSuffix ) {
00837       phoneType = KABC::PhoneNumber::Car;
00838       name = stripWhiteSpaces(
00839                name.left( name.length() - theSuffix.length() ) );
00840       goon = false;
00841     }
00842       }
00843       if ( goon && (*mPrefs).useISDNSuff() ) {
00844         QString theSuffix = decodeSuffix( (*mPrefs).iSDNSuff() );
00845     if ( name.right( theSuffix.length() ) == theSuffix ) {
00846       phoneType = KABC::PhoneNumber::Isdn;
00847       name = stripWhiteSpaces(
00848                name.left( name.length() - theSuffix.length() ) );
00849       goon = false;
00850     }
00851       }
00852       if ( goon && (*mPrefs).usePagerSuff() ) {
00853         QString theSuffix = decodeSuffix( (*mPrefs).pagerSuff() );
00854     if ( name.right( theSuffix.length() ) == theSuffix ) {
00855       phoneType = KABC::PhoneNumber::Pager;
00856       name = stripWhiteSpaces(
00857                name.left( name.length() - theSuffix.length() ) );
00858       goon = false;
00859     }
00860       }
00861 
00862 
00863       //
00864       // Search for a KAB entry whose name, if formatted in exactly the
00865       // same way as was done in readKabc, is equal to the actual name.
00866       //
00867       
00868       for ( it = addressBook->begin(); it != addressBook->end(); it++ ) {
00869         QString kabName = (*it).familyName();
00870     KABC::AddressBook::Iterator it3;
00871     KABC::Addressee::List tmp;
00872     bool firstCharIsUnique = true;
00873     unsigned int minLength;
00874 
00875 
00876     for ( it3 = addressBook->begin(); it3 != addressBook->end(); it3++ )
00877       if ( ( (*it3).familyName() == kabName ) && ( it3 != it ) ) {
00878         tmp.append( (*it3) );
00879         if ( (*it3).givenName()[0] == (*it).givenName()[0] )
00880           firstCharIsUnique = false;
00881       }
00882 
00883     // There are several KAB entries with the same family name.
00884     // So, we need to append the given name in order to
00885     // distinguish them.
00886     if ( ( tmp.size() > 0 ) && !(*it).givenName().isEmpty() ) {
00887       kabName += ", ";
00888           
00889       if ( firstCharIsUnique )
00890         kabName += (*it).givenName()[0] + ".";
00891       else
00892         kabName += (*it).givenName();
00893     }
00894           
00895     // Truncate name field if it's too long for mobile phone
00896     if ( kabName.length() > mPBNameLength )
00897       kabName = kabName.remove( mPBNameLength,
00898                                 kabName.length() - mPBNameLength );
00899 
00900         minLength = kabName.length();
00901     if ( name.length() < minLength )
00902       minLength = name.length();
00903       
00904     if ( name.left( minLength ) == kabName.left( minLength ) ) {
00905       (*it).insertPhoneNumber( KABC::PhoneNumber( phoneNumber,
00906                                                   phoneType ) );
00907       
00908       equivalentEntryFound = true;
00909       break;
00910     }
00911       }
00912       
00913       //
00914       // If no equivalent entry was found in KAB, we need to generate
00915       // a complete new entry.
00916       //
00917       
00918       if ( !equivalentEntryFound ) {
00919         KABC::Addressee entry;
00920         QStringList *fields = new QStringList;
00921 
00922   
00923         *fields = QStringList::split( ',', name );
00924     
00925     if ( fields->count() > 1 ) {
00926       // Name string contains comma separated entry so that we
00927       // need to build family and given names out of them.
00928       QString givenName = "";
00929       
00930 
00931       entry.setFamilyName( stripWhiteSpaces( (*fields)[ 0 ] ) );
00932       
00933       for ( unsigned int i = 1; i < fields->count(); i++ )
00934         givenName += stripWhiteSpaces( (*fields)[ i ] ) + " ";
00935       entry.setGivenName( stripWhiteSpaces( givenName ) );
00936     } else
00937       // Name string contains only one string without comma.
00938       entry.setFamilyName( stripWhiteSpaces( name ) );
00939 
00940         entry.insertPhoneNumber( KABC::PhoneNumber( phoneNumber, phoneType ) );
00941 
00942         addressBook->insertAddressee( entry );
00943       }
00944     }
00945 
00946     kabEntry->mToBeUpdated = false;
00947     kabEntry->mToBeInserted = false;
00948   }
00949   
00950   addressBook->save( ticket );
00951   
00952   emit transientStatusMessage( i18n( "Wrote KDE address book." ) );
00953   
00954   setKabState( LOADED );
00955 }
00956 
00957 
00958 void MobileGui::refreshStatus()
00959 {
00960   mScheduler->executeId( "+cbc" );
00961   mScheduler->executeId( "+csq" );
00962 }
00963 
00964 
00965 void MobileGui::processResult( ATCommand *command )
00966 {
00967   if ( command->id() == "+cbc" )
00968     mBatteryChargeLabel->setText( command->resultField( 1 ) + " %" );
00969   else
00970   if ( command->id() == "+csq" )
00971     mSignalQualityLabel->setText( command->resultField( 0 ) );
00972   else
00973   if ( command->id() == "+cgmi" ) {
00974     mMobManufacturer = command->resultField( 0 );
00975     mManufacturerLabel->setText( mMobManufacturer );
00976   } else
00977   if ( command->id() == "+cgmm" ) {
00978     mMobModel = command->resultField( 0 );
00979     mModelLabel->setText( mMobModel );
00980   } else
00981   if ( command->id() == "+cgmr" )
00982     mGSMVersionLabel->setText( command->resultField( 0 ) );
00983   else
00984   if ( command->id() == "+cgsn" )
00985     mSerialNumberLabel->setText( command->resultField( 0 ) );
00986   else
00987   if ( command->id() == "+cpbr=?" )
00988   {
00989     QStringList tmpList = QStringList::split( "-", command->resultField( 0 ) );
00990     QString tmpString = tmpList.first().right( tmpList.first().length() - 1 );
00991     mPBStartIndex = tmpString.toUInt();
00992     mPBNameLength = command->resultField( 2 ).toUInt();
00993   } else
00994   if ( command->id() == "+cpbs?" ) {
00995     mPBLength = command->resultField( 2 ).toUInt();
00996 
00997     // Allocate and initialize memory for the buckets of indices
00998     mPBIndexOccupied.resize( mPBLength, false );
00999     for ( unsigned int i = 0; i < mPBLength; i++ )
01000       mPBIndexOccupied[ i ] = false;
01001   } else
01002   if ( command->id() == "+cpbr=" ) {
01003     fillPhonebook( command );
01004     
01005     if ( mComingFromSyncPhonebooks ) {
01006       mComingFromSyncPhonebooks = false;
01007       mergePhonebooks();
01008     }
01009   } else
01010   if ( command->id() == mLastWriteId )
01011     writePhonebookPostProcessing();
01012   else
01013   if ( command->id() == "+cpbs=?" ) {
01014     QPtrList<QStringList> *list = command->resultFields();
01015     QStringList *fields = list->first();
01016 
01017 
01018     while( fields ) {
01019       for ( unsigned int i = 0; i < fields->count(); i++ ) {
01020         QString memory = dequote( (*fields)[ i ] );
01021 
01022 
01023     if ( memory == "FD" )
01024       mMobHasFD = true;
01025         else
01026     if ( memory == "LD" )
01027       mMobHasLD = true;
01028     else
01029     if ( memory == "ME" )
01030       mMobHasME = true;
01031     else
01032     if ( memory == "MT" )
01033       mMobHasMT = true;
01034     else
01035     if ( memory == "TA" )
01036       mMobHasTA = true;
01037     else
01038     if ( ( memory == "OW" ) ||
01039          ( ( memory == "ON" ) && ( mMobManufacturer == "SIEMENS" ) ) )
01040       mMobHasOW = true;
01041     else
01042     if ( ( mMobManufacturer == "SIEMENS" ) && ( memory == "MC" ) )
01043       mMobHasMC = true;
01044     else
01045     if ( ( mMobManufacturer == "SIEMENS" ) && ( memory == "RC" ) )
01046       mMobHasRC = true;
01047       }
01048       
01049       fields = list->next();
01050     }
01051   }
01052 }
01053 
01054 
01055 QString MobileGui::noSpaces( const QString &theString )
01056 {
01057   QString result = "";
01058   
01059   
01060   for ( unsigned int i = 0; i < theString.length(); i++ )
01061     if ( theString[ i ].latin1() != ' ' )
01062       result += theString[ i ];
01063   
01064   return result;
01065 }
01066 
01067 
01068 int MobileGui::firstFreeIndex()
01069 {
01070   unsigned int i;
01071   
01072   
01073   if ( mPBIndexOccupied.capacity() == 0 )
01074     return 0;
01075 
01076   for ( i = 1; i < mPBLength; i++ )
01077     if ( !mPBIndexOccupied[ i ] )
01078       break;
01079 
01080   if ( i < mPBLength )
01081     return i;
01082 
01083   return 0;
01084 }
01085 
01086 
01087 QString MobileGui::string2GSM( const QString &theString )
01088 {
01089   QString result = "";
01090 
01091 
01092   for ( unsigned int i = 0; i < theString.length(); i++ )
01093     switch ( theString[ i ].latin1() ) {
01094       case 'Ä': result += '['; break;
01095       case 'ä': result += '{'; break;
01096       case 'Ö': result += 92; break;
01097       case 'ö': result += '|'; break;
01098       case 'Ü': result += '^'; break;
01099       case 'ü': result += '~'; break;
01100       case 'ß': result += 30; break;
01101       case 'è': result += 4; break;
01102       case 'é': result += 5; break;
01103       
01104       default: result += theString[ i ];
01105     }
01106   
01107   return result;
01108 }
01109 
01110 
01111 QString MobileGui::GSM2String( const QString &theString )
01112 {
01113   QString result = "";
01114 
01115 
01116   for ( unsigned int i = 0; i < theString.length(); i++ )
01117     switch ( theString[ i ].latin1() ) {
01118       case '[': result += 'Ä'; break;
01119       case '{': result += 'ä'; break;
01120       case 92:  result += 'Ö'; break;
01121       case '|': result += 'ö'; break;
01122       case '^': result += 'Ü'; break;
01123       case '~': result += 'ü'; break;
01124       case 30:  result += 'ß'; break;
01125       case 4:   result += 'è'; break;
01126       case 5:   result += 'é'; break;
01127 
01128       default: result += theString[ i ];
01129     }
01130 
01131   return result;
01132 }
01133 
01134 
01135 void MobileGui::fillPhonebook( ATCommand *cmd )
01136 {
01137   mSyncer->mMobileEntries.clear();
01138     
01139   QPtrList<QStringList> *list = cmd->resultFields();
01140   QStringList *fields = list->first();
01141 
01142   while( fields ) {
01143     if ( fields->count() != 4 )
01144       kdDebug() << "Error! Unexpected number of address fields." << endl;
01145     else {
01146       QString index = (*fields)[0];
01147       QString phone = (*fields)[1];
01148       QString type = (*fields)[2];
01149       QString name = GSM2String( (*fields)[3] );
01150 
01151       SyncEntryMobile *phoneEntry = new SyncEntryMobile( true, dequote( index ),
01152                                                          dequote( phone ),
01153                              dequote( name ) );
01154       mPBIndexOccupied[ index.toUInt() - mPBStartIndex ] = true;
01155       mSyncer->mMobileEntries.append( phoneEntry );
01156     }
01157     fields = list->next();
01158   }
01159 
01160   // Display mobile entries
01161   updateMobileBook();
01162 
01163   emit transientStatusMessage(i18n("Read mobile phonebook."));
01164   emit phonebookRead();
01165   
01166   setMobState( LOADED );
01167 }
01168 
01169 
01170 QString MobileGui::quote( const QString &str )
01171 {
01172   if ( ( str.left(1) == "\"" ) && ( str.right(1) == "\"" ) )
01173     return str;
01174   
01175   return "\"" + str + "\"";
01176 }
01177 
01178 
01179 QString MobileGui::dequote( const QString &str )
01180 {
01181   int pos = 0;
01182   int len = str.length();
01183 
01184 
01185   if ( str.left(1) == "\"" ) {
01186     pos = 1;
01187     len --;
01188   } 
01189   
01190   if ( str.right(1) == "\"" )
01191     len--;
01192   
01193   return str.mid( pos, len );
01194 }
01195 
01196 
01197 void MobileGui::savePhonebook()
01198 {
01199   if ( mMobState == UNLOADED )
01200     return;
01201     
01202   QString fileName = KFileDialog::getSaveFileName( "phonebook.csv" );
01203   QFile outFile( fileName );
01204 
01205   if ( outFile.open( IO_WriteOnly ) ) {
01206     QTextStream t( &outFile );        // use a text stream
01207 
01208     for( uint i = 0; i < mSyncer->mMobileEntries.count(); i++) {
01209       SyncEntryMobile *e = mSyncer->mMobileEntries.at( i );
01210       
01211       
01212       if ( !e->mToBeDeleted )
01213         t << e->mIndex << "," << e->mPhone << "," << e->mName << endl;
01214     }
01215 
01216     outFile.close();
01217   }
01218 }
01219 
01220 
01221 void MobileGui::deleteMobPhonebook()
01222 {
01223 
01224   //
01225   // Process all elements selected in the GUI
01226   //
01227   
01228   PhoneBookItem *item = (PhoneBookItem *) mMobileBook->firstChild();
01229   while ( item ) {
01230     if ( item->isOn() ) {
01231       SyncEntryMobile *mobileItem = (SyncEntryMobile *) item->syncEntry();
01232 
01233 
01234       // Deselect current item
01235       item->setOn( false );
01236       mobileItem->mOn = false;
01237       
01238       // Mark current item as deleted
01239       mobileItem->mToBeDeleted = true;
01240     }
01241     
01242     item = (PhoneBookItem *) item->nextSibling();
01243   }
01244       
01245   // Update GUI
01246   updateMobileBook();
01247   setMobState( MODIFIED );
01248 }
01249 
01250 
01251 void MobileGui::mergePhonebooks()
01252 {
01253   uint i;
01254   
01255   
01256   //
01257   // Transfer current Selection State from GUI to mSyncer
01258   //
01259 
01260   PhoneBookItem *item = (PhoneBookItem *) mKabBook->firstChild();
01261   while ( item ) {
01262     item->syncEntry()->mOn = item->isOn();
01263     item = (PhoneBookItem *) item->nextSibling();
01264   }
01265 
01266   item = (PhoneBookItem *) mMobileBook->firstChild();
01267   while ( item ) {
01268     item->syncEntry()->mOn = item->isOn();
01269     item = (PhoneBookItem *) item->nextSibling();
01270   }
01271   
01272   mSyncer->mCommonEntries.clear();
01273 
01274 
01275   //
01276   // Put KDE Address Book list into Common List
01277   //
01278 
01279   for ( i = 0; i < mSyncer->mKabEntries.count(); i++ )
01280     if ( mSyncer->mKabEntries.at( i )->mOn ) {
01281       mSyncer->mCommonEntries.append(
01282         new SyncEntryCommon( true, mSyncer->mKabEntries.at( i ), 0 ) );
01283       mSyncer->mKabEntries.at( i )->mOn = false;
01284     }
01285 
01286 
01287   //
01288   // Put Mobile Address Book list into Common List; Merge equivalent entries
01289   //
01290   
01291   for ( i = 0; i < mSyncer->mMobileEntries.count(); i++ ) {
01292     SyncEntryMobile *mobileEntry = mSyncer->mMobileEntries.at( i );
01293     bool equivalentEntryFound = false;
01294     uint j;
01295     
01296     
01297     if( !mobileEntry->mToBeDeleted )
01298       for ( j = 0; j < mSyncer->mCommonEntries.count(); j++ ) {
01299         SyncEntryCommon *theCommonEntry = mSyncer->mCommonEntries.at( j );
01300       
01301       
01302         if ( theCommonEntry->mKabEntry &&
01303          ( theCommonEntry->mKabEntry->mName == mobileEntry->mName ) ) {
01304           theCommonEntry->mMobileEntry = mobileEntry;
01305       equivalentEntryFound = true;
01306     
01307           if ( noSpaces( theCommonEntry->mKabEntry->mPhone ) ==
01308            mobileEntry->mPhone ) {
01309         mobileEntry->mOn = false;
01310         break;
01311           } else {
01312         // Conflict: 2 Entries have same name but different numbers.
01313         // Prompt user.
01314             QString text = "<qt><b>" + i18n( "Kab Entry:" ) + "</b><br>";
01315             text += "  " + theCommonEntry->mKabEntry->mName + " " +
01316                        theCommonEntry->mKabEntry->mPhone + "<br>";
01317             text += "<b>" + i18n( "Mobile Entry:" ) + "</b><br>";
01318             text += "  " + mobileEntry->mName + " " + mobileEntry->mPhone;
01319             text += "</qt>";
01320       
01321             QMessageBox *msg =
01322           new QMessageBox( i18n( "Conflicting Entries" ), text,
01323                            QMessageBox::Warning, 1, 2, 0, this );
01324             msg->setButtonText( 1, i18n( "Use Kab Entry" ) );
01325             msg->setButtonText( 2, i18n( "Use Mobile Entry" ) );
01326       
01327         switch ( msg->exec() ) {
01328           case 1:
01329             // Use KDE Address Book Entry
01330             mobileEntry->mPhone = theCommonEntry->mKabEntry->mPhone;
01331             mobileEntry->mName = theCommonEntry->mKabEntry->mName;
01332             mobileEntry->mOn = true;
01333             mobileEntry->mToBeUpdated = true;
01334           
01335             setMobState( MODIFIED );
01336             break;
01337           
01338           case 2:
01339             // Use Mobile Address Book Entry
01340             theCommonEntry->mKabEntry->mPhone = mobileEntry->mPhone;
01341             theCommonEntry->mKabEntry->mName = mobileEntry->mName;
01342             theCommonEntry->mKabEntry->mOn = true;
01343         theCommonEntry->mKabEntry->mToBeUpdated = true;
01344         
01345         mobileEntry->mOn = false;
01346           
01347             setKabState( MODIFIED );
01348             break;
01349         }
01350       }
01351         }
01352       }
01353 
01354     if ( !equivalentEntryFound && mobileEntry->mOn ) {
01355       // No equivalent entry exists; generate a new one.
01356       mSyncer->mCommonEntries.append(
01357         new SyncEntryCommon( true, 0, mobileEntry ) );
01358       mobileEntry->mOn = false;
01359     }
01360   }
01361 
01362 
01363   //
01364   // Create new KAB and Mobile Entries
01365   //
01366   
01367   for ( i = 0; i < mSyncer->mCommonEntries.count(); i++ ) {
01368     SyncEntryCommon *entry = mSyncer->mCommonEntries.at( i );
01369     SyncEntryKab *kabEntry = entry->mKabEntry;
01370     SyncEntryMobile *mobileEntry = entry->mMobileEntry;
01371 
01372 
01373     if ( kabEntry && !mobileEntry ) {
01374       // Create Mobile Entry
01375       entry->mMobileEntry = new SyncEntryMobile( true, "", kabEntry->mPhone,
01376                                                  kabEntry->mName );
01377       entry->mMobileEntry->mToBeInserted = true;
01378       mSyncer->mMobileEntries.append( entry->mMobileEntry );
01379 
01380       setMobState( MODIFIED );
01381     } else
01382     if ( mobileEntry && !kabEntry ) {
01383       // Create KAB Entry
01384       entry->mKabEntry = new SyncEntryKab( true, mobileEntry->mIndex,
01385                                            mobileEntry->mName,
01386                        mobileEntry->mPhone );
01387       entry->mKabEntry->mToBeInserted = true;
01388       mSyncer->mKabEntries.append( entry->mKabEntry );
01389 
01390       setKabState( MODIFIED );
01391     }
01392   }
01393 
01394 
01395   //
01396   // Update GUI
01397   //
01398 
01399   updateKabBook();
01400   updateMobileBook();
01401 
01402   emit transientStatusMessage( i18n( "Synced phonebooks." ) );
01403   PushButton8_3->setEnabled( true );
01404 }
01405 
01406 
01407 void MobileGui::syncPhonebooks()
01408 {
01409   PushButton8_3->setEnabled( false );
01410 
01411   if ( mKabState == UNLOADED )
01412     readKabc();
01413   if ( mMobState == UNLOADED ) {
01414     mComingFromSyncPhonebooks = true;
01415     readPhonebook();
01416   } else
01417     mergePhonebooks();
01418 }
01419 
01420 
01421 void MobileGui::updateKabBook()
01422 {
01423   mKabBook->clear();
01424   
01425   for ( uint i = 0; i < mSyncer->mKabEntries.count(); i++ ) {
01426     SyncEntryKab *kabEntry = mSyncer->mKabEntries.at( i );
01427     PhoneBookItem *item = new PhoneBookItem( mKabBook, kabEntry,
01428                                              kabEntry->mName, kabEntry->mPhone,
01429                          kabEntry->mIndex );
01430     item->setOn( kabEntry->mOn );
01431   }
01432 }
01433 
01434 
01435 void MobileGui::updateMobileBook()
01436 {
01437   mMobileBook->clear();
01438   
01439   for ( uint i = 0; i < mSyncer->mMobileEntries.count(); i++ ) {
01440     SyncEntryMobile *entry = mSyncer->mMobileEntries.at( i );
01441     
01442     if ( !entry->mToBeDeleted ) {
01443       PhoneBookItem *item = new PhoneBookItem( mMobileBook, entry, entry->mName,
01444                                                entry->mPhone, entry->mIndex );
01445       item->setOn( entry->mOn );
01446     }
01447   }
01448 }
01449 
01450 
01451 void MobileGui::toggleConnection()
01452 {
01453   if ( mConnectButton->text() == i18n( "Connect" ) ) {
01454     emit connectModem();
01455     
01456     readModelInformation();
01457     refreshStatus();
01458     
01459     mConnectButton->setText( tr2i18n( "Disconnect" ) );
01460     PushButton1->setEnabled( true );
01461     PushButton5_3->setEnabled( true );
01462 
01463     mABTab->setEnabled( true );
01464     setKabState( UNLOADED );
01465     setMobState( UNLOADED );
01466 
01467     ((MobileMain *) mparent)->statusBar()->changeItem( i18n(" Connected "), 1 );
01468   } else {
01469     warnKabState( UNLOADED );
01470 
01471     mComingFromToggleConnection = true;
01472     if ( !warnMobState( UNLOADED ) ) {
01473       mComingFromToggleConnection = false;
01474       disconnectGUI();
01475     }
01476   }
01477 }
01478 
01479 
01480 void MobileGui::disconnectGUI()
01481 {
01482   emit disconnectModem();
01483     
01484   mManufacturerLabel->setText( "x" );
01485   mModelLabel->setText( "x" );
01486   mGSMVersionLabel->setText( "x" );
01487   mSerialNumberLabel->setText( "x" );
01488 
01489   mBatteryChargeLabel->setText( "xx %" );
01490   mSignalQualityLabel->setText( "x" );
01491 
01492   mConnectButton->setText( tr2i18n( "Connect" ) );
01493   PushButton1->setEnabled( false );
01494   PushButton5_3->setEnabled( false );
01495     
01496   mKabBook->clear();
01497   mMobileBook->clear();
01498   setKabState( UNLOADED );
01499   setMobState( UNLOADED );
01500 
01501   mABTab->setEnabled( false );
01502   
01503   mMobHasFD = false;
01504   mMobHasLD = false;
01505   mMobHasME = false;
01506   mMobHasMT = false;
01507   mMobHasTA = false;
01508   mMobHasOW = false;
01509   mMobHasMC = false;
01510   mMobHasRC = false;
01511   
01512   mPBIndexOccupied.resize( 0, false );
01513 
01514   ((MobileMain *) mparent)->statusBar()->changeItem( i18n(" Disconnected "),
01515                                                      1 );
01516 }
01517 
01518 
01519 void MobileGui::termAddOutput( const char *line )
01520 {
01521   mTermIO->append( line );
01522   mTermIO->setCursorPosition( mTermIO->paragraphs() - 1, 0 );
01523 }
01524 
01525 
01526 void MobileGui::setKabState( ABState newState )
01527 {
01528   switch ( mKabState ) {
01529     case UNLOADED:
01530       groupBox3->setTitle( tr2i18n( "KDE Address Book" ) );
01531       mReadKabButton->setEnabled( true );
01532       PushButton8->setEnabled( false );
01533       break;
01534       
01535     case LOADED:
01536       if ( newState == MODIFIED ) {
01537         groupBox3->setTitle( tr2i18n( "KDE Address Book (modified)" ) );
01538     mReadKabButton->setEnabled( true );
01539     PushButton8->setEnabled( true );
01540       } else
01541       if ( newState == UNLOADED ) {
01542         groupBox3->setTitle( tr2i18n( "KDE Address Book" ) );
01543     mReadKabButton->setEnabled( true );
01544     PushButton8->setEnabled( false );
01545       }
01546       break;
01547 
01548     case MODIFIED:
01549       if ( newState != MODIFIED ) {
01550         groupBox3->setTitle( tr2i18n( "KDE Address Book" ) );
01551     mReadKabButton->setEnabled( true );
01552     PushButton8->setEnabled( false );
01553       }
01554       break;
01555   }
01556   
01557   mKabState = newState;
01558 }
01559 
01560 
01561 void MobileGui::warnKabState( ABState newState )
01562 {
01563   if ( ( mKabState == MODIFIED ) && ( newState != MODIFIED ) ) {
01564     QString text = "<qt><b>" + i18n( "Warning" ) + "</b><br>";
01565     text += i18n( "The KDE address book contains unsaved changes." ) +
01566             "<br></qt>";
01567       
01568     QMessageBox *msg = new QMessageBox( i18n( "Unsaved Changes" ), text,
01569                                         QMessageBox::Critical, 1, 2, 0, this );
01570     msg->setButtonText( 1, i18n( "Save" ) );
01571     msg->setButtonText( 2, i18n( "Discard" ) );
01572       
01573     switch ( msg->exec() ) {
01574       case 1:
01575         // Save Changes first
01576     writeKabc();
01577     break;
01578           
01579       case 2:
01580     break;
01581     }
01582   }
01583 }
01584 
01585 
01586 void MobileGui::setMobState( ABState newState )
01587 {
01588   switch ( mMobState ) {
01589     case UNLOADED:
01590       if ( newState == UNLOADED ) {
01591         groupBox4->setTitle( tr2i18n( "Mobile Phone Book" ) );
01592         PushButton3->setEnabled( true );
01593         PushButton12->setEnabled( false );
01594         PushButton4_2->setEnabled( false );
01595     MobDeleteButton->setEnabled( false );
01596       } else
01597       if ( newState == LOADED ) {
01598         groupBox4->setTitle( tr2i18n( "Mobile Phone Book" ) );
01599         PushButton3->setEnabled( true );
01600         PushButton12->setEnabled( false );
01601         PushButton4_2->setEnabled( true );
01602     MobDeleteButton->setEnabled( true );
01603       }
01604       break;
01605       
01606     case LOADED:
01607       if ( newState == MODIFIED ) {
01608         groupBox4->setTitle( tr2i18n( "Mobile Phone Book (modified)" ) );
01609     PushButton3->setEnabled( true );
01610     PushButton12->setEnabled( true );
01611     PushButton4_2->setEnabled( true );
01612     MobDeleteButton->setEnabled( true );
01613       } else
01614       if ( newState == UNLOADED ) {
01615         groupBox4->setTitle( tr2i18n( "Mobile Phone Book" ) );
01616     PushButton3->setEnabled( true );
01617     PushButton12->setEnabled( false );
01618     PushButton4_2->setEnabled( false );
01619     MobDeleteButton->setEnabled( false );
01620       }
01621       break;
01622 
01623     case MODIFIED:
01624       if ( newState == UNLOADED ) {
01625         groupBox4->setTitle( tr2i18n( "Mobile Phone Book" ) );
01626     PushButton3->setEnabled( true );
01627     PushButton12->setEnabled( false );
01628     PushButton4_2->setEnabled( false );
01629     MobDeleteButton->setEnabled( false );
01630       } else
01631       if ( newState == LOADED ) {
01632         groupBox4->setTitle( tr2i18n( "Mobile Phone Book" ) );
01633     PushButton3->setEnabled( true );
01634     PushButton12->setEnabled( false );
01635     PushButton4_2->setEnabled( true );
01636     MobDeleteButton->setEnabled( true );
01637       }
01638       break;
01639   }
01640   
01641   mMobState = newState;
01642 }
01643 
01644 
01645 bool MobileGui::warnMobState( ABState newState )
01646 {
01647   if ( ( mMobState == MODIFIED ) && ( newState != MODIFIED ) )
01648   {
01649     QString text = "<qt><b>" + i18n( "Warning" ) + "</b><br>";
01650     text += i18n( "The mobile phone book contains unsaved changes." ) +
01651             "<br></qt>";
01652       
01653     QMessageBox *msg = new QMessageBox( i18n( "Unsaved Changes" ), text,
01654                                         QMessageBox::Critical, 1, 2, 0, this );
01655     msg->setButtonText( 1, i18n( "Save" ) );
01656     msg->setButtonText( 2, i18n( "Discard" ) );
01657       
01658     switch ( msg->exec() ) {
01659       case 1:
01660         // Save Changes first
01661     writePhonebook();
01662     return true;
01663     break;
01664           
01665       case 2:
01666         return false;
01667     break;
01668     }
01669   }
01670   
01671   return false;
01672 }
KDE Home | KDE Accessibility Home | Description of Access Keys