libkdepim

kincidencechooser.cpp

00001 /*
00002   This file is part of libkdepim.
00003 
00004   Copyright (c) 2004 Lutz Rogowski <rogowski@kde.org>
00005   Copyright (c) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.net>
00006 
00007   This program is free software; you can redistribute it and/or modify
00008   it under the terms of the GNU General Public License as published by
00009   the Free Software Foundation; either version 2 of the License, or
00010   (at your option) any later version.
00011 
00012   This program is distributed in the hope that it will be useful,
00013   but WITHOUT ANY WARRANTY; without even the implied warranty of
00014   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00015   GNU General Public License for more details.
00016 
00017   You should have received a copy of the GNU General Public License
00018   along with this program; if not, write to the Free Software
00019   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020 
00021   As a special exception, permission is given to link this program
00022   with any edition of Qt, and distribute the resulting executable,
00023   without including the source code for Qt in the source distribution.
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   // row 1: dialog description
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   // row 2: info box
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   // row 3: take duration prefs
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   // duration options box (in row 3)
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   // init the folder buttons
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   // row 4: "take" button box
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   // final settings
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/*not modal*/, 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/*not modal*/, 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"
KDE Home | KDE Accessibility Home | Description of Access Keys