Fix dnd email
[kdepim.git] / kalarm / repetitionbutton.cpp
blobb391881cba53990ba214ca8c8d1df4b5219eefaf
1 /*
2 * repetitionbutton.cpp - pushbutton and dialog to specify alarm repetition
3 * Program: kalarm
4 * Copyright © 2004-2011 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.
21 #include "kalarm.h"
22 #include "repetitionbutton.h"
24 #include "buttongroup.h"
25 #include "radiobutton.h"
26 #include "spinbox.h"
27 #include "timeperiod.h"
28 #include "timeselector.h"
30 #include <KLocalizedString>
32 #include <QGroupBox>
33 #include <QVBoxLayout>
34 #include <QHBoxLayout>
35 #include <QDialogButtonBox>
37 using namespace KCalCore;
40 /*=============================================================================
41 = Class RepetitionButton
42 = Button to display the Simple Alarm Repetition dialog.
43 =============================================================================*/
45 RepetitionButton::RepetitionButton(const QString& caption, bool waitForInitialisation, QWidget* parent)
46 : QPushButton(caption, parent),
47 mDialog(Q_NULLPTR),
48 mMaxDuration(-1),
49 mDateOnly(false),
50 mWaitForInit(waitForInitialisation),
51 mReadOnly(false)
53 setCheckable(true);
54 setChecked(false);
55 connect(this, &RepetitionButton::clicked, this, &RepetitionButton::slotPressed);
58 void RepetitionButton::set(const Repetition& repetition)
60 mRepetition = repetition;
61 setChecked(mRepetition);
64 /******************************************************************************
65 * Set the data for the dialog.
67 void RepetitionButton::set(const Repetition& repetition, bool dateOnly, int maxDuration)
69 mRepetition = repetition;
70 mMaxDuration = maxDuration;
71 mDateOnly = dateOnly;
72 setChecked(mRepetition);
75 /******************************************************************************
76 * Create the alarm repetition dialog.
77 * If 'waitForInitialisation' is true, the dialog won't be displayed until set()
78 * is called to initialise its data.
80 void RepetitionButton::activate(bool waitForInitialisation)
82 if (!mDialog)
83 mDialog = new RepetitionDlg(i18nc("@title:window", "Alarm Sub-Repetition"), mReadOnly, this);
84 mDialog->set(mRepetition, mDateOnly, mMaxDuration);
85 if (waitForInitialisation)
86 Q_EMIT needsInitialisation(); // request dialog initialisation
87 else
88 displayDialog(); // display the dialog now
91 /******************************************************************************
92 * Set the data for the dialog and display it.
93 * To be called only after needsInitialisation() has been emitted.
95 void RepetitionButton::initialise(const Repetition& repetition, bool dateOnly, int maxDuration)
97 mRepetition = (maxDuration > 0 && repetition.intervalMinutes() > maxDuration)
98 ? Repetition() : repetition;
99 mMaxDuration = maxDuration;
100 mDateOnly = dateOnly;
101 if (mDialog)
103 mDialog->set(mRepetition, dateOnly, maxDuration);
104 displayDialog(); // display the dialog now
106 else
107 setChecked(mRepetition);
110 /******************************************************************************
111 * Display the alarm sub-repetition dialog.
112 * Alarm repetition has the following restrictions:
113 * 1) Not allowed for a repeat-at-login alarm
114 * 2) For a date-only alarm, the repeat interval must be a whole number of days.
115 * 3) The overall repeat duration must be less than the recurrence interval.
117 void RepetitionButton::displayDialog()
119 bool change = false;
120 if (mReadOnly)
122 mDialog->setReadOnly(true);
123 mDialog->exec();
125 else if (mDialog->exec() == QDialog::Accepted)
127 mRepetition = mDialog->repetition();
128 change = true;
130 setChecked(mRepetition);
131 delete mDialog;
132 mDialog = Q_NULLPTR;
133 if (change)
134 Q_EMIT changed(); // delete dialog first, or initialise() will redisplay dialog
138 /*=============================================================================
139 = Class RepetitionDlg
140 = Simple alarm repetition dialog.
141 =============================================================================*/
143 static const int MAX_COUNT = 9999; // maximum range for count spinbox
146 RepetitionDlg::RepetitionDlg(const QString& caption, bool readOnly, QWidget* parent)
147 : QDialog(parent),
148 mMaxDuration(-1),
149 mDateOnly(false),
150 mReadOnly(readOnly)
152 setWindowTitle(caption);
154 QVBoxLayout* topLayout = new QVBoxLayout(this);
156 mTimeSelector = new TimeSelector(i18nc("@option:check Repeat every 10 minutes", "Repeat every"),
157 i18nc("@info:whatsthis", "Instead of the alarm triggering just once at each recurrence, "
158 "checking this option makes the alarm trigger multiple times at each recurrence."),
159 i18nc("@info:whatsthis", "Enter the time between repetitions of the alarm"),
160 true, this);
161 mTimeSelector->setFixedSize(mTimeSelector->sizeHint());
162 connect(mTimeSelector, &TimeSelector::valueChanged, this, &RepetitionDlg::intervalChanged);
163 connect(mTimeSelector, &TimeSelector::toggled, this, &RepetitionDlg::repetitionToggled);
164 topLayout->addWidget(mTimeSelector, 0, Qt::AlignLeft);
166 mButtonBox = new QGroupBox(this);
167 topLayout->addWidget(mButtonBox);
168 mButtonGroup = new ButtonGroup(mButtonBox);
169 connect(mButtonGroup, &ButtonGroup::buttonSet, this, &RepetitionDlg::typeClicked);
171 QVBoxLayout* vlayout = new QVBoxLayout(mButtonBox);
172 QHBoxLayout* layout = new QHBoxLayout();
173 layout->setMargin(0);
174 vlayout->addLayout(layout);
175 mCountButton = new RadioButton(i18nc("@option:radio", "Number of repetitions:"), mButtonBox);
176 mCountButton->setFixedSize(mCountButton->sizeHint());
177 mCountButton->setWhatsThis(i18nc("@info:whatsthis", "Check to specify the number of times the alarm should repeat after each recurrence"));
178 mButtonGroup->addButton(mCountButton);
179 layout->addWidget(mCountButton);
180 mCount = new SpinBox(1, MAX_COUNT, mButtonBox);
181 mCount->setFixedSize(mCount->sizeHint());
182 mCount->setSingleShiftStep(10);
183 mCount->setSelectOnStep(false);
184 connect(mCount, static_cast<void (SpinBox::*)(int)>(&SpinBox::valueChanged), this, &RepetitionDlg::countChanged);
185 mCount->setWhatsThis(i18nc("@info:whatsthis", "Enter the number of times to trigger the alarm after its initial occurrence"));
186 layout->addWidget(mCount);
187 mCountButton->setFocusWidget(mCount);
188 layout->addStretch();
190 layout = new QHBoxLayout();
191 layout->setMargin(0);
192 vlayout->addLayout(layout);
193 mDurationButton = new RadioButton(i18nc("@option:radio", "Duration:"), mButtonBox);
194 mDurationButton->setFixedSize(mDurationButton->sizeHint());
195 mDurationButton->setWhatsThis(i18nc("@info:whatsthis", "Check to specify how long the alarm is to be repeated"));
196 mButtonGroup->addButton(mDurationButton);
197 layout->addWidget(mDurationButton);
198 mDuration = new TimePeriod(true, mButtonBox);
199 mDuration->setFixedSize(mDuration->sizeHint());
200 connect(mDuration, &TimePeriod::valueChanged, this, &RepetitionDlg::durationChanged);
201 mDuration->setWhatsThis(i18nc("@info:whatsthis", "Enter the length of time to repeat the alarm"));
202 layout->addWidget(mDuration);
203 mDurationButton->setFocusWidget(mDuration);
204 layout->addStretch();
206 QDialogButtonBox *buttonBox = new QDialogButtonBox(this);
207 buttonBox->addButton(QDialogButtonBox::Ok);
208 buttonBox->addButton(QDialogButtonBox::Cancel);
209 connect(buttonBox, &QDialogButtonBox::accepted,
210 this, &QDialog::accept);
211 connect(buttonBox, &QDialogButtonBox::rejected,
212 this, &QDialog::reject);
213 topLayout->addWidget(buttonBox);
215 mCountButton->setChecked(true);
216 repetitionToggled(false);
217 setReadOnly(mReadOnly);
220 /******************************************************************************
221 * Set the state of all controls to reflect the data in the specified alarm.
223 void RepetitionDlg::set(const Repetition& repetition, bool dateOnly, int maxDuration)
225 if (dateOnly != mDateOnly)
227 mDateOnly = dateOnly;
228 mTimeSelector->setDateOnly(mDateOnly);
229 mDuration->setDateOnly(mDateOnly);
231 mMaxDuration = maxDuration;
232 if (mMaxDuration)
234 int maxhm = (mMaxDuration > 0) ? mMaxDuration : 9999;
235 int maxdw = (mMaxDuration > 0) ? mMaxDuration / 1440 : 9999;
236 mTimeSelector->setMaximum(maxhm, maxdw);
237 mDuration->setMaximum(maxhm, maxdw);
239 // Set the units - needed later if the control is unchecked initially.
240 TimePeriod::Units units = mDateOnly ? TimePeriod::Days : TimePeriod::HoursMinutes;
241 mTimeSelector->setPeriod(repetition.interval(), mDateOnly, units);
242 if (!mMaxDuration || !repetition)
243 mTimeSelector->setChecked(false);
244 else
246 bool on = mTimeSelector->isChecked();
247 repetitionToggled(on); // enable/disable controls
248 if (on)
249 intervalChanged(repetition.interval()); // ensure mCount range is set
250 mCount->setValue(repetition.count());
251 mDuration->setPeriod(repetition.duration(), mDateOnly, units);
252 mCountButton->setChecked(true);
254 mTimeSelector->setEnabled(mMaxDuration);
257 /******************************************************************************
258 * Set the read-only status.
260 void RepetitionDlg::setReadOnly(bool ro)
262 ro = ro || mReadOnly;
263 mTimeSelector->setReadOnly(ro);
264 mCountButton->setReadOnly(ro);
265 mCount->setReadOnly(ro);
266 mDurationButton->setReadOnly(ro);
267 mDuration->setReadOnly(ro);
270 /******************************************************************************
271 * Get the entered interval and repeat count.
273 Repetition RepetitionDlg::repetition() const
275 int count = 0;
276 Duration interval = mTimeSelector->period();
277 if (!interval.isNull())
279 if (mCountButton->isChecked())
280 count = mCount->value();
281 else if (mDurationButton->isChecked())
282 count = mDuration->period().asSeconds() / interval.asSeconds();
284 return Repetition(interval, count);
287 /******************************************************************************
288 * Called when the time interval widget has changed value.
289 * Adjust the maximum repetition count accordingly.
291 void RepetitionDlg::intervalChanged(const Duration& interval)
293 if (mTimeSelector->isChecked() && interval.asSeconds() > 0)
295 mCount->setRange(1, (mMaxDuration >= 0 ? mMaxDuration / (interval.asSeconds()/60) : MAX_COUNT));
296 if (mCountButton->isChecked())
297 countChanged(mCount->value());
298 else
299 durationChanged(mDuration->period());
303 /******************************************************************************
304 * Called when the count spinbox has changed value.
305 * Adjust the duration accordingly.
307 void RepetitionDlg::countChanged(int count)
309 Duration interval = mTimeSelector->period();
310 if (!interval.isNull())
312 bool blocked = mDuration->signalsBlocked();
313 mDuration->blockSignals(true);
314 mDuration->setPeriod(interval * count, mDateOnly,
315 (mDateOnly ? TimePeriod::Days : TimePeriod::HoursMinutes));
316 mDuration->blockSignals(blocked);
320 /******************************************************************************
321 * Called when the duration widget has changed value.
322 * Adjust the count accordingly.
324 void RepetitionDlg::durationChanged(const Duration& duration)
326 Duration interval = mTimeSelector->period();
327 if (!interval.isNull())
329 bool blocked = mCount->signalsBlocked();
330 mCount->blockSignals(true);
331 mCount->setValue(duration.asSeconds() / interval.asSeconds());
332 mCount->blockSignals(blocked);
336 /******************************************************************************
337 * Called when the time period widget is toggled on or off.
339 void RepetitionDlg::repetitionToggled(bool on)
341 if (mMaxDuration == 0)
342 on = false;
343 mButtonBox->setEnabled(on);
344 mCount->setEnabled(on && mCountButton->isChecked());
345 mDuration->setEnabled(on && mDurationButton->isChecked());
348 /******************************************************************************
349 * Called when one of the count or duration radio buttons is toggled.
351 void RepetitionDlg::typeClicked()
353 if (mTimeSelector->isChecked())
355 mCount->setEnabled(mCountButton->isChecked());
356 mDuration->setEnabled(mDurationButton->isChecked());
360 // vim: et sw=4: