kalarm

soundpicker.cpp

00001 /*
00002  *  soundpicker.cpp  -  widget to select a sound file or a beep
00003  *  Program:  kalarm
00004  *  Copyright (C) 2002, 2004, 2005 by David Jarvie <software@astrojar.org.uk>
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 <config.h>
00022 #include "kalarm.h"
00023 
00024 #include <qlayout.h>
00025 #include <qregexp.h>
00026 #include <qtooltip.h>
00027 #include <qtimer.h>
00028 #include <qhbox.h>
00029 #include <qwhatsthis.h>
00030 
00031 #include <kglobal.h>
00032 #include <klocale.h>
00033 #include <kfiledialog.h>
00034 #include <kstandarddirs.h>
00035 #include <kiconloader.h>
00036 #ifndef WITHOUT_ARTS
00037 #include <arts/kplayobjectfactory.h>
00038 #endif
00039 #include <kdebug.h>
00040 
00041 #include "buttongroup.h"
00042 #include "checkbox.h"
00043 #include "functions.h"
00044 #include "kalarmapp.h"
00045 #include "pushbutton.h"
00046 #include "radiobutton.h"
00047 #include "sounddlg.h"
00048 #include "soundpicker.moc"
00049 
00050 
00051 // Collect these widget labels together to ensure consistent wording and
00052 // translations across different modules.
00053 QString SoundPicker::i18n_Sound()       { return i18n("An audio sound", "Sound"); }
00054 QString SoundPicker::i18n_s_Sound()     { return i18n("An audio sound", "&Sound"); }
00055 QString SoundPicker::i18n_Beep()        { return i18n("Beep"); }
00056 QString SoundPicker::i18n_b_Beep()      { return i18n("&Beep"); }
00057 QString SoundPicker::i18n_Speak()       { return i18n("Speak"); }
00058 QString SoundPicker::i18n_p_Speak()     { return i18n("S&peak"); }
00059 QString SoundPicker::i18n_File()        { return i18n("File"); }
00060 
00061 
00062 SoundPicker::SoundPicker(QWidget* parent, const char* name)
00063     : QFrame(parent, name),
00064       mRevertType(false)
00065 {
00066     // Sound checkbox
00067     setFrameStyle(QFrame::NoFrame);
00068     QHBoxLayout* soundLayout = new QHBoxLayout(this, 0, 2*KDialog::spacingHint());
00069     soundLayout->setAlignment(Qt::AlignVCenter);
00070     mCheckbox = new CheckBox(i18n_s_Sound(), this);
00071     mCheckbox->setFixedSize(mCheckbox->sizeHint());
00072     connect(mCheckbox, SIGNAL(toggled(bool)), SLOT(slotSoundToggled(bool)));
00073     QWhatsThis::add(mCheckbox,
00074           i18n("Check to enable sound when the message is displayed. Select the type of sound from the displayed options."));
00075     soundLayout->addWidget(mCheckbox);
00076 
00077     // Sound type
00078     mTypeGroup = new ButtonGroup(this);
00079     mTypeGroup->hide();
00080     connect(mTypeGroup, SIGNAL(buttonSet(int)), SLOT(slotTypeChanged(int)));
00081 
00082     // Beep radio button
00083     mBeepRadio = new RadioButton(i18n_Beep(), this, "beepButton");
00084     mBeepRadio->setFixedSize(mBeepRadio->sizeHint());
00085     QWhatsThis::add(mBeepRadio, i18n("If checked, a beep will sound when the alarm is displayed."));
00086     mTypeGroup->insert(mBeepRadio, BEEP);
00087     soundLayout->addWidget(mBeepRadio);
00088 
00089     // File radio button
00090     QHBox* box = new QHBox(this);
00091     mFileRadio = new RadioButton(i18n_File(), box, "audioFileButton");
00092     mFileRadio->setFixedSize(mFileRadio->sizeHint());
00093     QWhatsThis::add(mFileRadio, i18n("If checked, a sound file will be played when the alarm is displayed."));
00094     mTypeGroup->insert(mFileRadio, PLAY_FILE);
00095 
00096     // Sound file picker button
00097     mFilePicker = new PushButton(box);
00098     mFilePicker->setPixmap(SmallIcon("playsound"));
00099     mFilePicker->setFixedSize(mFilePicker->sizeHint());
00100     connect(mFilePicker, SIGNAL(clicked()), SLOT(slotPickFile()));
00101     QWhatsThis::add(mFilePicker, i18n("Configure a sound file to play when the alarm is displayed."));
00102     box->setFixedSize(box->sizeHint());
00103     soundLayout->addWidget(box);
00104     box->setFocusProxy(mFileRadio);
00105 
00106     // Speak radio button
00107     mSpeakRadio = new RadioButton(i18n_p_Speak(), this, "speakButton");
00108     mSpeakRadio->setFixedSize(mSpeakRadio->sizeHint());
00109     QWhatsThis::add(mSpeakRadio, i18n("If checked, the message will be spoken when the alarm is displayed."));
00110     mTypeGroup->insert(mSpeakRadio, SPEAK);
00111     soundLayout->addWidget(mSpeakRadio);
00112 
00113     if (!theApp()->speechEnabled())
00114         mSpeakRadio->hide();     // speech capability is not installed
00115 
00116     setTabOrder(mCheckbox, mBeepRadio);
00117     setTabOrder(mBeepRadio, mFileRadio);
00118     setTabOrder(mFileRadio, mFilePicker);
00119     setTabOrder(mFilePicker, mSpeakRadio);
00120 
00121     // Initialise the file picker button state and tooltip
00122     slotSoundToggled(false);
00123 }
00124 
00125 /******************************************************************************
00126 * Set the read-only status of the widget.
00127 */
00128 void SoundPicker::setReadOnly(bool readOnly)
00129 {
00130     mCheckbox->setReadOnly(readOnly);
00131     mBeepRadio->setReadOnly(readOnly);
00132     mFileRadio->setReadOnly(readOnly);
00133 #ifdef WITHOUT_ARTS
00134     mFilePicker->setReadOnly(readOnly);
00135 #endif
00136     mSpeakRadio->setReadOnly(readOnly);
00137     mReadOnly = readOnly;
00138 }
00139 
00140 /******************************************************************************
00141 * Show or hide the Speak option.
00142 */
00143 void SoundPicker::showSpeak(bool show)
00144 {
00145     if (!theApp()->speechEnabled())
00146         return;     // speech capability is not installed
00147 
00148     bool shown = !mSpeakRadio->isHidden();
00149     if (show  &&  !shown)
00150         mSpeakRadio->show();
00151     else if (!show  &&  shown)
00152     {
00153         if (mSpeakRadio->isOn())
00154             mCheckbox->setChecked(false);
00155         mSpeakRadio->hide();
00156     }
00157 }
00158 
00159 /******************************************************************************
00160 * Return whether sound is selected.
00161 */
00162 bool SoundPicker::sound() const
00163 {
00164     return mCheckbox->isChecked();
00165 }
00166 
00167 /******************************************************************************
00168 * Return the currently selected option.
00169 */
00170 SoundPicker::Type SoundPicker::type() const
00171 {
00172     return static_cast<SoundPicker::Type>(mTypeGroup->selectedId());
00173 }
00174 
00175 /******************************************************************************
00176 * Return whether beep is selected.
00177 */
00178 bool SoundPicker::beep() const
00179 {
00180     return mCheckbox->isChecked()  &&  mBeepRadio->isOn();
00181 }
00182 
00183 /******************************************************************************
00184 * Return whether speech is selected.
00185 */
00186 bool SoundPicker::speak() const
00187 {
00188     return mCheckbox->isChecked()  &&  !mSpeakRadio->isHidden()  &&  mSpeakRadio->isOn();
00189 }
00190 
00191 /******************************************************************************
00192 * Return the selected sound file, if the main checkbox is checked.
00193 * Returns null string if beep is currently selected.
00194 */
00195 QString SoundPicker::file() const
00196 {
00197     return mCheckbox->isChecked() && mFileRadio->isOn() ? mFile : QString::null;
00198 }
00199 
00200 /******************************************************************************
00201 * Return the specified volumes (range 0 - 1).
00202 * Returns < 0 if beep is currently selected, or if 'set volume' is not selected.
00203 */
00204 float SoundPicker::volume(float& fadeVolume, int& fadeSeconds) const
00205 {
00206     if (mCheckbox->isChecked() && mFileRadio->isOn() && !mFile.isEmpty())
00207     {
00208         fadeVolume  = mFadeVolume;
00209         fadeSeconds = mFadeSeconds;
00210         return mVolume;
00211     }
00212     else
00213     {
00214         fadeVolume  = -1;
00215         fadeSeconds = 0;
00216         return -1;
00217     }
00218 }
00219 
00220 /******************************************************************************
00221 * Return whether sound file repetition is selected, if the main checkbox is checked.
00222 * Returns false if beep is currently selected.
00223 */
00224 bool SoundPicker::repeat() const
00225 {
00226     return mCheckbox->isChecked() && mFileRadio->isOn() && !mFile.isEmpty() && mRepeat;
00227 }
00228 
00229 /******************************************************************************
00230 * Initialise the widget's state.
00231 */
00232 void SoundPicker::set(bool sound, SoundPicker::Type defaultType, const QString& f, float volume, float fadeVolume, int fadeSeconds, bool repeat)
00233 {
00234     if (defaultType == PLAY_FILE  &&  f.isEmpty())
00235         defaultType = BEEP;
00236     mLastType    = static_cast<Type>(0);
00237     mFile        = f;
00238     mVolume      = volume;
00239     mFadeVolume  = fadeVolume;
00240     mFadeSeconds = fadeSeconds;
00241     mRepeat      = repeat;
00242     QToolTip::add(mFilePicker, mFile);
00243     mCheckbox->setChecked(sound);
00244     mTypeGroup->setButton(defaultType);
00245 }
00246 
00247 /******************************************************************************
00248 * Called when the sound checkbox is toggled.
00249 */
00250 void SoundPicker::slotSoundToggled(bool on)
00251 {
00252     mBeepRadio->setEnabled(on);
00253     mSpeakRadio->setEnabled(on);
00254     mFileRadio->setEnabled(on);
00255     mFilePicker->setEnabled(on && mFileRadio->isOn());
00256     if (on  &&  mSpeakRadio->isHidden()  &&  mSpeakRadio->isOn())
00257         mBeepRadio->setChecked(true);
00258     if (on)
00259         mBeepRadio->setFocus();
00260 }
00261 
00262 /******************************************************************************
00263 * Called when the sound option is changed.
00264 */
00265 void SoundPicker::slotTypeChanged(int id)
00266 {
00267     Type newType = static_cast<Type>(id);
00268     if (newType == mLastType  ||  mRevertType)
00269         return;
00270     if (mLastType == PLAY_FILE)
00271         mFilePicker->setEnabled(false);
00272     else if (newType == PLAY_FILE)
00273     {
00274         if (mFile.isEmpty())
00275         {
00276             slotPickFile();
00277             if (mFile.isEmpty())
00278                 return;    // revert to previously selected type
00279         }
00280         mFilePicker->setEnabled(mCheckbox->isChecked());
00281     }
00282     mLastType = newType;
00283 }
00284 
00285 /******************************************************************************
00286 * Called when the file picker button is clicked.
00287 */
00288 void SoundPicker::slotPickFile()
00289 {
00290 #ifdef WITHOUT_ARTS
00291     QString url = browseFile(mDefaultDir, mFile);
00292     if (!url.isEmpty())
00293         mFile = url;
00294 #else
00295     QString file = mFile;
00296     SoundDlg dlg(mFile, mVolume, mFadeVolume, mFadeSeconds, mRepeat, i18n("Sound File"), this, "soundDlg");
00297     dlg.setReadOnly(mReadOnly);
00298     bool accepted = (dlg.exec() == QDialog::Accepted);
00299     if (mReadOnly)
00300         return;
00301     if (accepted)
00302     {
00303         float volume, fadeVolume;
00304         int   fadeTime;
00305         file         = dlg.getFile();
00306         mRepeat      = dlg.getSettings(volume, fadeVolume, fadeTime);
00307         mVolume      = volume;
00308         mFadeVolume  = fadeVolume;
00309         mFadeSeconds = fadeTime;
00310     }
00311     if (!file.isEmpty())
00312     {
00313         mFile       = file;
00314         mDefaultDir = dlg.defaultDir();
00315     }
00316 #endif
00317     QToolTip::add(mFilePicker, mFile);
00318     if (mFile.isEmpty())
00319     {
00320         // No audio file is selected, so revert to 'beep'.
00321         // But wait a moment until setting the radio button, or it won't work.
00322         mRevertType = true;   // prevent sound dialogue popping up twice
00323         QTimer::singleShot(0, this, SLOT(setLastType()));
00324     }
00325 }
00326 
00327 /******************************************************************************
00328 * Select the previously selected sound type.
00329 */
00330 void SoundPicker::setLastType()
00331 {
00332     mTypeGroup->setButton(mLastType);
00333     mRevertType = false;
00334 }
00335 
00336 /******************************************************************************
00337 * Display a dialogue to choose a sound file, initially highlighting any
00338 * specified file. 'initialFile' must be a full path name or URL.
00339 * 'defaultDir' is updated to the directory containing the chosen file.
00340 * Reply = URL selected. If none is selected, URL.isEmpty() is true.
00341 */
00342 QString SoundPicker::browseFile(QString& defaultDir, const QString& initialFile)
00343 {
00344     static QString kdeSoundDir;     // directory containing KDE sound files
00345     if (defaultDir.isEmpty())
00346     {
00347         if (kdeSoundDir.isNull())
00348             kdeSoundDir = KGlobal::dirs()->findResourceDir("sound", "KDE_Notify.wav");
00349         defaultDir = kdeSoundDir;
00350     }
00351 #ifdef WITHOUT_ARTS
00352     QString filter = QString::fromLatin1("*.wav *.mp3 *.ogg|%1\n*|%2").arg(i18n("Sound Files")).arg(i18n("All Files"));
00353 #else
00354     QString filter = KDE::PlayObjectFactory::mimeTypes().join(" ");
00355 #endif
00356     return KAlarm::browseFile(i18n("Choose Sound File"), defaultDir, initialFile, filter, KFile::ExistingOnly, 0, "pickSoundFile");
00357 }
KDE Home | KDE Accessibility Home | Description of Access Keys