2 * repetitionbutton.cpp - pushbutton and dialog to specify alarm repetition
4 * Copyright © 2004-2009 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.moc"
24 #include "buttongroup.h"
25 #include "radiobutton.h"
27 #include "timeperiod.h"
28 #include "timeselector.h"
34 #include <QVBoxLayout>
35 #include <QHBoxLayout>
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, SIGNAL(clicked()), SLOT(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 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 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
)
153 setButtons(Ok
|Cancel
);
154 int spacing
= spacingHint();
155 QWidget
* page
= new QWidget(this);
157 QVBoxLayout
* topLayout
= new QVBoxLayout(page
);
158 topLayout
->setMargin(0);
159 topLayout
->setSpacing(spacing
);
161 mTimeSelector
= new TimeSelector(i18nc("@option:check Repeat every 10 minutes", "Repeat every"), QString(),
162 i18nc("@info:whatsthis", "Instead of the alarm triggering just once at each recurrence, "
163 "checking this option makes the alarm trigger multiple times at each recurrence."),
164 i18nc("@info:whatsthis", "Enter the time between repetitions of the alarm"),
166 mTimeSelector
->setFixedSize(mTimeSelector
->sizeHint());
167 connect(mTimeSelector
, SIGNAL(valueChanged(const KCal::Duration
&)), SLOT(intervalChanged(const KCal::Duration
&)));
168 connect(mTimeSelector
, SIGNAL(toggled(bool)), SLOT(repetitionToggled(bool)));
169 topLayout
->addWidget(mTimeSelector
, 0, Qt::AlignLeft
);
171 mButtonBox
= new QGroupBox(page
);
172 topLayout
->addWidget(mButtonBox
);
173 mButtonGroup
= new ButtonGroup(mButtonBox
);
174 connect(mButtonGroup
, SIGNAL(buttonSet(QAbstractButton
*)), SLOT(typeClicked()));
176 QVBoxLayout
* vlayout
= new QVBoxLayout(mButtonBox
);
177 vlayout
->setMargin(marginHint());
178 vlayout
->setSpacing(spacing
);
179 QHBoxLayout
* layout
= new QHBoxLayout();
180 layout
->setMargin(0);
181 vlayout
->addLayout(layout
);
182 mCountButton
= new RadioButton(i18nc("@option:radio", "Number of repetitions:"), mButtonBox
);
183 mCountButton
->setFixedSize(mCountButton
->sizeHint());
184 mCountButton
->setWhatsThis(i18nc("@info:whatsthis", "Check to specify the number of times the alarm should repeat after each recurrence"));
185 mButtonGroup
->addButton(mCountButton
);
186 layout
->addWidget(mCountButton
);
187 mCount
= new SpinBox(1, MAX_COUNT
, mButtonBox
);
188 mCount
->setFixedSize(mCount
->sizeHint());
189 mCount
->setSingleShiftStep(10);
190 mCount
->setSelectOnStep(false);
191 connect(mCount
, SIGNAL(valueChanged(int)), SLOT(countChanged(int)));
192 mCount
->setWhatsThis(i18nc("@info:whatsthis", "Enter the number of times to trigger the alarm after its initial occurrence"));
193 layout
->addWidget(mCount
);
194 mCountButton
->setFocusWidget(mCount
);
195 layout
->addStretch();
197 layout
= new QHBoxLayout();
198 layout
->setMargin(0);
199 vlayout
->addLayout(layout
);
200 mDurationButton
= new RadioButton(i18nc("@option:radio", "Duration:"), mButtonBox
);
201 mDurationButton
->setFixedSize(mDurationButton
->sizeHint());
202 mDurationButton
->setWhatsThis(i18nc("@info:whatsthis", "Check to specify how long the alarm is to be repeated"));
203 mButtonGroup
->addButton(mDurationButton
);
204 layout
->addWidget(mDurationButton
);
205 mDuration
= new TimePeriod(true, mButtonBox
);
206 mDuration
->setFixedSize(mDuration
->sizeHint());
207 connect(mDuration
, SIGNAL(valueChanged(const KCal::Duration
&)), SLOT(durationChanged(const KCal::Duration
&)));
208 mDuration
->setWhatsThis(i18nc("@info:whatsthis", "Enter the length of time to repeat the alarm"));
209 layout
->addWidget(mDuration
);
210 mDurationButton
->setFocusWidget(mDuration
);
211 layout
->addStretch();
213 mCountButton
->setChecked(true);
214 repetitionToggled(false);
215 setReadOnly(mReadOnly
);
218 /******************************************************************************
219 * Set the state of all controls to reflect the data in the specified alarm.
221 void RepetitionDlg::set(const Repetition
& repetition
, bool dateOnly
, int maxDuration
)
223 if (dateOnly
!= mDateOnly
)
225 mDateOnly
= dateOnly
;
226 mTimeSelector
->setDateOnly(mDateOnly
);
227 mDuration
->setDateOnly(mDateOnly
);
229 mMaxDuration
= maxDuration
;
232 int maxhm
= (mMaxDuration
> 0) ? mMaxDuration
: 9999;
233 int maxdw
= (mMaxDuration
> 0) ? mMaxDuration
/ 1440 : 9999;
234 mTimeSelector
->setMaximum(maxhm
, maxdw
);
235 mDuration
->setMaximum(maxhm
, maxdw
);
237 // Set the units - needed later if the control is unchecked initially.
238 TimePeriod::Units units
= mDateOnly
? TimePeriod::Days
: TimePeriod::HoursMinutes
;
239 mTimeSelector
->setPeriod(repetition
.interval(), mDateOnly
, units
);
240 if (!mMaxDuration
|| !repetition
)
241 mTimeSelector
->setChecked(false);
244 bool on
= mTimeSelector
->isChecked();
245 repetitionToggled(on
); // enable/disable controls
247 intervalChanged(repetition
.interval()); // ensure mCount range is set
248 mCount
->setValue(repetition
.count());
249 mDuration
->setPeriod(repetition
.duration(), mDateOnly
, units
);
250 mCountButton
->setChecked(true);
252 mTimeSelector
->setEnabled(mMaxDuration
);
255 /******************************************************************************
256 * Set the read-only status.
258 void RepetitionDlg::setReadOnly(bool ro
)
260 ro
= ro
|| mReadOnly
;
261 mTimeSelector
->setReadOnly(ro
);
262 mCountButton
->setReadOnly(ro
);
263 mCount
->setReadOnly(ro
);
264 mDurationButton
->setReadOnly(ro
);
265 mDuration
->setReadOnly(ro
);
268 /******************************************************************************
269 * Get the entered interval and repeat count.
271 Repetition
RepetitionDlg::repetition() const
274 Duration interval
= mTimeSelector
->period();
277 if (mCountButton
->isChecked())
278 count
= mCount
->value();
279 else if (mDurationButton
->isChecked())
280 count
= mDuration
->period().asSeconds() / interval
.asSeconds();
282 return Repetition(interval
, count
);
285 /******************************************************************************
286 * Called when the time interval widget has changed value.
287 * Adjust the maximum repetition count accordingly.
289 void RepetitionDlg::intervalChanged(const KCal::Duration
& interval
)
291 if (mTimeSelector
->isChecked() && interval
.asSeconds() > 0)
293 mCount
->setRange(1, (mMaxDuration
>= 0 ? mMaxDuration
/ (interval
.asSeconds()/60) : MAX_COUNT
));
294 if (mCountButton
->isChecked())
295 countChanged(mCount
->value());
297 durationChanged(mDuration
->period());
301 /******************************************************************************
302 * Called when the count spinbox has changed value.
303 * Adjust the duration accordingly.
305 void RepetitionDlg::countChanged(int count
)
307 Duration interval
= mTimeSelector
->period();
310 bool blocked
= mDuration
->signalsBlocked();
311 mDuration
->blockSignals(true);
312 mDuration
->setPeriod(interval
* count
, mDateOnly
,
313 (mDateOnly
? TimePeriod::Days
: TimePeriod::HoursMinutes
));
314 mDuration
->blockSignals(blocked
);
318 /******************************************************************************
319 * Called when the duration widget has changed value.
320 * Adjust the count accordingly.
322 void RepetitionDlg::durationChanged(const KCal::Duration
& duration
)
324 Duration interval
= mTimeSelector
->period();
327 bool blocked
= mCount
->signalsBlocked();
328 mCount
->blockSignals(true);
329 mCount
->setValue(duration
.asSeconds() / interval
.asSeconds());
330 mCount
->blockSignals(blocked
);
334 /******************************************************************************
335 * Called when the time period widget is toggled on or off.
337 void RepetitionDlg::repetitionToggled(bool on
)
339 if (mMaxDuration
== 0)
341 mButtonBox
->setEnabled(on
);
342 mCount
->setEnabled(on
&& mCountButton
->isChecked());
343 mDuration
->setEnabled(on
&& mDurationButton
->isChecked());
346 /******************************************************************************
347 * Called when one of the count or duration radio buttons is toggled.
349 void RepetitionDlg::typeClicked()
351 if (mTimeSelector
->isChecked())
353 mCount
->setEnabled(mCountButton
->isChecked());
354 mDuration
->setEnabled(mDurationButton
->isChecked());