akonadi
changerecorder_p.h
00001 /* 00002 Copyright (c) 2007 Volker Krause <vkrause@kde.org> 00003 00004 This library is free software; you can redistribute it and/or modify it 00005 under the terms of the GNU Library General Public License as published by 00006 the Free Software Foundation; either version 2 of the License, or (at your 00007 option) any later version. 00008 00009 This library is distributed in the hope that it will be useful, but WITHOUT 00010 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00011 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public 00012 License for more details. 00013 00014 You should have received a copy of the GNU Library General Public License 00015 along with this library; see the file COPYING.LIB. If not, write to the 00016 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 00017 02110-1301, USA. 00018 */ 00019 00020 #ifndef AKONADI_CHANGERECORDER_P_H 00021 #define AKONADI_CHANGERECORDER_P_H 00022 00023 #include "akonadiprivate_export.h" 00024 #include "monitor_p.h" 00025 00026 class AKONADI_TESTS_EXPORT Akonadi::ChangeRecorderPrivate : public Akonadi::MonitorPrivate 00027 { 00028 public: 00029 ChangeRecorderPrivate( MonitorDependeciesFactory *dependenciesFactory_, ChangeRecorder* parent ) : 00030 MonitorPrivate( dependenciesFactory_, parent ), 00031 settings( 0 ), 00032 enableChangeRecording( true ) 00033 { 00034 } 00035 00036 Q_DECLARE_PUBLIC( ChangeRecorder ) 00037 QSettings *settings; 00038 bool enableChangeRecording; 00039 00040 virtual int pipelineSize() const 00041 { 00042 if ( enableChangeRecording ) 00043 return 0; // we fill the pipeline ourselves when using change recording 00044 return MonitorPrivate::pipelineSize(); 00045 } 00046 00047 virtual void slotNotify( const NotificationMessage::List &msgs ) 00048 { 00049 Q_Q( ChangeRecorder ); 00050 const int oldChanges = pendingNotifications.size(); 00051 MonitorPrivate::slotNotify( msgs ); // with change recording disabled this will automatically take care of dispatching notification messages 00052 if ( enableChangeRecording && pendingNotifications.size() != oldChanges ) { 00053 saveNotifications(); 00054 emit q->changesAdded(); 00055 } 00056 } 00057 00058 virtual bool emitNotification(const Akonadi::NotificationMessage& msg) 00059 { 00060 const bool someoneWasListening = MonitorPrivate::emitNotification( msg ); 00061 if ( !someoneWasListening && enableChangeRecording ) 00062 QMetaObject::invokeMethod( q_ptr, "replayNext", Qt::QueuedConnection ); // skip notifications noone was listening to 00063 return someoneWasListening; 00064 } 00065 00066 void loadNotifications() 00067 { 00068 pendingNotifications.clear(); 00069 00070 const QString changesFileName = settings->fileName() + QLatin1String( "_changes.dat" ); 00071 00078 if ( !QFile::exists( changesFileName ) ) { 00079 QStringList list; 00080 settings->beginGroup( QLatin1String( "ChangeRecorder" ) ); 00081 const int size = settings->beginReadArray( QLatin1String( "change" ) ); 00082 00083 for ( int i = 0; i < size; ++i ) { 00084 settings->setArrayIndex( i ); 00085 NotificationMessage msg; 00086 msg.setSessionId( settings->value( QLatin1String( "sessionId" ) ).toByteArray() ); 00087 msg.setType( (NotificationMessage::Type)settings->value( QLatin1String( "type" ) ).toInt() ); 00088 msg.setOperation( (NotificationMessage::Operation)settings->value( QLatin1String( "op" ) ).toInt() ); 00089 msg.setUid( settings->value( QLatin1String( "uid" ) ).toLongLong() ); 00090 msg.setRemoteId( settings->value( QLatin1String( "rid" ) ).toString() ); 00091 msg.setResource( settings->value( QLatin1String( "resource" ) ).toByteArray() ); 00092 msg.setParentCollection( settings->value( QLatin1String( "parentCol" ) ).toLongLong() ); 00093 msg.setParentDestCollection( settings->value( QLatin1String( "parentDestCol" ) ).toLongLong() ); 00094 msg.setMimeType( settings->value( QLatin1String( "mimeType" ) ).toString() ); 00095 list = settings->value( QLatin1String( "itemParts" ) ).toStringList(); 00096 QSet<QByteArray> itemParts; 00097 Q_FOREACH( const QString &entry, list ) 00098 itemParts.insert( entry.toLatin1() ); 00099 msg.setItemParts( itemParts ); 00100 pendingNotifications << msg; 00101 } 00102 00103 settings->endArray(); 00104 00105 // save notifications to the new file... 00106 saveNotifications(); 00107 00108 // ...delete the legacy list... 00109 settings->remove( QString() ); 00110 settings->endGroup(); 00111 00112 // ...and continue as usually 00113 } 00114 00115 QFile file( changesFileName ); 00116 if ( !file.open( QIODevice::ReadOnly ) ) 00117 return; 00118 pendingNotifications = loadFrom( &file ); 00119 } 00120 00121 QQueue<NotificationMessage> loadFrom( QIODevice *device ) 00122 { 00123 QDataStream stream( device ); 00124 stream.setVersion( QDataStream::Qt_4_6 ); 00125 00126 qulonglong size; 00127 QByteArray sessionId, resource; 00128 int type, operation; 00129 qlonglong uid, parentCollection, parentDestCollection; 00130 QString remoteId, mimeType; 00131 QSet<QByteArray> itemParts; 00132 00133 QQueue<NotificationMessage> list; 00134 00135 stream >> size; 00136 for ( qulonglong i = 0; i < size; ++i ) { 00137 NotificationMessage msg; 00138 00139 stream >> sessionId; 00140 stream >> type; 00141 stream >> operation; 00142 stream >> uid; 00143 stream >> remoteId; 00144 stream >> resource; 00145 stream >> parentCollection; 00146 stream >> parentDestCollection; 00147 stream >> mimeType; 00148 stream >> itemParts; 00149 00150 msg.setSessionId( sessionId ); 00151 msg.setType( static_cast<NotificationMessage::Type>( type ) ); 00152 msg.setOperation( static_cast<NotificationMessage::Operation>( operation ) ); 00153 msg.setUid( uid ); 00154 msg.setRemoteId( remoteId ); 00155 msg.setResource( resource ); 00156 msg.setParentCollection( parentCollection ); 00157 msg.setParentDestCollection( parentDestCollection ); 00158 msg.setMimeType( mimeType ); 00159 msg.setItemParts( itemParts ); 00160 list << msg; 00161 } 00162 return list; 00163 } 00164 00165 void addToStream( QDataStream &stream, const NotificationMessage &msg ) 00166 { 00167 stream << msg.sessionId(); 00168 stream << int(msg.type()); 00169 stream << int(msg.operation()); 00170 stream << qulonglong(msg.uid()); 00171 stream << msg.remoteId(); 00172 stream << msg.resource(); 00173 stream << qulonglong(msg.parentCollection()); 00174 stream << qulonglong(msg.parentDestCollection()); 00175 stream << msg.mimeType(); 00176 stream << msg.itemParts(); 00177 } 00178 00179 void saveNotifications() 00180 { 00181 if ( !settings ) 00182 return; 00183 00184 QFile file( settings->fileName() + QLatin1String( "_changes.dat" ) ); 00185 QFileInfo info( file ); 00186 if ( !QFile::exists( info.absolutePath() ) ) { 00187 QDir dir; 00188 dir.mkpath( info.absolutePath() ); 00189 } 00190 if ( !file.open( QIODevice::WriteOnly ) ) { 00191 qWarning() << "could not save notifications to file " << file.fileName(); 00192 return; 00193 } 00194 saveTo(&file); 00195 } 00196 00197 void saveTo( QIODevice *device ) 00198 { 00199 00200 QDataStream stream( device ); 00201 stream.setVersion( QDataStream::Qt_4_6 ); 00202 00203 stream << (qulonglong)(pipeline.count() + pendingNotifications.count()); 00204 00205 for ( int i = 0; i < pipeline.count(); ++i ) { 00206 const NotificationMessage msg = pipeline.at( i ); 00207 addToStream( stream, msg ); 00208 } 00209 00210 for ( int i = 0; i < pendingNotifications.count(); ++i ) { 00211 const NotificationMessage msg = pendingNotifications.at( i ); 00212 addToStream( stream, msg ); 00213 } 00214 } 00215 }; 00216 00217 #endif