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 #if KDE_IS_VERSION(3,1,90)
199  mAddressBook = TDEABC::StdAddressBook::self(true);
200  if (mAddressBook)
201  connect(mAddressBook, TQ_SIGNAL(addressBookChanged(AddressBook*)), TQ_SLOT(updateSelectionList()));
202 #else
203  mAddressBook = TDEABC::StdAddressBook::self();
204  if (mAddressBook)
205  updateSelectionList();
206 #endif
207  }
208  else
209  updateSelectionList();
210  if (!mAddressBook)
211  KMessageBox::error(this, i18n("Error reading address book"));
212 }
213 
214 /******************************************************************************
215 * Close the address book.This is called at program termination.
216 */
217 void BirthdayDlg::close()
218 {
219  if (mAddressBook)
220  {
221  TDEABC::StdAddressBook::close();
222  mAddressBook = 0;
223  }
224 }
225 
226 /******************************************************************************
227 * Initialise or update the birthday selection list by fetching all birthdays
228 * from the address book and displaying those which do not already have alarms.
229 */
230 void BirthdayDlg::updateSelectionList()
231 {
232  // Compile a list of all pending alarm messages which look like birthdays
233  TQStringList messageList;
234  KAEvent event;
235  Event::List events = AlarmCalendar::activeCalendar()->events();
236  for (Event::List::ConstIterator it = events.begin(); it != events.end(); ++it)
237  {
238  Event* kcalEvent = *it;
239  event.set(*kcalEvent);
240  if (event.action() == KAEvent::MESSAGE
241  && event.recurType() == KARecurrence::ANNUAL_DATE
242  && (mPrefixText.isEmpty() || event.message().startsWith(mPrefixText)))
243  messageList.append(event.message());
244  }
245 
246  // Fetch all birthdays from the address book
247  for (TDEABC::AddressBook::ConstIterator abit = mAddressBook->begin(); abit != mAddressBook->end(); ++abit)
248  {
249  const TDEABC::Addressee& addressee = *abit;
250  if (addressee.birthday().isValid())
251  {
252  // Create a list entry for this birthday
253  TQDate birthday = addressee.birthday().date();
254  TQString name = addressee.nickName();
255  if (name.isEmpty())
256  name = addressee.realName();
257  // Check if the birthday already has an alarm
258  TQString text = mPrefixText + name + mSuffixText;
259  bool alarmExists = (messageList.find(text) != messageList.end());
260  // Check if the birthday is already in the selection list
261  bool inSelectionList = false;
262  AddresseeItem* item = 0;
263  for (TQListViewItem* qitem = mAddresseeList->firstChild(); qitem; qitem = qitem->nextSibling())
264  {
265  item = dynamic_cast<AddresseeItem*>(qitem);
266  if (item && item->text(AddresseeItem::NAME) == name && item->birthday() == birthday)
267  {
268  inSelectionList = true;
269  break;
270  }
271  }
272 
273  if (alarmExists && inSelectionList)
274  delete item; // alarm exists, so remove from selection list
275  else if (!alarmExists && !inSelectionList)
276  new AddresseeItem(mAddresseeList, name, birthday); // add to list
277  }
278  }
279 // mAddresseeList->setUpdatesEnabled(true);
280 
281  // Enable/disable OK button according to whether anything is currently selected
282  bool selection = false;
283  for (TQListViewItem* item = mAddresseeList->firstChild(); item; item = item->nextSibling())
284  if (mAddresseeList->isSelected(item))
285  {
286  selection = true;
287  break;
288  }
289  enableButtonOK(selection);
290 }
291 
292 /******************************************************************************
293 * Return a list of events for birthdays chosen.
294 */
295 TQValueList<KAEvent> BirthdayDlg::events() const
296 {
297  TQValueList<KAEvent> list;
298  TQDate today = TQDate::currentDate();
299  TQDateTime todayNoon(today, TQTime(12, 0, 0));
300  int thisYear = today.year();
301  int reminder = mReminder->minutes();
302 
303  for (TQListViewItem* item = mAddresseeList->firstChild(); item; item = item->nextSibling())
304  {
305  if (mAddresseeList->isSelected(item))
306  {
307  AddresseeItem* aItem = dynamic_cast<AddresseeItem*>(item);
308  if (aItem)
309  {
310  TQDate date = aItem->birthday();
311  date.setYMD(thisYear, date.month(), date.day());
312  if (date <= today)
313  date.setYMD(thisYear + 1, date.month(), date.day());
314  KAEvent event(date,
315  mPrefix->text() + aItem->text(AddresseeItem::NAME) + mSuffix->text(),
316  mFontColourButton->bgColour(), mFontColourButton->fgColour(),
317  mFontColourButton->font(), KAEvent::MESSAGE, mLateCancel->minutes(),
318  mFlags);
319  float fadeVolume;
320  int fadeSecs;
321  float volume = mSoundPicker->volume(fadeVolume, fadeSecs);
322  event.setAudioFile(mSoundPicker->file(), volume, fadeVolume, fadeSecs);
323  TQValueList<int> months;
324  months.append(date.month());
325  event.setRecurAnnualByDate(1, months, 0, Preferences::defaultFeb29Type(), -1, TQDate());
326  event.setRepetition(mSubRepetition->interval(), mSubRepetition->count());
327  event.setNextOccurrence(todayNoon);
328  if (reminder)
329  event.setReminder(reminder, false);
330  if (mSpecialActionsButton)
331  event.setActions(mSpecialActionsButton->preAction(),
332  mSpecialActionsButton->postAction());
333  list.append(event);
334  }
335  }
336  }
337  return list;
338 }
339 
340 /******************************************************************************
341 * Called when the OK button is selected to import the selected birthdays.
342 */
343 void BirthdayDlg::slotOk()
344 {
345  // Save prefix and suffix texts to use as future defaults
346  TDEConfig* config = kapp->config();
347  config->setGroup(TQString::fromLatin1("General"));
348  config->writeEntry(TQString::fromLatin1("BirthdayPrefix"), mPrefix->text());
349  config->writeEntry(TQString::fromLatin1("BirthdaySuffix"), mSuffix->text());
350  config->sync();
351 
352  mFlags = (mSoundPicker->sound() == SoundPicker::BEEP ? KAEvent::BEEP : 0)
353  | (mSoundPicker->repeat() ? KAEvent::REPEAT_SOUND : 0)
354  | (mConfirmAck->isChecked() ? KAEvent::CONFIRM_ACK : 0)
355  | (mFontColourButton->defaultFont() ? KAEvent::DEFAULT_FONT : 0)
356  | KAEvent::ANY_TIME;
357  KDialogBase::slotOk();
358 }
359 
360 /******************************************************************************
361 * Called when the group of items selected changes.
362 * Enable/disable the OK button depending on whether anything is selected.
363 */
364 void BirthdayDlg::slotSelectionChanged()
365 {
366  for (TQListViewItem* item = mAddresseeList->firstChild(); item; item = item->nextSibling())
367  if (mAddresseeList->isSelected(item))
368  {
369  enableButtonOK(true);
370  return;
371  }
372  enableButtonOK(false);
373 
374 }
375 
376 /******************************************************************************
377 * Called when the prefix or suffix text has lost keyboard focus.
378 * If the text has changed, re-evaluates the selection list according to the new
379 * birthday alarm text format.
380 */
381 void BirthdayDlg::slotTextLostFocus()
382 {
383  TQString prefix = mPrefix->text();
384  TQString suffix = mSuffix->text();
385  if (prefix != mPrefixText || suffix != mSuffixText)
386  {
387  // Text has changed - re-evaluate the selection list
388  mPrefixText = prefix;
389  mSuffixText = suffix;
390  loadAddressBook();
391  }
392 }
393 
394 
395 /*=============================================================================
396 = Class: AddresseeItem
397 =============================================================================*/
398 
399 AddresseeItem::AddresseeItem(TQListView* parent, const TQString& name, const TQDate& birthday)
400  : TQListViewItem(parent),
401  mBirthday(birthday)
402 {
403  setText(NAME, name);
404  setText(BIRTHDAY, TDEGlobal::locale()->formatDate(mBirthday, true));
405  mBirthdayOrder.sprintf("%04d%03d", mBirthday.year(), mBirthday.dayOfYear());
406 }
407 
408 TQString AddresseeItem::key(int column, bool) const
409 {
410  if (column == BIRTHDAY)
411  return mBirthdayOrder;
412  return text(column).lower();
413 }
414 
415 
416 /*=============================================================================
417 = Class: BListView
418 =============================================================================*/
419 
420 BListView::BListView(TQWidget* parent, const char* name)
421  : TDEListView(parent, name)
422 {
423  TDEAccel* accel = new TDEAccel(this);
424  accel->insert(TDEStdAccel::SelectAll, this, TQ_SLOT(slotSelectAll()));
425  accel->insert(TDEStdAccel::Deselect, this, TQ_SLOT(slotDeselect()));
426  accel->readSettings();
427 }
KAEvent corresponds to a KCal::Event instance.
Definition: alarmevent.h:232
the KAlarm application object