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
54using namespace KCal;
55
56
57class 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
70const TDEABC::AddressBook* BirthdayDlg::mAddressBook = 0;
71
72
73BirthdayDlg::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 = tdeApp->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*/
194void 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*/
217void 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*/
230void 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*/
295TQValueList<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*/
343void BirthdayDlg::slotOk()
344{
345 // Save prefix and suffix texts to use as future defaults
346 TDEConfig* config = tdeApp->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*/
364void 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*/
381void 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
399AddresseeItem::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
408TQString 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
420BListView::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