kandy Library API Documentation

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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, 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 <qlabel.h>
00026 #include <qlistview.h>
00027 #include <qfile.h>
00028 #include <qtextstream.h>
00029 #include <qmessagebox.h>
00030 
00031 #include <kdebug.h>
00032 #include <kfiledialog.h>
00033 #include <kmessagebox.h>
00034 #include <klocale.h>
00035 #include <kapplication.h>
00036 
00037 #include <kabc/stdaddressbook.h>
00038 
00039 #include "atcommand.h"
00040 #include "commandscheduler.h"
00041 
00042 #include "mobilegui.h"
00043 #include "mobilegui.moc"
00044 
00045 class SyncEntry {
00046   public:
00047     SyncEntry() { mOn = true; }
00048   
00049     bool mOn;
00050 };
00051 
00052 class SyncEntryKab : public SyncEntry {
00053   public:
00054     SyncEntryKab(bool on,const QString &index,const QString &name,
00055                  const QString &type,const QString &phone,const QString &phonetype)
00056     {
00057       mOn = on;
00058       mIndex = index;
00059       mName = name;
00060       mType = type;
00061       mPhone = phone;
00062       mPhonetype = phonetype;
00063     }
00064   
00065     QString mIndex;
00066     QString mName;
00067     QString mType;
00068     QString mPhone;
00069     QString mPhonetype;
00070 
00071     KABC::Addressee mAddressee;
00072 };
00073 
00074 class SyncEntryMobile : public SyncEntry {
00075   public:
00076     SyncEntryMobile(bool on,const QString &index,const QString &phone,
00077                     const QString &type,const QString &name)
00078     {
00079       mOn = on;
00080       mIndex = index;
00081       mName = name;
00082       mType = type;
00083       mPhone = phone;
00084     }
00085     
00086     QString mIndex;
00087     QString mName;
00088     QString mType;
00089     QString mPhone;
00090 };
00091 
00092 class SyncEntryCommon : public SyncEntry {
00093   public:
00094     SyncEntryCommon(bool on,SyncEntryKab *kabEntry,SyncEntryMobile *mobileEntry)
00095     {
00096       mOn = on;
00097       mKabEntry = kabEntry;
00098       mMobileEntry = mobileEntry;
00099     }
00100     
00101     SyncEntryKab *mKabEntry;
00102     SyncEntryMobile *mMobileEntry;
00103 };
00104 
00105 class AddressSyncer {
00106   public:
00107     AddressSyncer()
00108     {
00109       mKabEntries.setAutoDelete(true);
00110       mMobileEntries.setAutoDelete(true);
00111       mCommonEntries.setAutoDelete(true);
00112     }
00113   
00114     QPtrList<SyncEntryKab> mKabEntries;
00115     QPtrList<SyncEntryMobile> mMobileEntries;
00116     QPtrList<SyncEntryCommon> mCommonEntries; 
00117 };
00118 
00119 
00120 class PhoneBookItem : public QCheckListItem {
00121   public:
00122     PhoneBookItem(QListView *v) : QCheckListItem(v,"",QCheckListItem::CheckBox)
00123     {
00124       mSyncEntry = 0;
00125     }
00126     PhoneBookItem(QListView *v,SyncEntry *syncEntry,const QString &index,
00127                   const QString &phone,
00128                   const QString &type, const QString &name) :
00129       QCheckListItem(v,index,QCheckListItem::CheckBox)
00130     {
00131       mSyncEntry = syncEntry;
00132       
00133       setText(1,phone);
00134       setText(2,type);
00135       setText(3,name);
00136     }
00137 
00138     void setItem(const QString &index,const QString &phone,
00139                  const QString &type, const QString &name)
00140     {
00141       setText(0,index);
00142       setText(1,phone);
00143       setText(2,type);
00144       setText(3,name);
00145     }
00146 
00147     void setIndex(int i) { setText(0,QString::number(i)); }
00148     QString index() { return text(0); }
00149     QString phone() { return text(1); }
00150     QString type() { return text(2); }
00151     QString name() { return text(3); }
00152 
00153     SyncEntry *syncEntry() { return mSyncEntry; }
00154 
00155   private:
00156     SyncEntry *mSyncEntry;
00157 };
00158 
00159 
00160 /* 
00161  *  Constructs a MobileGui which is a child of 'parent', with the 
00162  *  name 'name' and widget flags set to 'f' 
00163  *
00164  *  The dialog will by default be modeless, unless you set 'modal' to
00165  *  TRUE to construct a modal dialog.
00166  */
00167 MobileGui::MobileGui(CommandScheduler *scheduler,QWidget* parent,
00168                      const char* name,WFlags fl)
00169     : DCOPObject("KandyIface"),
00170       MobileGui_base(parent,name,fl)
00171 {
00172   mSyncing = false;
00173   mScheduler = scheduler;
00174   mSyncer = new AddressSyncer;
00175 
00176   connect(mScheduler,SIGNAL(commandProcessed(ATCommand *)),
00177           SLOT(processResult(ATCommand *)));
00178 }
00179 
00180 MobileGui::~MobileGui()
00181 {
00182   delete mSyncer;
00183 }
00184 
00185 void MobileGui::exit()
00186 {
00187   kapp->quit();
00188 }
00189 
00190 void MobileGui::readModelInformation()
00191 {
00192   mScheduler->executeId("+cgmi");
00193   mScheduler->executeId("+cgmm");
00194   mScheduler->executeId("+cgmr");
00195   mScheduler->executeId("+cgsn");
00196 }
00197 
00198 void MobileGui::readPhonebook()
00199 {
00200   mScheduler->executeId("+cpbr=1,150");
00201   
00202   emit statusMessage(i18n("Reading mobile phonebook..."));
00203 }
00204 
00205 void MobileGui::writePhonebook()
00206 {
00207   kdDebug() << "MobileGui::writePhonebook" << endl;
00208 
00209   for(uint i=0;i<mSyncer->mMobileEntries.count();++i) {
00210     SyncEntryMobile *entry = mSyncer->mMobileEntries.at(i);
00211 
00212 //    kdDebug() << "Writing " << entry->mIndex << " " << entry->mName
00213 //              << " " << entry->mPhone << endl;
00214 
00215     QString id = "+cpbw=" + entry->mIndex;
00216     mLastWriteId = id;
00217     ATCommand *cmd = new ATCommand(id);
00218     cmd->setAutoDelete(true);
00219     cmd->addParameter(new ATParameter(quote(entry->mPhone)));
00220     cmd->addParameter(new ATParameter(entry->mType));
00221     cmd->addParameter(new ATParameter(quote(entry->mName)));
00222 
00223     kdDebug() << "  " << cmd->cmd() << endl;
00224     kdDebug() << "  id: " << cmd->id() << endl;
00225     
00226     mScheduler->execute(cmd);
00227   }
00228 
00229   emit statusMessage(i18n("Writing mobile phonebook..."));  
00230 }
00231 
00232 void MobileGui::readKabc()
00233 {
00234   kdDebug() << "MobileGui::readKabc()" << endl;
00235 
00236   mSyncer->mKabEntries.clear();
00237 
00238   KABC::AddressBook *addressBook = KABC::StdAddressBook::self();
00239 
00240   KABC::AddressBook::Iterator it;
00241   for( it = addressBook->begin(); it != addressBook->end(); ++it ) {
00242     
00243     QString index = (*it).custom("KANDY","Index");
00244     QString type = (*it).custom("KANDY","Type");
00245     QString name = (*it).custom("KANDY","Name");
00246     QString phonetype = (*it).custom("KANDY","Phonetype");
00247     
00248     // Get phonenumber according to phonetype. If no number of this type was
00249     // found use the first phone number as default
00250     KABC::PhoneNumber phoneNumber;
00251     if ( phonetype.isEmpty() ) {
00252       KABC::PhoneNumber::List phoneNumbers = (*it).phoneNumbers();
00253       phoneNumber = phoneNumbers.first();
00254     } else {
00255       phoneNumber = (*it).phoneNumber( phonetype.toInt() );
00256     }
00257     QString phone = phoneNumber.number();
00258 
00259     SyncEntryKab *kabEntry;
00260     if (!index.isEmpty()) {
00261       // This entry was already stored on the phone at some time.
00262       kabEntry = new SyncEntryKab(true,index,name,type,phone,phonetype);
00263     } else {
00264       // This entry has never been on the phone.
00265       index = "";
00266       name = (*it).realName();
00267       if (phone.left(1) == "+") type = "145";
00268       else type = "129";
00269       
00270       kabEntry = new SyncEntryKab(false,index,name,type,phone,phonetype);
00271     }
00272 
00273     kabEntry->mAddressee = (*it);
00274 
00275     mSyncer->mKabEntries.append(kabEntry);
00276   }
00277 
00278   // Display kab entries
00279   updateKabBook();
00280   
00281   emit transientStatusMessage(i18n("Read KDE address book."));
00282 }
00283 
00284 void MobileGui::writeKabc()
00285 {
00286   kdDebug() << "MobileGui::writeKabc()" << endl;
00287 
00288   KABC::AddressBook *addressBook = KABC::StdAddressBook::self();
00289 
00290   KABC::Ticket *ticket = addressBook->requestSaveTicket();
00291 
00292   if ( !ticket ) {
00293     kdDebug() << "Error! No ticket to save." << endl;
00294     return;
00295   }
00296 
00297   for(uint i=0;i<mSyncer->mKabEntries.count();++i) {
00298     SyncEntryKab *kabEntry = mSyncer->mKabEntries.at(i);
00299 
00300     KABC::Addressee entry = kabEntry->mAddressee;
00301     
00302     QString name = kabEntry->mName;
00303     QString phonenumber = kabEntry->mPhone;
00304     QString index = kabEntry->mIndex;
00305     QString type = kabEntry->mType;
00306 
00307     entry.insertCustom( "KANDY", "Index", index );
00308     
00309     entry.setFormattedName( name );
00310 
00311     // Try to identify type of phonenumber and write it to the corresponding
00312     // telephone entry    
00313     int phoneType = 0;
00314     if (phonenumber.left(3) == "017" || phonenumber.left(6) == "+49017") {
00315       phoneType = KABC::PhoneNumber::Cell;
00316     }
00317     entry.insertPhoneNumber( KABC::PhoneNumber( phonenumber, phoneType ) );
00318     entry.insertCustom( "KANDY", "Phonetype", QString::number( phoneType ) );
00319     
00320     entry.insertCustom( "KANDY", "Name", name );
00321     entry.insertCustom( "KANDY", "Type", type );
00322 
00323     addressBook->insertAddressee( entry );
00324   }
00325   
00326   addressBook->save( ticket );
00327   
00328   emit transientStatusMessage(i18n("Wrote KDE address book"));
00329 }
00330 
00331 void MobileGui::refreshStatus()
00332 {
00333   mScheduler->executeId("+cbc");
00334   mScheduler->executeId("+csq");
00335 }
00336 
00337 void MobileGui::processResult(ATCommand *command)
00338 {
00339   if (command->id() == "+cbc") {
00340     mBatteryChargeLabel->setText(command->resultField(1) + " %");
00341   } else if (command->id() == "+csq") {
00342     mSignalQualityLabel->setText(command->resultField(0));
00343   } else if (command->id() == "+cgmi") {
00344     mManufacturerLabel->setText(command->resultField(0));
00345   } else if (command->id() == "+cgmm") {
00346     mModelLabel->setText(command->resultField(0));
00347   } else if (command->id() == "+cgmr") {
00348     mGSMVersionLabel->setText(command->resultField(0));
00349   } else if (command->id() == "+cgsn") {
00350     mSerialNumberLabel->setText(command->resultField(0));
00351   } else if (command->id() == "+cpbr=1,150") {
00352     fillPhonebook(command);
00353   } else if (command->id() == mLastWriteId) {
00354     mLastWriteId = "";
00355     emit transientStatusMessage(i18n("Wrote mobile phonebook."));
00356   }
00357   if (command->id() == mSyncReadId) {
00358     mSyncReadId = "";
00359     mergePhonebooks();
00360     writeKabc();
00361     writePhonebook();
00362     mSyncWriteId = mLastWriteId;
00363   }
00364   if (command->id() == mSyncWriteId) {
00365     mSyncWriteId = "";
00366     emit transientStatusMessage(i18n("Synced phonebooks."));
00367     mSyncing = false;
00368   }
00369 }
00370 
00371 void MobileGui::fillPhonebook(ATCommand *cmd)
00372 {
00373   kdDebug() << "MobileGui::fillPhonebook()" << endl;
00374 
00375 //  kdDebug() << "--- " << cmd->resultString() << endl;
00376 
00377   mSyncer->mMobileEntries.clear();
00378     
00379   QPtrList<QStringList> *list = cmd->resultFields();
00380   
00381   QStringList *fields = list->first();
00382   while(fields) {
00383     if (fields->count() != 4) {
00384       kdDebug() << "Error! Unexpected number of address fields." << endl;
00385     } else {
00386       QString index = (*fields)[0];
00387       QString phone = (*fields)[1];
00388       QString type = (*fields)[2];
00389       QString name = (*fields)[3];
00390       SyncEntryMobile *phoneEntry = new SyncEntryMobile(true,dequote(index),
00391           dequote(phone),dequote(type),dequote(name));
00392       mSyncer->mMobileEntries.append(phoneEntry);
00393     }
00394     fields = list->next();
00395   }
00396 
00397   // Display mobile entries
00398   updateMobileBook();
00399 
00400   emit transientStatusMessage(i18n("Read mobile phonebook."));
00401   
00402   emit phonebookRead();
00403 }
00404 
00405 QString MobileGui::quote(const QString &str)
00406 {
00407   if (str.left(1) == "\"" && str.right(1) == "\"") return str;
00408   
00409   return "\"" + str + "\"";
00410 }
00411 
00412 QString MobileGui::dequote(const QString &str)
00413 {
00414   int pos = 0;
00415   int len = str.length();
00416 
00417   if (str.left(1) == "\"") {
00418     ++pos;
00419     --len;
00420   } 
00421   if (str.right(1) == "\"") {
00422     --len;
00423   }
00424   
00425   return str.mid(pos,len);
00426 }
00427 
00428 void MobileGui::savePhonebook()
00429 {
00430   QString fileName = KFileDialog::getSaveFileName("phonebook.csv");
00431 
00432   QFile outFile(fileName);
00433   if ( outFile.open(IO_WriteOnly) ) {    // file opened successfully
00434     QTextStream t( &outFile );        // use a text stream
00435 
00436     for(uint i=0;i<mSyncer->mMobileEntries.count();++i) {
00437       SyncEntryMobile *e = mSyncer->mMobileEntries.at(i);
00438       t << e->mIndex << "," << e->mPhone << "," << e->mType << ","
00439         << e->mName << endl;
00440     }
00441 
00442     outFile.close();
00443   }
00444 }
00445 
00446 void MobileGui::mergePhonebooks()
00447 {
00448   kdDebug() << "MobileGui::mergePhonebooks()" << endl;
00449 
00450   // Update selection state from GUI.
00451   PhoneBookItem *item = (PhoneBookItem *)mKabBook->firstChild();
00452   while(item) {
00453     item->syncEntry()->mOn = item->isOn();
00454     item = (PhoneBookItem *)item->nextSibling();
00455   }
00456   item = (PhoneBookItem *)mMobileBook->firstChild();
00457   while(item) {
00458     item->syncEntry()->mOn = item->isOn();
00459     item = (PhoneBookItem *)item->nextSibling();
00460   }
00461 
00462   mSyncer->mCommonEntries.clear();
00463 
00464 //  kdDebug() << " Insert kab list" << endl;
00465 
00466   // Put Kab list into common list
00467   for(uint i=0;i<mSyncer->mKabEntries.count();++i) {
00468     if (mSyncer->mKabEntries.at(i)->mOn) {
00469       mSyncer->mCommonEntries.append(new SyncEntryCommon(true,mSyncer->mKabEntries.at(i),0));
00470     }
00471   }
00472 
00473 //  kdDebug() << " Insert mobile list" << endl;
00474 
00475   // Put mobile list into common list. Merge equivalent entries.
00476   for(uint i=0;i<mSyncer->mMobileEntries.count();++i) {
00477     SyncEntryMobile *mobileEntry = mSyncer->mMobileEntries.at(i);
00478 //    kdDebug() << "--- Inserting " << mobileEntry->mName << endl;
00479   
00480     uint j=0;
00481     for(;j<mSyncer->mCommonEntries.count();++j) {
00482       if (mSyncer->mCommonEntries.at(j)->mKabEntry) {
00483         if (mSyncer->mCommonEntries.at(j)->mKabEntry->mIndex ==
00484             mobileEntry->mIndex) {
00485           // Equivalent entry is already there. Merge entries.
00486           mSyncer->mCommonEntries.at(j)->mMobileEntry = mobileEntry;
00487           break;
00488         }
00489       }
00490     }
00491     if (j == mSyncer->mCommonEntries.count()) {
00492       if (mobileEntry->mOn) {
00493         // Entry wasn't found
00494         mSyncer->mCommonEntries.append(new SyncEntryCommon(true,0,mobileEntry));
00495       }
00496     }
00497   }
00498   
00499 //  kdDebug() << " Resolve conflicts" << endl;
00500 
00501   // Resolve conflicts
00502   bool kabUpdated = false;
00503   bool mobileUpdated = false;
00504   for(uint i=0;i<mSyncer->mCommonEntries.count();++i) {
00505     SyncEntryCommon *entry = mSyncer->mCommonEntries.at(i);
00506     SyncEntryKab *kabEntry = entry->mKabEntry;
00507     SyncEntryMobile *mobileEntry = entry->mMobileEntry;
00508     if (kabEntry && mobileEntry) {
00509       if (mobileEntry->mPhone == kabEntry->mPhone &&
00510           mobileEntry->mName == kabEntry->mName) {
00511         // Entries are identical. Do nothing.
00512       } else {
00513         // Merge mobileEntrys
00514         // This alters the mobile and kab lists. Perhaps we should reflect this in the GUI.
00515         QString text = "<qt><b>" + i18n("Kab Entry:") + "</b><br>";
00516         text += "  " + kabEntry->mName + " " + kabEntry->mPhone + "<br>";
00517         text += "<b>" + i18n("Mobile Entry:") + "</b><br>";
00518         text += "  " + mobileEntry->mName + " " + mobileEntry->mPhone;
00519         text += "</qt>";
00520       
00521         QMessageBox *msg = new QMessageBox(i18n("Conflicting Entries"),text,
00522                                          QMessageBox::Warning,1,2,0,this);
00523         msg->setButtonText(1,i18n("Use Kab Entry"));
00524         msg->setButtonText(2,i18n("Use Mobile Entry"));
00525         switch (msg->exec()) {
00526           case 1: // use kab entry
00527             mobileEntry->mPhone = kabEntry->mPhone;
00528             mobileEntry->mName = kabEntry->mName;
00529             mobileUpdated = true;
00530             break;
00531           case 2: // use mobile entry
00532             kabEntry->mPhone = mobileEntry->mPhone;
00533             kabEntry->mName = mobileEntry->mName;
00534             kabUpdated = true;
00535             break;
00536         }
00537       }
00538     }
00539   }
00540 
00541 //  kdDebug() << " Create new entries" << endl;
00542 
00543   // Create new entries
00544   for(uint i=0;i<mSyncer->mCommonEntries.count();++i) {
00545     SyncEntryCommon *entry = mSyncer->mCommonEntries.at(i);
00546     SyncEntryKab *kabEntry = entry->mKabEntry;
00547     SyncEntryMobile *mobileEntry = entry->mMobileEntry;
00548 
00549     if (kabEntry && !mobileEntry) {
00550       kdDebug() << "Creating mobile entry for " << kabEntry->mPhone << endl;
00551       // Create mobile entry
00552       // The type should be generated here.
00553       // The values should be checked for validity.
00554       entry->mMobileEntry = new SyncEntryMobile(true,"",kabEntry->mPhone,kabEntry->mType,
00555                                                 kabEntry->mName);
00556       mSyncer->mMobileEntries.append(entry->mMobileEntry);
00557 
00558       // Create new index
00559       QString index;
00560       for(uint j=1;j<150;++j) {
00561         uint k = 0;
00562         for(;k<mSyncer->mMobileEntries.count();++k) {
00563           if (mSyncer->mMobileEntries.at(k)->mIndex == QString::number(j)) {
00564             break;
00565           }
00566         }
00567         if (k == mSyncer->mMobileEntries.count()) {
00568           index = QString::number(j);
00569           break;
00570         }
00571       }
00572       entry->mMobileEntry->mIndex = index;
00573       
00574       kabEntry->mIndex = index;
00575 
00576       kabUpdated = true;
00577       mobileUpdated = true;
00578     } else if (mobileEntry && !kabEntry) {
00579       // Create kab entry
00580       QString phonetype = "0";
00581       entry->mKabEntry = new SyncEntryKab(true,mobileEntry->mIndex,mobileEntry->mName,
00582                                           mobileEntry->mType,mobileEntry->mPhone,
00583                                           phonetype);
00584       mSyncer->mKabEntries.append(entry->mKabEntry);
00585 
00586       kabUpdated = true;
00587     }
00588   }
00589 
00590 //  kdDebug() << "Update gui" << endl;
00591 
00592   // Update kab and mobile entries
00593   if (kabUpdated) updateKabBook();
00594   if (mobileUpdated) updateMobileBook();
00595 
00596   kdDebug() << "MobileGui::mergePhonebooks() done." << endl;
00597 }
00598 
00599 void MobileGui::syncPhonebooks()
00600 {
00601   if (mSyncing) return;
00602 
00603   mSyncing = true;
00604   readKabc();
00605   readPhonebook();
00606   mSyncReadId = "+cpbr=1,150";
00607 }
00608 
00609 void MobileGui::updateKabBook()
00610 {
00611   mKabBook->clear();
00612   for(uint i=0;i<mSyncer->mKabEntries.count();++i) {
00613     SyncEntryKab *kabEntry = mSyncer->mKabEntries.at(i);
00614     PhoneBookItem *item = new PhoneBookItem(mKabBook,kabEntry,kabEntry->mIndex,
00615         kabEntry->mPhone,kabEntry->mType,kabEntry->mName);
00616     item->setOn(kabEntry->mOn);
00617   }
00618 }
00619 
00620 void MobileGui::updateMobileBook()
00621 {
00622   mMobileBook->clear();
00623   for(uint i=0;i<mSyncer->mMobileEntries.count();++i) {
00624     SyncEntryMobile *entry = mSyncer->mMobileEntries.at(i);
00625     PhoneBookItem *item = new PhoneBookItem(mMobileBook,entry,entry->mIndex,
00626         entry->mPhone,entry->mType,entry->mName);
00627     item->setOn(entry->mOn);
00628   }
00629 }
KDE Logo
This file is part of the documentation for kandy Library Version 3.2.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat May 1 11:37:59 2004 by doxygen 1.2.15 written by Dimitri van Heesch, © 1997-2003