kalarm

birthdaydlg.cpp
1 /*
2  * birthdaydlg.cpp - dialog to pick birthdays from address book
3  * Program: kalarm
4  * Copyright © 2002-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 <tqgroupbox.h>
25 #include <tqhbox.h>
26 #include <tqlabel.h>
27 #include <tqlineedit.h>
28 #include <tqwhatsthis.h>
29 
30 #include <tdelocale.h>
31 #include <tdeglobal.h>
32 #include <tdeconfig.h>
33 #include <tdemessagebox.h>
34 #include <tdeaccel.h>
35 #include <tdeabc/addressbook.h>
36 #include <tdeabc/stdaddressbook.h>
37 #include <kdebug.h>
38 
39 #include "alarmcalendar.h"
40 #include "checkbox.h"
41 #include "colourcombo.h"
42 #include "editdlg.h"
43 #include "fontcolourbutton.h"
44 #include "kalarmapp.h"
45 #include "latecancel.h"
46 #include "preferences.h"
47 #include "reminder.h"
48 #include "repetition.h"
49 #include "shellprocess.h"
50 #include "soundpicker.h"
51 #include "specialactions.h"
52 #include "birthdaydlg.moc"
53 
54 using namespace KCal;
55 
56 
57 class AddresseeItem : public TQListViewItem
58 {
59  public:
60  enum columns { NAME = 0, BIRTHDAY = 1 };
61  AddresseeItem(TQListView* parent, const TQString& name, const TQDate& birthday);
62  TQDate birthday() const { return mBirthday; }
63  virtual TQString key(int column, bool ascending) const;
64  private:
65  TQDate mBirthday;
66  TQString mBirthdayOrder;
67 };
68 
69 
70 const TDEABC::AddressBook* BirthdayDlg::mAddressBook = 0;
71 
72 
73 BirthdayDlg::BirthdayDlg(TQWidget* parent)
74  : KDialogBase(KDialogBase::Plain, i18n("Import Birthdays From KAddressBook"), Ok|Cancel, Ok, parent, "BirthdayDlg"),
75  mSpecialActionsButton(0)
76 {
77  TQWidget* topWidget = plainPage();
78  TQBoxLayout* topLayout = new TQVBoxLayout(topWidget);
79  topLayout->setSpacing(spacingHint());
80 
81  // Prefix and suffix to the name in the alarm text
82  // Get default prefix and suffix texts from config file
83  TDEConfig* config = kapp->config();
84  config->setGroup(TQString::fromLatin1("General"));
85  mPrefixText = config->readEntry(TQString::fromLatin1("BirthdayPrefix"), i18n("Birthday: "));
86  mSuffixText = config->readEntry(TQString::fromLatin1("BirthdaySuffix"));
87 
88  TQGroupBox* textGroup = new TQGroupBox(2, TQt::Horizontal, i18n("Alarm Text"), topWidget);
89  topLayout->addWidget(textGroup);
90  TQLabel* label = new TQLabel(i18n("Pre&fix:"), textGroup);
91  mPrefix = new BLineEdit(mPrefixText, textGroup);
92  mPrefix->setMinimumSize(mPrefix->sizeHint());
93  label->setBuddy(mPrefix);
94  connect(mPrefix, TQ_SIGNAL(focusLost()), TQ_SLOT(slotTextLostFocus()));
95  TQWhatsThis::add(mPrefix,
96  i18n("Enter text to appear before the person's name in the alarm message, "
97  "including any necessary trailing spaces."));
98 
99  label = new TQLabel(i18n("S&uffix:"), textGroup);
100  mSuffix = new BLineEdit(mSuffixText, textGroup);
101  mSuffix->setMinimumSize(mSuffix->sizeHint());
102  label->setBuddy(mSuffix);
103  connect(mSuffix, TQ_SIGNAL(focusLost()), TQ_SLOT(slotTextLostFocus()));
104  TQWhatsThis::add(mSuffix,
105  i18n("Enter text to appear after the person's name in the alarm message, "
106  "including any necessary leading spaces."));
107 
108  TQGroupBox* group = new TQGroupBox(1, TQt::Horizontal, i18n("Select Birthdays"), topWidget);
109  topLayout->addWidget(group);
110  mAddresseeList = new BListView(group);
111  mAddresseeList->setMultiSelection(true);
112  mAddresseeList->setSelectionMode(TQListView::Extended);
113  mAddresseeList->setAllColumnsShowFocus(true);
114  mAddresseeList->setFullWidth(true);
115  mAddresseeList->addColumn(i18n("Name"));
116  mAddresseeList->addColumn(i18n("Birthday"));
117  connect(mAddresseeList, TQ_SIGNAL(selectionChanged()), TQ_SLOT(slotSelectionChanged()));
118  TQWhatsThis::add(mAddresseeList,
119  i18n("Select birthdays to set alarms for.\n"
120  "This list shows all birthdays in KAddressBook except those for which alarms already exist.\n\n"
121  "You can select multiple birthdays at one time by dragging the mouse over the list, "
122  "or by clicking the mouse while pressing Ctrl or Shift."));
123 
124  group = new TQGroupBox(i18n("Alarm Configuration"), topWidget);
125  topLayout->addWidget(group);
126  TQBoxLayout* groupLayout = new TQVBoxLayout(group, marginHint(), spacingHint());
127  groupLayout->addSpacing(fontMetrics().lineSpacing()/2);
128 
129  // Font and colour choice button and sample text
130  mFontColourButton = new FontColourButton(group);
131  mFontColourButton->setMaximumHeight(mFontColourButton->sizeHint().height() * 3/2);
132  groupLayout->addWidget(mFontColourButton);
133 
134  // Sound checkbox and file selector
135  mSoundPicker = new SoundPicker(group);
136  mSoundPicker->setFixedSize(mSoundPicker->sizeHint());
137  groupLayout->addWidget(mSoundPicker, 0, TQt::AlignAuto);
138 
139  // How much to advance warning to give
140  mReminder = new Reminder(i18n("&Reminder"),
141  i18n("Check to display a reminder in advance of the birthday."),
142  i18n("Enter the number of days before each birthday to display a reminder. "
143  "This is in addition to the alarm which is displayed on the birthday."),
144  false, false, group);
145  mReminder->setFixedSize(mReminder->sizeHint());
146  mReminder->setMaximum(0, 364);
147  mReminder->setMinutes(0, true);
148  groupLayout->addWidget(mReminder, 0, TQt::AlignAuto);
149 
150  // Acknowledgement confirmation required - default = no confirmation
151  TQHBoxLayout* layout = new TQHBoxLayout(groupLayout, 2*spacingHint());
152  mConfirmAck = EditAlarmDlg::createConfirmAckCheckbox(group);
153  layout->addWidget(mConfirmAck);
154  layout->addSpacing(2*spacingHint());
155  layout->addStretch();
156 
157  if (ShellProcess::authorised()) // don't display if shell commands not allowed (e.g. kiosk mode)
158  {
159  // Special actions button
160  mSpecialActionsButton = new SpecialActionsButton(i18n("Special Actions..."), group);
161  layout->addWidget(mSpecialActionsButton);
162  }
163 
164  // Late display checkbox - default = allow late display
165  layout = new TQHBoxLayout(groupLayout, 2*spacingHint());
166  mLateCancel = new LateCancelSelector(false, group);
167  layout->addWidget(mLateCancel);
168  layout->addStretch();
169 
170  // Sub-repetition button
171  mSubRepetition = new RepetitionButton(i18n("Sub-Repetition"), false, group);
172  mSubRepetition->set(0, 0, true, 364*24*60);
173  TQWhatsThis::add(mSubRepetition, i18n("Set up an additional alarm repetition"));
174  layout->addWidget(mSubRepetition);
175 
176  // Set the values to their defaults
177  mFontColourButton->setDefaultFont();
178  mFontColourButton->setBgColour(Preferences::defaultBgColour());
179  mFontColourButton->setFgColour(Preferences::defaultFgColour()); // set colour before setting alarm type buttons
180  mLateCancel->setMinutes(Preferences::defaultLateCancel(), true, TimePeriod::DAYS);
181  mConfirmAck->setChecked(Preferences::defaultConfirmAck());
182  mSoundPicker->set(Preferences::defaultSoundType(), Preferences::defaultSoundFile(),
183  Preferences::defaultSoundVolume(), -1, 0, Preferences::defaultSoundRepeat());
184  if (mSpecialActionsButton)
185  mSpecialActionsButton->setActions(Preferences::defaultPreAction(), Preferences::defaultPostAction());
186 
187  // Initialise the birthday selection list and disable the OK button
188  loadAddressBook();
189 }
190 
191 /******************************************************************************
192 * Load the address book in preparation for displaying the birthday selection list.
193 */
194 void BirthdayDlg::loadAddressBook()
195 {
196  if (!mAddressBook)
197  {
198  mAddressBook = TDEABC::StdAddressBook::self(true);
199  if (mAddressBook)
200  connect(mAddressBook, TQ_SIGNAL(addressBookChanged(AddressBook*)), TQ_SLOT(updateSelectionList()));
201  }
202  else
203  updateSelectionList();
204  if (!mAddressBook)
205  KMessageBox::error(this, i18n("Error reading address book"));
206 }
207 
208 /******************************************************************************
209 * Close the address book.This is called at program termination.
210 */
211 void BirthdayDlg::close()
212 {
213  if (mAddressBook)
214  {
215  TDEABC::StdAddressBook::close();
216  mAddressBook = 0;
217  }
218 }
219 
220 /******************************************************************************
221 * Initialise or update the birthday selection list by fetching all birthdays
222 * from the address book and displaying those which do not already have alarms.
223 */
224 void BirthdayDlg::updateSelectionList()
225 {
226  // Compile a list of all pending alarm messages which look like birthdays
227  TQStringList messageList;
228  KAEvent event;
229  Event::List events = AlarmCalendar::activeCalendar()->events();
230  for (Event::List::ConstIterator it = events.begin(); it != events.end(); ++it)
231  {
232  Event* kcalEvent = *it;
233  event.set(*kcalEvent);
234  if (event.action() == KAEvent::MESSAGE
235  && event.recurType() == KARecurrence::ANNUAL_DATE
236  && (mPrefixText.isEmpty() || event.message().startsWith(mPrefixText)))
237  messageList.append(event.message());
238  }
239 
240  // Fetch all birthdays from the address book
241  for (TDEABC::AddressBook::ConstIterator abit = mAddressBook->begin(); abit != mAddressBook->end(); ++abit)
242  {
243  const TDEABC::Addressee& addressee = *abit;
244  if (addressee.birthday().isValid())
245  {
246  // Create a list entry for this birthday
247  TQDate birthday = addressee.birthday().date();
248  TQString name = addressee.nickName();
249  if (name.isEmpty())
250  name = addressee.realName();
251  // Check if the birthday already has an alarm
252  TQString text = mPrefixText + name + mSuffixText;
253  bool alarmExists = (messageList.find(text) != messageList.end());
254  // Check if the birthday is already in the selection list
255  bool inSelectionList = false;
256  AddresseeItem* item = 0;
257  for (TQListViewItem* qitem = mAddresseeList->firstChild(); qitem; qitem = qitem->nextSibling())
258  {
259  item = dynamic_cast<AddresseeItem*>(qitem);
260  if (item && item->text(AddresseeItem::NAME) == name && item->birthday() == birthday)
261  {
262  inSelectionList = true;
263  break;
264  }
265  }
266 
267  if (alarmExists && inSelectionList)
268  delete item; // alarm exists, so remove from selection list
269  else if (!alarmExists && !inSelectionList)
270  new AddresseeItem(mAddresseeList, name, birthday); // add to list
271  }
272  }
273 // mAddresseeList->setUpdatesEnabled(true);
274 
275  // Enable/disable OK button according to whether anything is currently selected
276  bool selection = false;
277  for (TQListViewItem* item = mAddresseeList->firstChild(); item; item = item->nextSibling())
278  if (mAddresseeList->isSelected(item))
279  {
280  selection = true;
281  break;
282  }
283  enableButtonOK(selection);
284 }
285 
286 /******************************************************************************
287 * Return a list of events for birthdays chosen.
288 */
289 TQValueList<KAEvent> BirthdayDlg::events() const
290 {
291  TQValueList<KAEvent> list;
292  TQDate today = TQDate::currentDate();
293  TQDateTime todayNoon(today, TQTime(12, 0, 0));
294  int thisYear = today.year();
295  int reminder = mReminder->minutes();
296 
297  for (TQListViewItem* item = mAddresseeList->firstChild(); item; item = item->nextSibling())
298  {
299  if (mAddresseeList->isSelected(item))
300  {
301  AddresseeItem* aItem = dynamic_cast<AddresseeItem*>(item);
302  if (aItem)
303  {
304  TQDate date = aItem->birthday();
305  date.setYMD(thisYear, date.month(), date.day());
306  if (date <= today)
307  date.setYMD(thisYear + 1, date.month(), date.day());
308  KAEvent event(date,
309  mPrefix->text() + aItem->text(AddresseeItem::NAME) + mSuffix->text(),
310  mFontColourButton->bgColour(), mFontColourButton->fgColour(),
311  mFontColourButton->font(), KAEvent::MESSAGE, mLateCancel->minutes(),
312  mFlags);
313  float fadeVolume;
314  int fadeSecs;
315  float volume = mSoundPicker->volume(fadeVolume, fadeSecs);
316  event.setAudioFile(mSoundPicker->file(), volume, fadeVolume, fadeSecs);
317  TQValueList<int> months;
318  months.append(date.month());
319  event.setRecurAnnualByDate(1, months, 0, Preferences::defaultFeb29Type(), -1, TQDate());
320  event.setRepetition(mSubRepetition->interval(), mSubRepetition->count());
321  event.setNextOccurrence(todayNoon);
322  if (reminder)
323  event.setReminder(reminder, false);
324  if (mSpecialActionsButton)
325  event.setActions(mSpecialActionsButton->preAction(),
326  mSpecialActionsButton->postAction());
327  list.append(event);
328  }
329  }
330  }
331  return list;
332 }
333 
334 /******************************************************************************
335 * Called when the OK button is selected to import the selected birthdays.
336 */
337 void BirthdayDlg::slotOk()
338 {
339  // Save prefix and suffix texts to use as future defaults
340  TDEConfig* config = kapp->config();
341  config->setGroup(TQString::fromLatin1("General"));
342  config->writeEntry(TQString::fromLatin1("BirthdayPrefix"), mPrefix->text());
343  config->writeEntry(TQString::fromLatin1("BirthdaySuffix"), mSuffix->text());
344  config->sync();
345 
346  mFlags = (mSoundPicker->sound() == SoundPicker::BEEP ? KAEvent::BEEP : 0)
347  | (mSoundPicker->repeat() ? KAEvent::REPEAT_SOUND : 0)
348  | (mConfirmAck->isChecked() ? KAEvent::CONFIRM_ACK : 0)
349  | (mFontColourButton->defaultFont() ? KAEvent::DEFAULT_FONT : 0)
350  | KAEvent::ANY_TIME;
351  KDialogBase::slotOk();
352 }
353 
354 /******************************************************************************
355 * Called when the group of items selected changes.
356 * Enable/disable the OK button depending on whether anything is selected.
357 */
358 void BirthdayDlg::slotSelectionChanged()
359 {
360  for (TQListViewItem* item = mAddresseeList->firstChild(); item; item = item->nextSibling())
361  if (mAddresseeList->isSelected(item))
362  {
363  enableButtonOK(true);
364  return;
365  }
366  enableButtonOK(false);
367 
368 }
369 
370 /******************************************************************************
371 * Called when the prefix or suffix text has lost keyboard focus.
372 * If the text has changed, re-evaluates the selection list according to the new
373 * birthday alarm text format.
374 */
375 void BirthdayDlg::slotTextLostFocus()
376 {
377  TQString prefix = mPrefix->text();
378  TQString suffix = mSuffix->text();
379  if (prefix != mPrefixText || suffix != mSuffixText)
380  {
381  // Text has changed - re-evaluate the selection list
382  mPrefixText = prefix;
383  mSuffixText = suffix;
384  loadAddressBook();
385  }
386 }
387 
388 
389 /*=============================================================================
390 = Class: AddresseeItem
391 =============================================================================*/
392 
393 AddresseeItem::AddresseeItem(TQListView* parent, const TQString& name, const TQDate& birthday)
394  : TQListViewItem(parent),
395  mBirthday(birthday)
396 {
397  setText(NAME, name);
398  setText(BIRTHDAY, TDEGlobal::locale()->formatDate(mBirthday, true));
399  mBirthdayOrder.sprintf("%04d%03d", mBirthday.year(), mBirthday.dayOfYear());
400 }
401 
402 TQString AddresseeItem::key(int column, bool) const
403 {
404  if (column == BIRTHDAY)
405  return mBirthdayOrder;
406  return text(column).lower();
407 }
408 
409 
410 /*=============================================================================
411 = Class: BListView
412 =============================================================================*/
413 
414 BListView::BListView(TQWidget* parent, const char* name)
415  : TDEListView(parent, name)
416 {
417  TDEAccel* accel = new TDEAccel(this);
418  accel->insert(TDEStdAccel::SelectAll, this, TQ_SLOT(slotSelectAll()));
419  accel->insert(TDEStdAccel::Deselect, this, TQ_SLOT(slotDeselect()));
420  accel->readSettings();
421 }
KAEvent corresponds to a KCal::Event instance.
Definition: alarmevent.h:232
the KAlarm application object