00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "kincidencechooser.h"
00027
00028 #include "libkcal/incidence.h"
00029 #include "libkcal/incidenceformatter.h"
00030 using namespace KCal;
00031
00032 #include <kglobalsettings.h>
00033 #include <klocale.h>
00034 #include <kmessagebox.h>
00035
00036 #include <qapplication.h>
00037 #include <qbuttongroup.h>
00038 #include <qhbox.h>
00039 #include <qlabel.h>
00040 #include <qlayout.h>
00041 #include <qpushbutton.h>
00042 #include <qradiobutton.h>
00043 #include <qtextbrowser.h>
00044 #include <qtooltip.h>
00045 #include <qwhatsthis.h>
00046
00047 using namespace KPIM;
00048
00049 KIncidenceChooser::KIncidenceChooser( const QString &folder, ConflictAskPolicy askPolicy,
00050 bool folderOnly, QWidget *parent, char *name )
00051 : KDialog( parent, name, true ),
00052 mFolder( folder ), mAskPolicy( askPolicy ), mFolderOnly( folderOnly )
00053 {
00054 mTakeMode = Newer;
00055 QColor bc = KGlobalSettings::alternateBackgroundColor();
00056
00057 KDialog *topFrame = this;
00058 QGridLayout *topLayout = new QGridLayout( topFrame, 5, 1 );
00059 topLayout->setSpacing( spacingHint() );
00060 topLayout->setMargin( marginHint() );
00061
00062
00063 int iii = 0;
00064 setCaption( i18n( "Synchronization Conflict Detected" ) );
00065 QLabel *lab = new QLabel(
00066 i18n( "<qt>A synchronization conflict occurred: Probably someone "
00067 "modified an entry remotely (i.e. on the server), which you "
00068 "have also modified locally (i.e. on your client).</qt>" ), topFrame );
00069
00070 lab->setFrameShape( QFrame::StyledPanel );
00071 lab->setPaletteBackgroundColor( bc );
00072 topLayout->addMultiCellWidget( lab, iii, iii, 0, 1 );
00073 ++iii;
00074
00075
00076 QGridLayout *infoGrid = new QGridLayout( topLayout, 4, 3 );
00077 ++iii;
00078
00079 QLabel *conflictLab = new QLabel( i18n( "Conflict in folder:" ), topFrame );
00080 infoGrid->addWidget( conflictLab, 0, 0 );
00081
00082 QString folderStr = mFolder;
00083 if ( mFolder.isEmpty() ) {
00084 folderStr = i18n( "folder name was not specified", "not specified" );
00085 }
00086 QLabel *folderLab = new QLabel( QString( "%1" ).arg( folderStr ), topFrame );
00087 infoGrid->addWidget( folderLab, 0, 1 );
00088
00089 QLabel *locEntryLab = new QLabel( i18n( "Local entry:" ), topFrame );
00090 infoGrid->addWidget( locEntryLab, 1, 0 );
00091
00092 mLocEntryVal = new QLabel( "summary", topFrame );
00093 mLocEntryVal->setAlignment( Qt::AlignLeft | Qt::AlignVCenter );
00094 infoGrid->addWidget( mLocEntryVal, 1, 1 );
00095
00096 QLabel *locModLab = new QLabel( i18n( "Last modified:" ), topFrame );
00097 infoGrid->addWidget( locModLab, 2, 0 );
00098
00099 mLocModVal = new QLabel( "modified date/time", topFrame );
00100 mLocModVal->setAlignment( Qt::AlignLeft | Qt::AlignVCenter );
00101 infoGrid->addWidget( mLocModVal, 2, 1 );
00102
00103 mLocShowDetails = new QPushButton( i18n( "&Show Details..." ), topFrame );
00104 mLocShowDetails->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
00105 infoGrid->addWidget( mLocShowDetails, 2, 2 );
00106 QToolTip::add(
00107 mLocShowDetails,
00108 i18n( "Hide/Show entry details" ) );
00109 QWhatsThis::add(
00110 mLocShowDetails,
00111 i18n( "Press this button to toggle the entry details display." ) );
00112 connect( mLocShowDetails, SIGNAL(clicked()), this, SLOT (showLocalIncidence()) );
00113
00114 QLabel *remEntryLab = new QLabel( i18n( "Remote entry:" ), topFrame );
00115 infoGrid->addWidget( remEntryLab, 3, 0 );
00116
00117 mRemEntryVal = new QLabel( "summary", topFrame );
00118 mRemEntryVal->setAlignment( Qt::AlignLeft | Qt::AlignVCenter );
00119 infoGrid->addWidget( mRemEntryVal, 3, 1 );
00120
00121 QLabel *remModLab = new QLabel( i18n( "Last modified:" ), topFrame );
00122 infoGrid->addWidget( remModLab, 4, 0 );
00123
00124 mRemModVal = new QLabel( "modified date/time", topFrame );
00125 mRemModVal->setAlignment( Qt::AlignLeft | Qt::AlignVCenter );
00126 infoGrid->addWidget( mRemModVal, 4, 1 );
00127
00128 mRemShowDetails = new QPushButton( i18n( "Show &Details..." ), topFrame );
00129 mRemShowDetails->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
00130 infoGrid->addWidget( mRemShowDetails, 4, 2 );
00131 QToolTip::add(
00132 mRemShowDetails,
00133 i18n( "Hide/Show entry details" ) );
00134 QWhatsThis::add(
00135 mRemShowDetails,
00136 i18n( "Press this button to toggle the entry details display." ) );
00137 connect( mRemShowDetails, SIGNAL(clicked()), this, SLOT (showRemoteIncidence()) );
00138
00139
00140 mBg = new QButtonGroup( 4, Qt::Horizontal, i18n( "Take Option Duration" ), topFrame );
00141 mBg->setRadioButtonExclusive( true );
00142 lab = new QLabel(
00143 i18n( "<qt>Please choose how long the \"Take Option\" selected below "
00144 "should remain in effect:</qt>" ), mBg );
00145 mBg->setColumns( 1 );
00146 topLayout->addMultiCellWidget( mBg, iii, iii, 0, 1 );
00147 ++iii;
00148
00149 QRadioButton *syncOnceBut = new QRadioButton(
00150 i18n( "Apply to all conflicts occurring during this synchronization" ), mBg );
00151 mBg->insert( syncOnceBut, KIncidenceChooser::Sync );
00152 QToolTip::add(
00153 syncOnceBut,
00154 i18n( "Ask only for the first conflict during a synchronization" ) );
00155 QWhatsThis::add(
00156 syncOnceBut,
00157 i18n( "This option says to show the conflict resolution dialog only for the "
00158 "first conflict that may occur during a synchronization. That is, do not "
00159 "show this dialog again until a conflict occurs during another synchronization." ) );
00160
00161 const QString app = qApp->name();
00162 QRadioButton *syncSessionBut = new QRadioButton(
00163 i18n( "Apply to all conflicts during this %1 session" ).arg( app ), mBg );
00164 mBg->insert( syncSessionBut, KIncidenceChooser::Session );
00165 QToolTip::add(
00166 syncSessionBut,
00167 i18n( "Ask only for the first conflict after a %1 restart" ).arg( app ) );
00168 QWhatsThis::add(
00169 syncSessionBut,
00170 i18n( "This option says to show the conflict resolution dialog only for the "
00171 "first conflict that occurs since %1 was started. More specifically, "
00172 "do not show this dialog again during until %2 is restarted." ).arg( app, app ) );
00173
00174 QRadioButton *syncPermanentBut = new QRadioButton(
00175 i18n( "Apply always and permanently" ), mBg );
00176 mBg->insert( syncPermanentBut, KIncidenceChooser::Never );
00177 QToolTip::add(
00178 syncPermanentBut,
00179 i18n( "Never ask again (may require system administrative help to undo!)" ) );
00180 QWhatsThis::add(
00181 syncPermanentBut,
00182 i18n( "This option says to never show th conflict resolution dialog again, always "
00183 "using the take option chosen specified now. Be aware that this option cannot "
00184 "be undone without editing a file by-hand and may require system administrative "
00185 "help to undo." ) );
00186
00187 QRadioButton *syncAskBut = new QRadioButton(
00188 i18n( "Apply only to this conflict (ask each time)" ), mBg );
00189 mBg->insert( syncAskBut, KIncidenceChooser::Always );
00190 QToolTip::add(
00191 syncAskBut,
00192 i18n( "Ask for every conflict" ) );
00193 QWhatsThis::add(
00194 syncAskBut,
00195 i18n( "This option says to show the conflict resolution dialog "
00196 "for each and every conflict." ) );
00197
00198 mBg->setButton( mAskPolicy );
00199
00200
00201 QHBox *optGrid = new QHBox( mBg );
00202 QLabel *l = new QLabel( i18n( "The duration selection applies to:" ), optGrid );
00203 optGrid->setStretchFactor( l, 40 );
00204
00205 mFolderAllBut = new QRadioButton( i18n( "all folders" ), optGrid );
00206 QToolTip::add(
00207 mFolderAllBut,
00208 i18n( "Applies this setting as the default duration for all folders" ) );
00209 QWhatsThis::add(
00210 mFolderAllBut,
00211 i18n( "This option says to apply the duration setting to all shared folders that "
00212 "do not have their own specific setting. That is, this is the default setting "
00213 "for the take duration." ) );
00214 optGrid->setStretchFactor( mFolderAllBut, 30 );
00215
00216 mFolderOnlyBut = new QRadioButton( i18n( "this folder only" ), optGrid );
00217 QToolTip::add(
00218 mFolderOnlyBut,
00219 i18n( "Applies this setting as the duration for the folder \"%1\" only" ).arg( mFolder ) );
00220 QWhatsThis::add(
00221 mFolderOnlyBut,
00222 i18n( "This option says to apply the duration setting to the folder \"%1\" only. "
00223 "All other folders will use the default take duration setting." ).arg( mFolder ) );
00224 optGrid->setStretchFactor( mFolderOnlyBut, 30 );
00225
00226
00227 mFolderAllBut->setChecked( !mFolderOnly );
00228 mFolderOnlyBut->setChecked( mFolderOnly );
00229 connect( mFolderOnlyBut, SIGNAL(clicked()), this, SLOT(slotFolderOnly()) );
00230 connect( mFolderAllBut, SIGNAL(clicked()), this, SLOT(slotFolderAll()) );
00231
00232
00233 QButtonGroup *b_box = new QButtonGroup( 5, Qt::Horizontal, i18n( "Take Option" ), topFrame );
00234 b_box->setColumns( 1 );
00235 topLayout->addMultiCellWidget( b_box, iii, iii, 0, 1 );
00236 ++iii;
00237
00238 lab = new QLabel(
00239 i18n( "<qt>Please choose which of the two entries shall be retained:</qt>" ), b_box );
00240
00241 QPushButton *newBut = new QPushButton( i18n( "Take &Newer (last modified)" ), b_box );
00242 newBut->setFocus();
00243 connect( newBut, SIGNAL(clicked()), this, SLOT (takeNewerIncidence()) );
00244 QToolTip::add(
00245 newBut,
00246 i18n( "Take the newer version of the entry" ) );
00247 QWhatsThis::add(
00248 newBut,
00249 i18n( "A conflict was detected between your local copy of the entry "
00250 "and the remote entry on the server. Press the \"Take Newer\" button "
00251 "to use the version most recently modified, possibly overwriting your local copy" ) );
00252
00253 QPushButton *remBut = new QPushButton( i18n( "Take &Remote (server-side)" ), b_box );
00254 connect( remBut, SIGNAL(clicked()), this, SLOT (takeRemoteIncidence()) );
00255 QToolTip::add(
00256 remBut,
00257 i18n( "Take the server copy of the entry" ) );
00258 QWhatsThis::add(
00259 remBut,
00260 i18n( "A conflict was detected between your local copy of the entry "
00261 "and the remote entry on the server. Press the \"Take Remote\" button "
00262 "to use the server copy, thereby overwriting your local copy" ) );
00263
00264 QPushButton *locBut = new QPushButton( i18n( "Take &Local (client-side)" ), b_box );
00265 connect( locBut, SIGNAL(clicked()), this, SLOT (takeLocalIncidence()) );
00266 QToolTip::add(
00267 locBut,
00268 i18n( "Take your local copy of the entry" ) );
00269 QWhatsThis::add(
00270 locBut,
00271 i18n( "A conflict was detected between your local copy of the entry "
00272 "and the remote entry on the server. Press the \"Take Local\" button "
00273 "to make sure your local copy is used." ) );
00274
00275 QPushButton *bothBut =
00276 new QPushButton( i18n( "Take &Both (resulting in two different, parallel entries)" ), b_box );
00277 connect( bothBut, SIGNAL(clicked()), this, SLOT (takeBothIncidence()) );
00278 QToolTip::add(
00279 bothBut,
00280 i18n( "Take both copies of the entry" ) );
00281 QWhatsThis::add(
00282 bothBut,
00283 i18n( "A conflict was detected between your local copy of the entry "
00284 "and the remote entry on the server. Press the \"Take Both\" button "
00285 "to keep both the local and the server copies, resulting in "
00286 "two differing entries in parallel." ) );
00287
00288
00289
00290 mTbL = 0;
00291 mTbN = 0;
00292 mSelIncidence = 0;
00293 }
00294
00295 KIncidenceChooser::~KIncidenceChooser()
00296 {
00297 if ( mTbL ) {
00298 delete mTbL;
00299 }
00300 if ( mTbN ) {
00301 delete mTbN;
00302 }
00303 }
00304
00305 void KIncidenceChooser::setIncidences( Incidence *local, Incidence *remote )
00306 {
00307 mLocInc = local;
00308 mRemInc = remote;
00309 setLabels();
00310 }
00311
00312 Incidence *KIncidenceChooser::takeIncidence()
00313 {
00314 return mSelIncidence;
00315 }
00316
00317 KIncidenceChooser::TakeMode KIncidenceChooser::takeMode()
00318 {
00319 return mTakeMode;
00320 }
00321
00322 void KIncidenceChooser::setConflictAskPolicy( ConflictAskPolicy policy )
00323 {
00324 mAskPolicy = policy;
00325 }
00326
00327 KIncidenceChooser::ConflictAskPolicy KIncidenceChooser::conflictAskPolicy()
00328 {
00329 return mAskPolicy;
00330 }
00331
00332 void KIncidenceChooser::setFolderOnly( bool folderOnly )
00333 {
00334 mFolderOnly = folderOnly;
00335 }
00336
00337 bool KIncidenceChooser::folderOnly()
00338 {
00339 return mFolderOnly;
00340 }
00341
00342 void KIncidenceChooser::useGlobalMode()
00343 {
00344 if ( mAskPolicy != KIncidenceChooser::Always ) {
00345 QDialog::reject();
00346 }
00347 }
00348
00349 QString KIncidenceChooser::summaryStr( Incidence *incidence ) const
00350 {
00351 static QString etc = i18n( "elipsis", "..." );
00352
00353 uint maxLen = 30;
00354 QString s = incidence->summary();
00355 if ( s.isEmpty() ) {
00356 return i18n( "unspecified" );
00357 } else {
00358 if ( s.length() > maxLen ) {
00359 maxLen -= etc.length();
00360 s = s.left( maxLen );
00361 s += etc;
00362 }
00363 return s;
00364 }
00365 }
00366
00367 QString KIncidenceChooser::modifiedStr( Incidence *incidence ) const
00368 {
00369 return KGlobal::locale()->formatDateTime( incidence->lastModified() );
00370 }
00371
00372 void KIncidenceChooser::setLabels()
00373 {
00374 mLocEntryVal->setText( summaryStr( mLocInc ) );
00375 mLocModVal->setText( modifiedStr( mLocInc ) );
00376
00377 mRemEntryVal->setText( summaryStr( mRemInc ) );
00378 mRemModVal->setText( modifiedStr( mRemInc ) );
00379 }
00380
00381 void KIncidenceChooser::detailsDialogClosed()
00382 {
00383 KDialogBase* dialog = static_cast<KDialogBase *>( const_cast<QObject *>( sender() ) );
00384 if ( dialog == mTbL ) {
00385 mLocShowDetails->setText( i18n( "Show details..." ) );
00386 } else {
00387 mRemShowDetails->setText( i18n( "Show details..." ) );
00388 }
00389 }
00390
00391 void KIncidenceChooser::slotFolderAll()
00392 {
00393 mFolderOnlyBut->setChecked( false );
00394 }
00395
00396 void KIncidenceChooser::slotFolderOnly()
00397 {
00398 mFolderAllBut->setChecked( false );
00399 }
00400
00401 void KIncidenceChooser::showLocalIncidence()
00402 {
00403 if ( mTbL ) {
00404 if ( mTbL->isVisible() ) {
00405 mLocShowDetails->setText( i18n( "Show Details..." ) );
00406 mTbL->hide();
00407 } else {
00408 mLocShowDetails->setText( i18n( "Hide Details" ) );
00409 mTbL->show();
00410 mTbL->raise();
00411 }
00412 return;
00413 }
00414 mTbL = new KDialogBase( this, "", false, mLocEntryVal->text(), KDialogBase::Ok );
00415 mTbL->setEscapeButton( KDialogBase::Ok );
00416 connect( mTbL, SIGNAL(okClicked()), this, SLOT(detailsDialogClosed()) );
00417 QTextBrowser *textBrowser = new QTextBrowser( mTbL );
00418 mTbL->setMainWidget( textBrowser );
00419 textBrowser->setText( IncidenceFormatter::extensiveDisplayStr( 0, mLocInc ) );
00420 QToolTip::add( textBrowser, i18n( "Incidence details" ) );
00421 QWhatsThis::add( textBrowser, i18n( "This area shows the entry details" ) );
00422 mTbL->setMinimumSize( 400, 400 );
00423 mLocShowDetails->setText( i18n( "Hide Details" ) );
00424 mTbL->show();
00425 mTbL->raise();
00426 }
00427
00428 void KIncidenceChooser::showRemoteIncidence()
00429 {
00430 if ( mTbN ) {
00431 if ( mTbN->isVisible() ) {
00432 mRemShowDetails->setText( i18n( "Show Details" ) );
00433 mTbN->hide();
00434 } else {
00435 mRemShowDetails->setText( i18n( "Hide Details" ) );
00436 mTbN->show();
00437 mTbN->raise();
00438 }
00439 return;
00440 }
00441 mTbN = new KDialogBase( this, "", false, mRemEntryVal->text(), KDialogBase::Ok );
00442 mTbN->setEscapeButton( KDialogBase::Ok );
00443 connect( mTbN, SIGNAL(okClicked()), this, SLOT(detailsDialogClosed()) );
00444 QTextBrowser *textBrowser = new QTextBrowser( mTbN );
00445 mTbN->setMainWidget( textBrowser );
00446 textBrowser->setText( IncidenceFormatter::extensiveDisplayStr( 0, mRemInc ) );
00447 QToolTip::add( textBrowser, i18n( "Incidence details" ) );
00448 QWhatsThis::add( textBrowser, i18n( "This area shows the entry details" ) );
00449 mTbN->setMinimumSize( 400, 400 );
00450 mRemShowDetails->setText( i18n( "Hide Details" ) );
00451 mTbN->show();
00452 mTbN->raise();
00453 }
00454
00455 void KIncidenceChooser::takeNewerIncidence()
00456 {
00457 if ( mLocInc->lastModified() == mRemInc->lastModified() ) {
00458 mSelIncidence = 0;
00459 } else if ( mLocInc->lastModified() > mRemInc->lastModified() ) {
00460 mSelIncidence = mLocInc;
00461 } else {
00462 mSelIncidence = mRemInc;
00463 }
00464 mAskPolicy = ( ConflictAskPolicy )mBg->selectedId ();
00465 mTakeMode = Newer;
00466 mFolderOnly = mFolderOnlyBut->isChecked();
00467 QDialog::accept();
00468 }
00469
00470 void KIncidenceChooser::takeLocalIncidence()
00471 {
00472 mSelIncidence = mLocInc;
00473 mAskPolicy = ( ConflictAskPolicy )mBg->selectedId ();
00474 mTakeMode = Local;
00475 mFolderOnly = mFolderOnlyBut->isChecked();
00476 QDialog::accept();
00477 }
00478
00479 void KIncidenceChooser::takeRemoteIncidence()
00480 {
00481 mSelIncidence = mRemInc;
00482 mAskPolicy = ( ConflictAskPolicy )mBg->selectedId ();
00483 mTakeMode = Remote;
00484 mFolderOnly = mFolderOnlyBut->isChecked();
00485 QDialog::accept();
00486 }
00487
00488 void KIncidenceChooser::takeBothIncidence()
00489 {
00490 mSelIncidence = 0;
00491 mAskPolicy = ( ConflictAskPolicy )mBg->selectedId ();
00492 mTakeMode = Both;
00493 mFolderOnly = mFolderOnlyBut->isChecked();
00494 QDialog::accept();
00495 }
00496
00497 void KIncidenceChooser::closeEvent( QCloseEvent *e )
00498 {
00499 Q_UNUSED( e );
00500 KMessageBox::sorry( parentWidget(),
00501 i18n( "Sorry, you must select an entry from the conflict." ) );
00502 }
00503
00504 void KIncidenceChooser::keyPressEvent( QKeyEvent *e )
00505 {
00506 if ( e->state() == 0 && e->key() == Key_Escape ) {
00507 KMessageBox::sorry( parentWidget(),
00508 i18n( "Sorry, you must select an entry from the conflict." ) );
00509 e->ignore();
00510 return;
00511 }
00512 KDialog::keyPressEvent( e );
00513 }
00514
00515 #include "kincidencechooser.moc"