Fix dnd email
[kdepim.git] / kalarm / birthdaydlg.cpp
blobc42141c5e275cdb77f06f8a78aab8405d675a181
1 /*
2 * birthdaydlg.cpp - dialog to pick birthdays from address book
3 * Program: kalarm
4 * Copyright © 2002-2012 by David Jarvie <djarvie@kde.org>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 #include "birthdaydlg.h"
23 #include "kalarm.h"
24 #include "alarmcalendar.h"
25 #include "birthdaymodel.h"
26 #include "checkbox.h"
27 #include "editdlgtypes.h"
28 #include "fontcolourbutton.h"
29 #include "kalarmapp.h"
30 #include "latecancel.h"
31 #include "preferences.h"
32 #include "reminder.h"
33 #include "repetitionbutton.h"
34 #include "shellprocess.h"
35 #include "soundpicker.h"
36 #include "specialactions.h"
38 #include <AkonadiWidgets/controlgui.h>
39 #include <AkonadiCore/entitymimetypefiltermodel.h>
41 #include <KLocalizedString>
42 #include <kconfiggroup.h>
43 #include <kmessagebox.h>
44 #include <kstandardaction.h>
45 #include <kactioncollection.h>
46 #include <kdescendantsproxymodel.h>
47 #include <KSharedConfig>
49 #include <QAction>
50 #include <QGroupBox>
51 #include <QLabel>
52 #include <QTreeView>
53 #include <QHeaderView>
54 #include <QHBoxLayout>
55 #include <QVBoxLayout>
56 #include <QDialogButtonBox>
57 #include "kalarm_debug.h"
59 using namespace KCal;
62 BirthdayDlg::BirthdayDlg(QWidget* parent)
63 : QDialog(parent),
64 mSpecialActionsButton(Q_NULLPTR)
66 setObjectName(QStringLiteral("BirthdayDlg")); // used by LikeBack
67 setWindowTitle(i18nc("@title:window", "Import Birthdays From KAddressBook"));
69 QVBoxLayout* topLayout = new QVBoxLayout(this);
70 topLayout->setSpacing(style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing));
72 // Prefix and suffix to the name in the alarm text
73 // Get default prefix and suffix texts from config file
74 KConfigGroup config(KSharedConfig::openConfig(), "General");
75 mPrefixText = config.readEntry("BirthdayPrefix", i18nc("@info", "Birthday: "));
76 mSuffixText = config.readEntry("BirthdaySuffix");
78 QGroupBox* textGroup = new QGroupBox(i18nc("@title:group", "Alarm Text"), this);
79 topLayout->addWidget(textGroup);
80 QGridLayout* grid = new QGridLayout(textGroup);
81 grid->setMargin(style()->pixelMetric(QStyle::PM_DefaultChildMargin));
82 grid->setSpacing(style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing));
83 QLabel* label = new QLabel(i18nc("@label:textbox", "Prefix:"), textGroup);
84 label->setFixedSize(label->sizeHint());
85 grid->addWidget(label, 0, 0);
86 mPrefix = new BLineEdit(mPrefixText, textGroup);
87 mPrefix->setMinimumSize(mPrefix->sizeHint());
88 label->setBuddy(mPrefix);
89 connect(mPrefix, &BLineEdit::focusLost, this, &BirthdayDlg::slotTextLostFocus);
90 mPrefix->setWhatsThis(i18nc("@info:whatsthis",
91 "Enter text to appear before the person's name in the alarm message, "
92 "including any necessary trailing spaces."));
93 grid->addWidget(mPrefix, 0, 1);
95 label = new QLabel(i18nc("@label:textbox", "Suffix:"), textGroup);
96 label->setFixedSize(label->sizeHint());
97 grid->addWidget(label, 1, 0);
98 mSuffix = new BLineEdit(mSuffixText, textGroup);
99 mSuffix->setMinimumSize(mSuffix->sizeHint());
100 label->setBuddy(mSuffix);
101 connect(mSuffix, &BLineEdit::focusLost, this, &BirthdayDlg::slotTextLostFocus);
102 mSuffix->setWhatsThis(i18nc("@info:whatsthis",
103 "Enter text to appear after the person's name in the alarm message, "
104 "including any necessary leading spaces."));
105 grid->addWidget(mSuffix, 1, 1);
107 QGroupBox* group = new QGroupBox(i18nc("@title:group", "Select Birthdays"), this);
108 topLayout->addWidget(group);
109 QVBoxLayout* layout = new QVBoxLayout(group);
110 layout->setMargin(0);
112 // Start Akonadi server as we need it for the birthday model to access contacts information
113 Akonadi::ControlGui::start();
115 BirthdayModel* model = BirthdayModel::instance();
116 connect(model, &BirthdayModel::dataChanged, this, &BirthdayDlg::resizeViewColumns);
118 KDescendantsProxyModel* descendantsModel = new KDescendantsProxyModel(this);
119 descendantsModel->setSourceModel(model);
121 Akonadi::EntityMimeTypeFilterModel* mimeTypeFilter = new Akonadi::EntityMimeTypeFilterModel(this);
122 mimeTypeFilter->setSourceModel(descendantsModel);
123 mimeTypeFilter->addMimeTypeExclusionFilter(Akonadi::Collection::mimeType());
124 mimeTypeFilter->setHeaderGroup(Akonadi::EntityTreeModel::ItemListHeaders);
126 mBirthdaySortModel = new BirthdaySortModel(this);
127 mBirthdaySortModel->setSourceModel(mimeTypeFilter);
128 mBirthdaySortModel->setSortCaseSensitivity(Qt::CaseInsensitive);
129 mBirthdaySortModel->setPrefixSuffix(mPrefixText, mSuffixText);
130 mListView = new QTreeView(group);
131 mListView->setEditTriggers(QAbstractItemView::NoEditTriggers);
132 mListView->setModel(mBirthdaySortModel);
133 mListView->setRootIsDecorated(false); // don't show expander icons
134 mListView->setSortingEnabled(true);
135 mListView->sortByColumn(BirthdayModel::NameColumn);
136 mListView->setAllColumnsShowFocus(true);
137 mListView->setSelectionMode(QAbstractItemView::ExtendedSelection);
138 mListView->setSelectionBehavior(QAbstractItemView::SelectRows);
139 mListView->setTextElideMode(Qt::ElideRight);
140 mListView->header()->setResizeMode(BirthdayModel::NameColumn, QHeaderView::Stretch);
141 mListView->header()->setResizeMode(BirthdayModel::DateColumn, QHeaderView::ResizeToContents);
142 connect(mListView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &BirthdayDlg::slotSelectionChanged);
143 mListView->setWhatsThis(xi18nc("@info:whatsthis",
144 "<para>Select birthdays to set alarms for.<nl/>"
145 "This list shows all birthdays in <application>KAddressBook</application> except those for which alarms already exist.</para>"
146 "<para>You can select multiple birthdays at one time by dragging the mouse over the list, "
147 "or by clicking the mouse while pressing Ctrl or Shift.</para>"));
148 layout->addWidget(mListView);
150 group = new QGroupBox(i18nc("@title:group", "Alarm Configuration"), this);
151 topLayout->addWidget(group);
152 QVBoxLayout* groupLayout = new QVBoxLayout(group);
153 groupLayout->setMargin(style()->pixelMetric(QStyle::PM_DefaultChildMargin));
154 groupLayout->setSpacing(style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing));
156 // Sound checkbox and file selector
157 QHBoxLayout* hlayout = new QHBoxLayout();
158 hlayout->setMargin(0);
159 groupLayout->addLayout(hlayout);
160 mSoundPicker = new SoundPicker(group);
161 mSoundPicker->setFixedSize(mSoundPicker->sizeHint());
162 hlayout->addWidget(mSoundPicker);
163 hlayout->addSpacing(2 * style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing));
164 hlayout->addStretch();
166 // Font and colour choice button and sample text
167 mFontColourButton = new FontColourButton(group);
168 mFontColourButton->setMaximumHeight(mFontColourButton->sizeHint().height() * 3/2);
169 hlayout->addWidget(mFontColourButton);
170 connect(mFontColourButton, &FontColourButton::selected, this, &BirthdayDlg::setColours);
172 // How much advance warning to give
173 mReminder = new Reminder(i18nc("@info:whatsthis", "Check to display a reminder in advance of or after the birthday."),
174 i18nc("@info:whatsthis", "Enter the number of days before or after each birthday to display a reminder. "
175 "This is in addition to the alarm which is displayed on the birthday."),
176 i18nc("@info:whatsthis", "Select whether the reminder should be triggered before or after the birthday."),
177 false, false, group);
178 mReminder->setFixedSize(mReminder->sizeHint());
179 mReminder->setMaximum(0, 364);
180 mReminder->setMinutes(0, true);
181 groupLayout->addWidget(mReminder, 0, Qt::AlignLeft);
183 // Acknowledgement confirmation required - default = no confirmation
184 hlayout = new QHBoxLayout();
185 hlayout->setMargin(0);
186 hlayout->setSpacing(2 * style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing));
187 groupLayout->addLayout(hlayout);
188 mConfirmAck = EditDisplayAlarmDlg::createConfirmAckCheckbox(group);
189 mConfirmAck->setFixedSize(mConfirmAck->sizeHint());
190 hlayout->addWidget(mConfirmAck);
191 hlayout->addSpacing(2 * style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing));
192 hlayout->addStretch();
194 if (ShellProcess::authorised()) // don't display if shell commands not allowed (e.g. kiosk mode)
196 // Special actions button
197 mSpecialActionsButton = new SpecialActionsButton(false, group);
198 mSpecialActionsButton->setFixedSize(mSpecialActionsButton->sizeHint());
199 hlayout->addWidget(mSpecialActionsButton);
202 // Late display checkbox - default = allow late display
203 hlayout = new QHBoxLayout();
204 hlayout->setMargin(0);
205 hlayout->setSpacing(2 * style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing));
206 groupLayout->addLayout(hlayout);
207 mLateCancel = new LateCancelSelector(false, group);
208 mLateCancel->setFixedSize(mLateCancel->sizeHint());
209 hlayout->addWidget(mLateCancel);
210 hlayout->addStretch();
212 // Sub-repetition button
213 mSubRepetition = new RepetitionButton(i18nc("@action:button", "Sub-Repetition"), false, group);
214 mSubRepetition->setFixedSize(mSubRepetition->sizeHint());
215 mSubRepetition->set(Repetition(), true, 364*24*60);
216 mSubRepetition->setWhatsThis(i18nc("@info:whatsthis", "Set up an additional alarm repetition"));
217 hlayout->addWidget(mSubRepetition);
219 // Set the values to their defaults
220 setColours(Preferences::defaultFgColour(), Preferences::defaultBgColour());
221 mFontColourButton->setDefaultFont();
222 mFontColourButton->setBgColour(Preferences::defaultBgColour());
223 mFontColourButton->setFgColour(Preferences::defaultFgColour());
224 mLateCancel->setMinutes(Preferences::defaultLateCancel(), true, TimePeriod::Days);
225 mConfirmAck->setChecked(Preferences::defaultConfirmAck());
226 mSoundPicker->set(Preferences::defaultSoundType(), Preferences::defaultSoundFile(),
227 Preferences::defaultSoundVolume(), -1, 0, Preferences::defaultSoundRepeat());
228 if (mSpecialActionsButton)
230 KAEvent::ExtraActionOptions opts(0);
231 if (Preferences::defaultExecPreActionOnDeferral())
232 opts |= KAEvent::ExecPreActOnDeferral;
233 if (Preferences::defaultCancelOnPreActionError())
234 opts |= KAEvent::CancelOnPreActError;
235 if (Preferences::defaultDontShowPreActionError())
236 opts |= KAEvent::DontShowPreActError;
237 mSpecialActionsButton->setActions(Preferences::defaultPreAction(), Preferences::defaultPostAction(), opts);
241 mButtonBox = new QDialogButtonBox(this);
242 mButtonBox->addButton(QDialogButtonBox::Ok);
243 mButtonBox->addButton(QDialogButtonBox::Cancel);
244 connect(mButtonBox, &QDialogButtonBox::accepted,
245 this, &BirthdayDlg::slotOk);
246 connect(mButtonBox, &QDialogButtonBox::rejected,
247 this, &QDialog::reject);
248 topLayout->addWidget(mButtonBox);
251 KActionCollection* actions = new KActionCollection(this);
252 KStandardAction::selectAll(mListView, SLOT(selectAll()), actions);
253 KStandardAction::deselect(mListView, SLOT(clearSelection()), actions);
254 actions->addAssociatedWidget(mListView);
255 foreach (QAction* action, actions->actions())
256 action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
258 mButtonBox->button(QDialogButtonBox::Ok)->setEnabled(false); // only enable OK button when something is selected
261 /******************************************************************************
262 * Return a list of events for birthdays chosen.
264 QVector<KAEvent> BirthdayDlg::events() const
266 QVector<KAEvent> list;
267 QModelIndexList indexes = mListView->selectionModel()->selectedRows();
268 int count = indexes.count();
269 if (!count)
270 return list;
271 QDate today = KDateTime::currentLocalDate();
272 KDateTime todayStart(today, KDateTime::Spec(KDateTime::ClockTime));
273 int thisYear = today.year();
274 int reminder = mReminder->minutes();
275 for (int i = 0; i < count; ++i)
277 const QModelIndex nameIndex = indexes.at(i).model()->index(indexes.at(i).row(), 0);
278 const QModelIndex birthdayIndex = indexes.at(i).model()->index(indexes.at(i).row(), 1);
279 const QString name = nameIndex.data(Qt::DisplayRole).toString();
280 QDate date = birthdayIndex.data(BirthdayModel::DateRole).toDate();
281 date.setYMD(thisYear, date.month(), date.day());
282 if (date <= today)
283 date.setYMD(thisYear + 1, date.month(), date.day());
284 KAEvent event(KDateTime(date, KDateTime::Spec(KDateTime::ClockTime)),
285 mPrefix->text() + name + mSuffix->text(),
286 mFontColourButton->bgColour(), mFontColourButton->fgColour(),
287 mFontColourButton->font(), KAEvent::MESSAGE, mLateCancel->minutes(),
288 mFlags, true);
289 float fadeVolume;
290 int fadeSecs;
291 float volume = mSoundPicker->volume(fadeVolume, fadeSecs);
292 int repeatPause = mSoundPicker->repeatPause();
293 event.setAudioFile(mSoundPicker->file().toDisplayString(), volume, fadeVolume, fadeSecs, repeatPause);
294 QVector<int> months(1, date.month());
295 event.setRecurAnnualByDate(1, months, 0, KARecurrence::defaultFeb29Type(), -1, QDate());
296 event.setRepetition(mSubRepetition->repetition());
297 event.setNextOccurrence(todayStart);
298 if (reminder)
299 event.setReminder(reminder, false);
300 if (mSpecialActionsButton)
301 event.setActions(mSpecialActionsButton->preAction(),
302 mSpecialActionsButton->postAction(),
303 mSpecialActionsButton->options());
304 event.endChanges();
305 list.append(event);
307 return list;
310 /******************************************************************************
311 * Called when the OK button is selected to import the selected birthdays.
313 void BirthdayDlg::slotOk()
315 // Save prefix and suffix texts to use as future defaults
316 KConfigGroup config(KSharedConfig::openConfig(), "General");
317 config.writeEntry("BirthdayPrefix", mPrefix->text());
318 config.writeEntry("BirthdaySuffix", mSuffix->text());
319 config.sync();
321 mFlags = KAEvent::ANY_TIME;
322 if (mSoundPicker->sound() == Preferences::Sound_Beep) mFlags |= KAEvent::BEEP;
323 if (mSoundPicker->repeatPause() >= 0) mFlags |= KAEvent::REPEAT_SOUND;
324 if (mConfirmAck->isChecked()) mFlags |= KAEvent::CONFIRM_ACK;
325 if (mFontColourButton->defaultFont()) mFlags |= KAEvent::DEFAULT_FONT;
326 QDialog::accept();
329 /******************************************************************************
330 * Called when the group of items selected changes.
331 * Enable/disable the OK button depending on whether anything is selected.
333 void BirthdayDlg::slotSelectionChanged()
335 mButtonBox->button(QDialogButtonBox::Ok)->setEnabled(mListView->selectionModel()->hasSelection());
338 /******************************************************************************
339 * Called when the font/color button has been clicked.
340 * Set the colors in the message text entry control.
342 void BirthdayDlg::setColours(const QColor& fgColour, const QColor& bgColour)
344 QPalette pal = mPrefix->palette();
345 pal.setColor(mPrefix->backgroundRole(), bgColour);
346 pal.setColor(mPrefix->foregroundRole(), fgColour);
347 mPrefix->setPalette(pal);
348 mSuffix->setPalette(pal);
351 /******************************************************************************
352 * Called when the data has changed in the birthday list.
353 * Resize the date column.
355 void BirthdayDlg::resizeViewColumns()
357 mListView->resizeColumnToContents(BirthdayModel::DateColumn);
360 /******************************************************************************
361 * Called when the prefix or suffix text has lost keyboard focus.
362 * If the text has changed, re-evaluates the selection list according to the new
363 * birthday alarm text format.
365 void BirthdayDlg::slotTextLostFocus()
367 QString prefix = mPrefix->text();
368 QString suffix = mSuffix->text();
369 if (prefix != mPrefixText || suffix != mSuffixText)
371 // Text has changed - re-evaluate the selection list
372 mPrefixText = prefix;
373 mSuffixText = suffix;
374 mBirthdaySortModel->setPrefixSuffix(mPrefixText, mSuffixText);
378 // vim: et sw=4: