2 * editdlg.cpp - dialog to create or modify an alarm or alarm template
4 * Copyright © 2001-2012 by David Jarvie <djarvie@kde.org>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 #include "editdlg.moc"
23 #include "editdlg_p.moc"
24 #include "editdlgtypes.h"
26 #include "alarmcalendar.h"
28 #include "collectionmodel.h"
30 #include "alarmresources.h"
32 #include "alarmtimewidget.h"
33 #include "autoqpointer.h"
34 #include "buttongroup.h"
37 #include "functions.h"
38 #include "kalarmapp.h"
39 #include "latecancel.h"
41 #include "mainwindow.h"
42 #include "messagebox.h"
43 #include "packedlayout.h"
44 #include "preferences.h"
45 #include "radiobutton.h"
46 #include "recurrenceedit.h"
48 #include "shellprocess.h"
50 #include "stackedwidgets.h"
51 #include "templatepickdlg.h"
53 #include "timespinbox.h"
55 #include <libkdepim/misc/maillistdrag.h>
60 #include <kfiledialog.h>
61 #include <kpushbutton.h>
64 #include <kwindowsystem.h>
71 #include <QPushButton>
72 #include <QGridLayout>
73 #include <QHBoxLayout>
74 #include <QVBoxLayout>
75 #include <QDragEnterEvent>
76 #include <QResizeEvent>
78 #include <QStackedWidget>
83 using namespace KAlarmCal
;
85 static const char EDIT_DIALOG_NAME
[] = "EditDialog";
86 static const char TEMPLATE_DIALOG_NAME
[] = "EditTemplateDialog";
87 static const char EDIT_MORE_GROUP
[] = "ShowOpts";
88 static const char EDIT_MORE_KEY
[] = "EditMore";
89 static const int maxDelayTime
= 99*60 + 59; // < 100 hours
91 inline QString
recurText(const KAEvent
& event
)
94 if (event
.repetition())
95 r
= QString::fromLatin1("%1 / %2").arg(event
.recurrenceText()).arg(event
.repetitionText());
97 r
= event
.recurrenceText();
98 return i18nc("@title:tab", "Recurrence - [%1]", r
);
101 // Collect these widget labels together to ensure consistent wording and
102 // translations across different modules.
103 QString
EditAlarmDlg::i18n_chk_ShowInKOrganizer() { return i18nc("@option:check", "Show in KOrganizer"); }
106 EditAlarmDlg
* EditAlarmDlg::create(bool Template
, Type type
, QWidget
* parent
, GetResourceType getResource
)
111 case DISPLAY
: return new EditDisplayAlarmDlg(Template
, parent
, getResource
);
112 case COMMAND
: return new EditCommandAlarmDlg(Template
, parent
, getResource
);
113 case EMAIL
: return new EditEmailAlarmDlg(Template
, parent
, getResource
);
114 case AUDIO
: return new EditAudioAlarmDlg(Template
, parent
, getResource
);
120 EditAlarmDlg
* EditAlarmDlg::create(bool Template
, const KAEvent
* event
, bool newAlarm
, QWidget
* parent
,
121 GetResourceType getResource
, bool readOnly
)
123 switch (event
->actionTypes())
125 case KAEvent::ACT_COMMAND
: return new EditCommandAlarmDlg(Template
, event
, newAlarm
, parent
, getResource
, readOnly
);
126 case KAEvent::ACT_DISPLAY_COMMAND
:
127 case KAEvent::ACT_DISPLAY
: return new EditDisplayAlarmDlg(Template
, event
, newAlarm
, parent
, getResource
, readOnly
);
128 case KAEvent::ACT_EMAIL
: return new EditEmailAlarmDlg(Template
, event
, newAlarm
, parent
, getResource
, readOnly
);
129 case KAEvent::ACT_AUDIO
: return new EditAudioAlarmDlg(Template
, event
, newAlarm
, parent
, getResource
, readOnly
);
137 /******************************************************************************
140 * Template = true to edit/create an alarm template
141 * = false to edit/create an alarm.
142 * event != to initialise the dialog to show the specified event's data.
144 EditAlarmDlg::EditAlarmDlg(bool Template
, KAEvent::SubAction action
, QWidget
* parent
, GetResourceType getResource
)
147 mMainPageShown(false),
148 mRecurPageShown(false),
149 mRecurSetDefaultEndDate(true),
152 mDeferChangeButton(0),
154 mShowInKorganizer(0),
158 mDeferGroupHeight(0),
161 mDesiredReadOnly(false),
166 init(0, getResource
);
169 EditAlarmDlg::EditAlarmDlg(bool Template
, const KAEvent
* event
, bool newAlarm
, QWidget
* parent
,
170 GetResourceType getResource
, bool readOnly
)
172 mAlarmType(event
->actionSubType()),
173 mMainPageShown(false),
174 mRecurPageShown(false),
175 mRecurSetDefaultEndDate(true),
178 mDeferChangeButton(0),
180 mShowInKorganizer(0),
184 mDeferGroupHeight(0),
185 mEventId(newAlarm
? QString() : event
->id()),
188 mDesiredReadOnly(readOnly
),
193 init(event
, getResource
);
196 void EditAlarmDlg::init(const KAEvent
* event
, GetResourceType getResource
)
201 case RES_USE_EVENT_ID
:
204 mCollectionItemId
= event
->itemId();
207 // fall through to RES_PROMPT
209 mCollectionItemId
= -1;
213 mCollectionItemId
= -2;
216 case RES_USE_EVENT_ID
:
219 mResourceEventId
= event
->id();
222 // fall through to RES_PROMPT
224 mResourceEventId
= QString(""); // empty but non-null
228 mResourceEventId
.clear(); // null
234 void EditAlarmDlg::init(const KAEvent
* event
)
236 setObjectName(mTemplate
? "TemplEditDlg" : "EditDlg"); // used by LikeBack
239 caption
= mTemplate
? i18nc("@title:window", "Alarm Template [read-only]")
240 : event
->expired() ? i18nc("@title:window", "Archived Alarm [read-only]")
241 : i18nc("@title:window", "Alarm [read-only]");
243 caption
= type_caption();
245 setButtons((mReadOnly
? Cancel
|Try
|Default
: mTemplate
? Ok
|Cancel
|Try
|Default
: Ok
|Cancel
|Try
|Help
|Default
));
246 setDefaultButton(mReadOnly
? Cancel
: Ok
);
247 setButtonText(Help
, i18nc("@action:button", "Load Template..."));
248 setButtonIcon(Help
, KIcon());
249 setButtonIcon(Default
, KIcon());
250 connect(this, SIGNAL(tryClicked()), SLOT(slotTry()));
251 connect(this, SIGNAL(defaultClicked()), SLOT(slotDefault())); // More/Less Options button
252 connect(this, SIGNAL(helpClicked()), SLOT(slotHelp())); // Load Template button
253 KVBox
* mainWidget
= new KVBox(this);
254 mainWidget
->setMargin(0);
255 setMainWidget(mainWidget
);
258 KHBox
* box
= new KHBox(mainWidget
);
260 box
->setSpacing(spacingHint());
261 QLabel
* label
= new QLabel(i18nc("@label:textbox", "Template name:"), box
);
262 label
->setFixedSize(label
->sizeHint());
263 mTemplateName
= new KLineEdit(box
);
264 mTemplateName
->setReadOnly(mReadOnly
);
265 connect(mTemplateName
, SIGNAL(userTextChanged(QString
)), SLOT(contentsChanged()));
266 label
->setBuddy(mTemplateName
);
267 box
->setWhatsThis(i18nc("@info:whatsthis", "Enter the name of the alarm template"));
268 box
->setFixedHeight(box
->sizeHint().height());
270 mTabs
= new KTabWidget(mainWidget
);
271 mTabScrollGroup
= new StackedScrollGroup(this, mTabs
);
273 StackedScrollWidget
* mainScroll
= new StackedScrollWidget(mTabScrollGroup
);
274 mTabs
->addTab(mainScroll
, i18nc("@title:tab", "Alarm"));
276 PageFrame
* mainPage
= new PageFrame(mainScroll
);
277 mainScroll
->setWidget(mainPage
); // mainPage becomes the child of mainScroll
278 connect(mainPage
, SIGNAL(shown()), SLOT(slotShowMainPage()));
279 QVBoxLayout
* topLayout
= new QVBoxLayout(mainPage
);
280 topLayout
->setMargin(marginHint());
281 topLayout
->setSpacing(spacingHint());
284 StackedScrollWidget
* recurScroll
= new StackedScrollWidget(mTabScrollGroup
);
285 mTabs
->addTab(recurScroll
, QString());
287 KVBox
* recurTab
= new KVBox();
288 recurTab
->setMargin(marginHint());
289 recurScroll
->setWidget(recurTab
); // recurTab becomes the child of recurScroll
290 mRecurrenceEdit
= new RecurrenceEdit(mReadOnly
, recurTab
);
291 connect(mRecurrenceEdit
, SIGNAL(shown()), SLOT(slotShowRecurrenceEdit()));
292 connect(mRecurrenceEdit
, SIGNAL(typeChanged(int)), SLOT(slotRecurTypeChange(int)));
293 connect(mRecurrenceEdit
, SIGNAL(frequencyChanged()), SLOT(slotRecurFrequencyChange()));
294 connect(mRecurrenceEdit
, SIGNAL(repeatNeedsInitialisation()), SLOT(slotSetSubRepetition()));
295 connect(mRecurrenceEdit
, SIGNAL(contentsChanged()), SLOT(contentsChanged()));
297 // Controls specific to the alarm type
298 QGroupBox
* actionBox
= new QGroupBox(i18nc("@title:group", "Action"), mainPage
);
299 topLayout
->addWidget(actionBox
, 1);
300 QVBoxLayout
* layout
= new QVBoxLayout(actionBox
);
301 layout
->setMargin(marginHint());
302 layout
->setSpacing(spacingHint());
304 type_init(actionBox
, layout
);
308 // Deferred date/time: visible only for a deferred recurring event.
309 mDeferGroup
= new QGroupBox(i18nc("@title:group", "Deferred Alarm"), mainPage
);
310 topLayout
->addWidget(mDeferGroup
);
311 QHBoxLayout
* hlayout
= new QHBoxLayout(mDeferGroup
);
312 hlayout
->setMargin(marginHint());
313 hlayout
->setSpacing(spacingHint());
314 QLabel
* label
= new QLabel(i18nc("@label", "Deferred to:"), mDeferGroup
);
315 label
->setFixedSize(label
->sizeHint());
316 hlayout
->addWidget(label
);
317 mDeferTimeLabel
= new QLabel(mDeferGroup
);
318 hlayout
->addWidget(mDeferTimeLabel
);
320 mDeferChangeButton
= new QPushButton(i18nc("@action:button", "Change..."), mDeferGroup
);
321 mDeferChangeButton
->setFixedSize(mDeferChangeButton
->sizeHint());
322 connect(mDeferChangeButton
, SIGNAL(clicked()), SLOT(slotEditDeferral()));
323 mDeferChangeButton
->setWhatsThis(i18nc("@info:whatsthis", "Change the alarm's deferred time, or cancel the deferral"));
324 hlayout
->addWidget(mDeferChangeButton
);
325 //?? mDeferGroup->addSpace(0);
328 QHBoxLayout
* hlayout
= new QHBoxLayout();
329 hlayout
->setMargin(0);
330 topLayout
->addLayout(hlayout
);
332 // Date and time entry
335 QGroupBox
* templateTimeBox
= new QGroupBox(i18nc("@title:group", "Time"), mainPage
);
336 hlayout
->addWidget(templateTimeBox
);
337 QGridLayout
* grid
= new QGridLayout(templateTimeBox
);
338 grid
->setMargin(marginHint());
339 grid
->setSpacing(spacingHint());
340 mTemplateTimeGroup
= new ButtonGroup(templateTimeBox
);
341 connect(mTemplateTimeGroup
, SIGNAL(buttonSet(QAbstractButton
*)), SLOT(slotTemplateTimeType(QAbstractButton
*)));
342 connect(mTemplateTimeGroup
, SIGNAL(buttonSet(QAbstractButton
*)), SLOT(contentsChanged()));
344 mTemplateDefaultTime
= new RadioButton(i18nc("@option:radio", "Default time"), templateTimeBox
);
345 mTemplateDefaultTime
->setFixedSize(mTemplateDefaultTime
->sizeHint());
346 mTemplateDefaultTime
->setReadOnly(mReadOnly
);
347 mTemplateDefaultTime
->setWhatsThis(i18nc("@info:whatsthis", "Do not specify a start time for alarms based on this template. "
348 "The normal default start time will be used."));
349 mTemplateTimeGroup
->addButton(mTemplateDefaultTime
);
350 grid
->addWidget(mTemplateDefaultTime
, 0, 0, Qt::AlignLeft
);
352 KHBox
* box
= new KHBox(templateTimeBox
);
354 box
->setSpacing(spacingHint());
355 mTemplateUseTime
= new RadioButton(i18nc("@option:radio", "Time:"), box
);
356 mTemplateUseTime
->setFixedSize(mTemplateUseTime
->sizeHint());
357 mTemplateUseTime
->setReadOnly(mReadOnly
);
358 mTemplateUseTime
->setWhatsThis(i18nc("@info:whatsthis", "Specify a start time for alarms based on this template."));
359 mTemplateTimeGroup
->addButton(mTemplateUseTime
);
360 mTemplateTime
= new TimeEdit(box
);
361 mTemplateTime
->setFixedSize(mTemplateTime
->sizeHint());
362 mTemplateTime
->setReadOnly(mReadOnly
);
363 mTemplateTime
->setWhatsThis(i18nc("@info:whatsthis",
364 "<para>Enter the start time for alarms based on this template.</para><para>%1</para>",
365 TimeSpinBox::shiftWhatsThis()));
366 connect(mTemplateTime
, SIGNAL(valueChanged(int)), SLOT(contentsChanged()));
367 box
->setStretchFactor(new QWidget(box
), 1); // left adjust the controls
368 box
->setFixedHeight(box
->sizeHint().height());
369 grid
->addWidget(box
, 0, 1, Qt::AlignLeft
);
371 mTemplateAnyTime
= new RadioButton(i18nc("@option:radio", "Date only"), templateTimeBox
);
372 mTemplateAnyTime
->setFixedSize(mTemplateAnyTime
->sizeHint());
373 mTemplateAnyTime
->setReadOnly(mReadOnly
);
374 mTemplateAnyTime
->setWhatsThis(i18nc("@info:whatsthis", "Set the <interface>Any time</interface> option for alarms based on this template."));
375 mTemplateTimeGroup
->addButton(mTemplateAnyTime
);
376 grid
->addWidget(mTemplateAnyTime
, 1, 0, Qt::AlignLeft
);
378 box
= new KHBox(templateTimeBox
);
380 box
->setSpacing(spacingHint());
381 mTemplateUseTimeAfter
= new RadioButton(i18nc("@option:radio", "Time from now:"), box
);
382 mTemplateUseTimeAfter
->setFixedSize(mTemplateUseTimeAfter
->sizeHint());
383 mTemplateUseTimeAfter
->setReadOnly(mReadOnly
);
384 mTemplateUseTimeAfter
->setWhatsThis(i18nc("@info:whatsthis",
385 "Set alarms based on this template to start after the specified time "
386 "interval from when the alarm is created."));
387 mTemplateTimeGroup
->addButton(mTemplateUseTimeAfter
);
388 mTemplateTimeAfter
= new TimeSpinBox(1, maxDelayTime
, box
);
389 mTemplateTimeAfter
->setValue(1439);
390 mTemplateTimeAfter
->setFixedSize(mTemplateTimeAfter
->sizeHint());
391 mTemplateTimeAfter
->setReadOnly(mReadOnly
);
392 connect(mTemplateTimeAfter
, SIGNAL(valueChanged(int)), SLOT(contentsChanged()));
393 mTemplateTimeAfter
->setWhatsThis(i18nc("@info:whatsthis", "<para>%1</para><para>%2</para>",
394 AlarmTimeWidget::i18n_TimeAfterPeriod(), TimeSpinBox::shiftWhatsThis()));
395 box
->setFixedHeight(box
->sizeHint().height());
396 grid
->addWidget(box
, 1, 1, Qt::AlignLeft
);
398 hlayout
->addStretch();
402 mTimeWidget
= new AlarmTimeWidget(i18nc("@title:group", "Time"), AlarmTimeWidget::AT_TIME
, mainPage
);
403 connect(mTimeWidget
, SIGNAL(dateOnlyToggled(bool)), SLOT(slotAnyTimeToggled(bool)));
404 connect(mTimeWidget
, SIGNAL(changed(KDateTime
)), SLOT(contentsChanged()));
405 topLayout
->addWidget(mTimeWidget
);
408 // Optional controls depending on More/Less Options button
409 mMoreOptions
= new QFrame(mainPage
);
410 mMoreOptions
->setFrameStyle(QFrame::NoFrame
);
411 topLayout
->addWidget(mMoreOptions
);
412 QVBoxLayout
* moreLayout
= new QVBoxLayout(mMoreOptions
);
413 moreLayout
->setMargin(0);
414 moreLayout
->setSpacing(spacingHint());
417 mReminder
= createReminder(mMoreOptions
);
420 mReminder
->setFixedSize(mReminder
->sizeHint());
421 connect(mReminder
, SIGNAL(changed()), SLOT(contentsChanged()));
422 moreLayout
->addWidget(mReminder
, 0, Qt::AlignLeft
);
424 connect(mTimeWidget
, SIGNAL(changed(KDateTime
)), mReminder
, SLOT(setDefaultUnits(KDateTime
)));
427 // Late cancel selector - default = allow late display
428 mLateCancel
= new LateCancelSelector(true, mMoreOptions
);
429 connect(mLateCancel
, SIGNAL(changed()), SLOT(contentsChanged()));
430 moreLayout
->addWidget(mLateCancel
, 0, Qt::AlignLeft
);
432 PackedLayout
* playout
= new PackedLayout(Qt::AlignJustify
);
433 playout
->setSpacing(2*spacingHint());
434 moreLayout
->addLayout(playout
);
436 // Acknowledgement confirmation required - default = no confirmation
437 CheckBox
* confirmAck
= type_createConfirmAckCheckbox(mMoreOptions
);
440 confirmAck
->setFixedSize(confirmAck
->sizeHint());
441 connect(confirmAck
, SIGNAL(toggled(bool)), SLOT(contentsChanged()));
442 playout
->addWidget(confirmAck
);
445 if (theApp()->korganizerEnabled())
447 // Show in KOrganizer checkbox
448 mShowInKorganizer
= new CheckBox(i18n_chk_ShowInKOrganizer(), mMoreOptions
);
449 mShowInKorganizer
->setFixedSize(mShowInKorganizer
->sizeHint());
450 connect(mShowInKorganizer
, SIGNAL(toggled(bool)), SLOT(contentsChanged()));
451 mShowInKorganizer
->setWhatsThis(i18nc("@info:whatsthis", "Check to copy the alarm into KOrganizer's calendar"));
452 playout
->addWidget(mShowInKorganizer
);
455 setButtonWhatsThis(Ok
, i18nc("@info:whatsthis", "Schedule the alarm at the specified time."));
457 // Hide optional controls
458 KConfigGroup
config(KGlobal::config(), EDIT_MORE_GROUP
);
459 showOptions(config
.readEntry(EDIT_MORE_KEY
, false));
461 // Initialise the state of all controls according to the specified event, if any
464 mTemplateName
->setFocus();
468 // Save the initial state of all controls so that we can later tell if they have changed
469 saveState((event
&& (mTemplate
|| !event
->isTemplate())) ? event
: 0);
470 contentsChanged(); // enable/disable OK button
473 // Note the current desktop so that the dialog can be shown on it.
474 // If a main window is visible, the dialog will by KDE default always appear on its
475 // desktop. If the user invokes the dialog via the system tray on a different desktop,
476 // that can cause confusion.
477 mDesktop
= KWindowSystem::currentDesktop();
480 EditAlarmDlg::~EditAlarmDlg()
485 /******************************************************************************
486 * Initialise the dialog controls from the specified event.
488 void EditAlarmDlg::initValues(const KAEvent
* event
)
490 setReadOnly(mDesiredReadOnly
);
493 mOnlyDeferred
= false;
494 mExpiredRecurrence
= false;
495 mLateCancel
->showAutoClose(false);
496 bool deferGroupVisible
= false;
499 // Set the values to those for the specified event
501 mTemplateName
->setText(event
->templateName());
502 bool recurs
= event
->recurs();
503 if ((recurs
|| event
->repetition()) && !mTemplate
&& event
->deferred())
505 deferGroupVisible
= true;
506 mDeferDateTime
= event
->deferDateTime();
507 mDeferTimeLabel
->setText(mDeferDateTime
.formatLocale());
512 // Editing a template
513 int afterTime
= event
->isTemplate() ? event
->templateAfterTime() : -1;
514 bool noTime
= !afterTime
;
515 bool useTime
= !event
->mainDateTime().isDateOnly();
516 RadioButton
* button
= noTime
? mTemplateDefaultTime
:
517 (afterTime
> 0) ? mTemplateUseTimeAfter
:
518 useTime
? mTemplateUseTime
: mTemplateAnyTime
;
519 button
->setChecked(true);
520 mTemplateTimeAfter
->setValue(afterTime
> 0 ? afterTime
: 1);
521 if (!noTime
&& useTime
)
522 mTemplateTime
->setValue(event
->mainDateTime().kDateTime().time());
524 mTemplateTime
->setValue(0);
528 if (event
->isTemplate())
530 // Initialising from an alarm template: use current date
531 KDateTime now
= KDateTime::currentDateTime(Preferences::timeZone());
532 int afterTime
= event
->templateAfterTime();
535 mTimeWidget
->setDateTime(now
.addSecs(afterTime
* 60));
536 mTimeWidget
->selectTimeFromNow();
540 KDateTime dt
= event
->startDateTime().kDateTime();
541 dt
.setTimeSpec(Preferences::timeZone());
542 QDate d
= now
.date();
543 if (!dt
.isDateOnly() && now
.time() >= dt
.time())
544 d
= d
.addDays(1); // alarm time has already passed, so use tomorrow
546 mTimeWidget
->setDateTime(dt
);
551 mExpiredRecurrence
= recurs
&& event
->mainExpired();
552 mTimeWidget
->setDateTime(recurs
|| event
->category() == CalEvent::ARCHIVED
? event
->startDateTime()
553 : event
->mainExpired() ? event
->deferDateTime() : event
->mainDateTime());
557 KAEvent::SubAction action
= event
->actionSubType();
559 if (event
->commandScript())
560 altext
.setScript(event
->cleanText());
562 altext
.setText(event
->cleanText());
563 setAction(action
, altext
);
565 mLateCancel
->setMinutes(event
->lateCancel(), event
->startDateTime().isDateOnly(),
566 TimePeriod::HoursMinutes
);
567 if (mShowInKorganizer
)
568 mShowInKorganizer
->setChecked(event
->copyToKOrganizer());
569 type_initValues(event
);
570 mRecurrenceEdit
->set(*event
); // must be called after mTimeWidget is set up, to ensure correct date-only enabling
571 mTabs
->setTabText(mRecurPageIndex
, recurText(*event
));
575 // Set the values to their defaults
576 KDateTime defaultTime
= KDateTime::currentUtcDateTime().addSecs(60).toTimeSpec(Preferences::timeZone());
579 mTemplateDefaultTime
->setChecked(true);
580 mTemplateTime
->setValue(0);
581 mTemplateTimeAfter
->setValue(1);
584 mTimeWidget
->setDateTime(defaultTime
);
585 mLateCancel
->setMinutes((Preferences::defaultLateCancel() ? 1 : 0), false, TimePeriod::HoursMinutes
);
586 if (mShowInKorganizer
)
587 mShowInKorganizer
->setChecked(Preferences::defaultCopyToKOrganizer());
589 mRecurrenceEdit
->setDefaults(defaultTime
); // must be called after mTimeWidget is set up, to ensure correct date-only enabling
590 slotRecurFrequencyChange(); // update the Recurrence text
592 if (mReminder
&& mTimeWidget
)
593 mReminder
->setDefaultUnits(mTimeWidget
->getDateTime(0, false, false));
595 if (!deferGroupVisible
&& mDeferGroup
)
598 bool empty
= AlarmCalendar::resources()->events(CalEvent::TEMPLATE
).isEmpty();
599 enableButton(Help
, !empty
); // Load Templates button
602 /******************************************************************************
603 * Initialise various values in the New Alarm dialogue.
605 void EditAlarmDlg::setTime(const DateTime
& start
)
607 mTimeWidget
->setDateTime(start
);
609 void EditAlarmDlg::setRecurrence(const KARecurrence
& recur
, int subRepeatInterval
, int subRepeatCount
)
612 event
.setTime(mTimeWidget
->getDateTime(0, false, false));
613 event
.setRecurrence(recur
);
614 event
.setRepetition(Repetition(subRepeatInterval
, subRepeatCount
- 1));
615 mRecurrenceEdit
->set(event
);
617 void EditAlarmDlg::setRepeatAtLogin()
619 mRecurrenceEdit
->setRepeatAtLogin();
621 void EditAlarmDlg::setLateCancel(int minutes
)
623 mLateCancel
->setMinutes(minutes
, mTimeWidget
->getDateTime(0, false, false).isDateOnly(),
624 TimePeriod::HoursMinutes
);
626 void EditAlarmDlg::setShowInKOrganizer(bool show
)
628 mShowInKorganizer
->setChecked(show
);
631 /******************************************************************************
632 * Set the read-only status of all non-template controls.
634 void EditAlarmDlg::setReadOnly(bool readOnly
)
636 mReadOnly
= readOnly
;
639 mTimeWidget
->setReadOnly(readOnly
);
640 mLateCancel
->setReadOnly(readOnly
);
641 if (mDeferChangeButton
)
644 mDeferChangeButton
->hide();
646 mDeferChangeButton
->show();
648 if (mShowInKorganizer
)
649 mShowInKorganizer
->setReadOnly(readOnly
);
652 /******************************************************************************
653 * Save the state of all controls.
655 void EditAlarmDlg::saveState(const KAEvent
* event
)
660 mSavedEvent
= new KAEvent(*event
);
663 mSavedTemplateName
= mTemplateName
->text();
664 mSavedTemplateTimeType
= mTemplateTimeGroup
->checkedButton();
665 mSavedTemplateTime
= mTemplateTime
->time();
666 mSavedTemplateAfterTime
= mTemplateTimeAfter
->value();
668 checkText(mSavedTextFileCommandMessage
, false);
670 mSavedDateTime
= mTimeWidget
->getDateTime(0, false, false);
671 mSavedLateCancel
= mLateCancel
->minutes();
672 if (mShowInKorganizer
)
673 mSavedShowInKorganizer
= mShowInKorganizer
->isChecked();
674 mSavedRecurrenceType
= mRecurrenceEdit
->repeatType();
675 mSavedDeferTime
= mDeferDateTime
.kDateTime();
678 /******************************************************************************
679 * Check whether any of the controls has changed state since the dialog was
681 * Reply = true if any non-deferral controls have changed, or if it's a new event.
682 * = false if no non-deferral controls have changed. In this case,
683 * mOnlyDeferred indicates whether deferral controls may have changed.
685 bool EditAlarmDlg::stateChanged() const
688 mOnlyDeferred
= false;
691 QString textFileCommandMessage
;
692 checkText(textFileCommandMessage
, false);
695 if (mSavedTemplateName
!= mTemplateName
->text()
696 || mSavedTemplateTimeType
!= mTemplateTimeGroup
->checkedButton()
697 || (mTemplateUseTime
->isChecked() && mSavedTemplateTime
!= mTemplateTime
->time())
698 || (mTemplateUseTimeAfter
->isChecked() && mSavedTemplateAfterTime
!= mTemplateTimeAfter
->value()))
703 KDateTime dt
= mTimeWidget
->getDateTime(0, false, false);
704 if (mSavedDateTime
.timeSpec() != dt
.timeSpec() || mSavedDateTime
!= dt
)
707 if (mSavedLateCancel
!= mLateCancel
->minutes()
708 || (mShowInKorganizer
&& mSavedShowInKorganizer
!= mShowInKorganizer
->isChecked())
709 || textFileCommandMessage
!= mSavedTextFileCommandMessage
710 || mSavedRecurrenceType
!= mRecurrenceEdit
->repeatType())
712 if (type_stateChanged())
714 if (mRecurrenceEdit
->stateChanged())
716 if (mSavedEvent
&& mSavedEvent
->deferred())
717 mOnlyDeferred
= true;
722 /******************************************************************************
723 * Called whenever any of the controls changes state.
724 * Enable or disable the OK button depending on whether any controls have a
725 * different state from their initial state.
727 void EditAlarmDlg::contentsChanged()
729 // Don't do anything if it's a new alarm or we're still initialising
730 // (i.e. mSavedEvent null).
731 if (mSavedEvent
&& button(Ok
))
732 button(Ok
)->setEnabled(stateChanged() || mDeferDateTime
.kDateTime() != mSavedDeferTime
);
735 /******************************************************************************
736 * Get the currently entered dialog data.
737 * The data is returned in the supplied KAEvent instance.
738 * Reply = false if the only change has been to an existing deferral.
741 bool EditAlarmDlg::getEvent(KAEvent
& event
, Akonadi::Collection
& collection
)
743 bool EditAlarmDlg::getEvent(KAEvent
& event
, AlarmResource
*& resource
)
747 collection
= mCollection
;
749 resource
= mResource
;
753 // It's a new event, or the edit controls have changed
754 setEvent(event
, mAlarmMessage
, false);
758 // Only the deferral time may have changed
759 event
= *mSavedEvent
;
762 // Just modify the original event, to avoid expired recurring events
763 // being returned as rubbish.
764 if (mDeferDateTime
.isValid())
765 event
.defer(mDeferDateTime
, event
.reminderDeferral(), false);
772 /******************************************************************************
773 * Extract the data in the dialog and set up a KAEvent from it.
774 * If 'trial' is true, the event is set up for a simple one-off test, ignoring
775 * recurrence, reminder, template etc. data.
777 void EditAlarmDlg::setEvent(KAEvent
& event
, const QString
& text
, bool trial
)
783 dt
= mAlarmDateTime
.effectiveKDateTime();
784 else if (mTemplateUseTime
->isChecked())
785 dt
= KDateTime(QDate(2000,1,1), mTemplateTime
->time());
788 int lateCancel
= (trial
|| !mLateCancel
->isEnabled()) ? 0 : mLateCancel
->minutes();
789 type_setEvent(event
, dt
, text
, lateCancel
, trial
);
793 if (mRecurrenceEdit
->repeatType() != RecurrenceEdit::NO_RECUR
)
795 mRecurrenceEdit
->updateEvent(event
, !mTemplate
);
796 KDateTime now
= KDateTime::currentDateTime(mAlarmDateTime
.timeSpec());
797 bool dateOnly
= mAlarmDateTime
.isDateOnly();
798 if ((dateOnly
&& mAlarmDateTime
.date() < now
.date())
799 || (!dateOnly
&& mAlarmDateTime
.kDateTime() < now
))
801 // A timed recurrence has an entered start date which has
802 // already expired, so we must adjust the next repetition.
803 event
.setNextOccurrence(now
);
805 mAlarmDateTime
= event
.startDateTime();
806 if (mDeferDateTime
.isValid() && mDeferDateTime
< mAlarmDateTime
)
808 bool deferral
= true;
809 bool deferReminder
= false;
810 int reminder
= mReminder
? mReminder
->minutes() : 0;
813 DateTime remindTime
= mAlarmDateTime
.addMins(-reminder
);
814 if (mDeferDateTime
>= remindTime
)
816 if (remindTime
> KDateTime::currentUtcDateTime())
817 deferral
= false; // ignore deferral if it's after next reminder
818 else if (mDeferDateTime
> remindTime
)
819 deferReminder
= true; // it's the reminder which is being deferred
823 event
.defer(mDeferDateTime
, deferReminder
, false);
828 int afterTime
= mTemplateDefaultTime
->isChecked() ? 0
829 : mTemplateUseTimeAfter
->isChecked() ? mTemplateTimeAfter
->value() : -1;
830 event
.setTemplate(mTemplateName
->text(), afterTime
);
835 /******************************************************************************
836 * Get the currently specified alarm flag bits.
838 KAEvent::Flags
EditAlarmDlg::getAlarmFlags() const
840 KAEvent::Flags
flags(0);
841 if (mShowInKorganizer
&& mShowInKorganizer
->isEnabled() && mShowInKorganizer
->isChecked())
842 flags
|= KAEvent::COPY_KORGANIZER
;
843 if (mRecurrenceEdit
->repeatType() == RecurrenceEdit::AT_LOGIN
)
844 flags
|= KAEvent::REPEAT_AT_LOGIN
;
845 if (mTemplate
? mTemplateAnyTime
->isChecked() : mAlarmDateTime
.isDateOnly())
846 flags
|= KAEvent::ANY_TIME
;
850 /******************************************************************************
851 * Called when the dialog is displayed.
852 * The first time through, sets the size to the same as the last time it was
855 void EditAlarmDlg::showEvent(QShowEvent
* se
)
857 KDialog::showEvent(se
);
858 if (!mDeferGroupHeight
)
861 mDeferGroupHeight
= mDeferGroup
->height() + spacingHint();
863 if (KAlarm::readConfigWindowSize(mTemplate
? TEMPLATE_DIALOG_NAME
: EDIT_DIALOG_NAME
, s
))
865 bool defer
= mDeferGroup
&& !mDeferGroup
->isHidden();
866 s
.setHeight(s
.height() + (defer
? mDeferGroupHeight
: 0));
868 mTabScrollGroup
->setSized();
873 KWindowSystem::setOnDesktop(winId(), mDesktop
); // ensure it displays on the desktop expected by the user
876 /******************************************************************************
877 * Called when the dialog is closed.
879 void EditAlarmDlg::closeEvent(QCloseEvent
* ce
)
882 KDialog::closeEvent(ce
);
885 /******************************************************************************
886 * Update the tab sizes (again) and if the resized dialog height is greater
887 * than the minimum, resize it again. This is necessary because (a) resizing
888 * tabs doesn't always work properly the first time, and (b) resizing to the
889 * minimum size hint doesn't always work either.
891 void EditAlarmDlg::slotResize()
893 QSize s
= mTabScrollGroup
->adjustSize(true);
894 s
= minimumSizeHint();
895 if (height() > s
.height())
897 // Resize to slightly greater than the minimum height.
898 // This is for some unknown reason necessary, since
899 // sometimes resizing to the minimum height fails.
900 resize(s
.width(), s
.height() + 2);
904 /******************************************************************************
905 * Called when the dialog's size has changed.
906 * Records the new size (adjusted to ignore the optional height of the deferred
907 * time edit widget) in the config file.
909 void EditAlarmDlg::resizeEvent(QResizeEvent
* re
)
911 if (isVisible() && mDeferGroupHeight
)
913 QSize s
= re
->size();
914 s
.setHeight(s
.height() - (!mDeferGroup
|| mDeferGroup
->isHidden() ? 0 : mDeferGroupHeight
));
915 KAlarm::writeConfigWindowSize(mTemplate
? TEMPLATE_DIALOG_NAME
: EDIT_DIALOG_NAME
, s
);
917 KDialog::resizeEvent(re
);
920 /******************************************************************************
921 * Called when any button is clicked.
923 void EditAlarmDlg::slotButtonClicked(int button
)
931 KDialog::slotButtonClicked(button
);
934 /******************************************************************************
935 * Called when the OK button is clicked.
936 * Validate the input data.
938 bool EditAlarmDlg::validate()
942 // No changes have been made except possibly to an existing deferral
945 return mOnlyDeferred
;
947 RecurrenceEdit::RepeatType recurType
= mRecurrenceEdit
->repeatType();
949 && mTabs
->currentIndex() == mRecurPageIndex
&& recurType
== RecurrenceEdit::AT_LOGIN
)
950 mTimeWidget
->setDateTime(mRecurrenceEdit
->endDateTime());
951 bool timedRecurrence
= mRecurrenceEdit
->isTimedRepeatType(); // does it recur other than at login?
954 // Check that the template name is not blank and is unique
956 QString name
= mTemplateName
->text();
958 errmsg
= i18nc("@info", "You must enter a name for the alarm template");
959 else if (name
!= mSavedTemplateName
)
961 if (AlarmCalendar::resources()->templateEvent(name
))
962 errmsg
= i18nc("@info", "Template name is already in use");
964 if (!errmsg
.isEmpty())
966 mTemplateName
->setFocus();
967 KAMessageBox::sorry(this, errmsg
);
971 else if (mTimeWidget
)
974 mAlarmDateTime
= mTimeWidget
->getDateTime(0, !timedRecurrence
, false, &errWidget
);
977 // It's more than just an existing deferral being changed, so the time matters
978 mTabs
->setCurrentIndex(mMainPageIndex
);
979 errWidget
->setFocus();
980 mTimeWidget
->getDateTime(); // display the error message now
984 if (!type_validate(false))
989 if (mChanged
&& mRecurrenceEdit
->repeatType() != RecurrenceEdit::NO_RECUR
)
991 // Check whether the start date/time must be adjusted
992 // to match the recurrence specification.
993 DateTime dt
= mAlarmDateTime
; // setEvent() changes mAlarmDateTime
995 setEvent(event
, mAlarmMessage
, false);
996 mAlarmDateTime
= dt
; // restore
997 KDateTime pre
= dt
.effectiveKDateTime();
998 bool dateOnly
= dt
.isDateOnly();
1000 pre
= pre
.addDays(-1);
1002 pre
= pre
.addSecs(-1);
1004 event
.nextOccurrence(pre
, next
, KAEvent::IGNORE_REPETITION
);
1007 QString prompt
= dateOnly
? i18nc("@info The parameter is a date value",
1008 "The start date does not match the alarm's recurrence pattern, "
1009 "so it will be adjusted to the date of the next recurrence (%1).",
1010 KGlobal::locale()->formatDate(next
.date(), KLocale::ShortDate
))
1011 : i18nc("@info The parameter is a date/time value",
1012 "The start date/time does not match the alarm's recurrence pattern, "
1013 "so it will be adjusted to the date/time of the next recurrence (%1).",
1014 KGlobal::locale()->formatDateTime(next
.kDateTime(), KLocale::ShortDate
));
1015 if (KAMessageBox::warningContinueCancel(this, prompt
) != KMessageBox::Continue
)
1020 if (timedRecurrence
)
1024 Akonadi::Collection c
;
1025 getEvent(event
, c
); // this may adjust mAlarmDateTime
1028 getEvent(event
, r
); // this may adjust mAlarmDateTime
1030 KDateTime now
= KDateTime::currentDateTime(mAlarmDateTime
.timeSpec());
1031 bool dateOnly
= mAlarmDateTime
.isDateOnly();
1032 if ((dateOnly
&& mAlarmDateTime
.date() < now
.date())
1033 || (!dateOnly
&& mAlarmDateTime
.kDateTime() < now
))
1035 // A timed recurrence has an entered start date which
1036 // has already expired, so we must adjust it.
1037 if (event
.nextOccurrence(now
, mAlarmDateTime
, KAEvent::ALLOW_FOR_REPETITION
) == KAEvent::NO_OCCURRENCE
)
1039 KAMessageBox::sorry(this, i18nc("@info", "Recurrence has already expired"));
1042 if (event
.workTimeOnly() && !event
.nextTrigger(KAEvent::DISPLAY_TRIGGER
).isValid())
1044 if (KAMessageBox::warningContinueCancel(this, i18nc("@info", "The alarm will never occur during working hours"))
1045 != KMessageBox::Continue
)
1051 QWidget
* errWidget
= mRecurrenceEdit
->checkData(mAlarmDateTime
.effectiveKDateTime(), errmsg
);
1054 mTabs
->setCurrentIndex(mRecurPageIndex
);
1055 errWidget
->setFocus();
1056 KAMessageBox::sorry(this, errmsg
);
1060 if (recurType
!= RecurrenceEdit::NO_RECUR
)
1063 int longestRecurMinutes
= -1;
1064 int reminder
= mReminder
? mReminder
->minutes() : 0;
1065 if (reminder
&& !mReminder
->isOnceOnly())
1067 mRecurrenceEdit
->updateEvent(recurEvent
, false);
1068 longestRecurMinutes
= recurEvent
.longestRecurrenceInterval().asSeconds() / 60;
1069 if (longestRecurMinutes
&& reminder
>= longestRecurMinutes
)
1071 mTabs
->setCurrentIndex(mMainPageIndex
);
1072 mReminder
->setFocusOnCount();
1073 KAMessageBox::sorry(this, i18nc("@info", "Reminder period must be less than the recurrence interval, unless <interface>%1</interface> is checked.",
1074 Reminder::i18n_chk_FirstRecurrenceOnly()));
1078 if (mRecurrenceEdit
->subRepetition())
1080 if (longestRecurMinutes
< 0)
1082 mRecurrenceEdit
->updateEvent(recurEvent
, false);
1083 longestRecurMinutes
= recurEvent
.longestRecurrenceInterval().asSeconds() / 60;
1085 if (longestRecurMinutes
> 0
1086 && recurEvent
.repetition().intervalMinutes() * recurEvent
.repetition().count() >= longestRecurMinutes
- reminder
)
1088 KAMessageBox::sorry(this, i18nc("@info", "The duration of a repetition within the recurrence must be less than the recurrence interval minus any reminder period"));
1089 mRecurrenceEdit
->activateSubRepetition(); // display the alarm repetition dialog again
1092 if (!recurEvent
.repetition().isDaily()
1093 && ((mTemplate
&& mTemplateAnyTime
->isChecked()) || (!mTemplate
&& mAlarmDateTime
.isDateOnly())))
1095 KAMessageBox::sorry(this, i18nc("@info", "For a repetition within the recurrence, its period must be in units of days or weeks for a date-only alarm"));
1096 mRecurrenceEdit
->activateSubRepetition(); // display the alarm repetition dialog again
1101 if (!checkText(mAlarmMessage
))
1105 mCollection
= Akonadi::Collection();
1106 // An item ID = -2 indicates that the caller already
1107 // knows which collection to use.
1108 if (mCollectionItemId
>= -1)
1110 if (mCollectionItemId
>= 0)
1112 mCollection
= AlarmCalendar::resources()->collectionForEvent(mCollectionItemId
);
1113 if (mCollection
.isValid())
1115 CalEvent::Type type
= mTemplate
? CalEvent::TEMPLATE
: CalEvent::ACTIVE
;
1116 if (!(AkonadiModel::instance()->types(mCollection
) & type
))
1117 mCollection
= Akonadi::Collection(); // event may have expired while dialog was open
1120 bool cancelled
= false;
1121 CalEvent::Type type
= mTemplate
? CalEvent::TEMPLATE
: CalEvent::ACTIVE
;
1122 if (CollectionControlModel::isWritableEnabled(mCollection
, type
) <= 0)
1123 mCollection
= CollectionControlModel::destination(type
, this, false, &cancelled
);
1124 if (!mCollection
.isValid())
1127 KAMessageBox::sorry(this, i18nc("@info", "You must select a calendar to save the alarm in"));
1133 // A null resource event ID indicates that the caller already
1134 // knows which resource to use.
1135 if (!mResourceEventId
.isNull())
1137 if (!mResourceEventId
.isEmpty())
1139 mResource
= AlarmCalendar::resources()->resourceForEvent(mResourceEventId
);
1142 CalEvent::Type type
= mTemplate
? CalEvent::TEMPLATE
: CalEvent::ACTIVE
;
1143 if (mResource
->alarmType() != type
)
1144 mResource
= 0; // event may have expired while dialog was open
1147 bool cancelled
= false;
1148 if (!mResource
|| !mResource
->writable())
1150 CalEvent::Type type
= mTemplate
? CalEvent::TEMPLATE
: CalEvent::ACTIVE
;
1151 mResource
= AlarmResources::instance()->destination(type
, this, false, &cancelled
);
1156 KAMessageBox::sorry(this, i18nc("@info", "You must select a calendar to save the alarm in"));
1164 /******************************************************************************
1165 * Called when the Try button is clicked.
1166 * Display/execute the alarm immediately for the user to check its configuration.
1168 void EditAlarmDlg::slotTry()
1171 if (checkText(text
))
1173 if (!type_validate(true))
1176 setEvent(event
, text
, true);
1177 if (!mNewAlarm
&& !stateChanged())
1179 // It's an existing alarm which hasn't been changed yet:
1180 // enable KALARM_UID environment variable to be set.
1181 event
.setEventId(mEventId
);
1184 void* result
= theApp()->execAlarm(event
, event
.firstAlarm(), false, false);
1185 type_executedTry(text
, result
);
1189 /******************************************************************************
1190 * Called when the Load Template button is clicked.
1191 * Prompt to select a template and initialise the dialog with its contents.
1193 void EditAlarmDlg::slotHelp()
1195 KAEvent::Actions type
;
1199 case KAEvent::MESSAGE
: type
= KAEvent::ACT_DISPLAY
; break;
1200 case KAEvent::COMMAND
: type
= KAEvent::ACT_COMMAND
; break;
1201 case KAEvent::EMAIL
: type
= KAEvent::ACT_EMAIL
; break;
1202 case KAEvent::AUDIO
: type
= KAEvent::ACT_AUDIO
; break;
1206 // Use AutoQPointer to guard against crash on application exit while
1207 // the dialogue is still open. It prevents double deletion (both on
1208 // deletion of EditAlarmDlg, and on return from this function).
1209 AutoQPointer
<TemplatePickDlg
> dlg
= new TemplatePickDlg(type
, this);
1210 if (dlg
->exec() == QDialog::Accepted
)
1213 KAEvent event
= dlg
->selectedTemplate();
1217 initValues(dlg
->selectedTemplate());
1221 /******************************************************************************
1222 * Called when the More Options or Less Options buttons are clicked.
1223 * Show/hide the optional options and swap the More/Less buttons, and save the
1224 * new setting as the default from now on.
1226 void EditAlarmDlg::slotDefault()
1228 showOptions(!mShowingMore
);
1229 KConfigGroup
config(KGlobal::config(), EDIT_MORE_GROUP
);
1230 config
.writeEntry(EDIT_MORE_KEY
, mShowingMore
);
1233 /******************************************************************************
1234 * Show/hide the optional options and swap the More/Less buttons.
1236 void EditAlarmDlg::showOptions(bool more
)
1238 kDebug() << (more
? "More" : "Less");
1241 mMoreOptions
->show();
1242 setButtonText(Default
, i18nc("@action:button", "Less Options <<"));
1246 mMoreOptions
->hide();
1247 setButtonText(Default
, i18nc("@action:button", "More Options >>"));
1250 mTimeWidget
->showMoreOptions(more
);
1251 type_showOptions(more
);
1252 mRecurrenceEdit
->showMoreOptions(more
);
1253 mShowingMore
= more
;
1254 QTimer::singleShot(0, this, SLOT(slotResize()));
1257 /******************************************************************************
1258 * Called when the Change deferral button is clicked.
1260 void EditAlarmDlg::slotEditDeferral()
1265 Repetition repetition
= mRecurrenceEdit
->subRepetition();
1266 DateTime start
= mSavedEvent
->recurs() ? (mExpiredRecurrence
? DateTime() : mSavedEvent
->mainDateTime())
1267 : mTimeWidget
->getDateTime(0, !repetition
, !mExpiredRecurrence
);
1268 if (!start
.isValid())
1270 if (!mExpiredRecurrence
)
1274 KDateTime now
= KDateTime::currentUtcDateTime();
1277 if (repetition
&& start
< now
)
1279 // Sub-repetition - find the time of the next one
1280 int repeatNum
= repetition
.isDaily()
1281 ? (start
.daysTo(now
) + repetition
.intervalDays() - 1) / repetition
.intervalDays()
1282 : (start
.secsTo(now
) + repetition
.intervalSeconds() - 1) / repetition
.intervalSeconds();
1283 if (repeatNum
> repetition
.count())
1285 mTimeWidget
->getDateTime(); // output the appropriate error message
1288 start
= repetition
.duration(repeatNum
).end(start
.kDateTime());
1292 bool deferred
= mDeferDateTime
.isValid();
1293 // Use AutoQPointer to guard against crash on application exit while
1294 // the dialogue is still open. It prevents double deletion (both on
1295 // deletion of EditAlarmDlg, and on return from this function).
1296 AutoQPointer
<DeferAlarmDlg
> deferDlg
= new DeferAlarmDlg((deferred
? mDeferDateTime
: DateTime(now
.addSecs(60).toTimeSpec(start
.timeSpec()))),
1297 start
.isDateOnly(), deferred
, this);
1298 deferDlg
->setObjectName("EditDeferDlg"); // used by LikeBack
1301 // Don't allow deferral past the next recurrence
1302 int reminder
= mReminder
? mReminder
->minutes() : 0;
1305 DateTime remindTime
= start
.addMins(-reminder
);
1306 if (KDateTime::currentUtcDateTime() < remindTime
)
1309 deferDlg
->setLimit(start
.addSecs(-60));
1311 if (deferDlg
->exec() == QDialog::Accepted
)
1313 mDeferDateTime
= deferDlg
->getDateTime();
1314 mDeferTimeLabel
->setText(mDeferDateTime
.isValid() ? mDeferDateTime
.formatLocale() : QString());
1319 /******************************************************************************
1320 * Called when the main page is shown.
1321 * Sets the focus widget to the first edit field.
1323 void EditAlarmDlg::slotShowMainPage()
1325 if (!mMainPageShown
)
1328 mTemplateName
->setFocus();
1329 mMainPageShown
= true;
1333 // Set scroll position to top, since it otherwise jumps randomly
1334 StackedScrollWidget
* main
= static_cast<StackedScrollWidget
*>(mTabs
->widget(0));
1335 main
->verticalScrollBar()->setValue(0);
1339 if (!mReadOnly
&& mRecurPageShown
&& mRecurrenceEdit
->repeatType() == RecurrenceEdit::AT_LOGIN
)
1340 mTimeWidget
->setDateTime(mRecurrenceEdit
->endDateTime());
1341 if (mReadOnly
|| mRecurrenceEdit
->isTimedRepeatType())
1342 mTimeWidget
->setMinDateTime(); // don't set a minimum date/time
1344 mTimeWidget
->setMinDateTimeIsCurrent(); // set the minimum date/time to track the clock
1348 /******************************************************************************
1349 * Called when the recurrence edit page is shown.
1350 * The recurrence defaults are set to correspond to the start date.
1351 * The first time, for a new alarm, the recurrence end date is set according to
1352 * the alarm start time.
1354 void EditAlarmDlg::slotShowRecurrenceEdit()
1356 mRecurPageIndex
= mTabs
->currentIndex();
1357 if (!mReadOnly
&& !mTemplate
)
1359 mAlarmDateTime
= mTimeWidget
->getDateTime(0, false, false);
1360 KDateTime now
= KDateTime::currentDateTime(mAlarmDateTime
.timeSpec());
1361 bool expired
= (mAlarmDateTime
.effectiveKDateTime() < now
);
1362 if (mRecurSetDefaultEndDate
)
1364 mRecurrenceEdit
->setDefaultEndDate(expired
? now
.date() : mAlarmDateTime
.date());
1365 mRecurSetDefaultEndDate
= false;
1367 mRecurrenceEdit
->setStartDate(mAlarmDateTime
.date(), now
.date());
1368 if (mRecurrenceEdit
->repeatType() == RecurrenceEdit::AT_LOGIN
)
1369 mRecurrenceEdit
->setEndDateTime(expired
? now
: mAlarmDateTime
.kDateTime());
1371 mRecurPageShown
= true;
1374 /******************************************************************************
1375 * Called when the recurrence type selection changes.
1376 * Enables/disables date-only alarms as appropriate.
1377 * Enables/disables controls depending on at-login setting.
1379 void EditAlarmDlg::slotRecurTypeChange(int repeatType
)
1381 bool atLogin
= (mRecurrenceEdit
->repeatType() == RecurrenceEdit::AT_LOGIN
);
1384 bool recurs
= (mRecurrenceEdit
->repeatType() != RecurrenceEdit::NO_RECUR
);
1386 mDeferGroup
->setEnabled(recurs
);
1387 mTimeWidget
->enableAnyTime(!recurs
|| repeatType
!= RecurrenceEdit::SUBDAILY
);
1390 mAlarmDateTime
= mTimeWidget
->getDateTime(0, false, false);
1391 mRecurrenceEdit
->setEndDateTime(mAlarmDateTime
.kDateTime());
1394 mReminder
->enableOnceOnly(recurs
&& !atLogin
);
1397 mReminder
->setAfterOnly(atLogin
);
1398 mLateCancel
->setEnabled(!atLogin
);
1399 if (mShowInKorganizer
)
1400 mShowInKorganizer
->setEnabled(!atLogin
);
1401 slotRecurFrequencyChange();
1404 /******************************************************************************
1405 * Called when the recurrence frequency selection changes, or the sub-
1406 * repetition interval changes.
1407 * Updates the recurrence frequency text.
1409 void EditAlarmDlg::slotRecurFrequencyChange()
1411 slotSetSubRepetition();
1413 mRecurrenceEdit
->updateEvent(event
, false);
1414 mTabs
->setTabText(mRecurPageIndex
, recurText(event
));
1417 /******************************************************************************
1418 * Called when the Repetition within Recurrence button has been pressed to
1419 * display the sub-repetition dialog.
1420 * Alarm repetition has the following restrictions:
1421 * 1) Not allowed for a repeat-at-login alarm
1422 * 2) For a date-only alarm, the repeat interval must be a whole number of days.
1423 * 3) The overall repeat duration must be less than the recurrence interval.
1425 void EditAlarmDlg::slotSetSubRepetition()
1427 bool dateOnly
= mTemplate
? mTemplateAnyTime
->isChecked() : mTimeWidget
->anyTime();
1428 mRecurrenceEdit
->setSubRepetition((mReminder
? mReminder
->minutes() : 0), dateOnly
);
1431 /******************************************************************************
1432 * Called when one of the template time radio buttons is clicked,
1433 * to enable or disable the template time entry spin boxes.
1435 void EditAlarmDlg::slotTemplateTimeType(QAbstractButton
*)
1437 mTemplateTime
->setEnabled(mTemplateUseTime
->isChecked());
1438 mTemplateTimeAfter
->setEnabled(mTemplateUseTimeAfter
->isChecked());
1441 /******************************************************************************
1442 * Called when the "Any time" checkbox is toggled in the date/time widget.
1443 * Sets the advance reminder and late cancel units to days if any time is checked.
1445 void EditAlarmDlg::slotAnyTimeToggled(bool anyTime
)
1447 if (mReminder
&& mReminder
->isReminder())
1448 mReminder
->setDateOnly(anyTime
);
1449 mLateCancel
->setDateOnly(anyTime
);
1452 bool EditAlarmDlg::dateOnly() const
1454 return mTimeWidget
? mTimeWidget
->anyTime() : mTemplateAnyTime
->isChecked();
1457 bool EditAlarmDlg::isTimedRecurrence() const
1459 return mRecurrenceEdit
->isTimedRepeatType();
1462 void EditAlarmDlg::showMainPage()
1464 mTabs
->setCurrentIndex(mMainPageIndex
);