birthdaydlg.cpp
00001 /* 00002 * birthdaydlg.cpp - dialog to pick birthdays from address book 00003 * Program: kalarm 00004 * Copyright © 2002-2008 by David Jarvie <djarvie@kde.org> 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License along 00017 * with this program; if not, write to the Free Software Foundation, Inc., 00018 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00019 */ 00020 00021 #include "kalarm.h" 00022 00023 #include <tqlayout.h> 00024 #include <tqgroupbox.h> 00025 #include <tqhbox.h> 00026 #include <tqlabel.h> 00027 #include <tqlineedit.h> 00028 #include <tqwhatsthis.h> 00029 00030 #include <klocale.h> 00031 #include <kglobal.h> 00032 #include <kconfig.h> 00033 #include <kmessagebox.h> 00034 #include <kaccel.h> 00035 #include <kabc/addressbook.h> 00036 #include <kabc/stdaddressbook.h> 00037 #include <kdebug.h> 00038 00039 #include "alarmcalendar.h" 00040 #include "checkbox.h" 00041 #include "colourcombo.h" 00042 #include "editdlg.h" 00043 #include "fontcolourbutton.h" 00044 #include "kalarmapp.h" 00045 #include "latecancel.h" 00046 #include "preferences.h" 00047 #include "reminder.h" 00048 #include "repetition.h" 00049 #include "shellprocess.h" 00050 #include "soundpicker.h" 00051 #include "specialactions.h" 00052 #include "birthdaydlg.moc" 00053 00054 using namespace KCal; 00055 00056 00057 class AddresseeItem : public TQListViewItem 00058 { 00059 public: 00060 enum columns { NAME = 0, BIRTHDAY = 1 }; 00061 AddresseeItem(TQListView* parent, const TQString& name, const TQDate& birthday); 00062 TQDate birthday() const { return mBirthday; } 00063 virtual TQString key(int column, bool ascending) const; 00064 private: 00065 TQDate mBirthday; 00066 TQString mBirthdayOrder; 00067 }; 00068 00069 00070 const KABC::AddressBook* BirthdayDlg::mAddressBook = 0; 00071 00072 00073 BirthdayDlg::BirthdayDlg(TQWidget* parent) 00074 : KDialogBase(KDialogBase::Plain, i18n("Import Birthdays From KAddressBook"), Ok|Cancel, Ok, parent, "BirthdayDlg"), 00075 mSpecialActionsButton(0) 00076 { 00077 TQWidget* topWidget = plainPage(); 00078 TQBoxLayout* topLayout = new TQVBoxLayout(topWidget); 00079 topLayout->setSpacing(spacingHint()); 00080 00081 // Prefix and suffix to the name in the alarm text 00082 // Get default prefix and suffix texts from config file 00083 KConfig* config = kapp->config(); 00084 config->setGroup(TQString::fromLatin1("General")); 00085 mPrefixText = config->readEntry(TQString::fromLatin1("BirthdayPrefix"), i18n("Birthday: ")); 00086 mSuffixText = config->readEntry(TQString::fromLatin1("BirthdaySuffix")); 00087 00088 TQGroupBox* textGroup = new TQGroupBox(2, Qt::Horizontal, i18n("Alarm Text"), topWidget); 00089 topLayout->addWidget(textGroup); 00090 TQLabel* label = new TQLabel(i18n("Pre&fix:"), textGroup); 00091 mPrefix = new BLineEdit(mPrefixText, textGroup); 00092 mPrefix->setMinimumSize(mPrefix->sizeHint()); 00093 label->setBuddy(mPrefix); 00094 connect(mPrefix, TQT_SIGNAL(focusLost()), TQT_SLOT(slotTextLostFocus())); 00095 TQWhatsThis::add(mPrefix, 00096 i18n("Enter text to appear before the person's name in the alarm message, " 00097 "including any necessary trailing spaces.")); 00098 00099 label = new TQLabel(i18n("S&uffix:"), textGroup); 00100 mSuffix = new BLineEdit(mSuffixText, textGroup); 00101 mSuffix->setMinimumSize(mSuffix->sizeHint()); 00102 label->setBuddy(mSuffix); 00103 connect(mSuffix, TQT_SIGNAL(focusLost()), TQT_SLOT(slotTextLostFocus())); 00104 TQWhatsThis::add(mSuffix, 00105 i18n("Enter text to appear after the person's name in the alarm message, " 00106 "including any necessary leading spaces.")); 00107 00108 TQGroupBox* group = new TQGroupBox(1, Qt::Horizontal, i18n("Select Birthdays"), topWidget); 00109 topLayout->addWidget(group); 00110 mAddresseeList = new BListView(group); 00111 mAddresseeList->setMultiSelection(true); 00112 mAddresseeList->setSelectionMode(TQListView::Extended); 00113 mAddresseeList->setAllColumnsShowFocus(true); 00114 mAddresseeList->setFullWidth(true); 00115 mAddresseeList->addColumn(i18n("Name")); 00116 mAddresseeList->addColumn(i18n("Birthday")); 00117 connect(mAddresseeList, TQT_SIGNAL(selectionChanged()), TQT_SLOT(slotSelectionChanged())); 00118 TQWhatsThis::add(mAddresseeList, 00119 i18n("Select birthdays to set alarms for.\n" 00120 "This list shows all birthdays in KAddressBook except those for which alarms already exist.\n\n" 00121 "You can select multiple birthdays at one time by dragging the mouse over the list, " 00122 "or by clicking the mouse while pressing Ctrl or Shift.")); 00123 00124 group = new TQGroupBox(i18n("Alarm Configuration"), topWidget); 00125 topLayout->addWidget(group); 00126 TQBoxLayout* groupLayout = new TQVBoxLayout(group, marginHint(), spacingHint()); 00127 groupLayout->addSpacing(fontMetrics().lineSpacing()/2); 00128 00129 // Font and colour choice button and sample text 00130 mFontColourButton = new FontColourButton(group); 00131 mFontColourButton->setMaximumHeight(mFontColourButton->sizeHint().height() * 3/2); 00132 groupLayout->addWidget(mFontColourButton); 00133 00134 // Sound checkbox and file selector 00135 mSoundPicker = new SoundPicker(group); 00136 mSoundPicker->setFixedSize(mSoundPicker->sizeHint()); 00137 groupLayout->addWidget(mSoundPicker, 0, TQt::AlignAuto); 00138 00139 // How much to advance warning to give 00140 mReminder = new Reminder(i18n("&Reminder"), 00141 i18n("Check to display a reminder in advance of the birthday."), 00142 i18n("Enter the number of days before each birthday to display a reminder. " 00143 "This is in addition to the alarm which is displayed on the birthday."), 00144 false, false, group); 00145 mReminder->setFixedSize(mReminder->sizeHint()); 00146 mReminder->setMaximum(0, 364); 00147 mReminder->setMinutes(0, true); 00148 groupLayout->addWidget(mReminder, 0, TQt::AlignAuto); 00149 00150 // Acknowledgement confirmation required - default = no confirmation 00151 TQHBoxLayout* layout = new TQHBoxLayout(groupLayout, 2*spacingHint()); 00152 mConfirmAck = EditAlarmDlg::createConfirmAckCheckbox(group); 00153 layout->addWidget(mConfirmAck); 00154 layout->addSpacing(2*spacingHint()); 00155 layout->addStretch(); 00156 00157 if (ShellProcess::authorised()) // don't display if shell commands not allowed (e.g. kiosk mode) 00158 { 00159 // Special actions button 00160 mSpecialActionsButton = new SpecialActionsButton(i18n("Special Actions..."), group); 00161 layout->addWidget(mSpecialActionsButton); 00162 } 00163 00164 // Late display checkbox - default = allow late display 00165 layout = new TQHBoxLayout(groupLayout, 2*spacingHint()); 00166 mLateCancel = new LateCancelSelector(false, group); 00167 layout->addWidget(mLateCancel); 00168 layout->addStretch(); 00169 00170 // Sub-repetition button 00171 mSubRepetition = new RepetitionButton(i18n("Sub-Repetition"), false, group); 00172 mSubRepetition->set(0, 0, true, 364*24*60); 00173 TQWhatsThis::add(mSubRepetition, i18n("Set up an additional alarm repetition")); 00174 layout->addWidget(mSubRepetition); 00175 00176 // Set the values to their defaults 00177 mFontColourButton->setDefaultFont(); 00178 mFontColourButton->setBgColour(Preferences::defaultBgColour()); 00179 mFontColourButton->setFgColour(Preferences::defaultFgColour()); // set colour before setting alarm type buttons 00180 mLateCancel->setMinutes(Preferences::defaultLateCancel(), true, TimePeriod::DAYS); 00181 mConfirmAck->setChecked(Preferences::defaultConfirmAck()); 00182 mSoundPicker->set(Preferences::defaultSoundType(), Preferences::defaultSoundFile(), 00183 Preferences::defaultSoundVolume(), -1, 0, Preferences::defaultSoundRepeat()); 00184 if (mSpecialActionsButton) 00185 mSpecialActionsButton->setActions(Preferences::defaultPreAction(), Preferences::defaultPostAction()); 00186 00187 // Initialise the birthday selection list and disable the OK button 00188 loadAddressBook(); 00189 } 00190 00191 /****************************************************************************** 00192 * Load the address book in preparation for displaying the birthday selection list. 00193 */ 00194 void BirthdayDlg::loadAddressBook() 00195 { 00196 if (!mAddressBook) 00197 { 00198 #if KDE_IS_VERSION(3,1,90) 00199 mAddressBook = KABC::StdAddressBook::self(true); 00200 if (mAddressBook) 00201 connect(mAddressBook, TQT_SIGNAL(addressBookChanged(AddressBook*)), TQT_SLOT(updateSelectionList())); 00202 #else 00203 mAddressBook = KABC::StdAddressBook::self(); 00204 if (mAddressBook) 00205 updateSelectionList(); 00206 #endif 00207 } 00208 else 00209 updateSelectionList(); 00210 if (!mAddressBook) 00211 KMessageBox::error(this, i18n("Error reading address book")); 00212 } 00213 00214 /****************************************************************************** 00215 * Close the address book.This is called at program termination. 00216 */ 00217 void BirthdayDlg::close() 00218 { 00219 if (mAddressBook) 00220 { 00221 KABC::StdAddressBook::close(); 00222 mAddressBook = 0; 00223 } 00224 } 00225 00226 /****************************************************************************** 00227 * Initialise or update the birthday selection list by fetching all birthdays 00228 * from the address book and displaying those which do not already have alarms. 00229 */ 00230 void BirthdayDlg::updateSelectionList() 00231 { 00232 // Compile a list of all pending alarm messages which look like birthdays 00233 TQStringList messageList; 00234 KAEvent event; 00235 Event::List events = AlarmCalendar::activeCalendar()->events(); 00236 for (Event::List::ConstIterator it = events.begin(); it != events.end(); ++it) 00237 { 00238 Event* kcalEvent = *it; 00239 event.set(*kcalEvent); 00240 if (event.action() == KAEvent::MESSAGE 00241 && event.recurType() == KARecurrence::ANNUAL_DATE 00242 && (mPrefixText.isEmpty() || event.message().startsWith(mPrefixText))) 00243 messageList.append(event.message()); 00244 } 00245 00246 // Fetch all birthdays from the address book 00247 for (KABC::AddressBook::ConstIterator abit = mAddressBook->begin(); abit != mAddressBook->end(); ++abit) 00248 { 00249 const KABC::Addressee& addressee = *abit; 00250 if (addressee.birthday().isValid()) 00251 { 00252 // Create a list entry for this birthday 00253 TQDate birthday = addressee.birthday().date(); 00254 TQString name = addressee.nickName(); 00255 if (name.isEmpty()) 00256 name = addressee.realName(); 00257 // Check if the birthday already has an alarm 00258 TQString text = mPrefixText + name + mSuffixText; 00259 bool alarmExists = (messageList.find(text) != messageList.end()); 00260 // Check if the birthday is already in the selection list 00261 bool inSelectionList = false; 00262 AddresseeItem* item = 0; 00263 for (TQListViewItem* qitem = mAddresseeList->firstChild(); qitem; qitem = qitem->nextSibling()) 00264 { 00265 item = dynamic_cast<AddresseeItem*>(qitem); 00266 if (item && item->text(AddresseeItem::NAME) == name && item->birthday() == birthday) 00267 { 00268 inSelectionList = true; 00269 break; 00270 } 00271 } 00272 00273 if (alarmExists && inSelectionList) 00274 delete item; // alarm exists, so remove from selection list 00275 else if (!alarmExists && !inSelectionList) 00276 new AddresseeItem(mAddresseeList, name, birthday); // add to list 00277 } 00278 } 00279 // mAddresseeList->setUpdatesEnabled(true); 00280 00281 // Enable/disable OK button according to whether anything is currently selected 00282 bool selection = false; 00283 for (TQListViewItem* item = mAddresseeList->firstChild(); item; item = item->nextSibling()) 00284 if (mAddresseeList->isSelected(item)) 00285 { 00286 selection = true; 00287 break; 00288 } 00289 enableButtonOK(selection); 00290 } 00291 00292 /****************************************************************************** 00293 * Return a list of events for birthdays chosen. 00294 */ 00295 TQValueList<KAEvent> BirthdayDlg::events() const 00296 { 00297 TQValueList<KAEvent> list; 00298 TQDate today = TQDate::currentDate(); 00299 TQDateTime todayNoon(today, TQTime(12, 0, 0)); 00300 int thisYear = today.year(); 00301 int reminder = mReminder->minutes(); 00302 00303 for (TQListViewItem* item = mAddresseeList->firstChild(); item; item = item->nextSibling()) 00304 { 00305 if (mAddresseeList->isSelected(item)) 00306 { 00307 AddresseeItem* aItem = dynamic_cast<AddresseeItem*>(item); 00308 if (aItem) 00309 { 00310 TQDate date = aItem->birthday(); 00311 date.setYMD(thisYear, date.month(), date.day()); 00312 if (date <= today) 00313 date.setYMD(thisYear + 1, date.month(), date.day()); 00314 KAEvent event(date, 00315 mPrefix->text() + aItem->text(AddresseeItem::NAME) + mSuffix->text(), 00316 mFontColourButton->bgColour(), mFontColourButton->fgColour(), 00317 mFontColourButton->font(), KAEvent::MESSAGE, mLateCancel->minutes(), 00318 mFlags); 00319 float fadeVolume; 00320 int fadeSecs; 00321 float volume = mSoundPicker->volume(fadeVolume, fadeSecs); 00322 event.setAudioFile(mSoundPicker->file(), volume, fadeVolume, fadeSecs); 00323 TQValueList<int> months; 00324 months.append(date.month()); 00325 event.setRecurAnnualByDate(1, months, 0, Preferences::defaultFeb29Type(), -1, TQDate()); 00326 event.setRepetition(mSubRepetition->interval(), mSubRepetition->count()); 00327 event.setNextOccurrence(todayNoon); 00328 if (reminder) 00329 event.setReminder(reminder, false); 00330 if (mSpecialActionsButton) 00331 event.setActions(mSpecialActionsButton->preAction(), 00332 mSpecialActionsButton->postAction()); 00333 list.append(event); 00334 } 00335 } 00336 } 00337 return list; 00338 } 00339 00340 /****************************************************************************** 00341 * Called when the OK button is selected to import the selected birthdays. 00342 */ 00343 void BirthdayDlg::slotOk() 00344 { 00345 // Save prefix and suffix texts to use as future defaults 00346 KConfig* config = kapp->config(); 00347 config->setGroup(TQString::fromLatin1("General")); 00348 config->writeEntry(TQString::fromLatin1("BirthdayPrefix"), mPrefix->text()); 00349 config->writeEntry(TQString::fromLatin1("BirthdaySuffix"), mSuffix->text()); 00350 config->sync(); 00351 00352 mFlags = (mSoundPicker->sound() == SoundPicker::BEEP ? KAEvent::BEEP : 0) 00353 | (mSoundPicker->repeat() ? KAEvent::REPEAT_SOUND : 0) 00354 | (mConfirmAck->isChecked() ? KAEvent::CONFIRM_ACK : 0) 00355 | (mFontColourButton->defaultFont() ? KAEvent::DEFAULT_FONT : 0) 00356 | KAEvent::ANY_TIME; 00357 KDialogBase::slotOk(); 00358 } 00359 00360 /****************************************************************************** 00361 * Called when the group of items selected changes. 00362 * Enable/disable the OK button depending on whether anything is selected. 00363 */ 00364 void BirthdayDlg::slotSelectionChanged() 00365 { 00366 for (TQListViewItem* item = mAddresseeList->firstChild(); item; item = item->nextSibling()) 00367 if (mAddresseeList->isSelected(item)) 00368 { 00369 enableButtonOK(true); 00370 return; 00371 } 00372 enableButtonOK(false); 00373 00374 } 00375 00376 /****************************************************************************** 00377 * Called when the prefix or suffix text has lost keyboard focus. 00378 * If the text has changed, re-evaluates the selection list according to the new 00379 * birthday alarm text format. 00380 */ 00381 void BirthdayDlg::slotTextLostFocus() 00382 { 00383 TQString prefix = mPrefix->text(); 00384 TQString suffix = mSuffix->text(); 00385 if (prefix != mPrefixText || suffix != mSuffixText) 00386 { 00387 // Text has changed - re-evaluate the selection list 00388 mPrefixText = prefix; 00389 mSuffixText = suffix; 00390 loadAddressBook(); 00391 } 00392 } 00393 00394 00395 /*============================================================================= 00396 = Class: AddresseeItem 00397 =============================================================================*/ 00398 00399 AddresseeItem::AddresseeItem(TQListView* parent, const TQString& name, const TQDate& birthday) 00400 : TQListViewItem(parent), 00401 mBirthday(birthday) 00402 { 00403 setText(NAME, name); 00404 setText(BIRTHDAY, KGlobal::locale()->formatDate(mBirthday, true)); 00405 mBirthdayOrder.sprintf("%04d%03d", mBirthday.year(), mBirthday.dayOfYear()); 00406 } 00407 00408 TQString AddresseeItem::key(int column, bool) const 00409 { 00410 if (column == BIRTHDAY) 00411 return mBirthdayOrder; 00412 return text(column).lower(); 00413 } 00414 00415 00416 /*============================================================================= 00417 = Class: BListView 00418 =============================================================================*/ 00419 00420 BListView::BListView(TQWidget* parent, const char* name) 00421 : KListView(parent, name) 00422 { 00423 KAccel* accel = new KAccel(this); 00424 accel->insert(KStdAccel::SelectAll, TQT_TQOBJECT(this), TQT_SLOT(slotSelectAll())); 00425 accel->insert(KStdAccel::Deselect, TQT_TQOBJECT(this), TQT_SLOT(slotDeselect())); 00426 accel->readSettings(); 00427 }