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 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*/
211void 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*/
224void 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*/
289TQValueList<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*/
337void BirthdayDlg::slotOk()
338{
339 // Save prefix and suffix texts to use as future defaults
340 TDEConfig* config = tdeApp->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*/
358void 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*/
375void 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
393AddresseeItem::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
402TQString 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
414BListView::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