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 <tqlayout.h> 00024 #include <tqregexp.h> 00025 #include <tqtooltip.h> 00026 #include <tqtimer.h> 00027 #include <tqlabel.h> 00028 #include <tqhbox.h> 00029 #include <tqwhatsthis.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 TQString SoundPicker::i18n_Sound() { return i18n("An audio sound", "Sound"); } 00052 TQString SoundPicker::i18n_None() { return i18n("None"); } 00053 TQString SoundPicker::i18n_Beep() { return i18n("Beep"); } 00054 TQString SoundPicker::i18n_Speak() { return i18n("Speak"); } 00055 TQString SoundPicker::i18n_File() { return i18n("Sound file"); } 00056 00057 00058 SoundPicker::SoundPicker(TQWidget* parent, const char* name) 00059 : TQFrame(parent, name) 00060 { 00061 setFrameStyle(TQFrame::NoFrame); 00062 TQHBoxLayout* soundLayout = new TQHBoxLayout(this, 0, KDialog::spacingHint()); 00063 mTypeBox = new TQHBox(this); // this is to control the TQWhatsThis text display area 00064 mTypeBox->setSpacing(KDialog::spacingHint()); 00065 00066 TQLabel* label = new TQLabel(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, TQT_SIGNAL(activated(int)), TQT_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, TQT_SIGNAL(clicked()), TQT_SLOT(slotPickFile())); 00086 TQToolTip::add(mFilePicker, i18n("Configure sound file")); 00087 TQWhatsThis::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 TQString 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 TQWhatsThis::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 TQString SoundPicker::file() const 00146 { 00147 return (mTypeCombo->currentItem() == PLAY_FILE) ? mFile : TQString(); 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 TQString& 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 TQToolTip::add(mTypeCombo, mFile); 00195 else 00196 TQToolTip::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 TQString tooltip; 00209 if (mLastType == PLAY_FILE) 00210 { 00211 mFilePicker->setEnabled(false); 00212 TQToolTip::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 TQToolTip::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 TQString url = browseFile(mDefaultDir, mFile); 00235 if (!url.isEmpty()) 00236 mFile = url; 00237 #else 00238 TQString file = mFile; 00239 SoundDlg dlg(mFile, mVolume, mFadeVolume, mFadeSeconds, mRepeat, i18n("Sound File"), this, "soundDlg"); 00240 dlg.setReadOnly(mReadOnly); 00241 bool accepted = (dlg.exec() == TQDialog::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 TQToolTip::remove(mTypeCombo); 00265 } 00266 else 00267 TQToolTip::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 TQString SoundPicker::browseFile(TQString& defaultDir, const TQString& initialFile) 00277 { 00278 static TQString 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 TQString filter = TQString::fromLatin1("*.wav *.mp3 *.ogg|%1\n*|%2").arg(i18n("Sound Files")).arg(i18n("All Files")); 00287 #else 00288 TQStringList filters = KDE::PlayObjectFactory::mimeTypes(); 00289 TQString filter = filters.join(" "); 00290 #endif 00291 return KAlarm::browseFile(i18n("Choose Sound File"), defaultDir, initialFile, filter, KFile::ExistingOnly, 0, "pickSoundFile"); 00292 }