kalarm

soundpicker.cpp

00001 /*
00002  *  soundpicker.cpp  -  widget to select a sound file or a beep
00003  *  Program:  kalarm
00004  *  Copyright © 2002,2004-2007 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 <qlabel.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 "combobox.h"
00042 #include "functions.h"
00043 #include "kalarmapp.h"
00044 #include "pushbutton.h"
00045 #include "sounddlg.h"
00046 #include "soundpicker.moc"
00047 
00048 
00049 // Collect these widget labels together to ensure consistent wording and
00050 // translations across different modules.
00051 QString SoundPicker::i18n_Sound()       { return i18n("An audio sound", "Sound"); }
00052 QString SoundPicker::i18n_None()        { return i18n("None"); }
00053 QString SoundPicker::i18n_Beep()        { return i18n("Beep"); }
00054 QString SoundPicker::i18n_Speak()       { return i18n("Speak"); }
00055 QString SoundPicker::i18n_File()        { return i18n("Sound file"); }
00056 
00057 
00058 SoundPicker::SoundPicker(QWidget* parent, const char* name)
00059     : QFrame(parent, name)
00060 {
00061     setFrameStyle(QFrame::NoFrame);
00062     QHBoxLayout* soundLayout = new QHBoxLayout(this, 0, KDialog::spacingHint());
00063     mTypeBox = new QHBox(this);    // this is to control the QWhatsThis text display area
00064     mTypeBox->setSpacing(KDialog::spacingHint());
00065 
00066     QLabel* label = new QLabel(i18n("An audio sound", "&Sound:"), mTypeBox);
00067     label->setFixedSize(label->sizeHint());
00068 
00069     // Sound type combo box
00070     // The order of combo box entries must correspond with the 'Type' enum.
00071     mTypeCombo = new ComboBox(false, mTypeBox);
00072     mTypeCombo->insertItem(i18n_None());     // index NONE
00073     mTypeCombo->insertItem(i18n_Beep());     // index BEEP
00074     mTypeCombo->insertItem(i18n_File());     // index PLAY_FILE
00075     mSpeakShowing = !theApp()->speechEnabled();
00076     showSpeak(!mSpeakShowing);               // index SPEAK (only displayed if appropriate)
00077     connect(mTypeCombo, SIGNAL(activated(int)), SLOT(slotTypeSelected(int)));
00078     label->setBuddy(mTypeCombo);
00079     soundLayout->addWidget(mTypeBox);
00080 
00081     // Sound file picker button
00082     mFilePicker = new PushButton(this);
00083     mFilePicker->setPixmap(SmallIcon("playsound"));
00084     mFilePicker->setFixedSize(mFilePicker->sizeHint());
00085     connect(mFilePicker, SIGNAL(clicked()), SLOT(slotPickFile()));
00086     QToolTip::add(mFilePicker, i18n("Configure sound file"));
00087     QWhatsThis::add(mFilePicker, i18n("Configure a sound file to play when the alarm is displayed."));
00088     soundLayout->addWidget(mFilePicker);
00089 
00090     // Initialise the file picker button state and tooltip
00091     mTypeCombo->setCurrentItem(NONE);
00092     mFilePicker->setEnabled(false);
00093 }
00094 
00095 /******************************************************************************
00096 * Set the read-only status of the widget.
00097 */
00098 void SoundPicker::setReadOnly(bool readOnly)
00099 {
00100     mTypeCombo->setReadOnly(readOnly);
00101 #ifdef WITHOUT_ARTS
00102     mFilePicker->setReadOnly(readOnly);
00103 #endif
00104     mReadOnly = readOnly;
00105 }
00106 
00107 /******************************************************************************
00108 * Show or hide the Speak option.
00109 */
00110 void SoundPicker::showSpeak(bool show)
00111 {
00112     if (!theApp()->speechEnabled())
00113         show = false;    // speech capability is not installed
00114     if (show == mSpeakShowing)
00115         return;    // no change
00116     QString whatsThis = "<p>" + i18n("Choose a sound to play when the message is displayed.")
00117                       + "<br>" + i18n("%1: the message is displayed silently.").arg("<b>" + i18n_None() + "</b>")
00118                       + "<br>" + i18n("%1: a simple beep is sounded.").arg("<b>" + i18n_Beep() + "</b>")
00119                       + "<br>" + i18n("%1: an audio file is played. You will be prompted to choose the file and set play options.").arg("<b>" + i18n_File() + "</b>");
00120     if (!show  &&  mTypeCombo->currentItem() == SPEAK)
00121         mTypeCombo->setCurrentItem(NONE);
00122     if (mTypeCombo->count() == SPEAK+1)
00123         mTypeCombo->removeItem(SPEAK);    // precaution in case of mix-ups
00124     if (show)
00125     {
00126         mTypeCombo->insertItem(i18n_Speak());
00127         whatsThis += "<br>" + i18n("%1: the message text is spoken.").arg("<b>" + i18n_Speak() + "</b>") + "</p>";
00128     }
00129     QWhatsThis::add(mTypeBox, whatsThis + "</p>");
00130     mSpeakShowing = show;
00131 }
00132 
00133 /******************************************************************************
00134 * Return the currently selected option.
00135 */
00136 SoundPicker::Type SoundPicker::sound() const
00137 {
00138     return static_cast<SoundPicker::Type>(mTypeCombo->currentItem());
00139 }
00140 
00141 /******************************************************************************
00142 * Return the selected sound file, if the File option is selected.
00143 * Returns null string if File is not currently selected.
00144 */
00145 QString SoundPicker::file() const
00146 {
00147     return (mTypeCombo->currentItem() == PLAY_FILE) ? mFile : QString::null;
00148 }
00149 
00150 /******************************************************************************
00151 * Return the specified volumes (range 0 - 1).
00152 * Returns < 0 if beep is currently selected, or if 'set volume' is not selected.
00153 */
00154 float SoundPicker::volume(float& fadeVolume, int& fadeSeconds) const
00155 {
00156     if (mTypeCombo->currentItem() == PLAY_FILE  &&  !mFile.isEmpty())
00157     {
00158         fadeVolume  = mFadeVolume;
00159         fadeSeconds = mFadeSeconds;
00160         return mVolume;
00161     }
00162     else
00163     {
00164         fadeVolume  = -1;
00165         fadeSeconds = 0;
00166         return -1;
00167     }
00168 }
00169 
00170 /******************************************************************************
00171 * Return whether sound file repetition is selected, if the main checkbox is checked.
00172 * Returns false if beep is currently selected.
00173 */
00174 bool SoundPicker::repeat() const
00175 {
00176     return mTypeCombo->currentItem() == PLAY_FILE  &&  !mFile.isEmpty()  &&  mRepeat;
00177 }
00178 
00179 /******************************************************************************
00180 * Initialise the widget's state.
00181 */
00182 void SoundPicker::set(SoundPicker::Type type, const QString& f, float volume, float fadeVolume, int fadeSeconds, bool repeat)
00183 {
00184     if (type == PLAY_FILE  &&  f.isEmpty())
00185         type = BEEP;
00186     mFile        = f;
00187     mVolume      = volume;
00188     mFadeVolume  = fadeVolume;
00189     mFadeSeconds = fadeSeconds;
00190     mRepeat      = repeat;
00191     mTypeCombo->setCurrentItem(type);  // this doesn't trigger slotTypeSelected()
00192     mFilePicker->setEnabled(type == PLAY_FILE);
00193     if (type == PLAY_FILE)
00194         QToolTip::add(mTypeCombo, mFile);
00195     else
00196         QToolTip::remove(mTypeCombo);
00197     mLastType = type;
00198 }
00199 
00200 /******************************************************************************
00201 * Called when the sound option is changed.
00202 */
00203 void SoundPicker::slotTypeSelected(int id)
00204 {
00205     Type newType = static_cast<Type>(id);
00206     if (newType == mLastType)
00207         return;
00208     QString tooltip;
00209     if (mLastType == PLAY_FILE)
00210     {
00211         mFilePicker->setEnabled(false);
00212         QToolTip::remove(mTypeCombo);
00213     }
00214     else if (newType == PLAY_FILE)
00215     {
00216         if (mFile.isEmpty())
00217         {
00218             slotPickFile();
00219             if (mFile.isEmpty())
00220                 return;    // revert to previously selected type
00221         }
00222         mFilePicker->setEnabled(true);
00223         QToolTip::add(mTypeCombo, mFile);
00224     }
00225     mLastType = newType;
00226 }
00227 
00228 /******************************************************************************
00229 * Called when the file picker button is clicked.
00230 */
00231 void SoundPicker::slotPickFile()
00232 {
00233 #ifdef WITHOUT_ARTS
00234     QString url = browseFile(mDefaultDir, mFile);
00235     if (!url.isEmpty())
00236         mFile = url;
00237 #else
00238     QString file = mFile;
00239     SoundDlg dlg(mFile, mVolume, mFadeVolume, mFadeSeconds, mRepeat, i18n("Sound File"), this, "soundDlg");
00240     dlg.setReadOnly(mReadOnly);
00241     bool accepted = (dlg.exec() == QDialog::Accepted);
00242     if (mReadOnly)
00243         return;
00244     if (accepted)
00245     {
00246         float volume, fadeVolume;
00247         int   fadeTime;
00248         file         = dlg.getFile();
00249         mRepeat      = dlg.getSettings(volume, fadeVolume, fadeTime);
00250         mVolume      = volume;
00251         mFadeVolume  = fadeVolume;
00252         mFadeSeconds = fadeTime;
00253     }
00254     if (!file.isEmpty())
00255     {
00256         mFile       = file;
00257         mDefaultDir = dlg.defaultDir();
00258     }
00259 #endif
00260     if (mFile.isEmpty())
00261     {
00262         // No audio file is selected, so revert to previously selected option
00263         mTypeCombo->setCurrentItem(mLastType);
00264         QToolTip::remove(mTypeCombo);
00265     }
00266     else
00267         QToolTip::add(mTypeCombo, mFile);
00268 }
00269 
00270 /******************************************************************************
00271 * Display a dialogue to choose a sound file, initially highlighting any
00272 * specified file. 'initialFile' must be a full path name or URL.
00273 * 'defaultDir' is updated to the directory containing the chosen file.
00274 * Reply = URL selected. If none is selected, URL.isEmpty() is true.
00275 */
00276 QString SoundPicker::browseFile(QString& defaultDir, const QString& initialFile)
00277 {
00278     static QString kdeSoundDir;     // directory containing KDE sound files
00279     if (defaultDir.isEmpty())
00280     {
00281         if (kdeSoundDir.isNull())
00282             kdeSoundDir = KGlobal::dirs()->findResourceDir("sound", "KDE_Notify.wav");
00283         defaultDir = kdeSoundDir;
00284     }
00285 #ifdef WITHOUT_ARTS
00286     QString filter = QString::fromLatin1("*.wav *.mp3 *.ogg|%1\n*|%2").arg(i18n("Sound Files")).arg(i18n("All Files"));
00287 #else
00288     QStringList filters = KDE::PlayObjectFactory::mimeTypes();
00289     QString filter = filters.join(" ");
00290 #endif
00291     return KAlarm::browseFile(i18n("Choose Sound File"), defaultDir, initialFile, filter, KFile::ExistingOnly, 0, "pickSoundFile");
00292 }