kalarm

birthdaydlg.cpp

00001 /*
00002  *  birthdaydlg.cpp  -  dialog to pick birthdays from address book
00003  *  Program:  kalarm
00004  *  Copyright © 2002-2006 by David Jarvie <software@astrojar.org.uk>
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 <qlayout.h>
00024 #include <qgroupbox.h>
00025 #include <qhbox.h>
00026 #include <qlabel.h>
00027 #include <qlineedit.h>
00028 #include <qwhatsthis.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 QListViewItem
00058 {
00059     public:
00060         enum columns { NAME = 0, BIRTHDAY = 1 };
00061         AddresseeItem(QListView* parent, const QString& name, const QDate& birthday);
00062         QDate birthday() const   { return mBirthday; }
00063         virtual QString key(int column, bool ascending) const;
00064     private:
00065         QDate     mBirthday;
00066         QString   mBirthdayOrder;
00067 };
00068 
00069 
00070 const KABC::AddressBook* BirthdayDlg::mAddressBook = 0;
00071 
00072 
00073 BirthdayDlg::BirthdayDlg(QWidget* parent)
00074     : KDialogBase(KDialogBase::Plain, i18n("Import Birthdays From KAddressBook"), Ok|Cancel, Ok, parent, "BirthdayDlg"),
00075       mSpecialActionsButton(0)
00076 {
00077     QWidget* topWidget = plainPage();
00078     QBoxLayout* topLayout = new QVBoxLayout(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(QString::fromLatin1("General"));
00085     mPrefixText = config->readEntry(QString::fromLatin1("BirthdayPrefix"), i18n("Birthday: "));
00086     mSuffixText = config->readEntry(QString::fromLatin1("BirthdaySuffix"));
00087 
00088     QGroupBox* textGroup = new QGroupBox(2, Qt::Horizontal, i18n("Alarm Text"), topWidget);
00089     topLayout->addWidget(textGroup);
00090     QLabel* label = new QLabel(i18n("Pre&fix:"), textGroup);
00091     label->setFixedSize(label->sizeHint());
00092     mPrefix = new BLineEdit(mPrefixText, textGroup);
00093     mPrefix->setMinimumSize(mPrefix->sizeHint());
00094     label->setBuddy(mPrefix);
00095     connect(mPrefix, SIGNAL(focusLost()), SLOT(slotTextLostFocus()));
00096     QWhatsThis::add(mPrefix,
00097           i18n("Enter text to appear before the person's name in the alarm message, "
00098                "including any necessary trailing spaces."));
00099 
00100     label = new QLabel(i18n("S&uffix:"), textGroup);
00101     label->setFixedSize(label->sizeHint());
00102     mSuffix = new BLineEdit(mSuffixText, textGroup);
00103     mSuffix->setMinimumSize(mSuffix->sizeHint());
00104     label->setBuddy(mSuffix);
00105     connect(mSuffix, SIGNAL(focusLost()), SLOT(slotTextLostFocus()));
00106     QWhatsThis::add(mSuffix,
00107           i18n("Enter text to appear after the person's name in the alarm message, "
00108                "including any necessary leading spaces."));
00109 
00110     QGroupBox* group = new QGroupBox(1, Qt::Horizontal, i18n("Select Birthdays"), topWidget);
00111     topLayout->addWidget(group);
00112     mAddresseeList = new BListView(group);
00113     mAddresseeList->setMultiSelection(true);
00114     mAddresseeList->setSelectionMode(QListView::Extended);
00115     mAddresseeList->setAllColumnsShowFocus(true);
00116     mAddresseeList->setFullWidth(true);
00117     mAddresseeList->addColumn(i18n("Name"));
00118     mAddresseeList->addColumn(i18n("Birthday"));
00119     connect(mAddresseeList, SIGNAL(selectionChanged()), SLOT(slotSelectionChanged()));
00120     QWhatsThis::add(mAddresseeList,
00121           i18n("Select birthdays to set alarms for.\n"
00122                "This list shows all birthdays in KAddressBook except those for which alarms already exist.\n\n"
00123                "You can select multiple birthdays at one time by dragging the mouse over the list, "
00124                "or by clicking the mouse while pressing Ctrl or Shift."));
00125 
00126     group = new QGroupBox(i18n("Alarm Configuration"), topWidget);
00127     topLayout->addWidget(group);
00128     QBoxLayout* groupLayout = new QVBoxLayout(group, marginHint(), spacingHint());
00129     groupLayout->addSpacing(fontMetrics().lineSpacing()/2);
00130 
00131     // Colour choice drop-down list
00132     QBoxLayout* layout = new QHBoxLayout(groupLayout, 2*spacingHint());
00133     QHBox* box;
00134     mBgColourChoose = EditAlarmDlg::createBgColourChooser(&box, group);
00135     connect(mBgColourChoose, SIGNAL(highlighted(const QColor&)), SLOT(slotBgColourSelected(const QColor&)));
00136     layout->addWidget(box);
00137     layout->addStretch();
00138 
00139     // Font and colour choice drop-down list
00140     mFontColourButton = new FontColourButton(group);
00141     mFontColourButton->setFixedSize(mFontColourButton->sizeHint());
00142     connect(mFontColourButton, SIGNAL(selected()), SLOT(slotFontColourSelected()));
00143     layout->addWidget(mFontColourButton);
00144 
00145     // Sound checkbox and file selector
00146     mSoundPicker = new SoundPicker(group);
00147     mSoundPicker->setFixedSize(mSoundPicker->sizeHint());
00148     groupLayout->addWidget(mSoundPicker, 0, Qt::AlignAuto);
00149 
00150     // How much to advance warning to give
00151     mReminder = new Reminder(i18n("&Reminder"),
00152                              i18n("Check to display a reminder in advance of the birthday."),
00153                              i18n("Enter the number of days before each birthday to display a reminder. "
00154                                   "This is in addition to the alarm which is displayed on the birthday."),
00155                              false, false, group);
00156     mReminder->setFixedSize(mReminder->sizeHint());
00157     mReminder->setMaximum(0, 364);
00158     mReminder->setMinutes(0, true);
00159     groupLayout->addWidget(mReminder, 0, Qt::AlignAuto);
00160 
00161     // Acknowledgement confirmation required - default = no confirmation
00162     layout = new QHBoxLayout(groupLayout, 2*spacingHint());
00163     mConfirmAck = EditAlarmDlg::createConfirmAckCheckbox(group);
00164     mConfirmAck->setFixedSize(mConfirmAck->sizeHint());
00165     layout->addWidget(mConfirmAck);
00166     layout->addSpacing(2*spacingHint());
00167     layout->addStretch();
00168 
00169     if (ShellProcess::authorised())    // don't display if shell commands not allowed (e.g. kiosk mode)
00170     {
00171         // Special actions button
00172         mSpecialActionsButton = new SpecialActionsButton(i18n("Special Actions..."), group);
00173         mSpecialActionsButton->setFixedSize(mSpecialActionsButton->sizeHint());
00174         layout->addWidget(mSpecialActionsButton);
00175     }
00176 
00177     // Late display checkbox - default = allow late display
00178     layout = new QHBoxLayout(groupLayout, 2*spacingHint());
00179     mLateCancel = new LateCancelSelector(false, group);
00180     mLateCancel->setFixedSize(mLateCancel->sizeHint());
00181     layout->addWidget(mLateCancel);
00182     layout->addStretch();
00183 
00184     // Simple repetition button
00185     mSimpleRepetition = new RepetitionButton(i18n("Simple Repetition"), false, group);
00186     mSimpleRepetition->setFixedSize(mSimpleRepetition->sizeHint());
00187     mSimpleRepetition->set(0, 0, true, 364*24*60);
00188     QWhatsThis::add(mSimpleRepetition, i18n("Set up an additional alarm repetition"));
00189     layout->addWidget(mSimpleRepetition);
00190 
00191     // Set the values to their defaults
00192     mFontColourButton->setDefaultFont();
00193     mFontColourButton->setBgColour(Preferences::defaultBgColour());
00194     mBgColourChoose->setColour(Preferences::defaultBgColour());     // set colour before setting alarm type buttons
00195     mLateCancel->setMinutes(Preferences::defaultLateCancel(), true, TimePeriod::DAYS);
00196     mConfirmAck->setChecked(Preferences::defaultConfirmAck());
00197     mSoundPicker->set(Preferences::defaultSoundType(), Preferences::defaultSoundFile(),
00198                       Preferences::defaultSoundVolume(), -1, 0, Preferences::defaultSoundRepeat());
00199     if (mSpecialActionsButton)
00200         mSpecialActionsButton->setActions(Preferences::defaultPreAction(), Preferences::defaultPostAction());
00201 
00202     // Initialise the birthday selection list and disable the OK button
00203     loadAddressBook();
00204 }
00205 
00206 /******************************************************************************
00207 * Load the address book in preparation for displaying the birthday selection list.
00208 */
00209 void BirthdayDlg::loadAddressBook()
00210 {
00211     if (!mAddressBook)
00212     {
00213 #if KDE_IS_VERSION(3,1,90)
00214             mAddressBook = KABC::StdAddressBook::self(true);
00215         if (mAddressBook)
00216                     connect(mAddressBook, SIGNAL(addressBookChanged(AddressBook*)), SLOT(updateSelectionList()));
00217 #else
00218         mAddressBook = KABC::StdAddressBook::self();
00219         if (mAddressBook)
00220             updateSelectionList();
00221 #endif
00222     }
00223     else
00224         updateSelectionList();
00225         if (!mAddressBook)
00226                 KMessageBox::error(this, i18n("Error reading address book"));
00227 }
00228 
00229 /******************************************************************************
00230 * Initialise or update the birthday selection list by fetching all birthdays
00231 * from the address book and displaying those which do not already have alarms.
00232 */
00233 void BirthdayDlg::updateSelectionList()
00234 {
00235     // Compile a list of all pending alarm messages which look like birthdays
00236     QStringList messageList;
00237     KAEvent event;
00238     Event::List events = AlarmCalendar::activeCalendar()->events();
00239     for (Event::List::ConstIterator it = events.begin();  it != events.end();  ++it)
00240     {
00241         Event* kcalEvent = *it;
00242         event.set(*kcalEvent);
00243         if (event.action() == KAEvent::MESSAGE
00244         &&  event.recurType() == KARecurrence::ANNUAL_DATE
00245         &&  (mPrefixText.isEmpty()  ||  event.message().startsWith(mPrefixText)))
00246             messageList.append(event.message());
00247     }
00248 
00249     // Fetch all birthdays from the address book
00250     for (KABC::AddressBook::ConstIterator abit = mAddressBook->begin();  abit != mAddressBook->end();  ++abit)
00251     {
00252         const KABC::Addressee& addressee = *abit;
00253         if (addressee.birthday().isValid())
00254         {
00255             // Create a list entry for this birthday
00256             QDate birthday = addressee.birthday().date();
00257             QString name = addressee.nickName();
00258             if (name.isEmpty())
00259                 name = addressee.realName();
00260             // Check if the birthday already has an alarm
00261             QString text = mPrefixText + name + mSuffixText;
00262             bool alarmExists = (messageList.find(text) != messageList.end());
00263             // Check if the birthday is already in the selection list
00264             bool inSelectionList = false;
00265             AddresseeItem* item = 0;
00266             for (QListViewItem* qitem = mAddresseeList->firstChild();  qitem;  qitem = qitem->nextSibling())
00267             {
00268                 item = dynamic_cast<AddresseeItem*>(qitem);
00269                 if (item  &&  item->text(AddresseeItem::NAME) == name  &&  item->birthday() == birthday)
00270                 {
00271                     inSelectionList = true;
00272                     break;
00273                 }
00274             }
00275 
00276             if (alarmExists  &&  inSelectionList)
00277                 delete item;     // alarm exists, so remove from selection list
00278             else if (!alarmExists  &&  !inSelectionList)
00279                 new AddresseeItem(mAddresseeList, name, birthday);   // add to list
00280         }
00281     }
00282 //  mAddresseeList->setUpdatesEnabled(true);
00283 
00284     // Enable/disable OK button according to whether anything is currently selected
00285     bool selection = false;
00286     for (QListViewItem* item = mAddresseeList->firstChild();  item;  item = item->nextSibling())
00287         if (mAddresseeList->isSelected(item))
00288         {
00289             selection = true;
00290             break;
00291         }
00292     enableButtonOK(selection);
00293 }
00294 
00295 /******************************************************************************
00296 * Return a list of events for birthdays chosen.
00297 */
00298 QValueList<KAEvent> BirthdayDlg::events() const
00299 {
00300     QValueList<KAEvent> list;
00301     QDate today = QDate::currentDate();
00302     QDateTime todayNoon(today, QTime(12, 0, 0));
00303     int thisYear = today.year();
00304     int reminder = mReminder->minutes();
00305 
00306     for (QListViewItem* item = mAddresseeList->firstChild();  item;  item = item->nextSibling())
00307     {
00308         if (mAddresseeList->isSelected(item))
00309         {
00310             AddresseeItem* aItem = dynamic_cast<AddresseeItem*>(item);
00311             if (aItem)
00312             {
00313                 QDate date = aItem->birthday();
00314                 date.setYMD(thisYear, date.month(), date.day());
00315                 if (date <= today)
00316                     date.setYMD(thisYear + 1, date.month(), date.day());
00317                 KAEvent event(date,
00318                               mPrefix->text() + aItem->text(AddresseeItem::NAME) + mSuffix->text(),
00319                               mBgColourChoose->color(), mFontColourButton->fgColour(),
00320                               mFontColourButton->font(), KAEvent::MESSAGE, mLateCancel->minutes(),
00321                               mFlags);
00322                 float fadeVolume;
00323                 int   fadeSecs;
00324                 float volume = mSoundPicker->volume(fadeVolume, fadeSecs);
00325                 event.setAudioFile(mSoundPicker->file(), volume, fadeVolume, fadeSecs);
00326                 QValueList<int> months;
00327                 months.append(date.month());
00328                 event.setRecurAnnualByDate(1, months, 0, Preferences::defaultFeb29Type(), -1, QDate());
00329                 event.setNextOccurrence(todayNoon, true);
00330                 event.setRepetition(mSimpleRepetition->interval(), mSimpleRepetition->count());
00331                 if (reminder)
00332                     event.setReminder(reminder, false);
00333                 if (mSpecialActionsButton)
00334                     event.setActions(mSpecialActionsButton->preAction(),
00335                                      mSpecialActionsButton->postAction());
00336                 list.append(event);
00337             }
00338         }
00339     }
00340     return list;
00341 }
00342 
00343 /******************************************************************************
00344 * Called when the OK button is selected to import the selected birthdays.
00345 */
00346 void BirthdayDlg::slotOk()
00347 {
00348     // Save prefix and suffix texts to use as future defaults
00349     KConfig* config = kapp->config();
00350     config->setGroup(QString::fromLatin1("General"));
00351     config->writeEntry(QString::fromLatin1("BirthdayPrefix"), mPrefix->text());
00352     config->writeEntry(QString::fromLatin1("BirthdaySuffix"), mSuffix->text());
00353     config->sync();
00354 
00355     mFlags = (mSoundPicker->sound() == SoundPicker::BEEP ? KAEvent::BEEP : 0)
00356            | (mSoundPicker->repeat()                     ? KAEvent::REPEAT_SOUND : 0)
00357            | (mConfirmAck->isChecked()                   ? KAEvent::CONFIRM_ACK : 0)
00358            | (mFontColourButton->defaultFont()           ? KAEvent::DEFAULT_FONT : 0)
00359            |                                               KAEvent::ANY_TIME;
00360     KDialogBase::slotOk();
00361 }
00362 
00363 /******************************************************************************
00364 * Called when the group of items selected changes.
00365 * Enable/disable the OK button depending on whether anything is selected.
00366 */
00367 void BirthdayDlg::slotSelectionChanged()
00368 {
00369     for (QListViewItem* item = mAddresseeList->firstChild();  item;  item = item->nextSibling())
00370         if (mAddresseeList->isSelected(item))
00371         {
00372             enableButtonOK(true);
00373             return;
00374         }
00375     enableButtonOK(false);
00376 
00377 }
00378 
00379 /******************************************************************************
00380 * Called when the prefix or suffix text has lost keyboard focus.
00381 * If the text has changed, re-evaluates the selection list according to the new
00382 * birthday alarm text format.
00383 */
00384 void BirthdayDlg::slotTextLostFocus()
00385 {
00386     QString prefix = mPrefix->text();
00387     QString suffix = mSuffix->text();
00388     if (prefix != mPrefixText  ||  suffix != mSuffixText)
00389     {
00390         // Text has changed - re-evaluate the selection list
00391         mPrefixText = prefix;
00392         mSuffixText = suffix;
00393         loadAddressBook();
00394     }
00395 }
00396 
00397 /******************************************************************************
00398 *  Called when the a new background colour has been selected using the colour
00399 *  combo box.
00400 */
00401 void BirthdayDlg::slotBgColourSelected(const QColor& colour)
00402 {
00403     mFontColourButton->setBgColour(colour);
00404 }
00405 
00406 /******************************************************************************
00407 *  Called when the a new font and colour have been selected using the font &
00408 *  colour pushbutton.
00409 */
00410 void BirthdayDlg::slotFontColourSelected()
00411 {
00412     mBgColourChoose->setColour(mFontColourButton->bgColour());
00413 }
00414 
00415 
00416 /*=============================================================================
00417 = Class: AddresseeItem
00418 =============================================================================*/
00419 
00420 AddresseeItem::AddresseeItem(QListView* parent, const QString& name, const QDate& birthday)
00421     : QListViewItem(parent),
00422       mBirthday(birthday)
00423 {
00424     setText(NAME, name);
00425     setText(BIRTHDAY, KGlobal::locale()->formatDate(mBirthday, true));
00426     mBirthdayOrder.sprintf("%04d%03d", mBirthday.year(), mBirthday.dayOfYear());
00427 }
00428 
00429 QString AddresseeItem::key(int column, bool) const
00430 {
00431     if (column == BIRTHDAY)
00432         return mBirthdayOrder;
00433     return text(column).lower();
00434 }
00435 
00436 
00437 /*=============================================================================
00438 = Class: BListView
00439 =============================================================================*/
00440 
00441 BListView::BListView(QWidget* parent, const char* name)
00442     : KListView(parent, name)
00443 {
00444     KAccel* accel = new KAccel(this);
00445     accel->insert(KStdAccel::SelectAll, this, SLOT(slotSelectAll()));
00446     accel->insert(KStdAccel::Deselect, this, SLOT(slotDeselect()));
00447     accel->readSettings();
00448 }
KDE Home | KDE Accessibility Home | Description of Access Keys