Remove KActionCollection::setComponentData: this does not work on a KActionCollection...
[kdepim.git] / kalarm / birthdaydlg.cpp
blob251a35661c2403eedb79ac4dc46d45b7a4897a17
1 /*
2 * birthdaydlg.cpp - dialog to pick birthdays from address book
3 * Program: kalarm
4 * Copyright © 2002-2011 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.moc"
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 <akonadi/control.h>
39 #include <akonadi/entitymimetypefiltermodel.h>
41 #include <klocale.h>
42 #include <kglobal.h>
43 #include <kconfiggroup.h>
44 #include <kmessagebox.h>
45 #include <kstandardaction.h>
46 #include <kactioncollection.h>
47 #include <kdescendantsproxymodel.h>
48 #include <khbox.h>
49 #include <kdebug.h>
51 #include <QAction>
52 #include <QGroupBox>
53 #include <QLabel>
54 #include <QTreeView>
55 #include <QHeaderView>
56 #include <QHBoxLayout>
57 #include <QVBoxLayout>
59 using namespace KCal;
62 BirthdayDlg::BirthdayDlg(QWidget* parent)
63 : KDialog(parent),
64 mSpecialActionsButton(0)
66 setObjectName("BirthdayDlg"); // used by LikeBack
67 setCaption(i18nc("@title:window", "Import Birthdays From KAddressBook"));
68 setButtons(Ok | Cancel);
69 setDefaultButton(Ok);
71 connect(this, SIGNAL(okClicked()), SLOT(slotOk()));
73 QWidget* topWidget = new QWidget(this);
74 setMainWidget(topWidget);
75 QVBoxLayout* topLayout = new QVBoxLayout(topWidget);
76 topLayout->setMargin(0);
77 topLayout->setSpacing(spacingHint());
79 // Prefix and suffix to the name in the alarm text
80 // Get default prefix and suffix texts from config file
81 KConfigGroup config(KGlobal::config(), "General");
82 mPrefixText = config.readEntry("BirthdayPrefix", i18nc("@info/plain", "Birthday: "));
83 mSuffixText = config.readEntry("BirthdaySuffix");
85 QGroupBox* textGroup = new QGroupBox(i18nc("@title:group", "Alarm Text"), topWidget);
86 topLayout->addWidget(textGroup);
87 QGridLayout* grid = new QGridLayout(textGroup);
88 grid->setMargin(marginHint());
89 grid->setSpacing(spacingHint());
90 QLabel* label = new QLabel(i18nc("@label:textbox", "Prefix:"), textGroup);
91 label->setFixedSize(label->sizeHint());
92 grid->addWidget(label, 0, 0);
93 mPrefix = new BLineEdit(mPrefixText, textGroup);
94 mPrefix->setMinimumSize(mPrefix->sizeHint());
95 label->setBuddy(mPrefix);
96 connect(mPrefix, SIGNAL(focusLost()), SLOT(slotTextLostFocus()));
97 mPrefix->setWhatsThis(i18nc("@info:whatsthis",
98 "Enter text to appear before the person's name in the alarm message, "
99 "including any necessary trailing spaces."));
100 grid->addWidget(mPrefix, 0, 1);
102 label = new QLabel(i18nc("@label:textbox", "Suffix:"), textGroup);
103 label->setFixedSize(label->sizeHint());
104 grid->addWidget(label, 1, 0);
105 mSuffix = new BLineEdit(mSuffixText, textGroup);
106 mSuffix->setMinimumSize(mSuffix->sizeHint());
107 label->setBuddy(mSuffix);
108 connect(mSuffix, SIGNAL(focusLost()), SLOT(slotTextLostFocus()));
109 mSuffix->setWhatsThis(i18nc("@info:whatsthis",
110 "Enter text to appear after the person's name in the alarm message, "
111 "including any necessary leading spaces."));
112 grid->addWidget(mSuffix, 1, 1);
114 QGroupBox* group = new QGroupBox(i18nc("@title:group", "Select Birthdays"), topWidget);
115 topLayout->addWidget(group);
116 QVBoxLayout* layout = new QVBoxLayout(group);
117 layout->setMargin(0);
119 // Start Akonadi server as we need it for the birthday model to access contacts information
120 Akonadi::Control::start();
122 BirthdayModel* model = BirthdayModel::instance();
123 connect(model, SIGNAL(dataChanged(const QModelIndex&,const QModelIndex&)), SLOT(resizeViewColumns()));
125 KDescendantsProxyModel* descendantsModel = new KDescendantsProxyModel(this);
126 descendantsModel->setSourceModel(model);
128 Akonadi::EntityMimeTypeFilterModel* mimeTypeFilter = new Akonadi::EntityMimeTypeFilterModel(this);
129 mimeTypeFilter->setSourceModel(descendantsModel);
130 mimeTypeFilter->addMimeTypeExclusionFilter(Akonadi::Collection::mimeType());
131 mimeTypeFilter->setHeaderGroup(Akonadi::EntityTreeModel::ItemListHeaders);
133 mBirthdaySortModel = new BirthdaySortModel(this);
134 mBirthdaySortModel->setSourceModel(mimeTypeFilter);
135 mBirthdaySortModel->setSortCaseSensitivity(Qt::CaseInsensitive);
136 mBirthdaySortModel->setPrefixSuffix(mPrefixText, mSuffixText);
137 mListView = new QTreeView(group);
138 mListView->setModel(mBirthdaySortModel);
139 mListView->setRootIsDecorated(false); // don't show expander icons
140 mListView->setSortingEnabled(true);
141 mListView->sortByColumn(BirthdayModel::NameColumn);
142 mListView->setAllColumnsShowFocus(true);
143 mListView->setSelectionMode(QAbstractItemView::ExtendedSelection);
144 mListView->setSelectionBehavior(QAbstractItemView::SelectRows);
145 mListView->setTextElideMode(Qt::ElideRight);
146 mListView->header()->setResizeMode(BirthdayModel::NameColumn, QHeaderView::Stretch);
147 mListView->header()->setResizeMode(BirthdayModel::DateColumn, QHeaderView::ResizeToContents);
148 connect(mListView->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&,const QItemSelection&)), SLOT(slotSelectionChanged()));
149 mListView->setWhatsThis(i18nc("@info:whatsthis",
150 "<para>Select birthdays to set alarms for.<nl/>"
151 "This list shows all birthdays in <application>KAddressBook</application> except those for which alarms already exist.</para>"
152 "<para>You can select multiple birthdays at one time by dragging the mouse over the list, "
153 "or by clicking the mouse while pressing Ctrl or Shift.</para>"));
154 layout->addWidget(mListView);
156 group = new QGroupBox(i18nc("@title:group", "Alarm Configuration"), topWidget);
157 topLayout->addWidget(group);
158 QVBoxLayout* groupLayout = new QVBoxLayout(group);
159 groupLayout->setMargin(marginHint());
160 groupLayout->setSpacing(spacingHint());
162 // Sound checkbox and file selector
163 QHBoxLayout* hlayout = new QHBoxLayout();
164 hlayout->setMargin(0);
165 groupLayout->addLayout(hlayout);
166 mSoundPicker = new SoundPicker(group);
167 mSoundPicker->setFixedSize(mSoundPicker->sizeHint());
168 hlayout->addWidget(mSoundPicker);
169 hlayout->addSpacing(2*spacingHint());
170 hlayout->addStretch();
172 // Font and colour choice button and sample text
173 mFontColourButton = new FontColourButton(group);
174 mFontColourButton->setMaximumHeight(mFontColourButton->sizeHint().height() * 3/2);
175 hlayout->addWidget(mFontColourButton);
176 connect(mFontColourButton, SIGNAL(selected(const QColor&, const QColor&)), SLOT(setColours(const QColor&, const QColor&)));
178 // How much advance warning to give
179 mReminder = new Reminder(i18nc("@info:whatsthis", "Check to display a reminder in advance of or after the birthday."),
180 i18nc("@info:whatsthis", "Enter the number of days before or after each birthday to display a reminder. "
181 "This is in addition to the alarm which is displayed on the birthday."),
182 i18nc("@info:whatsthis", "Select whether the reminder should be triggered before or after the birthday."),
183 false, false, group);
184 mReminder->setFixedSize(mReminder->sizeHint());
185 mReminder->setMaximum(0, 364);
186 mReminder->setMinutes(0, true);
187 groupLayout->addWidget(mReminder, 0, Qt::AlignLeft);
189 // Acknowledgement confirmation required - default = no confirmation
190 hlayout = new QHBoxLayout();
191 hlayout->setMargin(0);
192 hlayout->setSpacing(2*spacingHint());
193 groupLayout->addLayout(hlayout);
194 mConfirmAck = EditDisplayAlarmDlg::createConfirmAckCheckbox(group);
195 mConfirmAck->setFixedSize(mConfirmAck->sizeHint());
196 hlayout->addWidget(mConfirmAck);
197 hlayout->addSpacing(2*spacingHint());
198 hlayout->addStretch();
200 if (ShellProcess::authorised()) // don't display if shell commands not allowed (e.g. kiosk mode)
202 // Special actions button
203 mSpecialActionsButton = new SpecialActionsButton(false, group);
204 mSpecialActionsButton->setFixedSize(mSpecialActionsButton->sizeHint());
205 hlayout->addWidget(mSpecialActionsButton);
208 // Late display checkbox - default = allow late display
209 hlayout = new QHBoxLayout();
210 hlayout->setMargin(0);
211 hlayout->setSpacing(2*spacingHint());
212 groupLayout->addLayout(hlayout);
213 mLateCancel = new LateCancelSelector(false, group);
214 mLateCancel->setFixedSize(mLateCancel->sizeHint());
215 hlayout->addWidget(mLateCancel);
216 hlayout->addStretch();
218 // Sub-repetition button
219 mSubRepetition = new RepetitionButton(i18nc("@action:button", "Sub-Repetition"), false, group);
220 mSubRepetition->setFixedSize(mSubRepetition->sizeHint());
221 mSubRepetition->set(Repetition(), true, 364*24*60);
222 mSubRepetition->setWhatsThis(i18nc("@info:whatsthis", "Set up an additional alarm repetition"));
223 hlayout->addWidget(mSubRepetition);
225 // Set the values to their defaults
226 setColours(Preferences::defaultFgColour(), Preferences::defaultBgColour());
227 mFontColourButton->setDefaultFont();
228 mFontColourButton->setBgColour(Preferences::defaultBgColour());
229 mFontColourButton->setFgColour(Preferences::defaultFgColour());
230 mLateCancel->setMinutes(Preferences::defaultLateCancel(), true, TimePeriod::Days);
231 mConfirmAck->setChecked(Preferences::defaultConfirmAck());
232 mSoundPicker->set(Preferences::defaultSoundType(), Preferences::defaultSoundFile(),
233 Preferences::defaultSoundVolume(), -1, 0, Preferences::defaultSoundRepeat());
234 if (mSpecialActionsButton)
235 mSpecialActionsButton->setActions(Preferences::defaultPreAction(), Preferences::defaultPostAction(),
236 Preferences::defaultCancelOnPreActionError(), Preferences::defaultDontShowPreActionError());
238 KActionCollection* actions = new KActionCollection(this);
239 KStandardAction::selectAll(mListView, SLOT(selectAll()), actions);
240 KStandardAction::deselect(mListView, SLOT(clearSelection()), actions);
241 actions->addAssociatedWidget(mListView);
242 foreach (QAction* action, actions->actions())
243 action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
245 enableButtonOk(false); // only enable OK button when something is selected
248 /******************************************************************************
249 * Return a list of events for birthdays chosen.
251 QList<KAEvent> BirthdayDlg::events() const
253 QList<KAEvent> list;
254 QModelIndexList indexes = mListView->selectionModel()->selectedRows();
255 int count = indexes.count();
256 if (!count)
257 return list;
258 QDate today = KDateTime::currentLocalDate();
259 KDateTime todayStart(today, KDateTime::ClockTime);
260 int thisYear = today.year();
261 int reminder = mReminder->minutes();
262 for (int i = 0; i < count; ++i)
264 const QModelIndex nameIndex = indexes.at(i).model()->index(indexes.at(i).row(), 0);
265 const QModelIndex birthdayIndex = indexes.at(i).model()->index(indexes.at(i).row(), 1);
266 const QString name = nameIndex.data(Qt::DisplayRole).toString();
267 QDate date = birthdayIndex.data(BirthdayModel::DateRole).toDate();
268 date.setYMD(thisYear, date.month(), date.day());
269 if (date <= today)
270 date.setYMD(thisYear + 1, date.month(), date.day());
271 KAEvent event(KDateTime(date, KDateTime::ClockTime),
272 mPrefix->text() + name + mSuffix->text(),
273 mFontColourButton->bgColour(), mFontColourButton->fgColour(),
274 mFontColourButton->font(), KAEvent::MESSAGE, mLateCancel->minutes(),
275 mFlags, true);
276 float fadeVolume;
277 int fadeSecs;
278 float volume = mSoundPicker->volume(fadeVolume, fadeSecs);
279 event.setAudioFile(mSoundPicker->file().prettyUrl(), volume, fadeVolume, fadeSecs);
280 QList<int> months;
281 months.append(date.month());
282 event.setRecurAnnualByDate(1, months, 0, KARecurrence::defaultFeb29Type(), -1, QDate());
283 event.setRepetition(mSubRepetition->repetition());
284 event.setNextOccurrence(todayStart);
285 if (reminder)
286 event.setReminder(reminder, false);
287 if (mSpecialActionsButton)
288 event.setActions(mSpecialActionsButton->preAction(),
289 mSpecialActionsButton->postAction(),
290 mSpecialActionsButton->cancelOnError(),
291 mSpecialActionsButton->dontShowError());
292 event.endChanges();
293 list.append(event);
295 return list;
298 /******************************************************************************
299 * Called when the OK button is selected to import the selected birthdays.
301 void BirthdayDlg::slotOk()
303 // Save prefix and suffix texts to use as future defaults
304 KConfigGroup config(KGlobal::config(), "General");
305 config.writeEntry("BirthdayPrefix", mPrefix->text());
306 config.writeEntry("BirthdaySuffix", mSuffix->text());
307 config.sync();
309 mFlags = (mSoundPicker->sound() == Preferences::Sound_Beep ? KAEvent::BEEP : 0)
310 | (mSoundPicker->repeat() ? KAEvent::REPEAT_SOUND : 0)
311 | (mConfirmAck->isChecked() ? KAEvent::CONFIRM_ACK : 0)
312 | (mFontColourButton->defaultFont() ? KAEvent::DEFAULT_FONT : 0)
313 | KAEvent::ANY_TIME;
314 KDialog::accept();
317 /******************************************************************************
318 * Called when the group of items selected changes.
319 * Enable/disable the OK button depending on whether anything is selected.
321 void BirthdayDlg::slotSelectionChanged()
323 enableButtonOk(mListView->selectionModel()->hasSelection());
326 /******************************************************************************
327 * Called when the font/color button has been clicked.
328 * Set the colors in the message text entry control.
330 void BirthdayDlg::setColours(const QColor& fgColour, const QColor& bgColour)
332 QPalette pal = mPrefix->palette();
333 pal.setColor(mPrefix->backgroundRole(), bgColour);
334 pal.setColor(mPrefix->foregroundRole(), fgColour);
335 mPrefix->setPalette(pal);
336 mSuffix->setPalette(pal);
339 /******************************************************************************
340 * Called when the data has changed in the birthday list.
341 * Resize the date column.
343 void BirthdayDlg::resizeViewColumns()
345 mListView->resizeColumnToContents(BirthdayModel::DateColumn);
348 /******************************************************************************
349 * Called when the prefix or suffix text has lost keyboard focus.
350 * If the text has changed, re-evaluates the selection list according to the new
351 * birthday alarm text format.
353 void BirthdayDlg::slotTextLostFocus()
355 QString prefix = mPrefix->text();
356 QString suffix = mSuffix->text();
357 if (prefix != mPrefixText || suffix != mSuffixText)
359 // Text has changed - re-evaluate the selection list
360 mPrefixText = prefix;
361 mSuffixText = suffix;
362 mBirthdaySortModel->setPrefixSuffix(mPrefixText, mSuffixText);
366 // vim: et sw=4: