2 * repetitionbutton.cpp - pushbutton and dialog to specify alarm repetition
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.
22 #include "repetitionbutton.h"
24 #include "buttongroup.h"
25 #include "radiobutton.h"
27 #include "timeperiod.h"
28 #include "timeselector.h"
30 #include <KLocalizedString>
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
),
50 mWaitForInit(waitForInitialisation
),
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
;
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
)
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
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
;
103 mDialog
->set(mRepetition
, dateOnly
, maxDuration
);
104 displayDialog(); // display the dialog now
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()
122 mDialog
->setReadOnly(true);
125 else if (mDialog
->exec() == QDialog::Accepted
)
127 mRepetition
= mDialog
->repetition();
130 setChecked(mRepetition
);
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
)
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"),
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
;
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);
246 bool on
= mTimeSelector
->isChecked();
247 repetitionToggled(on
); // enable/disable controls
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
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());
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)
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());