/* * birthdaydlg.cpp - dialog to pick birthdays from address book * Program: kalarm * Copyright © 2002-2012 by David Jarvie * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "birthdaydlg.h" #include "kalarm.h" #include "alarmcalendar.h" #include "birthdaymodel.h" #include "checkbox.h" #include "editdlgtypes.h" #include "fontcolourbutton.h" #include "kalarmapp.h" #include "latecancel.h" #include "preferences.h" #include "reminder.h" #include "repetitionbutton.h" #include "shellprocess.h" #include "soundpicker.h" #include "specialactions.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace KCal; BirthdayDlg::BirthdayDlg(QWidget* parent) : KDialog(parent), mSpecialActionsButton(0) { setObjectName(QLatin1String("BirthdayDlg")); // used by LikeBack setCaption(i18nc("@title:window", "Import Birthdays From KAddressBook")); setButtons(Ok | Cancel); setDefaultButton(Ok); connect(this, SIGNAL(okClicked()), SLOT(slotOk())); QWidget* topWidget = new QWidget(this); setMainWidget(topWidget); QVBoxLayout* topLayout = new QVBoxLayout(topWidget); topLayout->setMargin(0); topLayout->setSpacing(spacingHint()); // Prefix and suffix to the name in the alarm text // Get default prefix and suffix texts from config file KConfigGroup config(KGlobal::config(), "General"); mPrefixText = config.readEntry("BirthdayPrefix", i18nc("@info/plain", "Birthday: ")); mSuffixText = config.readEntry("BirthdaySuffix"); QGroupBox* textGroup = new QGroupBox(i18nc("@title:group", "Alarm Text"), topWidget); topLayout->addWidget(textGroup); QGridLayout* grid = new QGridLayout(textGroup); grid->setMargin(marginHint()); grid->setSpacing(spacingHint()); QLabel* label = new QLabel(i18nc("@label:textbox", "Prefix:"), textGroup); label->setFixedSize(label->sizeHint()); grid->addWidget(label, 0, 0); mPrefix = new BLineEdit(mPrefixText, textGroup); mPrefix->setMinimumSize(mPrefix->sizeHint()); label->setBuddy(mPrefix); connect(mPrefix, SIGNAL(focusLost()), SLOT(slotTextLostFocus())); mPrefix->setWhatsThis(i18nc("@info:whatsthis", "Enter text to appear before the person's name in the alarm message, " "including any necessary trailing spaces.")); grid->addWidget(mPrefix, 0, 1); label = new QLabel(i18nc("@label:textbox", "Suffix:"), textGroup); label->setFixedSize(label->sizeHint()); grid->addWidget(label, 1, 0); mSuffix = new BLineEdit(mSuffixText, textGroup); mSuffix->setMinimumSize(mSuffix->sizeHint()); label->setBuddy(mSuffix); connect(mSuffix, SIGNAL(focusLost()), SLOT(slotTextLostFocus())); mSuffix->setWhatsThis(i18nc("@info:whatsthis", "Enter text to appear after the person's name in the alarm message, " "including any necessary leading spaces.")); grid->addWidget(mSuffix, 1, 1); QGroupBox* group = new QGroupBox(i18nc("@title:group", "Select Birthdays"), topWidget); topLayout->addWidget(group); QVBoxLayout* layout = new QVBoxLayout(group); layout->setMargin(0); // Start Akonadi server as we need it for the birthday model to access contacts information Akonadi::Control::start(); BirthdayModel* model = BirthdayModel::instance(); connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), SLOT(resizeViewColumns())); KDescendantsProxyModel* descendantsModel = new KDescendantsProxyModel(this); descendantsModel->setSourceModel(model); Akonadi::EntityMimeTypeFilterModel* mimeTypeFilter = new Akonadi::EntityMimeTypeFilterModel(this); mimeTypeFilter->setSourceModel(descendantsModel); mimeTypeFilter->addMimeTypeExclusionFilter(Akonadi::Collection::mimeType()); mimeTypeFilter->setHeaderGroup(Akonadi::EntityTreeModel::ItemListHeaders); mBirthdaySortModel = new BirthdaySortModel(this); mBirthdaySortModel->setSourceModel(mimeTypeFilter); mBirthdaySortModel->setSortCaseSensitivity(Qt::CaseInsensitive); mBirthdaySortModel->setPrefixSuffix(mPrefixText, mSuffixText); mListView = new QTreeView(group); mListView->setEditTriggers(QAbstractItemView::NoEditTriggers); mListView->setModel(mBirthdaySortModel); mListView->setRootIsDecorated(false); // don't show expander icons mListView->setSortingEnabled(true); mListView->sortByColumn(BirthdayModel::NameColumn); mListView->setAllColumnsShowFocus(true); mListView->setSelectionMode(QAbstractItemView::ExtendedSelection); mListView->setSelectionBehavior(QAbstractItemView::SelectRows); mListView->setTextElideMode(Qt::ElideRight); mListView->header()->setResizeMode(BirthdayModel::NameColumn, QHeaderView::Stretch); mListView->header()->setResizeMode(BirthdayModel::DateColumn, QHeaderView::ResizeToContents); connect(mListView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SLOT(slotSelectionChanged())); mListView->setWhatsThis(i18nc("@info:whatsthis", "Select birthdays to set alarms for." "This list shows all birthdays in KAddressBook except those for which alarms already exist." "You can select multiple birthdays at one time by dragging the mouse over the list, " "or by clicking the mouse while pressing Ctrl or Shift.")); layout->addWidget(mListView); group = new QGroupBox(i18nc("@title:group", "Alarm Configuration"), topWidget); topLayout->addWidget(group); QVBoxLayout* groupLayout = new QVBoxLayout(group); groupLayout->setMargin(marginHint()); groupLayout->setSpacing(spacingHint()); // Sound checkbox and file selector QHBoxLayout* hlayout = new QHBoxLayout(); hlayout->setMargin(0); groupLayout->addLayout(hlayout); mSoundPicker = new SoundPicker(group); mSoundPicker->setFixedSize(mSoundPicker->sizeHint()); hlayout->addWidget(mSoundPicker); hlayout->addSpacing(2*spacingHint()); hlayout->addStretch(); // Font and colour choice button and sample text mFontColourButton = new FontColourButton(group); mFontColourButton->setMaximumHeight(mFontColourButton->sizeHint().height() * 3/2); hlayout->addWidget(mFontColourButton); connect(mFontColourButton, SIGNAL(selected(QColor,QColor)), SLOT(setColours(QColor,QColor))); // How much advance warning to give mReminder = new Reminder(i18nc("@info:whatsthis", "Check to display a reminder in advance of or after the birthday."), i18nc("@info:whatsthis", "Enter the number of days before or after each birthday to display a reminder. " "This is in addition to the alarm which is displayed on the birthday."), i18nc("@info:whatsthis", "Select whether the reminder should be triggered before or after the birthday."), false, false, group); mReminder->setFixedSize(mReminder->sizeHint()); mReminder->setMaximum(0, 364); mReminder->setMinutes(0, true); groupLayout->addWidget(mReminder, 0, Qt::AlignLeft); // Acknowledgement confirmation required - default = no confirmation hlayout = new QHBoxLayout(); hlayout->setMargin(0); hlayout->setSpacing(2*spacingHint()); groupLayout->addLayout(hlayout); mConfirmAck = EditDisplayAlarmDlg::createConfirmAckCheckbox(group); mConfirmAck->setFixedSize(mConfirmAck->sizeHint()); hlayout->addWidget(mConfirmAck); hlayout->addSpacing(2*spacingHint()); hlayout->addStretch(); if (ShellProcess::authorised()) // don't display if shell commands not allowed (e.g. kiosk mode) { // Special actions button mSpecialActionsButton = new SpecialActionsButton(false, group); mSpecialActionsButton->setFixedSize(mSpecialActionsButton->sizeHint()); hlayout->addWidget(mSpecialActionsButton); } // Late display checkbox - default = allow late display hlayout = new QHBoxLayout(); hlayout->setMargin(0); hlayout->setSpacing(2*spacingHint()); groupLayout->addLayout(hlayout); mLateCancel = new LateCancelSelector(false, group); mLateCancel->setFixedSize(mLateCancel->sizeHint()); hlayout->addWidget(mLateCancel); hlayout->addStretch(); // Sub-repetition button mSubRepetition = new RepetitionButton(i18nc("@action:button", "Sub-Repetition"), false, group); mSubRepetition->setFixedSize(mSubRepetition->sizeHint()); mSubRepetition->set(Repetition(), true, 364*24*60); mSubRepetition->setWhatsThis(i18nc("@info:whatsthis", "Set up an additional alarm repetition")); hlayout->addWidget(mSubRepetition); // Set the values to their defaults setColours(Preferences::defaultFgColour(), Preferences::defaultBgColour()); mFontColourButton->setDefaultFont(); mFontColourButton->setBgColour(Preferences::defaultBgColour()); mFontColourButton->setFgColour(Preferences::defaultFgColour()); mLateCancel->setMinutes(Preferences::defaultLateCancel(), true, TimePeriod::Days); mConfirmAck->setChecked(Preferences::defaultConfirmAck()); mSoundPicker->set(Preferences::defaultSoundType(), Preferences::defaultSoundFile(), Preferences::defaultSoundVolume(), -1, 0, Preferences::defaultSoundRepeat()); if (mSpecialActionsButton) { KAEvent::ExtraActionOptions opts(0); if (Preferences::defaultExecPreActionOnDeferral()) opts |= KAEvent::ExecPreActOnDeferral; if (Preferences::defaultCancelOnPreActionError()) opts |= KAEvent::CancelOnPreActError; if (Preferences::defaultDontShowPreActionError()) opts |= KAEvent::DontShowPreActError; mSpecialActionsButton->setActions(Preferences::defaultPreAction(), Preferences::defaultPostAction(), opts); } KActionCollection* actions = new KActionCollection(this); KStandardAction::selectAll(mListView, SLOT(selectAll()), actions); KStandardAction::deselect(mListView, SLOT(clearSelection()), actions); actions->addAssociatedWidget(mListView); foreach (QAction* action, actions->actions()) action->setShortcutContext(Qt::WidgetWithChildrenShortcut); enableButtonOk(false); // only enable OK button when something is selected } /****************************************************************************** * Return a list of events for birthdays chosen. */ QVector BirthdayDlg::events() const { QVector list; QModelIndexList indexes = mListView->selectionModel()->selectedRows(); int count = indexes.count(); if (!count) return list; QDate today = KDateTime::currentLocalDate(); KDateTime todayStart(today, KDateTime::ClockTime); int thisYear = today.year(); int reminder = mReminder->minutes(); for (int i = 0; i < count; ++i) { const QModelIndex nameIndex = indexes.at(i).model()->index(indexes.at(i).row(), 0); const QModelIndex birthdayIndex = indexes.at(i).model()->index(indexes.at(i).row(), 1); const QString name = nameIndex.data(Qt::DisplayRole).toString(); QDate date = birthdayIndex.data(BirthdayModel::DateRole).toDate(); date.setYMD(thisYear, date.month(), date.day()); if (date <= today) date.setYMD(thisYear + 1, date.month(), date.day()); KAEvent event(KDateTime(date, KDateTime::ClockTime), mPrefix->text() + name + mSuffix->text(), mFontColourButton->bgColour(), mFontColourButton->fgColour(), mFontColourButton->font(), KAEvent::MESSAGE, mLateCancel->minutes(), mFlags, true); float fadeVolume; int fadeSecs; float volume = mSoundPicker->volume(fadeVolume, fadeSecs); int repeatPause = mSoundPicker->repeatPause(); event.setAudioFile(mSoundPicker->file().prettyUrl(), volume, fadeVolume, fadeSecs, repeatPause); QVector months(1, date.month()); event.setRecurAnnualByDate(1, months, 0, KARecurrence::defaultFeb29Type(), -1, QDate()); event.setRepetition(mSubRepetition->repetition()); event.setNextOccurrence(todayStart); if (reminder) event.setReminder(reminder, false); if (mSpecialActionsButton) event.setActions(mSpecialActionsButton->preAction(), mSpecialActionsButton->postAction(), mSpecialActionsButton->options()); event.endChanges(); list.append(event); } return list; } /****************************************************************************** * Called when the OK button is selected to import the selected birthdays. */ void BirthdayDlg::slotOk() { // Save prefix and suffix texts to use as future defaults KConfigGroup config(KGlobal::config(), "General"); config.writeEntry("BirthdayPrefix", mPrefix->text()); config.writeEntry("BirthdaySuffix", mSuffix->text()); config.sync(); mFlags = KAEvent::ANY_TIME; if (mSoundPicker->sound() == Preferences::Sound_Beep) mFlags |= KAEvent::BEEP; if (mSoundPicker->repeatPause() >= 0) mFlags |= KAEvent::REPEAT_SOUND; if (mConfirmAck->isChecked()) mFlags |= KAEvent::CONFIRM_ACK; if (mFontColourButton->defaultFont()) mFlags |= KAEvent::DEFAULT_FONT; KDialog::accept(); } /****************************************************************************** * Called when the group of items selected changes. * Enable/disable the OK button depending on whether anything is selected. */ void BirthdayDlg::slotSelectionChanged() { enableButtonOk(mListView->selectionModel()->hasSelection()); } /****************************************************************************** * Called when the font/color button has been clicked. * Set the colors in the message text entry control. */ void BirthdayDlg::setColours(const QColor& fgColour, const QColor& bgColour) { QPalette pal = mPrefix->palette(); pal.setColor(mPrefix->backgroundRole(), bgColour); pal.setColor(mPrefix->foregroundRole(), fgColour); mPrefix->setPalette(pal); mSuffix->setPalette(pal); } /****************************************************************************** * Called when the data has changed in the birthday list. * Resize the date column. */ void BirthdayDlg::resizeViewColumns() { mListView->resizeColumnToContents(BirthdayModel::DateColumn); } /****************************************************************************** * Called when the prefix or suffix text has lost keyboard focus. * If the text has changed, re-evaluates the selection list according to the new * birthday alarm text format. */ void BirthdayDlg::slotTextLostFocus() { QString prefix = mPrefix->text(); QString suffix = mSuffix->text(); if (prefix != mPrefixText || suffix != mSuffixText) { // Text has changed - re-evaluate the selection list mPrefixText = prefix; mSuffixText = suffix; mBirthdaySortModel->setPrefixSuffix(mPrefixText, mSuffixText); } } #include "moc_birthdaydlg.cpp" // vim: et sw=4: