00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "conflictresolvedialog_p.h"
00022
00023 #include "abstractdifferencesreporter.h"
00024 #include "differencesalgorithminterface.h"
00025 #include "typepluginloader_p.h"
00026
00027 #include <QtGui/QVBoxLayout>
00028 #include <QtGui/QLabel>
00029
00030 #include <kcolorscheme.h>
00031 #include <klocale.h>
00032 #include <kpushbutton.h>
00033 #include <ktextbrowser.h>
00034
00035 using namespace Akonadi;
00036
00037 static inline QString textToHTML( const QString &text )
00038 {
00039 return Qt::convertFromPlainText( text );
00040 }
00041
00042 class HtmlDifferencesReporter : public AbstractDifferencesReporter
00043 {
00044 public:
00045 HtmlDifferencesReporter()
00046 {
00047 }
00048
00049 QString toHtml() const
00050 {
00051 return header() + mContent + footer();
00052 }
00053
00054 void setPropertyNameTitle( const QString &title )
00055 {
00056 mNameTitle = title;
00057 }
00058
00059 void setLeftPropertyValueTitle( const QString &title )
00060 {
00061 mLeftTitle = title;
00062 }
00063
00064 void setRightPropertyValueTitle( const QString &title )
00065 {
00066 mRightTitle = title;
00067 }
00068
00069 void addProperty( Mode mode, const QString &name, const QString &leftValue, const QString &rightValue )
00070 {
00071 switch ( mode ) {
00072 case NormalMode:
00073 mContent.append( QString::fromLatin1( "<tr><td align=\"right\"><b>%1:</b></td><td>%2</td><td></td><td>%3</td></tr>" )
00074 .arg( name )
00075 .arg( textToHTML( leftValue ) )
00076 .arg( textToHTML( rightValue ) ) );
00077 break;
00078 case ConflictMode:
00079 mContent.append( QString::fromLatin1( "<tr><td align=\"right\"><b>%1:</b></td><td bgcolor=\"#ff8686\">%2</td><td></td><td bgcolor=\"#ff8686\">%3</td></tr>" )
00080 .arg( name )
00081 .arg( textToHTML( leftValue ) )
00082 .arg( textToHTML( rightValue ) ) );
00083 break;
00084 case AdditionalLeftMode:
00085 mContent.append( QString::fromLatin1( "<tr><td align=\"right\"><b>%1:</b></td><td bgcolor=\"#9cff83\">%2</td><td></td><td></td></tr>" )
00086 .arg( name )
00087 .arg( textToHTML( leftValue ) ) );
00088 break;
00089 case AdditionalRightMode:
00090 mContent.append( QString::fromLatin1( "<tr><td align=\"right\"><b>%1:</b></td><td></td><td></td><td bgcolor=\"#9cff83\">%2</td></tr>" )
00091 .arg( name )
00092 .arg( textToHTML( rightValue ) ) );
00093 break;
00094 }
00095 }
00096
00097 private:
00098 QString header() const
00099 {
00100 QString header = QLatin1String( "<html>" );
00101 header += QString::fromLatin1( "<body text=\"%1\" bgcolor=\"%2\">" )
00102 .arg( KColorScheme( QPalette::Active, KColorScheme::View ).foreground().color().name() )
00103 .arg( KColorScheme( QPalette::Active, KColorScheme::View ).background().color().name() );
00104 header += QLatin1String( "<center><table>" );
00105 header += QString::fromLatin1( "<tr><th align=\"center\">%1</th><th align=\"center\">%2</th><td> </td><th align=\"center\">%3</th></tr>" )
00106 .arg( mNameTitle )
00107 .arg( mLeftTitle )
00108 .arg( mRightTitle );
00109
00110 return header;
00111 }
00112
00113 QString footer() const
00114 {
00115 return QLatin1String( "</table></center>"
00116 "</body>"
00117 "</html>" );
00118 }
00119
00120 QString mContent;
00121 QString mNameTitle;
00122 QString mLeftTitle;
00123 QString mRightTitle;
00124 };
00125
00126 static void compareItems( AbstractDifferencesReporter *reporter, const Akonadi::Item &localItem, const Akonadi::Item &otherItem )
00127 {
00128 if ( localItem.modificationTime() != otherItem.modificationTime() ) {
00129 reporter->addProperty( AbstractDifferencesReporter::ConflictMode, i18n( "Modification Time" ),
00130 KGlobal::locale()->formatDateTime( localItem.modificationTime(), KLocale::ShortDate, true ),
00131 KGlobal::locale()->formatDateTime( otherItem.modificationTime(), KLocale::ShortDate, true ) );
00132 }
00133
00134 if ( localItem.flags() != otherItem.flags() ) {
00135 QStringList localFlags;
00136 foreach ( const QByteArray &localFlag, localItem.flags() )
00137 localFlags.append( QString::fromUtf8( localFlag ) );
00138
00139 QStringList otherFlags;
00140 foreach ( const QByteArray &otherFlag, otherItem.flags() )
00141 otherFlags.append( QString::fromUtf8( otherFlag ) );
00142
00143 reporter->addProperty( AbstractDifferencesReporter::ConflictMode, i18n( "Flags" ),
00144 localFlags.join( QLatin1String( ", " ) ),
00145 otherFlags.join( QLatin1String( ", " ) ) );
00146 }
00147
00148 QHash<QByteArray, QByteArray> localAttributes;
00149 foreach ( Akonadi::Attribute *attribute, localItem.attributes() ) {
00150 localAttributes.insert( attribute->type(), attribute->serialized() );
00151 }
00152
00153 QHash<QByteArray, QByteArray> otherAttributes;
00154 foreach ( Akonadi::Attribute *attribute, otherItem.attributes() ) {
00155 otherAttributes.insert( attribute->type(), attribute->serialized() );
00156 }
00157
00158 if ( localAttributes != otherAttributes ) {
00159 foreach ( const QByteArray &localKey, localAttributes.keys() ) {
00160 if ( !otherAttributes.contains( localKey ) ) {
00161 reporter->addProperty( AbstractDifferencesReporter::AdditionalLeftMode, i18n( "Attribute: %1", QString::fromUtf8( localKey ) ),
00162 QString::fromUtf8( localAttributes.value( localKey ) ),
00163 QString() );
00164 } else {
00165 const QByteArray localValue = localAttributes.value( localKey );
00166 const QByteArray otherValue = otherAttributes.value( localKey );
00167 if ( localValue != otherValue ) {
00168 reporter->addProperty( AbstractDifferencesReporter::ConflictMode, i18n( "Attribute: %1", QString::fromUtf8( localKey ) ),
00169 QString::fromUtf8( localValue ),
00170 QString::fromUtf8( otherValue ) );
00171 }
00172 }
00173 }
00174
00175 foreach ( const QByteArray &otherKey, otherAttributes.keys() ) {
00176 if ( !localAttributes.contains( otherKey ) ) {
00177 reporter->addProperty( AbstractDifferencesReporter::AdditionalRightMode, i18n( "Attribute: %1", QString::fromUtf8( otherKey ) ),
00178 QString(),
00179 QString::fromUtf8( otherAttributes.value( otherKey ) ) );
00180 }
00181 }
00182 }
00183 }
00184
00185 ConflictResolveDialog::ConflictResolveDialog( QWidget *parent )
00186 : KDialog( parent ), mResolveStrategy( ConflictHandler::UseBothItems )
00187 {
00188 setCaption( i18nc( "@title:window", "Conflict Resolution" ) );
00189 setButtons( User1 | User2 | User3 );
00190 setDefaultButton( User3 );
00191
00192 button( User3 )->setText( i18n( "Take left one" ) );
00193 button( User2 )->setText( i18n( "Take right one" ) );
00194 button( User1 )->setText( i18n( "Keep both" ) );
00195
00196 connect( this, SIGNAL( user1Clicked() ), SLOT( slotUseBothItemsChoosen() ) );
00197 connect( this, SIGNAL( user2Clicked() ), SLOT( slotUseOtherItemChoosen() ) );
00198 connect( this, SIGNAL( user3Clicked() ), SLOT( slotUseLocalItemChoosen() ) );
00199
00200 QWidget *mainWidget = new QWidget;
00201 QVBoxLayout *layout = new QVBoxLayout( mainWidget );
00202
00203 QLabel* label = new QLabel( i18nc( "@label", "Two updates conflict with each other.<nl/>Please choose which update(s) to apply." ), mainWidget );
00204 layout->addWidget( label );
00205
00206 mView = new KTextBrowser;
00207
00208 layout->addWidget( mView );
00209
00210 setMainWidget( mainWidget );
00211 }
00212
00213 void ConflictResolveDialog::setConflictingItems( const Akonadi::Item &localItem, const Akonadi::Item &otherItem )
00214 {
00215 mLocalItem = localItem;
00216 mOtherItem = otherItem;
00217
00218 HtmlDifferencesReporter reporter;
00219
00220 if ( mLocalItem.hasPayload() && mOtherItem.hasPayload() ) {
00221
00222 QObject *object = TypePluginLoader::objectForMimeTypeAndClass( localItem.mimeType(), localItem.availablePayloadMetaTypeIds() );
00223 if ( object ) {
00224 DifferencesAlgorithmInterface *algorithm = qobject_cast<DifferencesAlgorithmInterface*>( object );
00225 if ( algorithm ) {
00226 algorithm->compare( &reporter, localItem, otherItem );
00227 mView->setHtml( reporter.toHtml() );
00228 return;
00229 }
00230 }
00231
00232 reporter.addProperty( HtmlDifferencesReporter::NormalMode, i18n( "Data" ),
00233 QString::fromUtf8( mLocalItem.payloadData() ),
00234 QString::fromUtf8( mOtherItem.payloadData() ) );
00235 }
00236
00237 compareItems( &reporter, localItem, otherItem );
00238
00239 mView->setHtml( reporter.toHtml() );
00240 }
00241
00242 ConflictHandler::ResolveStrategy ConflictResolveDialog::resolveStrategy() const
00243 {
00244 return mResolveStrategy;
00245 }
00246
00247 void ConflictResolveDialog::slotUseLocalItemChoosen()
00248 {
00249 mResolveStrategy = ConflictHandler::UseLocalItem;
00250 accept();
00251 }
00252
00253 void ConflictResolveDialog::slotUseOtherItemChoosen()
00254 {
00255 mResolveStrategy = ConflictHandler::UseOtherItem;
00256 accept();
00257 }
00258
00259 void ConflictResolveDialog::slotUseBothItemsChoosen()
00260 {
00261 mResolveStrategy = ConflictHandler::UseBothItems;
00262 accept();
00263 }
00264
00265 #include "conflictresolvedialog_p.moc"