1/*
2 This file is part of libkdepim.
3
4 Copyright (c) 2004 Lutz Rogowski <rogowski@kde.org>
5 Copyright (c) 2009 Allen Winter <winter@kde.org>
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License along
18 with this program; if not, write to the Free Software Foundation, Inc.,
19 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20
21 As a special exception, permission is given to link this program
22 with any edition of Qt, and distribute the resulting executable,
23 without including the source code for Qt in the source distribution.
24*/
25
26#include "kincidencechooser.h"
27using namespace KPIM;
28
29
30#include <kcalutils/incidenceformatter.h>
31
32#include <KHBox>
33#include <KLocale>
34
35#include <QButtonGroup>
36#include <QGridLayout>
37#include <QGroupBox>
38#include <QLabel>
39#include <QPushButton>
40#include <QRadioButton>
41
42using namespace KCalCore;
43using namespace KCalUtils;
44
45int KIncidenceChooser::chooseMode = KIncidenceChooser::ask;
46
47KIncidenceChooser::KIncidenceChooser( QWidget *parent )
48 : KDialog( parent )
49{
50 setModal( true );
51 QWidget *topFrame = mainWidget();
52 QGridLayout *topLayout = new QGridLayout( topFrame );
53 topLayout->setMargin( 5 );
54 topLayout->setSpacing( 3 );
55
56 int iii = 0;
57 setWindowTitle( i18nc( "@title:window", "Conflict Detected" ) );
58 QLabel *lab;
59 lab = new QLabel(
60 i18nc( "@info",
61 "A conflict was detected. This probably means someone edited "
62 "the same incidence on the server while you changed it locally."
63 "<nl/><note>You have to check mail again to apply your changes "
64 "to the server.</note>" ), topFrame );
65 lab->setWordWrap( true );
66 topLayout->addWidget( lab, iii, 0, 1, 3 );
67 ++iii;
68 KHBox *b_box = new KHBox( topFrame );
69 topLayout->addWidget( b_box, iii, 0, 1, 3 );
70 ++iii;
71 QPushButton *locBut = new QPushButton( i18nc( "@action:button", "Take Local" ), b_box );
72 connect( locBut, SIGNAL(clicked()), this, SLOT(takeIncidence1()) );
73 locBut->setToolTip(
74 i18nc( "@info:tooltip", "Take your local copy of the incidence" ) );
75 locBut->setWhatsThis(
76 i18nc( "@info:whatsthis",
77 "A conflict was detected between your local copy of the incidence "
78 "and the remote incidence on the server. Press the \"Take Local\" "
79 "button to make sure your local copy is used." ) );
80
81 QPushButton *remBut = new QPushButton( i18nc( "@action:button", "Take New" ), b_box );
82 connect( remBut, SIGNAL(clicked()), this, SLOT(takeIncidence2()) );
83 remBut->setToolTip(
84 i18nc( "@info:tooltip", "Take the server copy of the incidence" ) );
85 remBut->setWhatsThis(
86 i18nc( "@info:whatsthis",
87 "A conflict was detected between your local copy of the incidence "
88 "and the remote incidence on the server. Press the \"Take New\" "
89 "button to use the server copy, thereby overwriting your local copy" ) );
90
91 QPushButton *bothBut = new QPushButton( i18nc( "@action:button", "Take Both" ), b_box );
92 bothBut->setFocus(); //kolab/issue4147: "Take Both" should be default
93 connect( bothBut, SIGNAL(clicked()), this, SLOT(takeBoth()) );
94 bothBut->setToolTip(
95 i18nc( "@info:tooltip", "Take both copies of the incidence" ) );
96 bothBut->setWhatsThis(
97 i18nc( "@info:whatsthis",
98 "A conflict was detected between your local copy of the incidence "
99 "and the remote incidence on the server. Press the \"Take Both\" "
100 "button to keep both the local and the server copies." ) );
101
102 topLayout->setSpacing( spacingHint() );
103 topLayout->setMargin( marginHint() );
104
105 mInc1lab = new QLabel( i18nc( "@label", "Local incidence" ), topFrame );
106 topLayout->addWidget( mInc1lab, iii, 0 );
107
108 mInc1Sumlab = new QLabel( i18nc( "@label", "Local incidence summary" ), topFrame );
109 topLayout->addWidget( mInc1Sumlab, iii, 1, 1, 2 );
110 ++iii;
111
112 topLayout->addWidget( new QLabel( i18nc( "@label", "Last modified:" ), topFrame ), iii, 0 );
113
114 mMod1lab = new QLabel( i18nc( "@label", "Set Last modified" ), topFrame );
115 topLayout->addWidget( mMod1lab, iii, 1 );
116
117 mShowDetails1 = new QPushButton( i18nc( "@action:button", "Show Details" ), topFrame );
118 mShowDetails1->setToolTip(
119 i18nc( "@info:tooltip", "Hide/Show incidence details" ) );
120 mShowDetails1->setWhatsThis(
121 i18nc( "@info:whatsthis",
122 "Press this button to toggle the incidence details display." ) );
123 connect( mShowDetails1, SIGNAL(clicked()), this, SLOT(showIncidence1()) );
124 topLayout->addWidget( mShowDetails1, iii, 2 );
125 ++iii;
126
127 mInc2lab = new QLabel( i18nc( "@label", "Local incidence" ), topFrame );
128 topLayout->addWidget( mInc2lab, iii, 0 );
129
130 mInc2Sumlab = new QLabel( i18nc( "@label", "Local incidence summary" ), topFrame );
131 topLayout->addWidget( mInc2Sumlab, iii, 1, 1, 2 );
132 ++iii;
133
134 topLayout->addWidget( new QLabel( i18nc( "@label", "Last modified:" ), topFrame ), iii, 0 );
135
136 mMod2lab = new QLabel( i18nc( "@label", "Set Last modified" ), topFrame );
137 topLayout->addWidget( mMod2lab, iii, 1 );
138
139 mShowDetails2 = new QPushButton( i18nc( "@action:button", "Show Details" ), topFrame );
140 mShowDetails2->setToolTip(
141 i18nc( "@info:tooltip", "Hide/Show incidence details" ) );
142 mShowDetails2->setWhatsThis(
143 i18nc( "@info:whatsthis",
144 "Press this button to toggle the incidence details display." ) );
145 connect( mShowDetails2, SIGNAL(clicked()), this, SLOT(showIncidence2()) );
146 topLayout->addWidget( mShowDetails2, iii, 2 );
147 ++iii;
148 //
149#if 0
150 // commented out for now, because the diff code has too many bugs
151 mDiffBut = new QPushButton( i18nc( "@action:button", "Show Differences" ), topFrame );
152 mDiffBut->setToolTip(
153 i18nc( "@info:tooltip", "Show the differences between the two incidences" ) );
154 mDiffBut->setWhatsThis(
155 i18nc( "@info:whatsthis",
156 "Press the \"Show Differences\" button to see the specific "
157 "differences between the incidences which are in conflict." ) );
158 connect( mDiffBut, SIGNAL(clicked()), this, SLOT(showDiff()) );
159 topLayout->addWidget( mDiffBut, iii, 0, 1, 3 );
160 ++iii;
161#else
162 mDiffBut = 0;
163#endif
164 QGroupBox *groupBox = new QGroupBox( i18nc( "@title:group", "Sync Preferences" ), topFrame );
165 QVBoxLayout *groupBoxLayout = new QVBoxLayout;
166 mBg = new QButtonGroup( topFrame );
167 groupBox->setToolTip( i18nc( "@info:tooltip", "Sync Preferences" ) );
168 groupBox->setWhatsThis( i18nc( "@info:whatsthis", "Sync Preferences" ) );
169 topLayout->addWidget( groupBox, iii, 0, 1, 3 );
170 ++iii;
171
172 QRadioButton *locRad = new QRadioButton(
173 i18nc( "@option:radio", "Take local copy on conflict" ) );
174 mBg->addButton( locRad, KIncidenceChooser::local );
175 locRad->setToolTip(
176 i18nc( "@info:tooltip", "Take local copy of the incidence on conflicts" ) );
177 locRad->setWhatsThis(
178 i18nc( "@info:whatsthis",
179 "When a conflict is detected between a local copy of an incidence "
180 "and a remote incidence on the server, this option enforces using "
181 "the local copy." ) );
182 groupBoxLayout->addWidget( locRad );
183
184 QRadioButton *remRad = new QRadioButton(
185 i18nc( "@option:radio", "Take remote copy on conflict" ) );
186 mBg->addButton( remRad, KIncidenceChooser::remote );
187 remRad->setToolTip(
188 i18nc( "@info:tooltip", "Take remote copy of the incidence on conflicts" ) );
189 remRad->setWhatsThis(
190 i18nc( "@info:whatsthis",
191 "When a conflict is detected between a local copy of an incidence "
192 "and a remote incidence on the server, this option enforces using "
193 "the remote copy." ) );
194 groupBoxLayout->addWidget( remRad );
195
196 QRadioButton *newRad = new QRadioButton(
197 i18nc( "@option:radio", "Take newest incidence on conflict" ) );
198 mBg->addButton( newRad, KIncidenceChooser::newest );
199 newRad->setToolTip(
200 i18nc( "@info:tooltip", "Take newest version of the incidence on conflicts" ) );
201 newRad->setWhatsThis(
202 i18nc( "@info:whatsthis",
203 "When a conflict is detected between a local copy of an incidence "
204 "and a remote incidence on the server, this option enforces using "
205 "the newest version available." ) );
206 groupBoxLayout->addWidget( newRad );
207
208 QRadioButton *askRad = new QRadioButton(
209 i18nc( "@option:radio", "Ask for every conflict" ) );
210 mBg->addButton( askRad, KIncidenceChooser::ask );
211 askRad->setToolTip(
212 i18nc( "@info:tooltip", "Ask for every incidence conflict" ) );
213 askRad->setWhatsThis(
214 i18nc( "@info:whatsthis",
215 "When a conflict is detected between a local copy of an incidence "
216 "and a remote incidence on the server, this option says to ask "
217 "the user which version they want to keep." ) );
218 groupBoxLayout->addWidget( askRad );
219
220 QRadioButton *bothRad = new QRadioButton(
221 i18nc( "@option:radio", "Take both on conflict" ) );
222 mBg->addButton( bothRad, KIncidenceChooser::both );
223 bothRad->setToolTip(
224 i18nc( "@info:tooltip", "Take both incidences on conflict" ) );
225 bothRad->setWhatsThis(
226 i18nc( "@info:whatsthis",
227 "When a conflict is detected between a local copy of an incidence "
228 "and a remote incidence on the server, this option says to keep "
229 "both versions of the incidence." ) );
230 groupBoxLayout->addWidget( bothRad );
231
232 mBg->button( chooseMode )->setChecked( true );
233 groupBox->setLayout( groupBoxLayout );
234
235 QPushButton *applyBut = new QPushButton(
236 i18nc( "@action:button", "Apply preference to all conflicts of this sync" ), topFrame );
237 connect( applyBut, SIGNAL(clicked()), this, SLOT(setSyncMode()) );
238 applyBut->setToolTip(
239 i18nc( "@info:tooltip",
240 "Apply the preference to all conflicts that may occur during the sync" ) );
241 applyBut->setWhatsThis(
242 i18nc( "@info:whatsthis",
243 "Press this button to apply the selected preference to all "
244 "future conflicts that might occur during this sync." ) );
245 topLayout->addWidget( applyBut, iii, 0, 1, 3 );
246
247 mTbL = 0;
248 mTbN = 0;
249 mDisplayDiff = 0;
250 mSelIncidence = Incidence::Ptr();
251 diff = 0;
252}
253
254KIncidenceChooser::~KIncidenceChooser()
255{
256 delete mTbL;
257 delete mTbN;
258 if ( mDisplayDiff ) {
259 delete mDisplayDiff;
260 delete diff;
261 }
262}
263
264void KIncidenceChooser::setIncidence( const Incidence::Ptr &local,
265 const Incidence::Ptr &remote )
266{
267
268 mInc1 = local;
269 mInc2 = remote;
270 setLabels();
271
272}
273Incidence::Ptr KIncidenceChooser::getIncidence( )
274{
275 Incidence::Ptr retval = mSelIncidence;
276 if ( chooseMode == KIncidenceChooser::local ) {
277 retval = mInc1;
278 } else if ( chooseMode == KIncidenceChooser::remote ) {
279 retval = mInc2;
280 } else if ( chooseMode == KIncidenceChooser::both ) {
281 retval = Incidence::Ptr();
282 } else if ( chooseMode == KIncidenceChooser::newest ) {
283 if ( mInc1->lastModified() == mInc2->lastModified() ) {
284 retval = Incidence::Ptr();
285 }
286 if ( mInc1->lastModified() > mInc2->lastModified() ) {
287 retval = mInc1;
288 } else {
289 retval = mInc2;
290 }
291 }
292 return retval;
293}
294
295void KIncidenceChooser::setSyncMode()
296{
297 chooseMode = mBg->checkedId();
298 if ( chooseMode != KIncidenceChooser::ask ) {
299 KDialog::accept();
300 }
301}
302
303void KIncidenceChooser::useGlobalMode()
304{
305 if ( chooseMode != KIncidenceChooser::ask ) {
306 KDialog::reject();
307 }
308}
309
310void KIncidenceChooser::setLabels()
311{
312 Incidence::Ptr inc = mInc1;
313 QLabel *des = mInc1lab;
314 QLabel *sum = mInc1Sumlab;
315
316 if ( inc->type() == Incidence::TypeEvent ) {
317 des->setText( i18nc( "@label", "Local Event" ) );
318 sum->setText( inc->summary().left( 30 ) );
319 if ( mDiffBut ) {
320 mDiffBut->setEnabled( true );
321 }
322 } else if ( inc->type() == Incidence::TypeTodo ) {
323 des->setText( i18nc( "@label", "Local Todo" ) );
324 sum->setText( inc->summary().left( 30 ) );
325 if ( mDiffBut ) {
326 mDiffBut->setEnabled( true );
327 }
328 } else if ( inc->type() == Incidence::TypeJournal ) {
329 des->setText( i18nc( "@label", "Local Journal" ) );
330 sum->setText( inc->description().left( 30 ) );
331 if ( mDiffBut ) {
332 mDiffBut->setEnabled( false );
333 }
334 }
335 mMod1lab->setText( KGlobal::locale()->formatDateTime( inc->lastModified().dateTime() ) );
336 inc = mInc2;
337 des = mInc2lab;
338 sum = mInc2Sumlab;
339 if ( inc->type() == Incidence::TypeEvent ) {
340 des->setText( i18nc( "@label", "New Event" ) );
341 sum->setText( inc->summary().left( 30 ) );
342 } else if ( inc->type() == Incidence::TypeJournal ) {
343 des->setText( i18nc( "@label", "New Todo" ) );
344 sum->setText( inc->summary().left( 30 ) );
345 } else if ( inc->type() == Incidence::TypeJournal ) {
346 des->setText( i18nc( "@label", "New Journal" ) );
347 sum->setText( inc->description().left( 30 ) );
348
349 }
350 mMod2lab->setText( KGlobal::locale()->formatDateTime( inc->lastModified().dateTime() ) );
351}
352
353void KIncidenceChooser::showIncidence1()
354{
355 if ( mTbL ) {
356 if ( mTbL->isVisible() ) {
357 mShowDetails1->setText( i18nc( "@action:button", "Show Details" ) );
358 mTbL->hide();
359 } else {
360 mShowDetails1->setText( i18nc( "@action:button", "Hide Details" ) );
361 mTbL->show();
362 mTbL->raise();
363 }
364 return;
365 }
366 mTbL = new KDialog( this );
367 mTbL->setCaption( mInc1lab->text() );
368 mTbL->setModal( false );
369 mTbL->setButtons( Ok );
370 connect( mTbL, SIGNAL(okClicked()), this, SLOT(detailsDialogClosed()) );
371 KTextBrowser *textBrowser = new KTextBrowser( mTbL );
372 mTbL->setMainWidget( textBrowser );
373 textBrowser->setHtml( IncidenceFormatter::extensiveDisplayStr( QString(), mInc1 ) );
374 textBrowser->setToolTip( i18nc( "@info:tooltip", "Incidence details" ) );
375 textBrowser->setWhatsThis( i18nc( "@info:whatsthis",
376 "This area shows the incidence details" ) );
377 mTbL->setMinimumSize( 400, 400 );
378 mShowDetails1->setText( i18nc( "@action:button", "Hide Details" ) );
379 mTbL->show();
380 mTbL->raise();
381}
382
383void KIncidenceChooser::detailsDialogClosed()
384{
385 KDialog *dialog = static_cast<KDialog *>( const_cast<QObject *>( sender() ) );
386 if ( dialog == mTbL ) {
387 mShowDetails1->setText( i18nc( "@action:button", "Show details..." ) );
388 } else {
389 mShowDetails2->setText( i18nc( "@action:button", "Show details..." ) );
390 }
391}
392
393void KIncidenceChooser::showDiff()
394{
395 if ( mDisplayDiff ) {
396 mDisplayDiff->show();
397 mDisplayDiff->raise();
398 return;
399 }
400 mDisplayDiff = new KPIM::HTMLDiffAlgoDisplay( this );
401 if ( mInc1->summary().left( 20 ) != mInc2->summary().left( 20 ) ) {
402 mDisplayDiff->setWindowTitle(
403 i18nc( "@title:window",
404 "Differences of %1 and %2",
405 mInc1->summary().left( 20 ), mInc2->summary().left( 20 ) ) );
406 } else {
407 mDisplayDiff->setWindowTitle(
408 i18nc( "@title:window",
409 "Differences of %1", mInc1->summary().left( 20 ) ) );
410 }
411
412 diff = new KPIM::CalendarDiffAlgo( mInc1, mInc2 );
413 diff->setLeftSourceTitle( i18nc( "@title:column", "Local incidence" ) );
414 diff->setRightSourceTitle( i18nc( "@title:column", "Remote incidence" ) );
415 diff->addDisplay( mDisplayDiff );
416 diff->run();
417 mDisplayDiff->show();
418 mDisplayDiff->raise();
419}
420
421void KIncidenceChooser::showIncidence2()
422{
423 if ( mTbN ) {
424 if ( mTbN->isVisible() ) {
425 mShowDetails2->setText( i18nc( "@label", "Show Details" ) );
426 mTbN->hide();
427 } else {
428 mShowDetails2->setText( i18nc( "@label", "Hide Details" ) );
429 mTbN->show();
430 mTbN->raise();
431 }
432 return;
433 }
434 mTbN = new KDialog( this );
435 mTbN->setCaption( mInc2lab->text() );
436 mTbN->setModal( false );
437 mTbN->setButtons( Ok );
438 connect( mTbN, SIGNAL(okClicked()), this, SLOT(detailsDialogClosed()) );
439 KTextBrowser *textBrowser = new KTextBrowser( mTbN );
440 mTbN->setMainWidget( textBrowser );
441 textBrowser->setHtml( IncidenceFormatter::extensiveDisplayStr( QString(), mInc2 ) );
442 textBrowser->setToolTip( i18nc( "@info:tooltip", "Incidence details" ) );
443 textBrowser->setWhatsThis( i18nc( "@info:whatsthis",
444 "This area shows the incidence details" ) );
445 mTbN->setMinimumSize( 400, 400 );
446 mShowDetails2->setText( i18nc( "@label", "Hide Details" ) );
447 mTbN->show();
448 mTbN->raise();
449}
450
451void KIncidenceChooser::takeIncidence1()
452{
453 mSelIncidence = mInc1;
454 KDialog::accept();
455}
456
457void KIncidenceChooser::takeIncidence2()
458{
459 mSelIncidence = mInc2;
460 KDialog::accept();
461}
462
463void KIncidenceChooser::takeBoth()
464{
465 mSelIncidence = Incidence::Ptr();
466 KDialog::accept();
467}
468
469