kalarm

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 <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     mPrefix = new BLineEdit(mPrefixText, textGroup);
00092     mPrefix->setMinimumSize(mPrefix->sizeHint());
00093     label->setBuddy(mPrefix);
00094     connect(mPrefix, SIGNAL(focusLost()), SLOT(slotTextLostFocus()));
00095     QWhatsThis::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 QLabel(i18n("S&uffix:"), textGroup);
00100     mSuffix = new BLineEdit(mSuffixText, textGroup);
00101     mSuffix->setMinimumSize(mSuffix->sizeHint());
00102     label->setBuddy(mSuffix);
00103     connect(mSuffix, SIGNAL(focusLost()), SLOT(slotTextLostFocus()));
00104     QWhatsThis::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     QGroupBox* group = new QGroupBox(1, Qt::Horizontal, i18n("Select Birthdays"), topWidget);
00109     topLayout->addWidget(group);
00110     mAddresseeList = new BListView(group);
00111     mAddresseeList->setMultiSelection(true);
00112     mAddresseeList->setSelectionMode(QListView::Extended);
00113     mAddresseeList->setAllColumnsShowFocus(true);
00114     mAddresseeList->setFullWidth(true);
00115     mAddresseeList->addColumn(i18n("Name"));
00116     mAddresseeList->addColumn(i18n("Birthday"));
00117     connect(mAddresseeList, SIGNAL(selectionChanged()), SLOT(slotSelectionChanged()));
00118     QWhatsThis::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 QGroupBox(i18n("Alarm Configuration"), topWidget);
00125     topLayout->addWidget(group);
00126     QBoxLayout* groupLayout = new QVBoxLayout(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, Qt::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, Qt::AlignAuto);
00149 
00150     // Acknowledgement confirmation required - default = no confirmation
00151     QHBoxLayout* layout = new QHBoxLayout(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 QHBoxLayout(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     QWhatsThis::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, SIGNAL(addressBookChanged(AddressBook*)), 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 * Initialise or update the birthday selection list by fetching all birthdays
00216 * from the address book and displaying those which do not already have alarms.
00217 */
00218 void BirthdayDlg::updateSelectionList()
00219 {
00220     // Compile a list of all pending alarm messages which look like birthdays
00221     QStringList messageList;
00222     KAEvent event;
00223     Event::List events = AlarmCalendar::activeCalendar()->events();
00224     for (Event::List::ConstIterator it = events.begin();  it != events.end();  ++it)
00225     {
00226         Event* kcalEvent = *it;
00227         event.set(*kcalEvent);
00228         if (event.action() == KAEvent::MESSAGE
00229         &&  event.recurType() == KARecurrence::ANNUAL_DATE
00230         &&  (mPrefixText.isEmpty()  ||  event.message().startsWith(mPrefixText)))
00231             messageList.append(event.message());
00232     }
00233 
00234     // Fetch all birthdays from the address book
00235     for (KABC::AddressBook::ConstIterator abit = mAddressBook->begin();  abit != mAddressBook->end();  ++abit)
00236     {
00237         const KABC::Addressee& addressee = *abit;
00238         if (addressee.birthday().isValid())
00239         {
00240             // Create a list entry for this birthday
00241             QDate birthday = addressee.birthday().date();
00242             QString name = addressee.nickName();
00243             if (name.isEmpty())
00244                 name = addressee.realName();
00245             // Check if the birthday already has an alarm
00246             QString text = mPrefixText + name + mSuffixText;
00247             bool alarmExists = (messageList.find(text) != messageList.end());
00248             // Check if the birthday is already in the selection list
00249             bool inSelectionList = false;
00250             AddresseeItem* item = 0;
00251             for (QListViewItem* qitem = mAddresseeList->firstChild();  qitem;  qitem = qitem->nextSibling())
00252             {
00253                 item = dynamic_cast<AddresseeItem*>(qitem);
00254                 if (item  &&  item->text(AddresseeItem::NAME) == name  &&  item->birthday() == birthday)
00255                 {
00256                     inSelectionList = true;
00257                     break;
00258                 }
00259             }
00260 
00261             if (alarmExists  &&  inSelectionList)
00262                 delete item;     // alarm exists, so remove from selection list
00263             else if (!alarmExists  &&  !inSelectionList)
00264                 new AddresseeItem(mAddresseeList, name, birthday);   // add to list
00265         }
00266     }
00267 //  mAddresseeList->setUpdatesEnabled(true);
00268 
00269     // Enable/disable OK button according to whether anything is currently selected
00270     bool selection = false;
00271     for (QListViewItem* item = mAddresseeList->firstChild();  item;  item = item->nextSibling())
00272         if (mAddresseeList->isSelected(item))
00273         {
00274             selection = true;
00275             break;
00276         }
00277     enableButtonOK(selection);
00278 }
00279 
00280 /******************************************************************************
00281 * Return a list of events for birthdays chosen.
00282 */
00283 QValueList<KAEvent> BirthdayDlg::events() const
00284 {
00285     QValueList<KAEvent> list;
00286     QDate today = QDate::currentDate();
00287     QDateTime todayNoon(today, QTime(12, 0, 0));
00288     int thisYear = today.year();
00289     int reminder = mReminder->minutes();
00290 
00291     for (QListViewItem* item = mAddresseeList->firstChild();  item;  item = item->nextSibling())
00292     {
00293         if (mAddresseeList->isSelected(item))
00294         {
00295             AddresseeItem* aItem = dynamic_cast<AddresseeItem*>(item);
00296             if (aItem)
00297             {
00298                 QDate date = aItem->birthday();
00299                 date.setYMD(thisYear, date.month(), date.day());
00300                 if (date <= today)
00301                     date.setYMD(thisYear + 1, date.month(), date.day());
00302                 KAEvent event(date,
00303                               mPrefix->text() + aItem->text(AddresseeItem::NAME) + mSuffix->text(),
00304                               mFontColourButton->bgColour(), mFontColourButton->fgColour(),
00305                               mFontColourButton->font(), KAEvent::MESSAGE, mLateCancel->minutes(),
00306                               mFlags);
00307                 float fadeVolume;
00308                 int   fadeSecs;
00309                 float volume = mSoundPicker->volume(fadeVolume, fadeSecs);
00310                 event.setAudioFile(mSoundPicker->file(), volume, fadeVolume, fadeSecs);
00311                 QValueList<int> months;
00312                 months.append(date.month());
00313                 event.setRecurAnnualByDate(1, months, 0, Preferences::defaultFeb29Type(), -1, QDate());
00314                 event.setRepetition(mSubRepetition->interval(), mSubRepetition->count());
00315                 event.setNextOccurrence(todayNoon);
00316                 if (reminder)
00317                     event.setReminder(reminder, false);
00318                 if (mSpecialActionsButton)
00319                     event.setActions(mSpecialActionsButton->preAction(),
00320                                      mSpecialActionsButton->postAction());
00321                 list.append(event);
00322             }
00323         }
00324     }
00325     return list;
00326 }
00327 
00328 /******************************************************************************
00329 * Called when the OK button is selected to import the selected birthdays.
00330 */
00331 void BirthdayDlg::slotOk()
00332 {
00333     // Save prefix and suffix texts to use as future defaults
00334     KConfig* config = kapp->config();
00335     config->setGroup(QString::fromLatin1("General"));
00336     config->writeEntry(QString::fromLatin1("BirthdayPrefix"), mPrefix->text());
00337     config->writeEntry(QString::fromLatin1("BirthdaySuffix"), mSuffix->text());
00338     config->sync();
00339 
00340     mFlags = (mSoundPicker->sound() == SoundPicker::BEEP ? KAEvent::BEEP : 0)
00341            | (mSoundPicker->repeat()                     ? KAEvent::REPEAT_SOUND : 0)
00342            | (mConfirmAck->isChecked()                   ? KAEvent::CONFIRM_ACK : 0)
00343            | (mFontColourButton->defaultFont()           ? KAEvent::DEFAULT_FONT : 0)
00344            |                                               KAEvent::ANY_TIME;
00345     KDialogBase::slotOk();
00346 }
00347 
00348 /******************************************************************************
00349 * Called when the group of items selected changes.
00350 * Enable/disable the OK button depending on whether anything is selected.
00351 */
00352 void BirthdayDlg::slotSelectionChanged()
00353 {
00354     for (QListViewItem* item = mAddresseeList->firstChild();  item;  item = item->nextSibling())
00355         if (mAddresseeList->isSelected(item))
00356         {
00357             enableButtonOK(true);
00358             return;
00359         }
00360     enableButtonOK(false);
00361 
00362 }
00363 
00364 /******************************************************************************
00365 * Called when the prefix or suffix text has lost keyboard focus.
00366 * If the text has changed, re-evaluates the selection list according to the new
00367 * birthday alarm text format.
00368 */
00369 void BirthdayDlg::slotTextLostFocus()
00370 {
00371     QString prefix = mPrefix->text();
00372     QString suffix = mSuffix->text();
00373     if (prefix != mPrefixText  ||  suffix != mSuffixText)
00374     {
00375         // Text has changed - re-evaluate the selection list
00376         mPrefixText = prefix;
00377         mSuffixText = suffix;
00378         loadAddressBook();
00379     }
00380 }
00381 
00382 
00383 /*=============================================================================
00384 = Class: AddresseeItem
00385 =============================================================================*/
00386 
00387 AddresseeItem::AddresseeItem(QListView* parent, const QString& name, const QDate& birthday)
00388     : QListViewItem(parent),
00389       mBirthday(birthday)
00390 {
00391     setText(NAME, name);
00392     setText(BIRTHDAY, KGlobal::locale()->formatDate(mBirthday, true));
00393     mBirthdayOrder.sprintf("%04d%03d", mBirthday.year(), mBirthday.dayOfYear());
00394 }
00395 
00396 QString AddresseeItem::key(int column, bool) const
00397 {
00398     if (column == BIRTHDAY)
00399         return mBirthdayOrder;
00400     return text(column).lower();
00401 }
00402 
00403 
00404 /*=============================================================================
00405 = Class: BListView
00406 =============================================================================*/
00407 
00408 BListView::BListView(QWidget* parent, const char* name)
00409     : KListView(parent, name)
00410 {
00411     KAccel* accel = new KAccel(this);
00412     accel->insert(KStdAccel::SelectAll, this, SLOT(slotSelectAll()));
00413     accel->insert(KStdAccel::Deselect, this, SLOT(slotDeselect()));
00414     accel->readSettings();
00415 }
KDE Home | KDE Accessibility Home | Description of Access Keys