2 * sounddlg.cpp - sound file selection and configuration dialog and widget
4 * Copyright © 2005-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.
22 #include "sounddlg.moc"
25 #include "functions.h"
28 #include "pushbutton.h"
30 #include "soundpicker.h"
34 #include <kstandarddirs.h>
35 #include <kiconloader.h>
37 #include <kio/netaccess.h>
38 #include <phonon/mediaobject.h>
39 #include <phonon/audiooutput.h>
45 #include <QApplication>
46 #include <QVBoxLayout>
47 #include <QGridLayout>
49 #include <QResizeEvent>
52 // Collect these widget labels together to ensure consistent wording and
53 // translations across different modules.
54 QString
SoundWidget::i18n_chk_Repeat() { return i18nc("@option:check", "Repeat"); }
56 static const char SOUND_DIALOG_NAME
[] = "SoundDialog";
59 SoundDlg::SoundDlg(const QString
& file
, float volume
, float fadeVolume
, int fadeSeconds
, int repeatPause
,
60 const QString
& caption
, QWidget
* parent
)
64 mSoundWidget
= new SoundWidget(true, true, this);
65 setMainWidget(mSoundWidget
);
67 setButtons(Ok
|Cancel
);
70 // Restore the dialog size from last time
72 if (KAlarm::readConfigWindowSize(SOUND_DIALOG_NAME
, s
))
75 // Initialise the control values
76 mSoundWidget
->set(file
, volume
, fadeVolume
, fadeSeconds
, repeatPause
);
79 /******************************************************************************
80 * Set the read-only status of the dialog.
82 void SoundDlg::setReadOnly(bool readOnly
)
84 if (readOnly
!= mReadOnly
)
86 mSoundWidget
->setReadOnly(readOnly
);
91 setDefaultButton(Cancel
);
95 setButtons(Ok
|Cancel
);
101 KUrl
SoundDlg::getFile() const
104 mSoundWidget
->file(url
);
108 /******************************************************************************
109 * Called when the dialog's size has changed.
110 * Records the new size in the config file.
112 void SoundDlg::resizeEvent(QResizeEvent
* re
)
115 KAlarm::writeConfigWindowSize(SOUND_DIALOG_NAME
, re
->size());
116 KDialog::resizeEvent(re
);
119 /******************************************************************************
120 * Called when the OK or Cancel button is clicked.
122 void SoundDlg::slotButtonClicked(int button
)
128 else if (mSoundWidget
->validate(true))
132 KDialog::slotButtonClicked(button
);
136 /*=============================================================================
138 = Select a sound file and configure how to play it.
139 =============================================================================*/
141 SoundWidget::SoundWidget(bool showPlay
, bool showRepeat
, QWidget
* parent
)
148 mEmptyFileAllowed(false)
150 QVBoxLayout
* layout
= new QVBoxLayout(this);
151 layout
->setMargin(0);
152 layout
->setSpacing(KDialog::spacingHint());
157 label
= new QLabel(i18nc("@label", "Sound file:"), this);
158 layout
->addWidget(label
);
161 KHBox
* box
= new KHBox(this);
163 layout
->addWidget(box
);
168 mFilePlay
= new QPushButton(box
);
169 mFilePlay
->setIcon(SmallIcon("media-playback-start"));
170 connect(mFilePlay
, SIGNAL(clicked()), SLOT(playSound()));
171 mFilePlay
->setToolTip(i18nc("@info:tooltip", "Test the sound"));
172 mFilePlay
->setWhatsThis(i18nc("@info:whatsthis", "Play the selected sound file."));
175 // File name edit box
176 mFileEdit
= new LineEdit(LineEdit::Url
, box
);
177 mFileEdit
->setAcceptDrops(true);
178 mFileEdit
->setWhatsThis(i18nc("@info:whatsthis", "Enter the name or URL of a sound file to play."));
180 label
->setBuddy(mFileEdit
);
181 connect(mFileEdit
, SIGNAL(textChanged(QString
)), SIGNAL(changed()));
183 // File browse button
184 mFileBrowseButton
= new PushButton(box
);
185 mFileBrowseButton
->setIcon(KIcon(SmallIcon("document-open")));
186 int size
= mFileBrowseButton
->sizeHint().height();
187 mFileBrowseButton
->setFixedSize(size
, size
);
188 connect(mFileBrowseButton
, SIGNAL(clicked()), SLOT(slotPickFile()));
189 mFileBrowseButton
->setToolTip(i18nc("@info:tooltip", "Choose a file"));
190 mFileBrowseButton
->setWhatsThis(i18nc("@info:whatsthis", "Select a sound file to play."));
194 int size
= qMax(mFilePlay
->sizeHint().height(), mFileBrowseButton
->sizeHint().height());
195 mFilePlay
->setFixedSize(size
, size
);
196 mFileBrowseButton
->setFixedSize(size
, size
);
201 // Sound repetition checkbox
202 mRepeatGroupBox
= new GroupBox(i18n_chk_Repeat(), this);
203 mRepeatGroupBox
->setCheckable(true);
204 mRepeatGroupBox
->setWhatsThis(i18nc("@info:whatsthis", "If checked, the sound file will be played repeatedly for as long as the message is displayed."));
205 connect(mRepeatGroupBox
, SIGNAL(toggled(bool)), SIGNAL(changed()));
206 layout
->addWidget(mRepeatGroupBox
);
207 QVBoxLayout
* glayout
= new QVBoxLayout(mRepeatGroupBox
);
209 // Pause between repetitions
210 KHBox
* box
= new KHBox(mRepeatGroupBox
);
212 box
->setSpacing(KDialog::spacingHint());
213 glayout
->addWidget(box
);
214 label
= new QLabel(i18nc("@label:spinbox Length of time to pause between repetitions", "Pause between repetitions:"), box
);
215 label
->setFixedSize(label
->sizeHint());
216 mRepeatPause
= new SpinBox(0, 999, box
);
217 mRepeatPause
->setSingleShiftStep(10);
218 mRepeatPause
->setFixedSize(mRepeatPause
->sizeHint());
219 label
->setBuddy(mRepeatPause
);
220 connect(mRepeatPause
, SIGNAL(valueChanged(int)), SIGNAL(changed()));
221 label
= new QLabel(i18nc("@label", "seconds"), box
);
222 label
->setFixedSize(label
->sizeHint());
223 box
->setWhatsThis(i18nc("@info:whatsthis", "Enter how many seconds to pause between repetitions."));
227 QGroupBox
* group
= new QGroupBox(i18nc("@title:group Sound volume", "Volume"), this);
228 layout
->addWidget(group
);
229 QGridLayout
* grid
= new QGridLayout(group
);
230 grid
->setMargin(KDialog::marginHint());
231 grid
->setSpacing(KDialog::spacingHint());
232 grid
->setColumnStretch(2, 1);
233 int indentWidth
= 3 * KDialog::spacingHint();
234 grid
->setColumnMinimumWidth(0, indentWidth
);
235 grid
->setColumnMinimumWidth(1, indentWidth
);
237 // 'Set volume' checkbox
238 box
= new KHBox(group
);
240 box
->setSpacing(KDialog::spacingHint());
241 grid
->addWidget(box
, 1, 0, 1, 3);
242 mVolumeCheckbox
= new CheckBox(i18nc("@option:check", "Set volume"), box
);
243 mVolumeCheckbox
->setFixedSize(mVolumeCheckbox
->sizeHint());
244 connect(mVolumeCheckbox
, SIGNAL(toggled(bool)), SLOT(slotVolumeToggled(bool)));
245 mVolumeCheckbox
->setWhatsThis(i18nc("@info:whatsthis", "Select to choose the volume for playing the sound file."));
248 mVolumeSlider
= new Slider(0, 100, 10, Qt::Horizontal
, box
);
249 mVolumeSlider
->setTickPosition(QSlider::TicksBelow
);
250 mVolumeSlider
->setTickInterval(10);
251 mVolumeSlider
->setSizePolicy(QSizePolicy(QSizePolicy::Expanding
, QSizePolicy::Fixed
));
252 mVolumeSlider
->setWhatsThis(i18nc("@info:whatsthis", "Choose the volume for playing the sound file."));
253 mVolumeCheckbox
->setFocusWidget(mVolumeSlider
);
254 connect(mVolumeSlider
, SIGNAL(valueChanged(int)), SIGNAL(changed()));
257 mFadeCheckbox
= new CheckBox(i18nc("@option:check", "Fade"), group
);
258 mFadeCheckbox
->setFixedSize(mFadeCheckbox
->sizeHint());
259 connect(mFadeCheckbox
, SIGNAL(toggled(bool)), SLOT(slotFadeToggled(bool)));
260 mFadeCheckbox
->setWhatsThis(i18nc("@info:whatsthis", "Select to fade the volume when the sound file first starts to play."));
261 grid
->addWidget(mFadeCheckbox
, 2, 1, 1, 2, Qt::AlignLeft
);
264 mFadeBox
= new KHBox(group
);
265 mFadeBox
->setMargin(0);
266 mFadeBox
->setSpacing(KDialog::spacingHint());
267 grid
->addWidget(mFadeBox
, 3, 2, Qt::AlignLeft
);
268 label
= new QLabel(i18nc("@label:spinbox Time period over which to fade the sound", "Fade time:"), mFadeBox
);
269 label
->setFixedSize(label
->sizeHint());
270 mFadeTime
= new SpinBox(1, 999, mFadeBox
);
271 mFadeTime
->setSingleShiftStep(10);
272 mFadeTime
->setFixedSize(mFadeTime
->sizeHint());
273 label
->setBuddy(mFadeTime
);
274 connect(mFadeTime
, SIGNAL(valueChanged(int)), SIGNAL(changed()));
275 label
= new QLabel(i18nc("@label", "seconds"), mFadeBox
);
276 label
->setFixedSize(label
->sizeHint());
277 mFadeBox
->setWhatsThis(i18nc("@info:whatsthis", "Enter how many seconds to fade the sound before reaching the set volume."));
280 mFadeVolumeBox
= new KHBox(group
);
281 mFadeVolumeBox
->setMargin(0);
282 mFadeVolumeBox
->setSpacing(KDialog::spacingHint());
283 grid
->addWidget(mFadeVolumeBox
, 4, 2);
284 label
= new QLabel(i18nc("@label:slider", "Initial volume:"), mFadeVolumeBox
);
285 label
->setFixedSize(label
->sizeHint());
286 mFadeSlider
= new Slider(0, 100, 10, Qt::Horizontal
, mFadeVolumeBox
);
287 mFadeSlider
->setTickPosition(QSlider::TicksBelow
);
288 mFadeSlider
->setTickInterval(10);
289 mFadeSlider
->setSizePolicy(QSizePolicy(QSizePolicy::Expanding
, QSizePolicy::Fixed
));
290 label
->setBuddy(mFadeSlider
);
291 connect(mFadeSlider
, SIGNAL(valueChanged(int)), SIGNAL(changed()));
292 mFadeVolumeBox
->setWhatsThis(i18nc("@info:whatsthis", "Choose the initial volume for playing the sound file."));
294 slotVolumeToggled(false);
297 SoundWidget::~SoundWidget()
299 delete mPlayer
; // this stops playing if not already stopped
303 /******************************************************************************
304 * Set the controls' values.
306 void SoundWidget::set(const QString
& file
, float volume
, float fadeVolume
, int fadeSeconds
, int repeatPause
)
308 // Initialise the control values
309 mFileEdit
->setText(KAlarm::pathOrUrl(file
));
312 mRepeatGroupBox
->setChecked(repeatPause
>= 0);
313 mRepeatPause
->setValue(repeatPause
>= 0 ? repeatPause
: 0);
315 mVolumeCheckbox
->setChecked(volume
>= 0);
316 mVolumeSlider
->setValue(volume
>= 0 ? static_cast<int>(volume
*100) : 100);
317 mFadeCheckbox
->setChecked(fadeVolume
>= 0);
318 mFadeSlider
->setValue(fadeVolume
>= 0 ? static_cast<int>(fadeVolume
*100) : 100);
319 mFadeTime
->setValue(fadeSeconds
);
320 slotVolumeToggled(volume
>= 0);
323 /******************************************************************************
324 * Set the read-only status of the widget.
326 void SoundWidget::setReadOnly(bool readOnly
)
328 if (readOnly
!= mReadOnly
)
330 mFileEdit
->setReadOnly(readOnly
);
331 mFileBrowseButton
->setReadOnly(readOnly
);
333 mRepeatGroupBox
->setReadOnly(readOnly
);
334 mVolumeCheckbox
->setReadOnly(readOnly
);
335 mVolumeSlider
->setReadOnly(readOnly
);
336 mFadeCheckbox
->setReadOnly(readOnly
);
337 mFadeTime
->setReadOnly(readOnly
);
338 mFadeSlider
->setReadOnly(readOnly
);
339 mReadOnly
= readOnly
;
343 /******************************************************************************
344 * Return the file name typed in the edit field.
346 QString
SoundWidget::fileName() const
348 return mFileEdit
->text();
351 /******************************************************************************
352 * Validate the entered file and return it.
354 bool SoundWidget::file(KUrl
& url
, bool showErrorMessage
) const
356 bool result
= validate(showErrorMessage
);
361 /******************************************************************************
362 * Return the entered repetition and volume settings:
363 * 'volume' is in range 0 - 1, or < 0 if volume is not to be set.
364 * 'fadeVolume is similar, with 'fadeTime' set to the fade interval in seconds.
366 void SoundWidget::getVolume(float& volume
, float& fadeVolume
, int& fadeSeconds
) const
368 volume
= mVolumeCheckbox
->isChecked() ? (float)mVolumeSlider
->value() / 100 : -1;
369 if (mFadeCheckbox
->isChecked())
371 fadeVolume
= (float)mFadeSlider
->value() / 100;
372 fadeSeconds
= mFadeTime
->value();
381 /******************************************************************************
382 * Return the entered repetition setting.
383 * Reply = seconds to pause between repetitions, or -1 if no repeat.
385 int SoundWidget::repeatPause() const
387 return mRepeatGroupBox
&& mRepeatGroupBox
->isChecked() ? mRepeatPause
->value() : -1;
390 /******************************************************************************
391 * Called when the dialog's size has changed.
392 * Records the new size in the config file.
394 void SoundWidget::resizeEvent(QResizeEvent
* re
)
396 mVolumeSlider
->resize(mFadeSlider
->size());
397 QWidget::resizeEvent(re
);
400 void SoundWidget::showEvent(QShowEvent
* se
)
402 mVolumeSlider
->resize(mFadeSlider
->size());
403 QWidget::showEvent(se
);
406 /******************************************************************************
407 * Called when the file browser button is clicked.
409 void SoundWidget::slotPickFile()
411 QString url
= SoundPicker::browseFile(mDefaultDir
, mFileEdit
->text());
413 mFileEdit
->setText(KAlarm::pathOrUrl(url
));
416 /******************************************************************************
417 * Called when the file play or stop button is clicked.
419 void SoundWidget::playSound()
423 // The file is currently playing. Stop it.
430 #warning Phonon::createPlayer() does not work
431 mPlayer
= Phonon::createPlayer(Phonon::MusicCategory
, mUrl
);
432 mPlayer
->setParent(this);
434 mPlayer
= new Phonon::MediaObject(this);
435 Phonon::AudioOutput
* output
= new Phonon::AudioOutput(Phonon::MusicCategory
, mPlayer
);
436 mPlayer
->setCurrentSource(mUrl
);
437 Phonon::createPath(mPlayer
, output
);
439 connect(mPlayer
, SIGNAL(finished()), SLOT(playFinished()));
440 mFilePlay
->setIcon(SmallIcon("media-playback-stop")); // change the play button to a stop button
441 mFilePlay
->setToolTip(i18nc("@info:tooltip", "Stop sound"));
442 mFilePlay
->setWhatsThis(i18nc("@info:whatsthis", "Stop playing the sound"));
446 /******************************************************************************
447 * Called when playing the file has completed, or to stop playing.
449 void SoundWidget::playFinished()
451 delete mPlayer
; // this stops playing if not already stopped
453 mFilePlay
->setIcon(SmallIcon("media-playback-start"));
454 mFilePlay
->setToolTip(i18nc("@info:tooltip", "Test the sound"));
455 mFilePlay
->setWhatsThis(i18nc("@info:whatsthis", "Play the selected sound file."));
458 /******************************************************************************
459 * Check whether the specified sound file exists.
461 bool SoundWidget::validate(bool showErrorMessage
) const
463 QString file
= mFileEdit
->text();
464 if (file
== mValidatedFile
&& !file
.isEmpty())
466 mValidatedFile
= file
;
467 if (file
.isEmpty() && mEmptyFileAllowed
)
472 KAlarm::FileErr err
= KAlarm::checkFileExists(file
, mUrl
);
473 if (err
== KAlarm::FileErr_None
)
475 if (err
== KAlarm::FileErr_Nonexistent
)
478 if (mUrl
.isLocalFile() && !file
.startsWith(QLatin1String("/")))
480 // It's a relative path.
481 // Find the first sound resource that contains files.
482 QStringList soundDirs
= KGlobal::dirs()->resourceDirs("sound");
483 if (!soundDirs
.isEmpty())
486 dir
.setFilter(QDir::Files
| QDir::Readable
);
487 for (int i
= 0, end
= soundDirs
.count(); i
< end
; ++i
)
490 if (dir
.isReadable() && dir
.count() > 2)
492 mUrl
.setPath(soundDirs
[i
]);
494 QString f
= mUrl
.toLocalFile();
495 err
= KAlarm::checkFileExists(f
, mUrl
);
496 if (err
== KAlarm::FileErr_None
)
498 if (err
!= KAlarm::FileErr_Nonexistent
)
500 file
= f
; // for inclusion in error message
506 if (err
== KAlarm::FileErr_Nonexistent
)
508 mUrl
.setPath(QDir::homePath());
510 QString f
= mUrl
.toLocalFile();
511 err
= KAlarm::checkFileExists(f
, mUrl
);
512 if (err
== KAlarm::FileErr_None
)
514 if (err
!= KAlarm::FileErr_Nonexistent
)
515 file
= f
; // for inclusion in error message
519 mFileEdit
->setFocus();
521 && KAlarm::showFileErrMessage(file
, err
, KAlarm::FileErr_BlankPlay
, const_cast<SoundWidget
*>(this)))
523 mValidatedFile
.clear();
528 /******************************************************************************
529 * Called when the Set Volume checkbox is toggled.
531 void SoundWidget::slotVolumeToggled(bool on
)
533 mVolumeSlider
->setEnabled(on
);
534 mFadeCheckbox
->setEnabled(on
);
535 slotFadeToggled(on
&& mFadeCheckbox
->isChecked());
538 /******************************************************************************
539 * Called when the Fade checkbox is toggled.
541 void SoundWidget::slotFadeToggled(bool on
)
543 mFadeBox
->setEnabled(on
);
544 mFadeVolumeBox
->setEnabled(on
);