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" |
27 | using 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 | |
42 | using namespace KCalCore; |
43 | using namespace KCalUtils; |
44 | |
45 | int KIncidenceChooser::chooseMode = KIncidenceChooser::ask; |
46 | |
47 | KIncidenceChooser::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 | |
254 | KIncidenceChooser::~KIncidenceChooser() |
255 | { |
256 | delete mTbL; |
257 | delete mTbN; |
258 | if ( mDisplayDiff ) { |
259 | delete mDisplayDiff; |
260 | delete diff; |
261 | } |
262 | } |
263 | |
264 | void KIncidenceChooser::setIncidence( const Incidence::Ptr &local, |
265 | const Incidence::Ptr &remote ) |
266 | { |
267 | |
268 | mInc1 = local; |
269 | mInc2 = remote; |
270 | setLabels(); |
271 | |
272 | } |
273 | Incidence::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 | |
295 | void KIncidenceChooser::setSyncMode() |
296 | { |
297 | chooseMode = mBg->checkedId(); |
298 | if ( chooseMode != KIncidenceChooser::ask ) { |
299 | KDialog::accept(); |
300 | } |
301 | } |
302 | |
303 | void KIncidenceChooser::useGlobalMode() |
304 | { |
305 | if ( chooseMode != KIncidenceChooser::ask ) { |
306 | KDialog::reject(); |
307 | } |
308 | } |
309 | |
310 | void 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 | |
353 | void 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 | |
383 | void 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 | |
393 | void 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 | |
421 | void 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 | |
451 | void KIncidenceChooser::takeIncidence1() |
452 | { |
453 | mSelIncidence = mInc1; |
454 | KDialog::accept(); |
455 | } |
456 | |
457 | void KIncidenceChooser::takeIncidence2() |
458 | { |
459 | mSelIncidence = mInc2; |
460 | KDialog::accept(); |
461 | } |
462 | |
463 | void KIncidenceChooser::takeBoth() |
464 | { |
465 | mSelIncidence = Incidence::Ptr(); |
466 | KDialog::accept(); |
467 | } |
468 | |
469 | |