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 
43 RepetitionButton::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 
58 void 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 */
68 void 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 */
82 void 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 */
97 void 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 */
121 void 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 
149 static const int MAX_COUNT = 9999; // maximum range for count spinbox
150 
151 
152 RepetitionDlg::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 */
218 void 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 */
259 void 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 */
272 int RepetitionDlg::interval() const
273 {
274  return mTimeSelector->minutes();
275 }
276 
277 /******************************************************************************
278 * Set the entered repeat count.
279 */
280 int 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 */
297 void 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 */
313 void 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 */
330 void 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 */
345 void 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 */
357 void RepetitionDlg::typeClicked()
358 {
359  if (mTimeSelector->isChecked())
360  {
361  mCount->setEnabled(mCountButton->isOn());
362  mDuration->setEnabled(mDurationButton->isOn());
363  }
364 }