2 * editdlg.cpp - dialog to create or modify an alarm or alarm template
4 * Copyright © 2001-2015 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.
23 #include "editdlg_p.h"
24 #include "editdlgtypes.h"
26 #include "alarmcalendar.h"
27 #include "collectionmodel.h"
28 #include "alarmtimewidget.h"
29 #include "autoqpointer.h"
30 #include "buttongroup.h"
33 #include "functions.h"
34 #include "kalarmapp.h"
35 #include "latecancel.h"
37 #include "mainwindow.h"
38 #include "messagebox.h"
39 #include "packedlayout.h"
40 #include "preferences.h"
41 #include "radiobutton.h"
42 #include "recurrenceedit.h"
44 #include "shellprocess.h"
46 #include "stackedwidgets.h"
47 #include "templatepickdlg.h"
49 #include "timespinbox.h"
51 #include <Libkdepim/MaillistDrag>
54 #include <KLocalizedString>
56 #include <KSharedConfig>
57 #include <kwindowsystem.h>
62 #include <QPushButton>
63 #include <QGridLayout>
64 #include <QHBoxLayout>
65 #include <QVBoxLayout>
66 #include <QResizeEvent>
70 #include <QDialogButtonBox>
71 #include "kalarm_debug.h"
74 using namespace KAlarmCal
;
76 static const char EDIT_DIALOG_NAME
[] = "EditDialog";
77 static const char TEMPLATE_DIALOG_NAME
[] = "EditTemplateDialog";
78 static const char EDIT_MORE_GROUP
[] = "ShowOpts";
79 static const char EDIT_MORE_KEY
[] = "EditMore";
80 static const int maxDelayTime
= 99*60 + 59; // < 100 hours
82 inline QString
recurText(const KAEvent
& event
)
85 if (event
.repetition())
86 r
= QStringLiteral("%1 / %2").arg(event
.recurrenceText()).arg(event
.repetitionText());
88 r
= event
.recurrenceText();
89 return i18nc("@title:tab", "Recurrence - [%1]", r
);
92 QList
<EditAlarmDlg
*> EditAlarmDlg::mWindowList
;
94 // Collect these widget labels together to ensure consistent wording and
95 // translations across different modules.
96 QString
EditAlarmDlg::i18n_chk_ShowInKOrganizer() { return i18nc("@option:check", "Show in KOrganizer"); }
99 EditAlarmDlg
* EditAlarmDlg::create(bool Template
, Type type
, QWidget
* parent
, GetResourceType getResource
)
104 case DISPLAY
: return new EditDisplayAlarmDlg(Template
, parent
, getResource
);
105 case COMMAND
: return new EditCommandAlarmDlg(Template
, parent
, getResource
);
106 case EMAIL
: return new EditEmailAlarmDlg(Template
, parent
, getResource
);
107 case AUDIO
: return new EditAudioAlarmDlg(Template
, parent
, getResource
);
113 EditAlarmDlg
* EditAlarmDlg::create(bool Template
, const KAEvent
* event
, bool newAlarm
, QWidget
* parent
,
114 GetResourceType getResource
, bool readOnly
)
116 switch (event
->actionTypes())
118 case KAEvent::ACT_COMMAND
: return new EditCommandAlarmDlg(Template
, event
, newAlarm
, parent
, getResource
, readOnly
);
119 case KAEvent::ACT_DISPLAY_COMMAND
:
120 case KAEvent::ACT_DISPLAY
: return new EditDisplayAlarmDlg(Template
, event
, newAlarm
, parent
, getResource
, readOnly
);
121 case KAEvent::ACT_EMAIL
: return new EditEmailAlarmDlg(Template
, event
, newAlarm
, parent
, getResource
, readOnly
);
122 case KAEvent::ACT_AUDIO
: return new EditAudioAlarmDlg(Template
, event
, newAlarm
, parent
, getResource
, readOnly
);
130 /******************************************************************************
133 * Template = true to edit/create an alarm template
134 * = false to edit/create an alarm.
135 * event != to initialise the dialog to show the specified event's data.
137 EditAlarmDlg::EditAlarmDlg(bool Template
, KAEvent::SubAction action
, QWidget
* parent
, GetResourceType getResource
)
140 mLoadTemplateButton(Q_NULLPTR
),
141 mMainPageShown(false),
142 mRecurPageShown(false),
143 mRecurSetDefaultEndDate(true),
144 mTemplateName(Q_NULLPTR
),
145 mDeferGroup(Q_NULLPTR
),
146 mDeferChangeButton(Q_NULLPTR
),
147 mTimeWidget(Q_NULLPTR
),
148 mShowInKorganizer(Q_NULLPTR
),
149 mDeferGroupHeight(0),
152 mDesiredReadOnly(false),
155 mSavedEvent(Q_NULLPTR
)
157 init(Q_NULLPTR
, getResource
);
158 mWindowList
.append(this);
161 EditAlarmDlg::EditAlarmDlg(bool Template
, const KAEvent
* event
, bool newAlarm
, QWidget
* parent
,
162 GetResourceType getResource
, bool readOnly
)
164 mAlarmType(event
->actionSubType()),
165 mLoadTemplateButton(Q_NULLPTR
),
166 mMainPageShown(false),
167 mRecurPageShown(false),
168 mRecurSetDefaultEndDate(true),
169 mTemplateName(Q_NULLPTR
),
170 mDeferGroup(Q_NULLPTR
),
171 mDeferChangeButton(Q_NULLPTR
),
172 mTimeWidget(Q_NULLPTR
),
173 mShowInKorganizer(Q_NULLPTR
),
174 mDeferGroupHeight(0),
175 mEventId(newAlarm
? QString() : event
->id()),
178 mDesiredReadOnly(readOnly
),
181 mSavedEvent(Q_NULLPTR
)
183 init(event
, getResource
);
184 mWindowList
.append(this);
187 void EditAlarmDlg::init(const KAEvent
* event
, GetResourceType getResource
)
191 case RES_USE_EVENT_ID
:
194 mCollectionItemId
= event
->itemId();
197 // fall through to RES_PROMPT
199 mCollectionItemId
= -1;
203 mCollectionItemId
= -2;
208 void EditAlarmDlg::init(const KAEvent
* event
)
210 setObjectName(mTemplate
? QStringLiteral("TemplEditDlg") : QStringLiteral("EditDlg")); // used by LikeBack
213 caption
= mTemplate
? i18nc("@title:window", "Alarm Template [read-only]")
214 : event
->expired() ? i18nc("@title:window", "Archived Alarm [read-only]")
215 : i18nc("@title:window", "Alarm [read-only]");
217 caption
= type_caption();
218 setWindowTitle(caption
);
220 // Create button box now so that types can work with it, but don't insert
221 // it into layout just yet
222 mButtonBox
= new QDialogButtonBox(this);
225 mButtonBox
->addButton(QDialogButtonBox::Cancel
);
226 mTryButton
= mButtonBox
->addButton(i18nc("@action:button", "Try"), QDialogButtonBox::ActionRole
);
227 mMoreLessButton
= mButtonBox
->addButton(QDialogButtonBox::RestoreDefaults
);
231 mButtonBox
->addButton(QDialogButtonBox::Ok
);
232 mButtonBox
->addButton(QDialogButtonBox::Cancel
);
233 mTryButton
= mButtonBox
->addButton(i18nc("@action:button", "Try"), QDialogButtonBox::ActionRole
);
234 mMoreLessButton
= mButtonBox
->addButton(QDialogButtonBox::RestoreDefaults
);
238 mButtonBox
->addButton(QDialogButtonBox::Ok
);
239 mButtonBox
->addButton(QDialogButtonBox::Cancel
);
240 mTryButton
= mButtonBox
->addButton(i18nc("@action:button", "Try"), QDialogButtonBox::ActionRole
);
241 mLoadTemplateButton
= mButtonBox
->addButton(i18nc("@action:button", "Load Template..."),
242 QDialogButtonBox::HelpRole
);
243 mMoreLessButton
= mButtonBox
->addButton(QDialogButtonBox::RestoreDefaults
);
245 connect(mButtonBox
, &QDialogButtonBox::clicked
,
246 this, &EditAlarmDlg::slotButtonClicked
);
248 if (mButtonBox
->button(QDialogButtonBox::Ok
))
249 mButtonBox
->button(QDialogButtonBox::Ok
)->setWhatsThis(i18nc("@info:whatsthis", "Schedule the alarm at the specified time."));
251 QVBoxLayout
* mainLayout
= new QVBoxLayout(this);
254 QFrame
*frame
= new QFrame
;
255 QHBoxLayout
* box
= new QHBoxLayout();
256 frame
->setLayout(box
);
258 box
->setSpacing(style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing
));
259 QLabel
* label
= new QLabel(i18nc("@label:textbox", "Template name:"));
260 label
->setFixedSize(label
->sizeHint());
261 box
->addWidget(label
);
262 mTemplateName
= new QLineEdit();
263 mTemplateName
->setReadOnly(mReadOnly
);
264 connect(mTemplateName
, &QLineEdit::textEdited
, this, &EditAlarmDlg::contentsChanged
);
265 label
->setBuddy(mTemplateName
);
266 box
->addWidget(mTemplateName
);
267 frame
->setWhatsThis(i18nc("@info:whatsthis", "Enter the name of the alarm template"));
268 frame
->setFixedHeight(box
->sizeHint().height());
269 mainLayout
->addWidget(frame
);
271 mTabs
= new QTabWidget(this);
272 mainLayout
->addWidget(mTabs
);
273 mTabScrollGroup
= new StackedScrollGroup(this, mTabs
);
275 StackedScrollWidget
* mainScroll
= new StackedScrollWidget(mTabScrollGroup
);
276 mTabs
->addTab(mainScroll
, i18nc("@title:tab", "Alarm"));
278 PageFrame
* mainPage
= new PageFrame(mainScroll
);
279 mainScroll
->setWidget(mainPage
); // mainPage becomes the child of mainScroll
280 connect(mainPage
, &PageFrame::shown
, this, &EditAlarmDlg::slotShowMainPage
);
281 QVBoxLayout
* topLayout
= new QVBoxLayout(mainPage
);
282 topLayout
->setMargin(style()->pixelMetric(QStyle::PM_DefaultChildMargin
));
283 topLayout
->setSpacing(style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing
));
286 StackedScrollWidget
* recurScroll
= new StackedScrollWidget(mTabScrollGroup
);
287 mTabs
->addTab(recurScroll
, QString());
289 QFrame
*recurTab
= new QFrame
;
290 QVBoxLayout
* recurTabLayout
= new QVBoxLayout();
291 recurTabLayout
->setMargin(style()->pixelMetric(QStyle::PM_DefaultChildMargin
));
292 recurTab
->setLayout(recurTabLayout
);
293 recurScroll
->setWidget(recurTab
); // recurTab becomes the child of recurScroll
294 mRecurrenceEdit
= new RecurrenceEdit(mReadOnly
);
295 recurTabLayout
->addWidget(mRecurrenceEdit
);
296 connect(mRecurrenceEdit
, &RecurrenceEdit::shown
, this, &EditAlarmDlg::slotShowRecurrenceEdit
);
297 connect(mRecurrenceEdit
, &RecurrenceEdit::typeChanged
, this, &EditAlarmDlg::slotRecurTypeChange
);
298 connect(mRecurrenceEdit
, &RecurrenceEdit::frequencyChanged
, this, &EditAlarmDlg::slotRecurFrequencyChange
);
299 connect(mRecurrenceEdit
, &RecurrenceEdit::repeatNeedsInitialisation
, this, &EditAlarmDlg::slotSetSubRepetition
);
300 connect(mRecurrenceEdit
, &RecurrenceEdit::contentsChanged
, this, &EditAlarmDlg::contentsChanged
);
302 // Controls specific to the alarm type
303 QGroupBox
* actionBox
= new QGroupBox(i18nc("@title:group", "Action"), mainPage
);
304 topLayout
->addWidget(actionBox
, 1);
305 QVBoxLayout
* layout
= new QVBoxLayout(actionBox
);
306 layout
->setMargin(style()->pixelMetric(QStyle::PM_DefaultChildMargin
));
307 layout
->setSpacing(style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing
));
309 type_init(actionBox
, layout
);
313 // Deferred date/time: visible only for a deferred recurring event.
314 mDeferGroup
= new QGroupBox(i18nc("@title:group", "Deferred Alarm"), mainPage
);
315 topLayout
->addWidget(mDeferGroup
);
316 QHBoxLayout
* hlayout
= new QHBoxLayout(mDeferGroup
);
317 hlayout
->setMargin(style()->pixelMetric(QStyle::PM_DefaultChildMargin
));
318 hlayout
->setSpacing(style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing
));
319 QLabel
* label
= new QLabel(i18nc("@label", "Deferred to:"), mDeferGroup
);
320 label
->setFixedSize(label
->sizeHint());
321 hlayout
->addWidget(label
);
322 mDeferTimeLabel
= new QLabel(mDeferGroup
);
323 hlayout
->addWidget(mDeferTimeLabel
);
325 mDeferChangeButton
= new QPushButton(i18nc("@action:button", "Change..."), mDeferGroup
);
326 mDeferChangeButton
->setFixedSize(mDeferChangeButton
->sizeHint());
327 connect(mDeferChangeButton
, &QPushButton::clicked
, this, &EditAlarmDlg::slotEditDeferral
);
328 mDeferChangeButton
->setWhatsThis(i18nc("@info:whatsthis", "Change the alarm's deferred time, or cancel the deferral"));
329 hlayout
->addWidget(mDeferChangeButton
);
330 //?? mDeferGroup->addSpace(0);
333 QHBoxLayout
* hlayout
= new QHBoxLayout();
334 hlayout
->setMargin(0);
335 topLayout
->addLayout(hlayout
);
337 // Date and time entry
340 QGroupBox
* templateTimeBox
= new QGroupBox(i18nc("@title:group", "Time"), mainPage
);
341 topLayout
->addWidget(templateTimeBox
);
342 QGridLayout
* grid
= new QGridLayout(templateTimeBox
);
343 grid
->setMargin(style()->pixelMetric(QStyle::PM_DefaultChildMargin
));
344 grid
->setSpacing(style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing
));
345 mTemplateTimeGroup
= new ButtonGroup(templateTimeBox
);
346 connect(mTemplateTimeGroup
, &ButtonGroup::buttonSet
, this, &EditAlarmDlg::slotTemplateTimeType
);
347 connect(mTemplateTimeGroup
, &ButtonGroup::buttonSet
, this, &EditAlarmDlg::contentsChanged
);
349 mTemplateDefaultTime
= new RadioButton(i18nc("@option:radio", "Default time"), templateTimeBox
);
350 mTemplateDefaultTime
->setFixedSize(mTemplateDefaultTime
->sizeHint());
351 mTemplateDefaultTime
->setReadOnly(mReadOnly
);
352 mTemplateDefaultTime
->setWhatsThis(i18nc("@info:whatsthis", "Do not specify a start time for alarms based on this template. "
353 "The normal default start time will be used."));
354 mTemplateTimeGroup
->addButton(mTemplateDefaultTime
);
355 grid
->addWidget(mTemplateDefaultTime
, 0, 0, Qt::AlignLeft
);
357 QWidget
*box
= new QWidget(templateTimeBox
);
358 QHBoxLayout
* layout
= new QHBoxLayout(box
);
359 layout
->setMargin(0);
360 layout
->setSpacing(style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing
));
361 mTemplateUseTime
= new RadioButton(i18nc("@option:radio", "Time:"), box
);
362 mTemplateUseTime
->setFixedSize(mTemplateUseTime
->sizeHint());
363 mTemplateUseTime
->setReadOnly(mReadOnly
);
364 mTemplateUseTime
->setWhatsThis(i18nc("@info:whatsthis", "Specify a start time for alarms based on this template."));
365 layout
->addWidget(mTemplateUseTime
);
366 mTemplateTimeGroup
->addButton(mTemplateUseTime
);
367 mTemplateTime
= new TimeEdit();
368 mTemplateTime
->setFixedSize(mTemplateTime
->sizeHint());
369 mTemplateTime
->setReadOnly(mReadOnly
);
370 mTemplateTime
->setWhatsThis(xi18nc("@info:whatsthis",
371 "<para>Enter the start time for alarms based on this template.</para><para>%1</para>",
372 TimeSpinBox::shiftWhatsThis()));
373 connect(mTemplateTime
, &TimeEdit::valueChanged
, this, &EditAlarmDlg::contentsChanged
);
374 layout
->addWidget(mTemplateTime
);
375 layout
->addStretch(1);
376 grid
->addWidget(box
, 0, 1, Qt::AlignLeft
);
378 mTemplateAnyTime
= new RadioButton(i18nc("@option:radio", "Date only"), templateTimeBox
);
379 mTemplateAnyTime
->setFixedSize(mTemplateAnyTime
->sizeHint());
380 mTemplateAnyTime
->setReadOnly(mReadOnly
);
381 mTemplateAnyTime
->setWhatsThis(xi18nc("@info:whatsthis", "Set the <interface>Any time</interface> option for alarms based on this template."));
382 mTemplateTimeGroup
->addButton(mTemplateAnyTime
);
383 grid
->addWidget(mTemplateAnyTime
, 1, 0, Qt::AlignLeft
);
385 box
= new QWidget(templateTimeBox
);
386 layout
= new QHBoxLayout(box
);
387 layout
->setMargin(0);
388 layout
->setSpacing(style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing
));
389 mTemplateUseTimeAfter
= new RadioButton(i18nc("@option:radio", "Time from now:"), box
);
390 mTemplateUseTimeAfter
->setFixedSize(mTemplateUseTimeAfter
->sizeHint());
391 mTemplateUseTimeAfter
->setReadOnly(mReadOnly
);
392 mTemplateUseTimeAfter
->setWhatsThis(i18nc("@info:whatsthis",
393 "Set alarms based on this template to start after the specified time "
394 "interval from when the alarm is created."));
395 layout
->addWidget(mTemplateUseTimeAfter
);
396 mTemplateTimeGroup
->addButton(mTemplateUseTimeAfter
);
397 mTemplateTimeAfter
= new TimeSpinBox(1, maxDelayTime
);
398 mTemplateTimeAfter
->setValue(1439);
399 mTemplateTimeAfter
->setFixedSize(mTemplateTimeAfter
->sizeHint());
400 mTemplateTimeAfter
->setReadOnly(mReadOnly
);
401 connect(mTemplateTimeAfter
, static_cast<void (TimeSpinBox::*)(int)>(&TimeSpinBox::valueChanged
), this, &EditAlarmDlg::contentsChanged
);
402 mTemplateTimeAfter
->setWhatsThis(xi18nc("@info:whatsthis", "<para>%1</para><para>%2</para>",
403 AlarmTimeWidget::i18n_TimeAfterPeriod(), TimeSpinBox::shiftWhatsThis()));
404 layout
->addWidget(mTemplateTimeAfter
);
405 box
->setFixedHeight(box
->sizeHint().height());
406 grid
->addWidget(box
, 1, 1, Qt::AlignLeft
);
408 hlayout
->addStretch();
412 mTimeWidget
= new AlarmTimeWidget(i18nc("@title:group", "Time"), AlarmTimeWidget::AT_TIME
, mainPage
);
413 connect(mTimeWidget
, &AlarmTimeWidget::dateOnlyToggled
, this, &EditAlarmDlg::slotAnyTimeToggled
);
414 connect(mTimeWidget
, &AlarmTimeWidget::changed
, this, &EditAlarmDlg::contentsChanged
);
415 topLayout
->addWidget(mTimeWidget
);
418 // Optional controls depending on More/Less Options button
419 mMoreOptions
= new QFrame(mainPage
);
420 mMoreOptions
->setFrameStyle(QFrame::NoFrame
);
421 topLayout
->addWidget(mMoreOptions
);
422 QVBoxLayout
* moreLayout
= new QVBoxLayout(mMoreOptions
);
423 moreLayout
->setMargin(0);
424 moreLayout
->setSpacing(style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing
));
427 mReminder
= createReminder(mMoreOptions
);
430 mReminder
->setFixedSize(mReminder
->sizeHint());
431 connect(mReminder
, &Reminder::changed
, this, &EditAlarmDlg::contentsChanged
);
432 moreLayout
->addWidget(mReminder
, 0, Qt::AlignLeft
);
434 connect(mTimeWidget
, &AlarmTimeWidget::changed
, mReminder
, &Reminder::setDefaultUnits
);
437 // Late cancel selector - default = allow late display
438 mLateCancel
= new LateCancelSelector(true, mMoreOptions
);
439 connect(mLateCancel
, &LateCancelSelector::changed
, this, &EditAlarmDlg::contentsChanged
);
440 moreLayout
->addWidget(mLateCancel
, 0, Qt::AlignLeft
);
442 PackedLayout
* playout
= new PackedLayout(Qt::AlignJustify
);
443 playout
->setSpacing(2 * style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing
));
444 moreLayout
->addLayout(playout
);
446 // Acknowledgement confirmation required - default = no confirmation
447 CheckBox
* confirmAck
= type_createConfirmAckCheckbox(mMoreOptions
);
450 confirmAck
->setFixedSize(confirmAck
->sizeHint());
451 connect(confirmAck
, &CheckBox::toggled
, this, &EditAlarmDlg::contentsChanged
);
452 playout
->addWidget(confirmAck
);
455 if (theApp()->korganizerEnabled())
457 // Show in KOrganizer checkbox
458 mShowInKorganizer
= new CheckBox(i18n_chk_ShowInKOrganizer(), mMoreOptions
);
459 mShowInKorganizer
->setFixedSize(mShowInKorganizer
->sizeHint());
460 connect(mShowInKorganizer
, &CheckBox::toggled
, this, &EditAlarmDlg::contentsChanged
);
461 mShowInKorganizer
->setWhatsThis(i18nc("@info:whatsthis", "Check to copy the alarm into KOrganizer's calendar"));
462 playout
->addWidget(mShowInKorganizer
);
465 mainLayout
->addWidget(mButtonBox
);
467 // Hide optional controls
468 KConfigGroup
config(KSharedConfig::openConfig(), EDIT_MORE_GROUP
);
469 showOptions(config
.readEntry(EDIT_MORE_KEY
, false));
471 // Initialise the state of all controls according to the specified event, if any
474 mTemplateName
->setFocus();
478 // Save the initial state of all controls so that we can later tell if they have changed
479 saveState((event
&& (mTemplate
|| !event
->isTemplate())) ? event
: Q_NULLPTR
);
480 contentsChanged(); // enable/disable OK button
483 // Note the current desktop so that the dialog can be shown on it.
484 // If a main window is visible, the dialog will by KDE default always appear on its
485 // desktop. If the user invokes the dialog via the system tray on a different desktop,
486 // that can cause confusion.
487 mDesktop
= KWindowSystem::currentDesktop();
489 if (theApp()->windowFocusBroken())
491 const QList
<QWidget
*> children
= findChildren
<QWidget
*>();
492 foreach (QWidget
* w
, children
)
493 w
->installEventFilter(this);
497 EditAlarmDlg::~EditAlarmDlg()
500 mWindowList
.removeAll(this);
503 /******************************************************************************
504 * Return the number of instances.
506 int EditAlarmDlg::instanceCount()
508 return mWindowList
.count();
511 /******************************************************************************
512 * Initialise the dialog controls from the specified event.
514 void EditAlarmDlg::initValues(const KAEvent
* event
)
516 setReadOnly(mDesiredReadOnly
);
519 mOnlyDeferred
= false;
520 mExpiredRecurrence
= false;
521 mLateCancel
->showAutoClose(false);
522 bool deferGroupVisible
= false;
525 // Set the values to those for the specified event
527 mTemplateName
->setText(event
->templateName());
528 bool recurs
= event
->recurs();
529 if ((recurs
|| event
->repetition()) && !mTemplate
&& event
->deferred())
531 deferGroupVisible
= true;
532 mDeferDateTime
= event
->deferDateTime();
533 mDeferTimeLabel
->setText(mDeferDateTime
.formatLocale());
538 // Editing a template
539 int afterTime
= event
->isTemplate() ? event
->templateAfterTime() : -1;
540 bool noTime
= !afterTime
;
541 bool useTime
= !event
->mainDateTime().isDateOnly();
542 RadioButton
* button
= noTime
? mTemplateDefaultTime
:
543 (afterTime
> 0) ? mTemplateUseTimeAfter
:
544 useTime
? mTemplateUseTime
: mTemplateAnyTime
;
545 button
->setChecked(true);
546 mTemplateTimeAfter
->setValue(afterTime
> 0 ? afterTime
: 1);
547 if (!noTime
&& useTime
)
548 mTemplateTime
->setValue(event
->mainDateTime().kDateTime().time());
550 mTemplateTime
->setValue(0);
554 if (event
->isTemplate())
556 // Initialising from an alarm template: use current date
557 KDateTime now
= KDateTime::currentDateTime(Preferences::timeZone());
558 int afterTime
= event
->templateAfterTime();
561 mTimeWidget
->setDateTime(now
.addSecs(afterTime
* 60));
562 mTimeWidget
->selectTimeFromNow();
566 KDateTime dt
= event
->startDateTime().kDateTime();
567 dt
.setTimeSpec(Preferences::timeZone());
568 QDate d
= now
.date();
569 if (!dt
.isDateOnly() && now
.time() >= dt
.time())
570 d
= d
.addDays(1); // alarm time has already passed, so use tomorrow
572 mTimeWidget
->setDateTime(dt
);
577 mExpiredRecurrence
= recurs
&& event
->mainExpired();
578 mTimeWidget
->setDateTime(recurs
|| event
->category() == CalEvent::ARCHIVED
? event
->startDateTime()
579 : event
->mainExpired() ? event
->deferDateTime() : event
->mainDateTime());
583 KAEvent::SubAction action
= event
->actionSubType();
585 if (event
->commandScript())
586 altext
.setScript(event
->cleanText());
588 altext
.setText(event
->cleanText());
589 setAction(action
, altext
);
591 mLateCancel
->setMinutes(event
->lateCancel(), event
->startDateTime().isDateOnly(),
592 TimePeriod::HoursMinutes
);
593 if (mShowInKorganizer
)
594 mShowInKorganizer
->setChecked(event
->copyToKOrganizer());
595 type_initValues(event
);
596 mRecurrenceEdit
->set(*event
); // must be called after mTimeWidget is set up, to ensure correct date-only enabling
597 mTabs
->setTabText(mRecurPageIndex
, recurText(*event
));
601 // Set the values to their defaults
602 KDateTime defaultTime
= KDateTime::currentUtcDateTime().addSecs(60).toTimeSpec(Preferences::timeZone());
605 mTemplateDefaultTime
->setChecked(true);
606 mTemplateTime
->setValue(0);
607 mTemplateTimeAfter
->setValue(1);
610 mTimeWidget
->setDateTime(defaultTime
);
611 mLateCancel
->setMinutes((Preferences::defaultLateCancel() ? 1 : 0), false, TimePeriod::HoursMinutes
);
612 if (mShowInKorganizer
)
613 mShowInKorganizer
->setChecked(Preferences::defaultCopyToKOrganizer());
614 type_initValues(Q_NULLPTR
);
615 mRecurrenceEdit
->setDefaults(defaultTime
); // must be called after mTimeWidget is set up, to ensure correct date-only enabling
616 slotRecurFrequencyChange(); // update the Recurrence text
618 if (mReminder
&& mTimeWidget
)
619 mReminder
->setDefaultUnits(mTimeWidget
->getDateTime(Q_NULLPTR
, false, false));
621 if (!deferGroupVisible
&& mDeferGroup
)
624 bool empty
= AlarmCalendar::resources()->events(CalEvent::TEMPLATE
).isEmpty();
625 if (mLoadTemplateButton
)
626 mLoadTemplateButton
->setEnabled(!empty
);
629 /******************************************************************************
630 * Initialise various values in the New Alarm dialogue.
632 void EditAlarmDlg::setTime(const DateTime
& start
)
634 mTimeWidget
->setDateTime(start
);
636 void EditAlarmDlg::setRecurrence(const KARecurrence
& recur
, const KCalCore::Duration
& subRepeatInterval
, int subRepeatCount
)
639 event
.setTime(mTimeWidget
->getDateTime(Q_NULLPTR
, false, false));
640 event
.setRecurrence(recur
);
641 event
.setRepetition(Repetition(subRepeatInterval
, subRepeatCount
- 1));
642 mRecurrenceEdit
->set(event
);
644 void EditAlarmDlg::setRepeatAtLogin()
646 mRecurrenceEdit
->setRepeatAtLogin();
648 void EditAlarmDlg::setLateCancel(int minutes
)
650 mLateCancel
->setMinutes(minutes
, mTimeWidget
->getDateTime(Q_NULLPTR
, false, false).isDateOnly(),
651 TimePeriod::HoursMinutes
);
653 void EditAlarmDlg::setShowInKOrganizer(bool show
)
655 mShowInKorganizer
->setChecked(show
);
658 /******************************************************************************
659 * Set the read-only status of all non-template controls.
661 void EditAlarmDlg::setReadOnly(bool readOnly
)
663 mReadOnly
= readOnly
;
666 mTimeWidget
->setReadOnly(readOnly
);
667 mLateCancel
->setReadOnly(readOnly
);
668 if (mDeferChangeButton
)
671 mDeferChangeButton
->hide();
673 mDeferChangeButton
->show();
675 if (mShowInKorganizer
)
676 mShowInKorganizer
->setReadOnly(readOnly
);
679 /******************************************************************************
680 * Save the state of all controls.
682 void EditAlarmDlg::saveState(const KAEvent
* event
)
685 mSavedEvent
= Q_NULLPTR
;
687 mSavedEvent
= new KAEvent(*event
);
690 mSavedTemplateName
= mTemplateName
->text();
691 mSavedTemplateTimeType
= mTemplateTimeGroup
->checkedButton();
692 mSavedTemplateTime
= mTemplateTime
->time();
693 mSavedTemplateAfterTime
= mTemplateTimeAfter
->value();
695 checkText(mSavedTextFileCommandMessage
, false);
697 mSavedDateTime
= mTimeWidget
->getDateTime(Q_NULLPTR
, false, false);
698 mSavedLateCancel
= mLateCancel
->minutes();
699 if (mShowInKorganizer
)
700 mSavedShowInKorganizer
= mShowInKorganizer
->isChecked();
701 mSavedRecurrenceType
= mRecurrenceEdit
->repeatType();
702 mSavedDeferTime
= mDeferDateTime
.kDateTime();
705 /******************************************************************************
706 * Check whether any of the controls has changed state since the dialog was
708 * Reply = true if any non-deferral controls have changed, or if it's a new event.
709 * = false if no non-deferral controls have changed. In this case,
710 * mOnlyDeferred indicates whether deferral controls may have changed.
712 bool EditAlarmDlg::stateChanged() const
715 mOnlyDeferred
= false;
718 QString textFileCommandMessage
;
719 checkText(textFileCommandMessage
, false);
722 if (mSavedTemplateName
!= mTemplateName
->text()
723 || mSavedTemplateTimeType
!= mTemplateTimeGroup
->checkedButton()
724 || (mTemplateUseTime
->isChecked() && mSavedTemplateTime
!= mTemplateTime
->time())
725 || (mTemplateUseTimeAfter
->isChecked() && mSavedTemplateAfterTime
!= mTemplateTimeAfter
->value()))
730 KDateTime dt
= mTimeWidget
->getDateTime(Q_NULLPTR
, false, false);
731 if (mSavedDateTime
.timeSpec() != dt
.timeSpec() || mSavedDateTime
!= dt
)
734 if (mSavedLateCancel
!= mLateCancel
->minutes()
735 || (mShowInKorganizer
&& mSavedShowInKorganizer
!= mShowInKorganizer
->isChecked())
736 || textFileCommandMessage
!= mSavedTextFileCommandMessage
737 || mSavedRecurrenceType
!= mRecurrenceEdit
->repeatType())
739 if (type_stateChanged())
741 if (mRecurrenceEdit
->stateChanged())
743 if (mSavedEvent
&& mSavedEvent
->deferred())
744 mOnlyDeferred
= true;
749 /******************************************************************************
750 * Called whenever any of the controls changes state.
751 * Enable or disable the OK button depending on whether any controls have a
752 * different state from their initial state.
754 void EditAlarmDlg::contentsChanged()
756 // Don't do anything if it's a new alarm or we're still initialising
757 // (i.e. mSavedEvent null).
758 if (mSavedEvent
&& mButtonBox
->button(QDialogButtonBox::Ok
))
759 mButtonBox
->button(QDialogButtonBox::Ok
)->setEnabled(stateChanged() || mDeferDateTime
.kDateTime() != mSavedDeferTime
);
762 /******************************************************************************
763 * Get the currently entered dialog data.
764 * The data is returned in the supplied KAEvent instance.
765 * Reply = false if the only change has been to an existing deferral.
767 bool EditAlarmDlg::getEvent(KAEvent
& event
, Akonadi::Collection
& collection
)
769 collection
= mCollection
;
772 // It's a new event, or the edit controls have changed
773 setEvent(event
, mAlarmMessage
, false);
777 // Only the deferral time may have changed
778 event
= *mSavedEvent
;
781 // Just modify the original event, to avoid expired recurring events
782 // being returned as rubbish.
783 if (mDeferDateTime
.isValid())
784 event
.defer(mDeferDateTime
, event
.reminderDeferral(), false);
791 /******************************************************************************
792 * Extract the data in the dialog and set up a KAEvent from it.
793 * If 'trial' is true, the event is set up for a simple one-off test, ignoring
794 * recurrence, reminder, template etc. data.
796 void EditAlarmDlg::setEvent(KAEvent
& event
, const QString
& text
, bool trial
)
802 dt
= mAlarmDateTime
.effectiveKDateTime();
803 else if (mTemplateUseTime
->isChecked())
804 dt
= KDateTime(QDate(2000,1,1), mTemplateTime
->time());
807 int lateCancel
= (trial
|| !mLateCancel
->isEnabled()) ? 0 : mLateCancel
->minutes();
808 type_setEvent(event
, dt
, text
, lateCancel
, trial
);
812 if (mRecurrenceEdit
->repeatType() != RecurrenceEdit::NO_RECUR
)
814 mRecurrenceEdit
->updateEvent(event
, !mTemplate
);
815 KDateTime now
= KDateTime::currentDateTime(mAlarmDateTime
.timeSpec());
816 bool dateOnly
= mAlarmDateTime
.isDateOnly();
817 if ((dateOnly
&& mAlarmDateTime
.date() < now
.date())
818 || (!dateOnly
&& mAlarmDateTime
.kDateTime() < now
))
820 // A timed recurrence has an entered start date which has
821 // already expired, so we must adjust the next repetition.
822 event
.setNextOccurrence(now
);
824 mAlarmDateTime
= event
.startDateTime();
825 if (mDeferDateTime
.isValid() && mDeferDateTime
< mAlarmDateTime
)
827 bool deferral
= true;
828 bool deferReminder
= false;
829 int reminder
= mReminder
? mReminder
->minutes() : 0;
832 DateTime remindTime
= mAlarmDateTime
.addMins(-reminder
);
833 if (mDeferDateTime
>= remindTime
)
835 if (remindTime
> KDateTime::currentUtcDateTime())
836 deferral
= false; // ignore deferral if it's after next reminder
837 else if (mDeferDateTime
> remindTime
)
838 deferReminder
= true; // it's the reminder which is being deferred
842 event
.defer(mDeferDateTime
, deferReminder
, false);
847 int afterTime
= mTemplateDefaultTime
->isChecked() ? 0
848 : mTemplateUseTimeAfter
->isChecked() ? mTemplateTimeAfter
->value() : -1;
849 event
.setTemplate(mTemplateName
->text(), afterTime
);
854 /******************************************************************************
855 * Get the currently specified alarm flag bits.
857 KAEvent::Flags
EditAlarmDlg::getAlarmFlags() const
859 KAEvent::Flags
flags(0);
860 if (mShowInKorganizer
&& mShowInKorganizer
->isEnabled() && mShowInKorganizer
->isChecked())
861 flags
|= KAEvent::COPY_KORGANIZER
;
862 if (mRecurrenceEdit
->repeatType() == RecurrenceEdit::AT_LOGIN
)
863 flags
|= KAEvent::REPEAT_AT_LOGIN
;
864 if (mTemplate
? mTemplateAnyTime
->isChecked() : mAlarmDateTime
.isDateOnly())
865 flags
|= KAEvent::ANY_TIME
;
869 /******************************************************************************
870 * Called when the dialog is displayed.
871 * The first time through, sets the size to the same as the last time it was
874 void EditAlarmDlg::showEvent(QShowEvent
* se
)
876 QDialog::showEvent(se
);
877 if (!mDeferGroupHeight
)
880 mDeferGroupHeight
= mDeferGroup
->height() + style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing
);
882 if (KAlarm::readConfigWindowSize(mTemplate
? TEMPLATE_DIALOG_NAME
: EDIT_DIALOG_NAME
, s
))
884 bool defer
= mDeferGroup
&& !mDeferGroup
->isHidden();
885 s
.setHeight(s
.height() + (defer
? mDeferGroupHeight
: 0));
887 mTabScrollGroup
->setSized();
892 KWindowSystem::setOnDesktop(winId(), mDesktop
); // ensure it displays on the desktop expected by the user
894 if (theApp()->needWindowFocusFix())
896 QApplication::setActiveWindow(this);
897 QTimer::singleShot(0, this, &EditAlarmDlg::focusFixTimer
);
901 /******************************************************************************
902 * Called when the window is first shown, to ensure that it initially becomes
904 * This is only required on Ubuntu's Unity desktop, which doesn't transfer
905 * keyboard focus properly between Edit Alarm Dialog windows and MessageWin
908 void EditAlarmDlg::focusFixTimer()
910 if (theApp()->needWindowFocusFix()
911 && QApplication::focusWidget()->window() != this)
913 QApplication::setActiveWindow(this);
914 QTimer::singleShot(0, this, &EditAlarmDlg::focusFixTimer
);
918 /******************************************************************************
919 * Called to detect when the mouse is pressed anywhere inside the window.
920 * Activates this window if a MessageWin window is also active.
921 * This is only required on Ubuntu's Unity desktop, which doesn't transfer
922 * keyboard focus properly between Edit Alarm Dialog windows and MessageWin
925 bool EditAlarmDlg::eventFilter(QObject
*, QEvent
* e
)
927 if (theApp()->needWindowFocusFix())
929 if (e
->type() == QEvent::MouseButtonPress
)
930 QApplication::setActiveWindow(this);
935 /******************************************************************************
936 * Called when the dialog is closed.
938 void EditAlarmDlg::closeEvent(QCloseEvent
* ce
)
941 QDialog::closeEvent(ce
);
944 /******************************************************************************
945 * Update the tab sizes (again) and if the resized dialog height is greater
946 * than the minimum, resize it again. This is necessary because (a) resizing
947 * tabs doesn't always work properly the first time, and (b) resizing to the
948 * minimum size hint doesn't always work either.
950 void EditAlarmDlg::slotResize()
952 QSize s
= mTabScrollGroup
->adjustSize(true);
953 s
= minimumSizeHint();
954 if (height() > s
.height())
956 // Resize to slightly greater than the minimum height.
957 // This is for some unknown reason necessary, since
958 // sometimes resizing to the minimum height fails.
959 resize(s
.width(), s
.height() + 2);
963 /******************************************************************************
964 * Called when the dialog's size has changed.
965 * Records the new size (adjusted to ignore the optional height of the deferred
966 * time edit widget) in the config file.
968 void EditAlarmDlg::resizeEvent(QResizeEvent
* re
)
970 if (isVisible() && mDeferGroupHeight
)
972 QSize s
= re
->size();
973 s
.setHeight(s
.height() - (!mDeferGroup
|| mDeferGroup
->isHidden() ? 0 : mDeferGroupHeight
));
974 KAlarm::writeConfigWindowSize(mTemplate
? TEMPLATE_DIALOG_NAME
: EDIT_DIALOG_NAME
, s
);
976 QDialog::resizeEvent(re
);
979 /******************************************************************************
980 * Called when any button is clicked.
982 void EditAlarmDlg::slotButtonClicked(QAbstractButton
*button
)
984 if (button
== mTryButton
)
986 else if (button
== mLoadTemplateButton
)
988 else if (button
== mMoreLessButton
)
990 else if (button
== mButtonBox
->button(QDialogButtonBox::Ok
))
999 /******************************************************************************
1000 * Called when the OK button is clicked.
1001 * Validate the input data.
1003 bool EditAlarmDlg::validate()
1005 if (!stateChanged())
1007 // No changes have been made except possibly to an existing deferral
1010 return mOnlyDeferred
;
1012 RecurrenceEdit::RepeatType recurType
= mRecurrenceEdit
->repeatType();
1014 && mTabs
->currentIndex() == mRecurPageIndex
&& recurType
== RecurrenceEdit::AT_LOGIN
)
1015 mTimeWidget
->setDateTime(mRecurrenceEdit
->endDateTime());
1016 bool timedRecurrence
= mRecurrenceEdit
->isTimedRepeatType(); // does it recur other than at login?
1019 // Check that the template name is not blank and is unique
1021 QString name
= mTemplateName
->text();
1023 errmsg
= i18nc("@info", "You must enter a name for the alarm template");
1024 else if (name
!= mSavedTemplateName
)
1026 if (AlarmCalendar::resources()->templateEvent(name
))
1027 errmsg
= i18nc("@info", "Template name is already in use");
1029 if (!errmsg
.isEmpty())
1031 mTemplateName
->setFocus();
1032 KAMessageBox::sorry(this, errmsg
);
1036 else if (mTimeWidget
)
1039 mAlarmDateTime
= mTimeWidget
->getDateTime(Q_NULLPTR
, !timedRecurrence
, false, &errWidget
);
1042 // It's more than just an existing deferral being changed, so the time matters
1043 mTabs
->setCurrentIndex(mMainPageIndex
);
1044 errWidget
->setFocus();
1045 mTimeWidget
->getDateTime(); // display the error message now
1049 if (!type_validate(false))
1054 if (mChanged
&& mRecurrenceEdit
->repeatType() != RecurrenceEdit::NO_RECUR
)
1056 // Check whether the start date/time must be adjusted
1057 // to match the recurrence specification.
1058 DateTime dt
= mAlarmDateTime
; // setEvent() changes mAlarmDateTime
1060 setEvent(event
, mAlarmMessage
, false);
1061 mAlarmDateTime
= dt
; // restore
1062 KDateTime pre
= dt
.effectiveKDateTime();
1063 bool dateOnly
= dt
.isDateOnly();
1065 pre
= pre
.addDays(-1);
1067 pre
= pre
.addSecs(-1);
1069 event
.nextOccurrence(pre
, next
, KAEvent::IGNORE_REPETITION
);
1072 QString prompt
= dateOnly
? i18nc("@info The parameter is a date value",
1073 "The start date does not match the alarm's recurrence pattern, "
1074 "so it will be adjusted to the date of the next recurrence (%1).",
1075 KLocale::global()->formatDate(next
.date(), KLocale::ShortDate
))
1076 : i18nc("@info The parameter is a date/time value",
1077 "The start date/time does not match the alarm's recurrence pattern, "
1078 "so it will be adjusted to the date/time of the next recurrence (%1).",
1079 KLocale::global()->formatDateTime(next
.kDateTime(), KLocale::ShortDate
));
1080 if (KAMessageBox::warningContinueCancel(this, prompt
) != KMessageBox::Continue
)
1085 if (timedRecurrence
)
1088 Akonadi::Collection c
;
1089 getEvent(event
, c
); // this may adjust mAlarmDateTime
1090 KDateTime now
= KDateTime::currentDateTime(mAlarmDateTime
.timeSpec());
1091 bool dateOnly
= mAlarmDateTime
.isDateOnly();
1092 if ((dateOnly
&& mAlarmDateTime
.date() < now
.date())
1093 || (!dateOnly
&& mAlarmDateTime
.kDateTime() < now
))
1095 // A timed recurrence has an entered start date which
1096 // has already expired, so we must adjust it.
1097 if (event
.nextOccurrence(now
, mAlarmDateTime
, KAEvent::ALLOW_FOR_REPETITION
) == KAEvent::NO_OCCURRENCE
)
1099 KAMessageBox::sorry(this, i18nc("@info", "Recurrence has already expired"));
1102 if (event
.workTimeOnly() && !event
.nextTrigger(KAEvent::DISPLAY_TRIGGER
).isValid())
1104 if (KAMessageBox::warningContinueCancel(this, i18nc("@info", "The alarm will never occur during working hours"))
1105 != KMessageBox::Continue
)
1111 QWidget
* errWidget
= mRecurrenceEdit
->checkData(mAlarmDateTime
.effectiveKDateTime(), errmsg
);
1114 mTabs
->setCurrentIndex(mRecurPageIndex
);
1115 errWidget
->setFocus();
1116 KAMessageBox::sorry(this, errmsg
);
1120 if (recurType
!= RecurrenceEdit::NO_RECUR
)
1123 int longestRecurMinutes
= -1;
1124 int reminder
= mReminder
? mReminder
->minutes() : 0;
1125 if (reminder
&& !mReminder
->isOnceOnly())
1127 mRecurrenceEdit
->updateEvent(recurEvent
, false);
1128 longestRecurMinutes
= recurEvent
.longestRecurrenceInterval().asSeconds() / 60;
1129 if (longestRecurMinutes
&& reminder
>= longestRecurMinutes
)
1131 mTabs
->setCurrentIndex(mMainPageIndex
);
1132 mReminder
->setFocusOnCount();
1133 KAMessageBox::sorry(this, xi18nc("@info", "Reminder period must be less than the recurrence interval, unless <interface>%1</interface> is checked.",
1134 Reminder::i18n_chk_FirstRecurrenceOnly()));
1138 if (mRecurrenceEdit
->subRepetition())
1140 if (longestRecurMinutes
< 0)
1142 mRecurrenceEdit
->updateEvent(recurEvent
, false);
1143 longestRecurMinutes
= recurEvent
.longestRecurrenceInterval().asSeconds() / 60;
1145 if (longestRecurMinutes
> 0
1146 && recurEvent
.repetition().intervalMinutes() * recurEvent
.repetition().count() >= longestRecurMinutes
- reminder
)
1148 KAMessageBox::sorry(this, i18nc("@info", "The duration of a repetition within the recurrence must be less than the recurrence interval minus any reminder period"));
1149 mRecurrenceEdit
->activateSubRepetition(); // display the alarm repetition dialog again
1152 if (!recurEvent
.repetition().isDaily()
1153 && ((mTemplate
&& mTemplateAnyTime
->isChecked()) || (!mTemplate
&& mAlarmDateTime
.isDateOnly())))
1155 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"));
1156 mRecurrenceEdit
->activateSubRepetition(); // display the alarm repetition dialog again
1161 if (!checkText(mAlarmMessage
))
1164 mCollection
= Akonadi::Collection();
1165 // An item ID = -2 indicates that the caller already
1166 // knows which collection to use.
1167 if (mCollectionItemId
>= -1)
1169 if (mCollectionItemId
>= 0)
1171 mCollection
= AlarmCalendar::resources()->collectionForEvent(mCollectionItemId
);
1172 if (mCollection
.isValid())
1174 CalEvent::Type type
= mTemplate
? CalEvent::TEMPLATE
: CalEvent::ACTIVE
;
1175 if (!(AkonadiModel::instance()->types(mCollection
) & type
))
1176 mCollection
= Akonadi::Collection(); // event may have expired while dialog was open
1179 bool cancelled
= false;
1180 CalEvent::Type type
= mTemplate
? CalEvent::TEMPLATE
: CalEvent::ACTIVE
;
1181 if (CollectionControlModel::isWritableEnabled(mCollection
, type
) <= 0)
1182 mCollection
= CollectionControlModel::destination(type
, this, false, &cancelled
);
1183 if (!mCollection
.isValid())
1186 KAMessageBox::sorry(this, i18nc("@info", "You must select a calendar to save the alarm in"));
1193 /******************************************************************************
1194 * Called when the Try button is clicked.
1195 * Display/execute the alarm immediately for the user to check its configuration.
1197 void EditAlarmDlg::slotTry()
1200 if (checkText(text
))
1202 if (!type_validate(true))
1205 setEvent(event
, text
, true);
1206 if (!mNewAlarm
&& !stateChanged())
1208 // It's an existing alarm which hasn't been changed yet:
1209 // enable KALARM_UID environment variable to be set.
1210 event
.setEventId(mEventId
);
1213 void* result
= theApp()->execAlarm(event
, event
.firstAlarm(), false, false);
1214 type_executedTry(text
, result
);
1218 /******************************************************************************
1219 * Called when the Load Template button is clicked.
1220 * Prompt to select a template and initialise the dialog with its contents.
1222 void EditAlarmDlg::slotHelp()
1224 KAEvent::Actions type
;
1228 case KAEvent::MESSAGE
: type
= KAEvent::ACT_DISPLAY
; break;
1229 case KAEvent::COMMAND
: type
= KAEvent::ACT_COMMAND
; break;
1230 case KAEvent::EMAIL
: type
= KAEvent::ACT_EMAIL
; break;
1231 case KAEvent::AUDIO
: type
= KAEvent::ACT_AUDIO
; break;
1235 // Use AutoQPointer to guard against crash on application exit while
1236 // the dialogue is still open. It prevents double deletion (both on
1237 // deletion of EditAlarmDlg, and on return from this function).
1238 AutoQPointer
<TemplatePickDlg
> dlg
= new TemplatePickDlg(type
, this);
1239 if (dlg
->exec() == QDialog::Accepted
)
1241 KAEvent event
= dlg
->selectedTemplate();
1246 /******************************************************************************
1247 * Called when the More Options or Less Options buttons are clicked.
1248 * Show/hide the optional options and swap the More/Less buttons, and save the
1249 * new setting as the default from now on.
1251 void EditAlarmDlg::slotDefault()
1253 showOptions(!mShowingMore
);
1254 KConfigGroup
config(KSharedConfig::openConfig(), EDIT_MORE_GROUP
);
1255 config
.writeEntry(EDIT_MORE_KEY
, mShowingMore
);
1258 /******************************************************************************
1259 * Show/hide the optional options and swap the More/Less buttons.
1261 void EditAlarmDlg::showOptions(bool more
)
1263 qCDebug(KALARM_LOG
) << (more
? "More" : "Less");
1266 mMoreOptions
->show();
1267 mMoreLessButton
->setText(i18nc("@action:Button", "Less Options <<"));
1271 mMoreOptions
->hide();
1272 mMoreLessButton
->setText(i18nc("@action:button", "More Options >>"));
1275 mTimeWidget
->showMoreOptions(more
);
1276 type_showOptions(more
);
1277 mRecurrenceEdit
->showMoreOptions(more
);
1278 mShowingMore
= more
;
1279 QTimer::singleShot(0, this, &EditAlarmDlg::slotResize
);
1282 /******************************************************************************
1283 * Called when the Change deferral button is clicked.
1285 void EditAlarmDlg::slotEditDeferral()
1290 Repetition repetition
= mRecurrenceEdit
->subRepetition();
1291 DateTime start
= mSavedEvent
->recurs() ? (mExpiredRecurrence
? DateTime() : mSavedEvent
->mainDateTime())
1292 : mTimeWidget
->getDateTime(Q_NULLPTR
, !repetition
, !mExpiredRecurrence
);
1293 if (!start
.isValid())
1295 if (!mExpiredRecurrence
)
1299 KDateTime now
= KDateTime::currentUtcDateTime();
1302 if (repetition
&& start
< now
)
1304 // Sub-repetition - find the time of the next one
1305 int repeatNum
= repetition
.isDaily()
1306 ? (start
.daysTo(now
) + repetition
.intervalDays() - 1) / repetition
.intervalDays()
1307 : (start
.secsTo(now
) + repetition
.intervalSeconds() - 1) / repetition
.intervalSeconds();
1308 if (repeatNum
> repetition
.count())
1310 mTimeWidget
->getDateTime(); // output the appropriate error message
1313 start
= repetition
.duration(repeatNum
).end(start
.kDateTime());
1317 bool deferred
= mDeferDateTime
.isValid();
1318 // Use AutoQPointer to guard against crash on application exit while
1319 // the dialogue is still open. It prevents double deletion (both on
1320 // deletion of EditAlarmDlg, and on return from this function).
1321 AutoQPointer
<DeferAlarmDlg
> deferDlg
= new DeferAlarmDlg((deferred
? mDeferDateTime
: DateTime(now
.addSecs(60).toTimeSpec(start
.timeSpec()))),
1322 start
.isDateOnly(), deferred
, this);
1323 deferDlg
->setObjectName(QStringLiteral("EditDeferDlg")); // used by LikeBack
1326 // Don't allow deferral past the next recurrence
1327 int reminder
= mReminder
? mReminder
->minutes() : 0;
1330 DateTime remindTime
= start
.addMins(-reminder
);
1331 if (KDateTime::currentUtcDateTime() < remindTime
)
1334 deferDlg
->setLimit(start
.addSecs(-60));
1336 if (deferDlg
->exec() == QDialog::Accepted
)
1338 mDeferDateTime
= deferDlg
->getDateTime();
1339 mDeferTimeLabel
->setText(mDeferDateTime
.isValid() ? mDeferDateTime
.formatLocale() : QString());
1344 /******************************************************************************
1345 * Called when the main page is shown.
1346 * Sets the focus widget to the first edit field.
1348 void EditAlarmDlg::slotShowMainPage()
1350 if (!mMainPageShown
)
1353 mTemplateName
->setFocus();
1354 mMainPageShown
= true;
1358 // Set scroll position to top, since it otherwise jumps randomly
1359 StackedScrollWidget
* main
= static_cast<StackedScrollWidget
*>(mTabs
->widget(0));
1360 main
->verticalScrollBar()->setValue(0);
1364 if (!mReadOnly
&& mRecurPageShown
&& mRecurrenceEdit
->repeatType() == RecurrenceEdit::AT_LOGIN
)
1365 mTimeWidget
->setDateTime(mRecurrenceEdit
->endDateTime());
1366 if (mReadOnly
|| mRecurrenceEdit
->isTimedRepeatType())
1367 mTimeWidget
->setMinDateTime(); // don't set a minimum date/time
1369 mTimeWidget
->setMinDateTimeIsCurrent(); // set the minimum date/time to track the clock
1373 /******************************************************************************
1374 * Called when the recurrence edit page is shown.
1375 * The recurrence defaults are set to correspond to the start date.
1376 * The first time, for a new alarm, the recurrence end date is set according to
1377 * the alarm start time.
1379 void EditAlarmDlg::slotShowRecurrenceEdit()
1381 mRecurPageIndex
= mTabs
->currentIndex();
1382 if (!mReadOnly
&& !mTemplate
)
1384 mAlarmDateTime
= mTimeWidget
->getDateTime(Q_NULLPTR
, false, false);
1385 KDateTime now
= KDateTime::currentDateTime(mAlarmDateTime
.timeSpec());
1386 bool expired
= (mAlarmDateTime
.effectiveKDateTime() < now
);
1387 if (mRecurSetDefaultEndDate
)
1389 mRecurrenceEdit
->setDefaultEndDate(expired
? now
.date() : mAlarmDateTime
.date());
1390 mRecurSetDefaultEndDate
= false;
1392 mRecurrenceEdit
->setStartDate(mAlarmDateTime
.date(), now
.date());
1393 if (mRecurrenceEdit
->repeatType() == RecurrenceEdit::AT_LOGIN
)
1394 mRecurrenceEdit
->setEndDateTime(expired
? now
: mAlarmDateTime
.kDateTime());
1396 mRecurPageShown
= true;
1399 /******************************************************************************
1400 * Called when the recurrence type selection changes.
1401 * Enables/disables date-only alarms as appropriate.
1402 * Enables/disables controls depending on at-login setting.
1404 void EditAlarmDlg::slotRecurTypeChange(int repeatType
)
1406 bool atLogin
= (mRecurrenceEdit
->repeatType() == RecurrenceEdit::AT_LOGIN
);
1409 bool recurs
= (mRecurrenceEdit
->repeatType() != RecurrenceEdit::NO_RECUR
);
1411 mDeferGroup
->setEnabled(recurs
);
1412 mTimeWidget
->enableAnyTime(!recurs
|| repeatType
!= RecurrenceEdit::SUBDAILY
);
1415 mAlarmDateTime
= mTimeWidget
->getDateTime(Q_NULLPTR
, false, false);
1416 mRecurrenceEdit
->setEndDateTime(mAlarmDateTime
.kDateTime());
1419 mReminder
->enableOnceOnly(recurs
&& !atLogin
);
1422 mReminder
->setAfterOnly(atLogin
);
1423 mLateCancel
->setEnabled(!atLogin
);
1424 if (mShowInKorganizer
)
1425 mShowInKorganizer
->setEnabled(!atLogin
);
1426 slotRecurFrequencyChange();
1429 /******************************************************************************
1430 * Called when the recurrence frequency selection changes, or the sub-
1431 * repetition interval changes.
1432 * Updates the recurrence frequency text.
1434 void EditAlarmDlg::slotRecurFrequencyChange()
1436 slotSetSubRepetition();
1438 mRecurrenceEdit
->updateEvent(event
, false);
1439 mTabs
->setTabText(mRecurPageIndex
, recurText(event
));
1442 /******************************************************************************
1443 * Called when the Repetition within Recurrence button has been pressed to
1444 * display the sub-repetition dialog.
1445 * Alarm repetition has the following restrictions:
1446 * 1) Not allowed for a repeat-at-login alarm
1447 * 2) For a date-only alarm, the repeat interval must be a whole number of days.
1448 * 3) The overall repeat duration must be less than the recurrence interval.
1450 void EditAlarmDlg::slotSetSubRepetition()
1452 bool dateOnly
= mTemplate
? mTemplateAnyTime
->isChecked() : mTimeWidget
->anyTime();
1453 mRecurrenceEdit
->setSubRepetition((mReminder
? mReminder
->minutes() : 0), dateOnly
);
1456 /******************************************************************************
1457 * Called when one of the template time radio buttons is clicked,
1458 * to enable or disable the template time entry spin boxes.
1460 void EditAlarmDlg::slotTemplateTimeType(QAbstractButton
*)
1462 mTemplateTime
->setEnabled(mTemplateUseTime
->isChecked());
1463 mTemplateTimeAfter
->setEnabled(mTemplateUseTimeAfter
->isChecked());
1466 /******************************************************************************
1467 * Called when the "Any time" checkbox is toggled in the date/time widget.
1468 * Sets the advance reminder and late cancel units to days if any time is checked.
1470 void EditAlarmDlg::slotAnyTimeToggled(bool anyTime
)
1472 if (mReminder
&& mReminder
->isReminder())
1473 mReminder
->setDateOnly(anyTime
);
1474 mLateCancel
->setDateOnly(anyTime
);
1477 bool EditAlarmDlg::dateOnly() const
1479 return mTimeWidget
? mTimeWidget
->anyTime() : mTemplateAnyTime
->isChecked();
1482 bool EditAlarmDlg::isTimedRecurrence() const
1484 return mRecurrenceEdit
->isTimedRepeatType();
1487 void EditAlarmDlg::showMainPage()
1489 mTabs
->setCurrentIndex(mMainPageIndex
);
1492 #include "moc_editdlg.cpp"
1493 #include "moc_editdlg_p.cpp"