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     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     // Font and colour choice button and sample text
00132     mFontColourButton = new FontColourButton(group);
00133     mFontColourButton->setMaximumHeight(mFontColourButton->sizeHint().height() * 3/2);
00134     groupLayout->addWidget(mFontColourButton);
00135 
00136     // Sound checkbox and file selector
00137     mSoundPicker = new SoundPicker(group);
00138     mSoundPicker->setFixedSize(mSoundPicker->sizeHint());
00139     groupLayout->addWidget(mSoundPicker, 0, Qt::AlignAuto);
00140 
00141     // How much to advance warning to give
00142     mReminder = new Reminder(i18n("&Reminder"),
00143                              i18n("Check to display a reminder in advance of the birthday."),
00144                              i18n("Enter the number of days before each birthday to display a reminder. "
00145                                   "This is in addition to the alarm which is displayed on the birthday."),
00146                              false, false, group);
00147     mReminder->setFixedSize(mReminder->sizeHint());
00148     mReminder->setMaximum(0, 364);
00149     mReminder->setMinutes(0, true);
00150     groupLayout->addWidget(mReminder, 0, Qt::AlignAuto);
00151 
00152     // Acknowledgement confirmation required - default = no confirmation
00153     QHBoxLayout* layout = new QHBoxLayout(groupLayout, 2*spacingHint());
00154     mConfirmAck = EditAlarmDlg::createConfirmAckCheckbox(group);
00155     mConfirmAck->setFixedSize(mConfirmAck->sizeHint());
00156     layout->addWidget(mConfirmAck);
00157     layout->addSpacing(2*spacingHint());
00158     layout->addStretch();
00159 
00160     if (ShellProcess::authorised())    // don't display if shell commands not allowed (e.g. kiosk mode)
00161     {
00162         // Special actions button
00163         mSpecialActionsButton = new SpecialActionsButton(i18n("Special Actions..."), group);
00164         mSpecialActionsButton->setFixedSize(mSpecialActionsButton->sizeHint());
00165         layout->addWidget(mSpecialActionsButton);
00166     }
00167 
00168     // Late display checkbox - default = allow late display
00169     layout = new QHBoxLayout(groupLayout, 2*spacingHint());
00170     mLateCancel = new LateCancelSelector(false, group);
00171     mLateCancel->setFixedSize(mLateCancel->sizeHint());
00172     layout->addWidget(mLateCancel);
00173     layout->addStretch();
00174 
00175     // Sub-repetition button
00176     mSubRepetition = new RepetitionButton(i18n("Sub-Repetition"), false, group);
00177     mSubRepetition->setFixedSize(mSubRepetition->sizeHint());
00178     mSubRepetition->set(0, 0, true, 364*24*60);
00179     QWhatsThis::add(mSubRepetition, i18n("Set up an additional alarm repetition"));
00180     layout->addWidget(mSubRepetition);
00181 
00182     // Set the values to their defaults
00183     mFontColourButton->setDefaultFont();
00184     mFontColourButton->setBgColour(Preferences::defaultBgColour());
00185     mFontColourButton->setFgColour(Preferences::defaultFgColour());     // set colour before setting alarm type buttons
00186     mLateCancel->setMinutes(Preferences::defaultLateCancel(), true, TimePeriod::DAYS);
00187     mConfirmAck->setChecked(Preferences::defaultConfirmAck());
00188     mSoundPicker->set(Preferences::defaultSoundType(), Preferences::defaultSoundFile(),
00189                       Preferences::defaultSoundVolume(), -1, 0, Preferences::defaultSoundRepeat());
00190     if (mSpecialActionsButton)
00191         mSpecialActionsButton->setActions(Preferences::defaultPreAction(), Preferences::defaultPostAction());
00192 
00193     // Initialise the birthday selection list and disable the OK button
00194     loadAddressBook();
00195 }
00196 
00197 /******************************************************************************
00198 * Load the address book in preparation for displaying the birthday selection list.
00199 */
00200 void BirthdayDlg::loadAddressBook()
00201 {
00202     if (!mAddressBook)
00203     {
00204 #if KDE_IS_VERSION(3,1,90)
00205             mAddressBook = KABC::StdAddressBook::self(true);
00206         if (mAddressBook)
00207                     connect(mAddressBook, SIGNAL(addressBookChanged(AddressBook*)), SLOT(updateSelectionList()));
00208 #else
00209         mAddressBook = KABC::StdAddressBook::self();
00210         if (mAddressBook)
00211             updateSelectionList();
00212 #endif
00213     }
00214     else
00215         updateSelectionList();
00216         if (!mAddressBook)
00217                 KMessageBox::error(this, i18n("Error reading address book"));
00218 }
00219 
00220 /******************************************************************************
00221 * Initialise or update the birthday selection list by fetching all birthdays
00222 * from the address book and displaying those which do not already have alarms.
00223 */
00224 void BirthdayDlg::updateSelectionList()
00225 {
00226     // Compile a list of all pending alarm messages which look like birthdays
00227     QStringList messageList;
00228     KAEvent event;
00229     Event::List events = AlarmCalendar::activeCalendar()->events();
00230     for (Event::List::ConstIterator it = events.begin();  it != events.end();  ++it)
00231     {
00232         Event* kcalEvent = *it;
00233         event.set(*kcalEvent);
00234         if (event.action() == KAEvent::MESSAGE
00235         &&  event.recurType() == KARecurrence::ANNUAL_DATE
00236         &&  (mPrefixText.isEmpty()  ||  event.message().startsWith(mPrefixText)))
00237             messageList.append(event.message());
00238     }
00239 
00240     // Fetch all birthdays from the address book
00241     for (KABC::AddressBook::ConstIterator abit = mAddressBook->begin();  abit != mAddressBook->end();  ++abit)
00242     {
00243         const KABC::Addressee& addressee = *abit;
00244         if (addressee.birthday().isValid())
00245         {
00246             // Create a list entry for this birthday
00247             QDate birthday = addressee.birthday().date();
00248             QString name = addressee.nickName();
00249             if (name.isEmpty())
00250                 name = addressee.realName();
00251             // Check if the birthday already has an alarm
00252             QString text = mPrefixText + name + mSuffixText;
00253             bool alarmExists = (messageList.find(text) != messageList.end());
00254             // Check if the birthday is already in the selection list
00255             bool inSelectionList = false;
00256             AddresseeItem* item = 0;
00257             for (QListViewItem* qitem = mAddresseeList->firstChild();  qitem;  qitem = qitem->nextSibling())
00258             {
00259                 item = dynamic_cast<AddresseeItem*>(qitem);
00260                 if (item  &&  item->text(AddresseeItem::NAME) == name  &&  item->birthday() == birthday)
00261                 {
00262                     inSelectionList = true;
00263                     break;
00264                 }
00265             }
00266 
00267             if (alarmExists  &&  inSelectionList)
00268                 delete item;     // alarm exists, so remove from selection list
00269             else if (!alarmExists  &&  !inSelectionList)
00270                 new AddresseeItem(mAddresseeList, name, birthday);   // add to list
00271         }
00272     }
00273 //  mAddresseeList->setUpdatesEnabled(true);
00274 
00275     // Enable/disable OK button according to whether anything is currently selected
00276     bool selection = false;
00277     for (QListViewItem* item = mAddresseeList->firstChild();  item;  item = item->nextSibling())
00278         if (mAddresseeList->isSelected(item))
00279         {
00280             selection = true;
00281             break;
00282         }
00283     enableButtonOK(selection);
00284 }
00285 
00286 /******************************************************************************
00287 * Return a list of events for birthdays chosen.
00288 */
00289 QValueList<KAEvent> BirthdayDlg::events() const
00290 {
00291     QValueList<KAEvent> list;
00292     QDate today = QDate::currentDate();
00293     QDateTime todayNoon(today, QTime(12, 0, 0));
00294     int thisYear = today.year();
00295     int reminder = mReminder->minutes();
00296 
00297     for (QListViewItem* item = mAddresseeList->firstChild();  item;  item = item->nextSibling())
00298     {
00299         if (mAddresseeList->isSelected(item))
00300         {
00301             AddresseeItem* aItem = dynamic_cast<AddresseeItem*>(item);
00302             if (aItem)
00303             {
00304                 QDate date = aItem->birthday();
00305                 date.setYMD(thisYear, date.month(), date.day());
00306                 if (date <= today)
00307                     date.setYMD(thisYear + 1, date.month(), date.day());
00308                 KAEvent event(date,
00309                               mPrefix->text() + aItem->text(AddresseeItem::NAME) + mSuffix->text(),
00310                               mFontColourButton->bgColour(), mFontColourButton->fgColour(),
00311                               mFontColourButton->font(), KAEvent::MESSAGE, mLateCancel->minutes(),
00312                               mFlags);
00313                 float fadeVolume;
00314                 int   fadeSecs;
00315                 float volume = mSoundPicker->volume(fadeVolume, fadeSecs);
00316                 event.setAudioFile(mSoundPicker->file(), volume, fadeVolume, fadeSecs);
00317                 QValueList<int> months;
00318                 months.append(date.month());
00319                 event.setRecurAnnualByDate(1, months, 0, Preferences::defaultFeb29Type(), -1, QDate());
00320                 event.setRepetition(mSubRepetition->interval(), mSubRepetition->count());
00321                 event.setNextOccurrence(todayNoon);
00322                 if (reminder)
00323                     event.setReminder(reminder, false);
00324                 if (mSpecialActionsButton)
00325                     event.setActions(mSpecialActionsButton->preAction(),
00326                                      mSpecialActionsButton->postAction());
00327                 list.append(event);
00328             }
00329         }
00330     }
00331     return list;
00332 }
00333 
00334 /******************************************************************************
00335 * Called when the OK button is selected to import the selected birthdays.
00336 */
00337 void BirthdayDlg::slotOk()
00338 {
00339     // Save prefix and suffix texts to use as future defaults
00340     KConfig* config = kapp->config();
00341     config->setGroup(QString::fromLatin1("General"));
00342     config->writeEntry(QString::fromLatin1("BirthdayPrefix"), mPrefix->text());
00343     config->writeEntry(QString::fromLatin1("BirthdaySuffix"), mSuffix->text());
00344     config->sync();
00345 
00346     mFlags = (mSoundPicker->sound() == SoundPicker::BEEP ? KAEvent::BEEP : 0)
00347            | (mSoundPicker->repeat()                     ? KAEvent::REPEAT_SOUND : 0)
00348            | (mConfirmAck->isChecked()                   ? KAEvent::CONFIRM_ACK : 0)
00349            | (mFontColourButton->defaultFont()           ? KAEvent::DEFAULT_FONT : 0)
00350            |                                               KAEvent::ANY_TIME;
00351     KDialogBase::slotOk();
00352 }
00353 
00354 /******************************************************************************
00355 * Called when the group of items selected changes.
00356 * Enable/disable the OK button depending on whether anything is selected.
00357 */
00358 void BirthdayDlg::slotSelectionChanged()
00359 {
00360     for (QListViewItem* item = mAddresseeList->firstChild();  item;  item = item->nextSibling())
00361         if (mAddresseeList->isSelected(item))
00362         {
00363             enableButtonOK(true);
00364             return;
00365         }
00366     enableButtonOK(false);
00367 
00368 }
00369 
00370 /******************************************************************************
00371 * Called when the prefix or suffix text has lost keyboard focus.
00372 * If the text has changed, re-evaluates the selection list according to the new
00373 * birthday alarm text format.
00374 */
00375 void BirthdayDlg::slotTextLostFocus()
00376 {
00377     QString prefix = mPrefix->text();
00378     QString suffix = mSuffix->text();
00379     if (prefix != mPrefixText  ||  suffix != mSuffixText)
00380     {
00381         // Text has changed - re-evaluate the selection list
00382         mPrefixText = prefix;
00383         mSuffixText = suffix;
00384         loadAddressBook();
00385     }
00386 }
00387 
00388 
00389 /*=============================================================================
00390 = Class: AddresseeItem
00391 =============================================================================*/
00392 
00393 AddresseeItem::AddresseeItem(QListView* parent, const QString& name, const QDate& birthday)
00394     : QListViewItem(parent),
00395       mBirthday(birthday)
00396 {
00397     setText(NAME, name);
00398     setText(BIRTHDAY, KGlobal::locale()->formatDate(mBirthday, true));
00399     mBirthdayOrder.sprintf("%04d%03d", mBirthday.year(), mBirthday.dayOfYear());
00400 }
00401 
00402 QString AddresseeItem::key(int column, bool) const
00403 {
00404     if (column == BIRTHDAY)
00405         return mBirthdayOrder;
00406     return text(column).lower();
00407 }
00408 
00409 
00410 /*=============================================================================
00411 = Class: BListView
00412 =============================================================================*/
00413 
00414 BListView::BListView(QWidget* parent, const char* name)
00415     : KListView(parent, name)
00416 {
00417     KAccel* accel = new KAccel(this);
00418     accel->insert(KStdAccel::SelectAll, this, SLOT(slotSelectAll()));
00419     accel->insert(KStdAccel::Deselect, this, SLOT(slotDeselect()));
00420     accel->readSettings();
00421 }
KDE Home | KDE Accessibility Home | Description of Access Keys