kalarm

repetition.cpp
1/*
2 * repetition.cpp - pushbutton and dialogue to specify alarm sub-repetition
3 * Program: kalarm
4 * Copyright © 2004,2005,2007,2008 by David Jarvie <djarvie@kde.org>
5 *
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.
10 *
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.
15 *
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.
19 */
20
21#include "kalarm.h"
22
23#include <tqlayout.h>
24#include <tqwhatsthis.h>
25
26#include <kdebug.h>
27#include <kdialog.h>
28#include <tdelocale.h>
29
30#include "buttongroup.h"
31#include "radiobutton.h"
32#include "spinbox.h"
33#include "timeperiod.h"
34#include "timeselector.h"
35#include "repetition.moc"
36
37
38/*=============================================================================
39= Class RepetitionButton
40= Button to display the Alarm Sub-Repetition dialogue.
41=============================================================================*/
42
43RepetitionButton::RepetitionButton(const TQString& caption, bool waitForInitialisation, TQWidget* parent, const char* name)
44 : TQPushButton(caption, parent, name),
45 mDialog(0),
46 mInterval(0),
47 mCount(0),
48 mMaxDuration(-1),
49 mDateOnly(false),
50 mWaitForInit(waitForInitialisation),
51 mReadOnly(false)
52{
53 setToggleButton(true);
54 setOn(false);
55 connect(this, TQ_SIGNAL(clicked()), TQ_SLOT(slotPressed()));
56}
57
58void RepetitionButton::set(int interval, int count)
59{
60 mInterval = interval;
61 mCount = count;
62 setOn(mInterval && mCount);
63}
64
65/******************************************************************************
66* Set the data for the dialog.
67*/
68void RepetitionButton::set(int interval, int count, bool dateOnly, int maxDuration)
69{
70 mInterval = interval;
71 mCount = count;
72 mMaxDuration = maxDuration;
73 mDateOnly = dateOnly;
74 setOn(mInterval && mCount);
75}
76
77/******************************************************************************
78* Create the alarm repetition dialog.
79* If 'waitForInitialisation' is true, the dialog won't be displayed until set()
80* is called to initialise its data.
81*/
82void RepetitionButton::activate(bool waitForInitialisation)
83{
84 if (!mDialog)
85 mDialog = new RepetitionDlg(i18n("Alarm Sub-Repetition"), mReadOnly, this);
86 mDialog->set(mInterval, mCount, mDateOnly, mMaxDuration);
87 if (waitForInitialisation)
88 emit needsInitialisation(); // request dialog initialisation
89 else
90 displayDialog(); // display the dialog now
91}
92
93/******************************************************************************
94* Set the data for the dialog and display it.
95* To be called only after needsInitialisation() has been emitted.
96*/
97void RepetitionButton::initialise(int interval, int count, bool dateOnly, int maxDuration)
98{
99 if (maxDuration > 0 && interval > maxDuration)
100 count = 0;
101 mCount = count;
102 mInterval = interval;
103 mMaxDuration = maxDuration;
104 mDateOnly = dateOnly;
105 if (mDialog)
106 {
107 mDialog->set(interval, count, dateOnly, maxDuration);
108 displayDialog(); // display the dialog now
109 }
110 else
111 setOn(mInterval && mCount);
112}
113
114/******************************************************************************
115* Display the alarm sub-repetition dialog.
116* Alarm repetition has the following restrictions:
117* 1) Not allowed for a repeat-at-login alarm
118* 2) For a date-only alarm, the repeat interval must be a whole number of days.
119* 3) The overall repeat duration must be less than the recurrence interval.
120*/
121void RepetitionButton::displayDialog()
122{
123 kdDebug(5950) << "RepetitionButton::displayDialog()" << endl;
124 bool change = false;
125 if (mReadOnly)
126 {
127 mDialog->setReadOnly(true);
128 mDialog->exec();
129 }
130 else if (mDialog->exec() == TQDialog::Accepted)
131 {
132 mCount = mDialog->count();
133 mInterval = mDialog->interval();
134 change = true;
135 }
136 setOn(mInterval && mCount);
137 delete mDialog;
138 mDialog = 0;
139 if (change)
140 emit changed(); // delete dialog first, or initialise() will redisplay dialog
141}
142
143
144/*=============================================================================
145= Class RepetitionDlg
146= Alarm sub-repetition dialogue.
147=============================================================================*/
148
149static const int MAX_COUNT = 9999; // maximum range for count spinbox
150
151
152RepetitionDlg::RepetitionDlg(const TQString& caption, bool readOnly, TQWidget* parent, const char* name)
153 : KDialogBase(parent, name, true, caption, Ok|Cancel),
154 mMaxDuration(-1),
155 mDateOnly(false),
156 mReadOnly(readOnly)
157{
158 int spacing = spacingHint();
159 TQWidget* page = new TQWidget(this);
160 setMainWidget(page);
161 TQVBoxLayout* topLayout = new TQVBoxLayout(page, 0, spacing);
162
163 mTimeSelector = new TimeSelector(i18n("Repeat every 10 minutes", "&Repeat every"), TQString(),
164 i18n("Instead of the alarm triggering just once at each recurrence, "
165 "checking this option makes the alarm trigger multiple times at each recurrence."),
166 i18n("Enter the time between repetitions of the alarm"),
167 true, page);
168 mTimeSelector->setFixedSize(mTimeSelector->sizeHint());
169 connect(mTimeSelector, TQ_SIGNAL(valueChanged(int)), TQ_SLOT(intervalChanged(int)));
170 connect(mTimeSelector, TQ_SIGNAL(toggled(bool)), TQ_SLOT(repetitionToggled(bool)));
171 topLayout->addWidget(mTimeSelector, 0, TQt::AlignAuto);
172
173 mButtonGroup = new ButtonGroup(page, "buttonGroup");
174 connect(mButtonGroup, TQ_SIGNAL(buttonSet(int)), TQ_SLOT(typeClicked()));
175 topLayout->addWidget(mButtonGroup);
176
177 TQBoxLayout* vlayout = new TQVBoxLayout(mButtonGroup, marginHint(), spacing);
178 TQBoxLayout* layout = new TQHBoxLayout(vlayout, spacing);
179 mCountButton = new RadioButton(i18n("&Number of repetitions:"), mButtonGroup);
180 mCountButton->setFixedSize(mCountButton->sizeHint());
181 TQWhatsThis::add(mCountButton,
182 i18n("Check to specify the number of times the alarm should repeat after each recurrence"));
183 layout->addWidget(mCountButton);
184 mCount = new SpinBox(1, MAX_COUNT, 1, mButtonGroup);
185 mCount->setFixedSize(mCount->sizeHint());
186 mCount->setLineShiftStep(10);
187 mCount->setSelectOnStep(false);
188 connect(mCount, TQ_SIGNAL(valueChanged(int)), TQ_SLOT(countChanged(int)));
189 TQWhatsThis::add(mCount,
190 i18n("Enter the number of times to trigger the alarm after its initial occurrence"));
191 layout->addWidget(mCount);
192 mCountButton->setFocusWidget(mCount);
193 layout->addStretch();
194
195 layout = new TQHBoxLayout(vlayout, spacing);
196 mDurationButton = new RadioButton(i18n("&Duration:"), mButtonGroup);
197 mDurationButton->setFixedSize(mDurationButton->sizeHint());
198 TQWhatsThis::add(mDurationButton,
199 i18n("Check to specify how long the alarm is to be repeated"));
200 layout->addWidget(mDurationButton);
201 mDuration = new TimePeriod(true, mButtonGroup);
202 mDuration->setFixedSize(mDuration->sizeHint());
203 connect(mDuration, TQ_SIGNAL(valueChanged(int)), TQ_SLOT(durationChanged(int)));
204 TQWhatsThis::add(mDuration,
205 i18n("Enter the length of time to repeat the alarm"));
206 layout->addWidget(mDuration);
207 mDurationButton->setFocusWidget(mDuration);
208 layout->addStretch();
209
210 mCountButton->setChecked(true);
211 repetitionToggled(false);
212 setReadOnly(mReadOnly);
213}
214
215/******************************************************************************
216* Set the state of all controls to reflect the data in the specified alarm.
217*/
218void RepetitionDlg::set(int interval, int count, bool dateOnly, int maxDuration)
219{
220 if (!interval)
221 count = 0;
222 else if (!count)
223 interval = 0;
224 if (dateOnly != mDateOnly)
225 {
226 mDateOnly = dateOnly;
227 mTimeSelector->setDateOnly(mDateOnly);
228 mDuration->setDateOnly(mDateOnly);
229 }
230 mMaxDuration = maxDuration;
231 if (mMaxDuration)
232 {
233 int maxhm = (mMaxDuration > 0) ? mMaxDuration : 9999;
234 int maxdw = (mMaxDuration > 0) ? mMaxDuration / 1440 : 9999;
235 mTimeSelector->setMaximum(maxhm, maxdw);
236 mDuration->setMaximum(maxhm, maxdw);
237 }
238 // Set the units - needed later if the control is unchecked initially.
239 TimePeriod::Units units = mDateOnly ? TimePeriod::DAYS : TimePeriod::HOURS_MINUTES;
240 mTimeSelector->setMinutes(interval, mDateOnly, units);
241 if (!mMaxDuration || !count)
242 mTimeSelector->setChecked(false);
243 else
244 {
245 bool on = mTimeSelector->isChecked();
246 repetitionToggled(on); // enable/disable controls
247 if (on)
248 intervalChanged(interval); // ensure mCount range is set
249 mCount->setValue(count);
250 mDuration->setMinutes(count * interval, mDateOnly, units);
251 mCountButton->setChecked(true);
252 }
253 mTimeSelector->setEnabled(mMaxDuration);
254}
255
256/******************************************************************************
257* Set the read-only status.
258*/
259void RepetitionDlg::setReadOnly(bool ro)
260{
261 ro = ro || mReadOnly;
262 mTimeSelector->setReadOnly(ro);
263 mCountButton->setReadOnly(ro);
264 mCount->setReadOnly(ro);
265 mDurationButton->setReadOnly(ro);
266 mDuration->setReadOnly(ro);
267}
268
269/******************************************************************************
270* Get the period between repetitions in minutes.
271*/
272int RepetitionDlg::interval() const
273{
274 return mTimeSelector->minutes();
275}
276
277/******************************************************************************
278* Set the entered repeat count.
279*/
280int RepetitionDlg::count() const
281{
282 int interval = mTimeSelector->minutes();
283 if (interval)
284 {
285 if (mCountButton->isOn())
286 return mCount->value();
287 if (mDurationButton->isOn())
288 return mDuration->minutes() / interval;
289 }
290 return 0; // no repetition
291}
292
293/******************************************************************************
294* Called when the time interval widget has changed value.
295* Adjust the maximum repetition count accordingly.
296*/
297void RepetitionDlg::intervalChanged(int minutes)
298{
299 if (mTimeSelector->isChecked() && minutes > 0)
300 {
301 mCount->setRange(1, (mMaxDuration >= 0 ? mMaxDuration / minutes : MAX_COUNT));
302 if (mCountButton->isOn())
303 countChanged(mCount->value());
304 else
305 durationChanged(mDuration->minutes());
306 }
307}
308
309/******************************************************************************
310* Called when the count spinbox has changed value.
311* Adjust the duration accordingly.
312*/
313void RepetitionDlg::countChanged(int count)
314{
315 int interval = mTimeSelector->minutes();
316 if (interval)
317 {
318 bool blocked = mDuration->signalsBlocked();
319 mDuration->blockSignals(true);
320 mDuration->setMinutes(count * interval, mDateOnly,
321 (mDateOnly ? TimePeriod::DAYS : TimePeriod::HOURS_MINUTES));
322 mDuration->blockSignals(blocked);
323 }
324}
325
326/******************************************************************************
327* Called when the duration widget has changed value.
328* Adjust the count accordingly.
329*/
330void RepetitionDlg::durationChanged(int minutes)
331{
332 int interval = mTimeSelector->minutes();
333 if (interval)
334 {
335 bool blocked = mCount->signalsBlocked();
336 mCount->blockSignals(true);
337 mCount->setValue(minutes / interval);
338 mCount->blockSignals(blocked);
339 }
340}
341
342/******************************************************************************
343* Called when the time period widget is toggled on or off.
344*/
345void RepetitionDlg::repetitionToggled(bool on)
346{
347 if (mMaxDuration == 0)
348 on = false;
349 mButtonGroup->setEnabled(on);
350 mCount->setEnabled(on && mCountButton->isOn());
351 mDuration->setEnabled(on && mDurationButton->isOn());
352}
353
354/******************************************************************************
355* Called when one of the count or duration radio buttons is toggled.
356*/
357void RepetitionDlg::typeClicked()
358{
359 if (mTimeSelector->isChecked())
360 {
361 mCount->setEnabled(mCountButton->isOn());
362 mDuration->setEnabled(mDurationButton->isOn());
363 }
364}