kitchensync Library API Documentation

syncalgo.cpp

00001 /*
00002     This file is part of KitchenSync.
00003 
00004     Copyright (c) 2002 Holger Freyther <zecke@handhelds.org>
00005 
00006     This library is free software; you can redistribute it and/or
00007     modify it under the terms of the GNU Library General Public
00008     License as published by the Free Software Foundation; either
00009     version 2 of the License, or (at your option) any later version.
00010 
00011     This library 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 GNU
00014     Library General Public License for more details.
00015 
00016     You should have received a copy of the GNU Library General Public License
00017     along with this library; see the file COPYING.LIB.  If not, write to
00018     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00019     Boston, MA 02111-1307, USA.
00020 */
00021 
00022 #include <kdebug.h>
00023 
00024 #include <syncee.h>
00025 
00026 #include "syncalgo.h"
00027 
00028 using namespace KSync;
00029 
00030 PIMSyncAlg::PIMSyncAlg( SyncUi* ui )
00031     : SyncAlgorithm( ui )
00032 {
00033 }
00034 
00035 PIMSyncAlg::~PIMSyncAlg()
00036 {
00037 }
00038 
00039 /*
00040  * let's find the best algorithm first. If both are MetaMode
00041  * use meta mode or if not use syncFirst
00042  */
00043 void PIMSyncAlg::syncToTarget( Syncee* syncee,
00044                                Syncee* target,
00045                                bool override)
00046 {
00047     if (syncee->syncMode() == Syncee::MetaLess ||
00048         syncee->firstSync() )
00049         return syncFirst(syncee, target, override);
00050     else if ( target->syncMode() == Syncee::MetaLess ||
00051               target->firstSync() )
00052         return syncFirst( syncee, target, override );
00053     else
00054         return syncMeta( syncee, target, override );
00055 }
00056 
00057 /*
00058  * First Sync or no MetaData
00059  * slightly changed syncToTarget from StandardSync
00060  */
00061 void PIMSyncAlg::syncFirst( Syncee* syncee,
00062                             Syncee* target,
00063                             bool override )
00064 {
00065     kdDebug(5231) << "SyncFirst " << endl;
00066     SyncEntry *targetEntry = 0l;
00067 
00068     /* start with the first */
00069     SyncEntry *sourceEntry = syncee->firstEntry();
00070     /* whilte it's not the last+1 one */
00071     while (sourceEntry) {
00072 
00073         if ( sourceEntry->state() == SyncEntry::Removed ) {
00074         kdDebug(5231) << "Entry removed " << sourceEntry->name() << endl;
00075             sourceEntry = syncee->nextEntry();
00076             continue;
00077         }
00078 
00079         /* let's see if it's in the other set */
00080         targetEntry = 0l;
00081         targetEntry = target->findEntry(sourceEntry->id());
00082 
00083         /* if it is check if modified. if not it's new */
00084         if (targetEntry) {
00085         kdDebug(5231) << "Found target " << endl;
00086             // Entry already exists in target
00087             if (sourceEntry->equals(targetEntry)) {
00088             kdDebug(5231) << "No action required" << endl;
00089                 // Entries are equal, no action required
00090             } else {
00091                 // Entries are different, resolve conflict
00092                 if (override && targetEntry->state() != SyncEntry::Removed ) {
00093                     // Force override
00094             kdDebug(5231) << "overriding and merging!" << endl;
00095             // we try to keep as much attributes as possible
00096             sourceEntry->mergeWith( targetEntry );
00097                     target->replaceEntry(targetEntry,sourceEntry->clone() );
00098                 } else {
00099                     if (syncee->hasChanged(sourceEntry) &&
00100                         target->hasChanged(targetEntry)) {
00101             kdDebug(5231) << "Deconflict " <<  endl;
00102             kdDebug(5231) << "Entry 1 state: " << sourceEntry->state() << endl;
00103             kdDebug(5231) << "Entry 2 state: " << targetEntry->state() << endl;
00104                         // Both entries have changed
00105                         SyncEntry *result = deconflict(sourceEntry,targetEntry);
00106                         if (result == sourceEntry) {
00107                 kdDebug(5231) << "Merging and then replacing!" << endl;
00108                 sourceEntry->mergeWith( targetEntry );
00109                             target->replaceEntry(targetEntry,sourceEntry->clone() );
00110                         }else
00111                             targetEntry->mergeWith( sourceEntry );
00112 
00113                     } else if (syncee->hasChanged(sourceEntry) &&
00114                                !target->hasChanged(targetEntry)) {
00115                         // take source entry
00116                         kdDebug(5231) << "Take source entry" << endl;
00117                         sourceEntry->mergeWith( targetEntry );
00118                         target->replaceEntry(targetEntry,sourceEntry->clone() );
00119                     } else if (!syncee->hasChanged(sourceEntry) &&
00120                                target->hasChanged(targetEntry)) {
00121                         // take target entry, no action required but merge
00122                         kdDebug(5231) << "Take target entry" << endl;
00123                         targetEntry->mergeWith(sourceEntry);
00124                     }
00125                 }
00126             }
00127         } else {
00128             // New entry if id starts with konnector id... set a new one
00129         kdDebug(5231) << "adding target " << endl;
00130             addEntry( syncee, target, sourceEntry );
00131         }
00132         sourceEntry = syncee->nextEntry();
00133     }
00134 }
00135 
00136 /*
00137  * We're now in the MetaMode
00138  * First sync added.
00139  * Then check the modified
00140  * Case 1)
00141  *  Modified   ---- untouched ----> Modify
00142  *  Modified   ---- Modified ---> Deconflict
00143  *  Modified   ---- Removed ----> Deconflict
00144  *  and vice versa
00145  *
00146  */
00147 void PIMSyncAlg::syncMeta( Syncee* syncee,
00148                            Syncee* target,
00149                            bool over )
00150 {
00151     kdDebug(5231) << "SyncMeta " << endl;
00152     QPtrList<SyncEntry> entries = syncee->added();
00153     SyncEntry* entry;
00154     SyncEntry* targetEntry;
00155     /* added */
00156     for ( entry = entries.first(); entry; entry = entries.next() ) {
00157         /* assign new uid */
00158     targetEntry = target->findEntry( entry->id() );
00159     kdDebug(5231) << "About to add " << entry->name() << endl;
00160     if(!targetEntry ){
00161       kdDebug(5231) << "Not added before " << endl;
00162           addEntry( syncee, target, entry );
00163     }else {
00164       kdDebug(5231) << "Added before " << endl;
00165     }
00166     }
00167     /* modified */
00168     forAll( syncee->modified(), syncee, target, over );
00169     forAll( syncee->removed(), syncee,  target,over );
00170 
00171 }
00172 
00173 void PIMSyncAlg::addEntry( Syncee* in, Syncee* out, SyncEntry* add )
00174 {
00175     if ( add->id().startsWith("Konnector-") ) {
00176         QString oldId = add->id();
00177         add->setId( in->newId() );
00178         in->insertId( add->type(), oldId, add->id() );
00179         out->insertId( add->type(), oldId, add->id() );
00180     }
00181     out->addEntry( add->clone() );
00182 }
00183 
00184 /*
00185  * Ok we are either modified
00186  * or removed
00187  * Now go through each item and look for one with the
00188  * same uid
00189  * If found check if it was Modified or Removed too
00190  * If yes check if they're equal otherwise
00191  * we need to deconflict
00192  */
00193 void PIMSyncAlg::forAll(QPtrList<SyncEntry> entries,  Syncee* syncee,
00194                         Syncee* target,
00195                         bool over )
00196 {
00197     kdDebug(5231) << "For All" << endl;
00198     SyncEntry* entry;
00199     SyncEntry* other;
00200     SyncEntry* result;
00201     /* for all modified and deleted*/
00202     for ( entry = entries.first(); entry; entry = entries.next() ) {
00203         result = 0;
00204         other = target->findEntry( entry->id()  );
00205         if (other ) { // exists, should always do
00206         kdDebug(5231) << "Entry 1 " << entry->name() << endl;
00207         kdDebug(5231) << "Entry 2 " << other->name() << endl;
00208 
00209             /* entry modified and other unchanged */
00210             if(entry->wasModified() && other->state()== SyncEntry::Undefined ) {
00211                 kdDebug(5231) << "Modified and unchanged " << endl;
00212                 entry->mergeWith( other );
00213                 target->replaceEntry( other, entry->clone() );
00214             }
00215             /* entry removed and other unchanged or removed too */
00216             else if ( entry->wasRemoved() &&
00217                       other->wasRemoved() ) {
00218                 kdDebug(5231) << "Removed and removed too " << endl;
00219                 // no need for merge
00220                 informBothDeleted( entry, other );
00221                 target->replaceEntry( other, entry->clone() );
00222              /* entry removed and other undefined confirmDelete */
00223             } else if ( entry->wasRemoved() &&
00224                        other->state() == SyncEntry::Undefined ) {
00225                 /* if confirmed that is fairly easy */
00226                 if (confirmDelete(entry, other) )
00227                     target->replaceEntry( other, entry->clone() );
00228                 /*
00229                  * aye aye how can we do this
00230                  * first of all we need to remove the modified flag
00231                  * then we need to set the support to 0 on the syncee
00232                  * and call a mergeWith
00233                  * then we reset the BitArray
00234                  */
00235                 else {
00236                     QBitArray ar = entry->syncee()->bitArray();
00237                     QBitArray oth;
00238                     oth.fill( false, ar.size() );
00239                     entry->syncee()->setSupports( oth );
00240                     /* refill the object with life */
00241                     entry->mergeWith( other );
00242 
00243                     /*
00244                      * This is specefic to two Syncees
00245                      * if!over we set the other to Modifed
00246                      * so the original(other) one will replace the former deleted one
00247                      * if we're on override there will be no second call
00248                      */
00249                     if (!over ) {
00250                         entry->setState( SyncEntry::Undefined );
00251                         other->setState( SyncEntry::Modified);
00252                     } else
00253                         entry->setState( SyncEntry::Modified);
00254 
00255                     /* restore */
00256                     entry->syncee()->setSupports( ar );
00257                 }
00258             }
00259             /* entry was removed and other changed */
00260             else if ( entry->wasRemoved() &&
00261                 other->wasModified() ) {
00262                 kdDebug(5231) << "Entry wasRemoved and other wasModified override is "
00263                           << over << endl;
00264                 if (!over)
00265                     result = deconflict(entry,other);
00266                 if (result == entry || over) {
00267                     // no need to merge here too we still remove
00268                     target->replaceEntry(other,entry->clone() );
00269                 }
00270 
00271             } else if ( entry->wasModified() && other->wasModified() ) {
00272                 kdDebug(5231) << "Both where modified override" << over<< endl;
00273                 kdDebug(5231) << "Entry1 timestamp " << entry->timestamp() << endl;
00274                 kdDebug(5231) << "Entry2 timestamp " << other->timestamp() << endl;
00275                 kdDebug(5231) << "Equals " << entry->equals( other ) << endl;
00276 
00277                 if (!over )
00278                     result = deconflict(entry,other);
00279 
00280                 if (result == entry || over) {
00281                     entry->mergeWith( other );
00282                     target->replaceEntry(other,entry->clone() );
00283                 }
00284 
00285             }
00286 
00287         } else {
00288         kdDebug(5231) << "added " << endl;
00289             addEntry(syncee, target, entry);
00290         }
00291 
00292     }
00293 }
KDE Logo
This file is part of the documentation for kitchensync Library Version 3.3.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Mar 23 22:41:42 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003