kpilot

internalEditorAction.cc

Go to the documentation of this file.
00001 /* KPilot
00002 **
00003 ** Copyright (C) 2003 Reinhold Kainhofer <reinhold@kainhofer.com>
00004 **
00005 */
00006 
00007 /*
00008 ** This program is free software; you can redistribute it and/or modify
00009 ** it under the terms of the GNU General Public License as published by
00010 ** the Free Software Foundation; either version 2 of the License, or
00011 ** (at your option) any later version.
00012 **
00013 ** This program is distributed in the hope that it will be useful,
00014 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00016 ** GNU General Public License for more details.
00017 **
00018 ** You should have received a copy of the GNU General Public License
00019 ** along with this program in a file called COPYING; if not, write to
00020 ** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
00021 ** MA 02110-1301, USA.
00022 */
00023 
00024 /*
00025 ** Bug reports and questions can be sent to kde-pim@kde.org
00026 */
00027 
00028 #include <options.h>
00029 
00030 #include <qtimer.h>
00031 #include <qlayout.h>
00032 #include <qlabel.h>
00033 #include <kmessagebox.h>
00034 #include <kdialog.h>
00035 #include <ktextedit.h>
00036 #include <kdialogbase.h>
00037 
00038 #include <pilotRecord.h>
00039 #include <pilotLocalDatabase.h>
00040 #include <pilotDatabase.h>
00041 #include <pilotSerialDatabase.h>
00042 #include "kpilotConfig.h"
00043 #include "internalEditorAction.h"
00044 
00045 #include <pilotAddress.h>
00046 #include <pilotMemo.h>
00047 #include <pilotDateEntry.h>
00048 #include <pilotTodoEntry.h>
00049 
00050 #include "khexedit/byteseditinterface.h"
00051 using namespace KHE;
00052 
00053 InternalEditorAction::InternalEditorAction(KPilotLink * p) :
00054     SyncAction(p, "internalSync")
00055 {
00056     FUNCTIONSETUP;
00057 }
00058 
00059 bool InternalEditorAction::exec()
00060 {
00061     FUNCTIONSETUP;
00062     emit logMessage(i18n("[Internal Editors]"));
00063     fInternalEditorSyncStatus=eSyncStarted;
00064     QTimer::singleShot(0, this, SLOT(syncDirtyDB()));
00065     return true;
00066 }
00067 
00068 void InternalEditorAction::syncDirtyDB()
00069 {
00070     FUNCTIONSETUP;
00071 
00072     if (fInternalEditorSyncStatus!=eSyncDirtyDB)
00073     {
00074         fInternalEditorSyncStatus=eSyncDirtyDB;
00075         dirtyDBs=KPilotSettings::dirtyDatabases();
00076         emit logMessage(i18n("Databases with changed records: %1").arg(dirtyDBs.join(CSL1(", "))));
00077         dbIter=dirtyDBs.begin();
00078     }
00079     else
00080     {
00081         dbIter++;
00082     }
00083     if (dbIter==dirtyDBs.end())
00084     {
00085         KPilotSettings::setDirtyDatabases(QStringList());
00086         KPilotConfig::sync();
00087         QTimer::singleShot(0, this, SLOT(syncFlagsChangedDB()));
00088         return;
00089     }
00090 #ifdef DEBUG
00091     DEBUGKPILOT<<"syncDirtyDB for DB "<<(*dbIter)<<endl;
00092 #endif
00093     // open the local and the serial database and copy every
00094     // changed record from the PC to the handheld
00095 
00096     PilotRecord*rec=0L;
00097     PilotLocalDatabase*localDB=new PilotLocalDatabase(*dbIter, false);
00098     PilotDatabase *serialDB= deviceLink()->database(*dbIter);
00099     if (!localDB->isOpen() || !serialDB->isOpen())
00100     {
00101         emit logError(i18n("Unable to open the serial or local database for %1. "
00102             "Skipping it.").arg(*dbIter));
00103         goto nextDB;
00104     }
00105     while ( (rec=localDB->readNextModifiedRec()) )
00106     {
00107         int id=rec->id();
00108 #ifdef DEBUG
00109         DEBUGKPILOT<<"ID of modified record is "<<id<<endl;
00110         DEBUGKPILOT<<endl<<endl;
00111 #endif
00112         if (id>0)
00113         {
00114             PilotRecord*serrec=serialDB->readRecordById(id);
00115             if (serrec && (serrec->isModified()) )
00116             {
00117                 bool kpilotOverrides=queryUseKPilotChanges(*dbIter, id, rec, serrec, localDB);
00118                 if (kpilotOverrides)
00119                     serialDB->writeRecord(rec);
00120                 else
00121                     localDB->writeRecord(serrec);
00122             }
00123             else
00124                 serialDB->writeRecord(rec);
00125         }
00126         else
00127         {
00128 #ifdef DEBUG
00129             DEBUGKPILOT<<"Generating ID for Record "<<rec->id()<<" with data "<<endl;
00130             DEBUGKPILOT<<rec->data()<<endl;
00131             DEBUGKPILOT<<"-----------------------------------------"<<endl;
00132 #endif
00133             int id=serialDB->writeRecord(rec);
00134             rec->setID(id);
00135 #ifdef DEBUG
00136             DEBUGKPILOT<<"New ID is "<<id<<endl;
00137             DEBUGKPILOT<<endl<<endl<<endl;
00138 #endif
00139             //localDB->writeRecord(rec);
00140             localDB->updateID(id);
00141         }
00142         KPILOT_DELETE(rec);
00143     }
00144 
00145 nextDB:
00146     localDB->resetSyncFlags();
00147     KPILOT_DELETE(localDB);
00148     KPILOT_DELETE(serialDB);
00149     QTimer::singleShot(0, this, SLOT(syncDirtyDB()));
00150 }
00151 
00152 bool InternalEditorAction::queryUseKPilotChanges(QString dbName, recordid_t id, PilotRecord*localrec, PilotRecord*serialrec, PilotDatabase*db)
00153 {
00154     FUNCTIONSETUP;
00155     bool knownDB=true;
00156     QString localEntry, serialEntry, recType(i18n("record"));
00157 
00158     if (dbName==CSL1("AddressDB") && db)
00159     {
00160         PilotAddressInfo info(db);
00161 
00162         PilotAddress localAddr(localrec);
00163         PilotAddress serialAddr(serialrec);
00164         localEntry=localAddr.getTextRepresentation(&info,Qt::RichText);
00165         serialEntry=serialAddr.getTextRepresentation(&info,Qt::RichText);
00166         recType=i18n("address");
00167     }
00168     else
00169     if (dbName==CSL1("ToDoDB") && db)
00170     {
00171         PilotToDoInfo info(db);
00172 
00173         PilotTodoEntry localTodo(localrec);
00174         PilotTodoEntry serialTodo(serialrec);
00175         localEntry=localTodo.getTextRepresentation(Qt::RichText);
00176         serialEntry=serialTodo.getTextRepresentation(Qt::RichText);
00177         recType=i18n("to-do entry");
00178     }
00179     else
00180     if (dbName==CSL1("MemoDB"))
00181     {
00182         PilotMemo localMemo(localrec);
00183         PilotMemo serialMemo(serialrec);
00184         localEntry=localMemo.getTextRepresentation(Qt::RichText);
00185         serialEntry=serialMemo.getTextRepresentation(Qt::RichText);
00186         recType=i18n("memo");
00187     }
00188     else
00189     if (dbName==CSL1("DatebookDB"))
00190     {
00191         PilotDateInfo info(db);
00192 
00193         PilotDateEntry localEvent(localrec);
00194         PilotDateEntry serialEvent(serialrec);
00195         localEntry=localEvent.getTextRepresentation(Qt::RichText);
00196         serialEntry=serialEvent.getTextRepresentation(Qt::RichText);
00197         recType=i18n("calendar entry");
00198     }
00199     else
00200     {
00201         knownDB=false;
00202     }
00203 
00204     QString dialogText(i18n("The %1 with ID %2 of the database \"%3\" was changed "
00205         "on the handheld and in the internal editor. Shall the changes in KPilot be copied to the handheld, and so override the changes there?").
00206         arg(recType).arg(id).arg(dbName));
00207 
00208     KDialogBase*resdlg=new KDialogBase(0L, "internalresolutiondialog", true,
00209         i18n("Conflict in database  %1").arg(*dbIter),
00210         KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok, true,
00211         i18n("Use KPilot"), i18n("Use Handheld") );
00212     resdlg->setButtonText(KDialogBase::Ok,  i18n("Use &KPilot"));
00213     resdlg->setButtonText(KDialogBase::Cancel, i18n("Use &Handheld"));
00214 
00215     QWidget*page=new QWidget(resdlg);
00216     resdlg->setMainWidget(page);
00217     QGridLayout*layout = new QGridLayout( page, 1, 1);
00218 
00219     QLabel *label=new QLabel(dialogText, page);
00220     label->setAlignment( QLabel::WordBreak );
00221     layout->addMultiCellWidget( label,  0,0, 0,1 );
00222 
00223     layout->addItem( new QSpacerItem( 20, 10, QSizePolicy::Minimum,
00224         QSizePolicy::Fixed ), 1, 0 );
00225 
00226     if (knownDB)
00227     {
00228         label=new QLabel(i18n("Entry in KPilot"), page);
00229         layout->addWidget( label, 2,0);
00230 
00231         KTextEdit*textBrowser = new KTextEdit(CSL1("<qt>")+localEntry+CSL1("</qt>"), QString::null, page);
00232         textBrowser->setReadOnly(true);
00233         layout->addWidget( textBrowser, 3,0);
00234 
00235         label=new QLabel(i18n("Entry on Handheld"), page);
00236         layout->addWidget( label, 2,1);
00237 
00238         textBrowser = new KTextEdit(CSL1("<qt>")+serialEntry+CSL1("</qt>"), QString::null, page);
00239         textBrowser->setReadOnly(true);
00240         layout->addWidget( textBrowser, 3,1);
00241     }
00242     else
00243     {
00244         label=new QLabel(i18n("Entry in KPilot"), page);
00245         layout->addMultiCellWidget( label, 2,2,0,1);
00246 
00247         // directly display the record's data:
00248         QWidget *hexEdit = KHE::createBytesEditWidget( page, "LocalBufferEdit" );
00249         if( hexEdit )
00250         {
00251             KHE::BytesEditInterface* hexEditIf = KHE::bytesEditInterface( hexEdit );
00252             Q_ASSERT( hexEditIf ); // This should not fail!
00253             if( hexEditIf )
00254             {
00255                 hexEditIf->setData( localrec->data(), localrec->size() );
00256 //                  Do we need the following call at all???
00257 //              hexEditIf->setMaxDataSize( localrec->getLen() );
00258                 hexEditIf->setReadOnly( true );
00259             }
00260         }
00261         else
00262         {
00263             QLabel*tmpW = new QLabel( i18n("To view and edit the record data, please install a hex editor (e.g. khexedit from kdeutils)."), page );
00264             tmpW->setBackgroundMode( Qt::PaletteMid );
00265             tmpW->setAlignment( Qt::AlignHCenter | Qt::AlignVCenter | Qt::WordBreak);
00266             tmpW->setFrameShape( QFrame::Panel );
00267             tmpW->setFrameShadow( QFrame::Sunken );
00268             hexEdit = tmpW;
00269         }
00270         layout->addMultiCellWidget( hexEdit, 3,3,0,1);
00271 
00272         label=new QLabel(i18n("Entry on Handheld"), page);
00273         layout->addMultiCellWidget( label, 4,4,0,1);
00274 
00275         // directly display the record's data:
00276         hexEdit = KHE::createBytesEditWidget( page, "SerialBufferEdit" );
00277         if( hexEdit )
00278         {
00279             KHE::BytesEditInterface* hexEditIf = KHE::bytesEditInterface( hexEdit );
00280             Q_ASSERT( hexEditIf ); // This should not fail!
00281             if( hexEditIf )
00282             {
00283                 hexEditIf->setData( serialrec->data(), serialrec->size() );
00284 //                  Do we need the following call at all???
00285 //              hexEditIf->setMaxDataSize( serialrec->getLen() );
00286                 hexEditIf->setReadOnly( true );
00287             }
00288         }
00289         else
00290         {
00291             QLabel*tmpW = new QLabel( i18n("To view and edit the record data, please install a hex editor (e.g. khexedit from kdeutils)."), page );
00292             tmpW->setBackgroundMode( Qt::PaletteMid );
00293             tmpW->setAlignment( Qt::AlignHCenter | Qt::AlignVCenter | Qt::WordBreak);
00294             tmpW->setFrameShape( QFrame::Panel );
00295             tmpW->setFrameShadow( QFrame::Sunken );
00296             hexEdit = tmpW;
00297         }
00298         layout->addMultiCellWidget( hexEdit, 5,5,0,1);
00299     }
00300 
00301     int res=resdlg->exec();
00302     KPILOT_DELETE(resdlg);
00303 
00304     return res==KDialogBase::Accepted;
00305 }
00306 
00307 
00308 void InternalEditorAction::syncFlagsChangedDB()
00309 {
00310     FUNCTIONSETUP;
00311     if (fInternalEditorSyncStatus!=eSyncFlagsChangedDB)
00312     {
00313         fInternalEditorSyncStatus=eSyncFlagsChangedDB;
00314         dirtyDBs=KPilotSettings::flagsChangedDatabases();
00315         emit logMessage(i18n("Databases with changed flags: %1").arg(dirtyDBs.join(CSL1(", "))));
00316         dbIter=dirtyDBs.begin();
00317     }
00318     else
00319     {
00320         dbIter++;
00321     }
00322     if (dbIter==dirtyDBs.end())
00323     {
00324         KPilotSettings::setFlagsChangedDatabases(QStringList());
00325         KPilotConfig::sync();
00326         QTimer::singleShot(0, this, SLOT(syncAppBlockChangedDB()));
00327         return;
00328     }
00329 
00330 #ifdef DEBUG
00331     DEBUGKPILOT<<"syncFlagsChangedDB for DB "<<(*dbIter)<<endl;
00332 #endif
00333 emit logError(i18n("Setting the database flags on the handheld is not yet supported."));
00334 QTimer::singleShot(0, this, SLOT(syncAppBlockChangedDB()));
00335 return;
00336 
00337     PilotLocalDatabase*localDB=new PilotLocalDatabase(*dbIter, false);
00338     PilotDatabase *serialDB=deviceLink()->database(*dbIter);
00339 
00340     // open the local and the serial database and copy the flags over
00341     // TODO: Implement the copying
00342     // TODO: Is there a way to detect if the flags were changed on the handheld?
00343 
00344     KPILOT_DELETE(localDB);
00345     KPILOT_DELETE(serialDB);
00346     QTimer::singleShot(0, this, SLOT(syncAppBlockChangedDB()));
00347 }
00348 
00349 void InternalEditorAction::syncAppBlockChangedDB()
00350 {
00351     FUNCTIONSETUP;
00352     if (fInternalEditorSyncStatus!=eSyncAppBlockChangedDB)
00353     {
00354         fInternalEditorSyncStatus=eSyncAppBlockChangedDB;
00355         dirtyDBs=KPilotSettings::appBlockChangedDatabases();
00356         emit logMessage(i18n("Databases with changed AppBlock: %1").arg(dirtyDBs.join(CSL1(", "))));
00357         dbIter=dirtyDBs.begin();
00358     }
00359     else
00360     {
00361         dbIter++;
00362     }
00363     if (dbIter==dirtyDBs.end())
00364     {
00365         KPilotSettings::setAppBlockChangedDatabases(QStringList());
00366         KPilotConfig::sync();
00367         QTimer::singleShot(0, this, SLOT(cleanup()));
00368         return;
00369     }
00370 #ifdef DEBUG
00371     DEBUGKPILOT<<"syncAppBlockChangedDB for DB "<<(*dbIter)<<endl;
00372 #endif
00373 
00374     PilotLocalDatabase*localDB=new PilotLocalDatabase(*dbIter, false);
00375     PilotDatabase *serialDB=deviceLink()->database(*dbIter);
00376 
00377     unsigned char*appBlock=new unsigned char[0xFFFF];
00378     int len=localDB->readAppBlock(appBlock, 0xFFFF);
00379     // TODO: Check if the app block was changed on the handheld, and if so, do conflict resolution
00380     serialDB->writeAppBlock(appBlock, len);
00381 
00382     KPILOT_DELETE(localDB);
00383     KPILOT_DELETE(serialDB);
00384     QTimer::singleShot(0, this, SLOT(syncAppBlockChangedDB()));
00385 }
00386 
00387 void InternalEditorAction::cleanup()
00388 {
00389     FUNCTIONSETUP;
00390     fInternalEditorSyncStatus=eSyncFinished;
00391     emit syncDone(this);
00392 }
00393 
00394 #include "internalEditorAction.moc"