kpilot/kpilot

internalEditorAction.cc

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 #ifdef USE_KHEXEDIT
00051 #include "khexedit/byteseditinterface.h"
00052 using namespace KHE;
00053 #endif
00054 
00055 InternalEditorAction::InternalEditorAction(KPilotLink * p) :
00056     SyncAction(p, "internalSync")
00057 {
00058     FUNCTIONSETUP;
00059 }
00060 
00061 bool InternalEditorAction::exec()
00062 {
00063     FUNCTIONSETUP;
00064     emit logMessage(i18n("[Internal Editors]"));
00065     fInternalEditorSyncStatus=eSyncStarted;
00066     QTimer::singleShot(0, this, SLOT(syncDirtyDB()));
00067     return true;
00068 }
00069 
00070 void InternalEditorAction::syncDirtyDB()
00071 {
00072     FUNCTIONSETUP;
00073 
00074     if (fInternalEditorSyncStatus!=eSyncDirtyDB)
00075     {
00076         fInternalEditorSyncStatus=eSyncDirtyDB;
00077         dirtyDBs=KPilotSettings::dirtyDatabases();
00078         emit logMessage(i18n("Databases with changed records: %1").arg(dirtyDBs.join(CSL1(", "))));
00079         dbIter=dirtyDBs.begin();
00080     }
00081     else
00082     {
00083         dbIter++;
00084     }
00085     if (dbIter==dirtyDBs.end())
00086     {
00087         KPilotSettings::setDirtyDatabases(QStringList());
00088         KPilotConfig::sync();
00089         QTimer::singleShot(0, this, SLOT(syncFlagsChangedDB()));
00090         return;
00091     }
00092 #ifdef DEBUG
00093     DEBUGKPILOT<<"syncDirtyDB for DB "<<(*dbIter)<<endl;
00094 #endif
00095     // open the local and the serial database and copy every
00096     // changed record from the PC to the handheld
00097 
00098     PilotRecord*rec=0L;
00099     PilotLocalDatabase*localDB=new PilotLocalDatabase(*dbIter, false);
00100     PilotDatabase *serialDB= deviceLink()->database(*dbIter);
00101     if (!localDB->isOpen() || !serialDB->isOpen())
00102     {
00103         emit logError(i18n("Unable to open the serial or local database for %1. "
00104             "Skipping it.").arg(*dbIter));
00105         goto nextDB;
00106     }
00107     while ( (rec=localDB->readNextModifiedRec()) )
00108     {
00109         int id=rec->id();
00110 #ifdef DEBUG
00111         DEBUGKPILOT<<"ID of modified record is "<<id<<endl;
00112         DEBUGKPILOT<<endl<<endl;
00113 #endif
00114         if (id>0)
00115         {
00116             PilotRecord*serrec=serialDB->readRecordById(id);
00117             if (serrec && (serrec->isModified()) )
00118             {
00119                 bool kpilotOverrides=queryUseKPilotChanges(*dbIter, id, rec, serrec, localDB);
00120                 if (kpilotOverrides)
00121                     serialDB->writeRecord(rec);
00122                 else
00123                     localDB->writeRecord(serrec);
00124             }
00125             else
00126                 serialDB->writeRecord(rec);
00127         }
00128         else
00129         {
00130 #ifdef DEBUG
00131             DEBUGKPILOT<<"Generating ID for Record "<<rec->id()<<" with data "<<endl;
00132             DEBUGKPILOT<<rec->data()<<endl;
00133             DEBUGKPILOT<<"-----------------------------------------"<<endl;
00134 #endif
00135             int id=serialDB->writeRecord(rec);
00136             rec->setID(id);
00137 #ifdef DEBUG
00138             DEBUGKPILOT<<"New ID is "<<id<<endl;
00139             DEBUGKPILOT<<endl<<endl<<endl;
00140 #endif
00141             //localDB->writeRecord(rec);
00142             localDB->updateID(id);
00143         }
00144         KPILOT_DELETE(rec);
00145     }
00146 
00147 nextDB:
00148     localDB->resetSyncFlags();
00149     KPILOT_DELETE(localDB);
00150     KPILOT_DELETE(serialDB);
00151     QTimer::singleShot(0, this, SLOT(syncDirtyDB()));
00152 }
00153 
00154 bool InternalEditorAction::queryUseKPilotChanges(QString dbName, recordid_t id, PilotRecord*localrec, PilotRecord*serialrec, PilotDatabase*db)
00155 {
00156     FUNCTIONSETUP;
00157     bool knownDB=true;
00158     QString localEntry, serialEntry, recType(i18n("record"));
00159 
00160     if (dbName==CSL1("AddressDB") && db)
00161     {
00162         PilotAddressInfo info(db);
00163 
00164         PilotAddress localAddr(&info, localrec);
00165         PilotAddress serialAddr(&info, serialrec);
00166         localEntry=localAddr.getTextRepresentation(true);
00167         serialEntry=serialAddr.getTextRepresentation(true);
00168         recType=i18n("address");
00169     }
00170     else
00171     if (dbName==CSL1("ToDoDB") && db)
00172     {
00173         PilotToDoInfo info(db);
00174 
00175         PilotTodoEntry localTodo(*(info.info()), localrec);
00176         PilotTodoEntry serialTodo(*(info.info()), serialrec);
00177         localEntry=localTodo.getTextRepresentation(true);
00178         serialEntry=serialTodo.getTextRepresentation(true);
00179         recType=i18n("to-do entry");
00180     }
00181     else
00182     if (dbName==CSL1("MemoDB"))
00183     {
00184         PilotMemo localMemo(localrec);
00185         PilotMemo serialMemo(serialrec);
00186         localEntry=localMemo.getTextRepresentation(true);
00187         serialEntry=serialMemo.getTextRepresentation(true);
00188         recType=i18n("memo");
00189     }
00190     else
00191     if (dbName==CSL1("DatebookDB"))
00192     {
00193         PilotDateInfo info(db);
00194 
00195         PilotDateEntry localEvent(*(info.info()), localrec);
00196         PilotDateEntry serialEvent(*(info.info()), serialrec);
00197         localEntry=localEvent.getTextRepresentation(true);
00198         serialEntry=serialEvent.getTextRepresentation(true);
00199         recType=i18n("calendar entry");
00200     }
00201     else
00202         knownDB=false;
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 #ifdef USE_KHEXEDIT
00245         label=new QLabel(i18n("Entry in KPilot"), page);
00246         layout->addMultiCellWidget( label, 2,2,0,1);
00247 
00248         // directly display the record's data:
00249         QWidget *hexEdit = KHE::createBytesEditWidget( page, "LocalBufferEdit" );
00250         if( hexEdit )
00251         {
00252             KHE::BytesEditInterface* hexEditIf = KHE::bytesEditInterface( hexEdit );
00253             Q_ASSERT( hexEditIf ); // This should not fail!
00254             if( hexEditIf )
00255             {
00256                 hexEditIf->setData( localrec->data(), localrec->size() );
00257 //                  Do we need the following call at all???
00258 //              hexEditIf->setMaxDataSize( localrec->getLen() );
00259                 hexEditIf->setReadOnly( true );
00260             }
00261         }
00262         else
00263         {
00264             QLabel*tmpW = new QLabel( i18n("To view and edit the record data, please install a hex editor (e.g. khexedit from kdeutils)."), page );
00265             tmpW->setBackgroundMode( Qt::PaletteMid );
00266             tmpW->setAlignment( Qt::AlignHCenter | Qt::AlignVCenter | Qt::WordBreak);
00267             tmpW->setFrameShape( QFrame::Panel );
00268             tmpW->setFrameShadow( QFrame::Sunken );
00269             hexEdit = tmpW;
00270         }
00271         layout->addMultiCellWidget( hexEdit, 3,3,0,1);
00272 
00273         label=new QLabel(i18n("Entry on Handheld"), page);
00274         layout->addMultiCellWidget( label, 4,4,0,1);
00275 
00276         // directly display the record's data:
00277         hexEdit = KHE::createBytesEditWidget( page, "SerialBufferEdit" );
00278         if( hexEdit )
00279         {
00280             KHE::BytesEditInterface* hexEditIf = KHE::bytesEditInterface( hexEdit );
00281             Q_ASSERT( hexEditIf ); // This should not fail!
00282             if( hexEditIf )
00283             {
00284                 hexEditIf->setData( serialrec->data(), serialrec->size() );
00285 //                  Do we need the following call at all???
00286 //              hexEditIf->setMaxDataSize( serialrec->getLen() );
00287                 hexEditIf->setReadOnly( true );
00288             }
00289         }
00290         else
00291         {
00292             QLabel*tmpW = new QLabel( i18n("To view and edit the record data, please install a hex editor (e.g. khexedit from kdeutils)."), page );
00293             tmpW->setBackgroundMode( Qt::PaletteMid );
00294             tmpW->setAlignment( Qt::AlignHCenter | Qt::AlignVCenter | Qt::WordBreak);
00295             tmpW->setFrameShape( QFrame::Panel );
00296             tmpW->setFrameShadow( QFrame::Sunken );
00297             hexEdit = tmpW;
00298         }
00299         layout->addMultiCellWidget( hexEdit, 5,5,0,1);
00300 #endif
00301     }
00302 
00303     int res=resdlg->exec();
00304     KPILOT_DELETE(resdlg);
00305 
00306     return res==KDialogBase::Accepted;
00307 }
00308 
00309 
00310 void InternalEditorAction::syncFlagsChangedDB()
00311 {
00312     FUNCTIONSETUP;
00313     if (fInternalEditorSyncStatus!=eSyncFlagsChangedDB)
00314     {
00315         fInternalEditorSyncStatus=eSyncFlagsChangedDB;
00316         dirtyDBs=KPilotSettings::flagsChangedDatabases();
00317         emit logMessage(i18n("Databases with changed flags: %1").arg(dirtyDBs.join(CSL1(", "))));
00318         dbIter=dirtyDBs.begin();
00319     }
00320     else
00321     {
00322         dbIter++;
00323     }
00324     if (dbIter==dirtyDBs.end())
00325     {
00326         KPilotSettings::setFlagsChangedDatabases(QStringList());
00327         KPilotConfig::sync();
00328         QTimer::singleShot(0, this, SLOT(syncAppBlockChangedDB()));
00329         return;
00330     }
00331 
00332 #ifdef DEBUG
00333     DEBUGKPILOT<<"syncFlagsChangedDB for DB "<<(*dbIter)<<endl;
00334 #endif
00335 emit logError(i18n("Setting the database flags on the handheld is not yet supported."));
00336 QTimer::singleShot(0, this, SLOT(syncAppBlockChangedDB()));
00337 return;
00338 
00339     PilotLocalDatabase*localDB=new PilotLocalDatabase(*dbIter, false);
00340     PilotDatabase *serialDB=deviceLink()->database(*dbIter);
00341 
00342     // open the local and the serial database and copy the flags over
00343     // TODO: Implement the copying
00344     // TODO: Is there a way to detect if the flags were changed on the handheld?
00345 
00346     KPILOT_DELETE(localDB);
00347     KPILOT_DELETE(serialDB);
00348     QTimer::singleShot(0, this, SLOT(syncAppBlockChangedDB()));
00349 }
00350 
00351 void InternalEditorAction::syncAppBlockChangedDB()
00352 {
00353     FUNCTIONSETUP;
00354     if (fInternalEditorSyncStatus!=eSyncAppBlockChangedDB)
00355     {
00356         fInternalEditorSyncStatus=eSyncAppBlockChangedDB;
00357         dirtyDBs=KPilotSettings::appBlockChangedDatabases();
00358         emit logMessage(i18n("Databases with changed AppBlock: %1").arg(dirtyDBs.join(CSL1(", "))));
00359         dbIter=dirtyDBs.begin();
00360     }
00361     else
00362     {
00363         dbIter++;
00364     }
00365     if (dbIter==dirtyDBs.end())
00366     {
00367         KPilotSettings::setAppBlockChangedDatabases(QStringList());
00368         KPilotConfig::sync();
00369         QTimer::singleShot(0, this, SLOT(cleanup()));
00370         return;
00371     }
00372 #ifdef DEBUG
00373     DEBUGKPILOT<<"syncAppBlockChangedDB for DB "<<(*dbIter)<<endl;
00374 #endif
00375 
00376     PilotLocalDatabase*localDB=new PilotLocalDatabase(*dbIter, false);
00377     PilotDatabase *serialDB=deviceLink()->database(*dbIter);
00378 
00379     unsigned char*appBlock=new unsigned char[0xFFFF];
00380     int len=localDB->readAppBlock(appBlock, 0xFFFF);
00381     // TODO: Check if the app block was changed on the handheld, and if so, do conflict resolution
00382     serialDB->writeAppBlock(appBlock, len);
00383 
00384     KPILOT_DELETE(localDB);
00385     KPILOT_DELETE(serialDB);
00386     QTimer::singleShot(0, this, SLOT(syncAppBlockChangedDB()));
00387 }
00388 
00389 void InternalEditorAction::cleanup()
00390 {
00391     FUNCTIONSETUP;
00392     fInternalEditorSyncStatus=eSyncFinished;
00393     emit syncDone(this);
00394 }
00395 
00396 #include "internalEditorAction.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys