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