Commit d019ff0b authored by David Jarvie's avatar David Jarvie
Browse files

Further implementation of notification alarm message option

parent 49066a48
Pipeline #35135 passed with stage
in 30 minutes and 28 seconds
......@@ -80,6 +80,7 @@ find_package(KF5JobWidgets ${KF5_MIN_VERSION} REQUIRED)
find_package(KF5KCMUtils ${KF5_MIN_VERSION} CONFIG REQUIRED)
find_package(KF5KIO ${KF5_MIN_VERSION} CONFIG REQUIRED)
find_package(KF5Notifications ${KF5_MIN_VERSION} CONFIG REQUIRED)
find_package(KF5NotifyConfig ${KF5_MIN_VERSION} CONFIG REQUIRED)
find_package(KF5Service ${KF5_MIN_VERSION} CONFIG REQUIRED)
find_package(KF5WidgetsAddons ${KF5_MIN_VERSION} CONFIG REQUIRED)
find_package(KF5WindowSystem ${KF5_MIN_VERSION} CONFIG REQUIRED)
......
KAlarm Change Log
=== Version 3.1.0 (KDE Applications 20.12) --- 11 September 2020 ===
=== Version 3.1.0 (KDE Applications 20.12) --- 21 September 2020 ===
+ Add option to show alarm message as a notification instead of in a window [KDE Bug 345922]
=== Version 3.0.2 (KDE Applications 20.08.2) --- 16 September 2020 ===
......
......@@ -172,6 +172,7 @@ target_link_libraries(kalarm_bin
KF5::Holidays
KF5::KIOWidgets
KF5::Notifications
KF5::NotifyConfig
KF5::TextWidgets
KF5::WindowSystem
KF5::XmlGui
......
<!DOCTYPE gui>
<gui name="kalarm" version="220" >
<gui name="kalarm" version="310" >
<ToolBar noMerge="1" name="mainToolBar" >
<Action name="new" />
<Separator/>
......@@ -68,6 +68,7 @@
<Action name="options_show_menubar"/>
<Separator/>
<Action name="options_configure_keybinding" />
<Action name="options_configure_notifications" />
<Action name="options_configure_toolbars" />
<Action name="options_configure" />
</Menu>
......
......@@ -87,7 +87,7 @@ class PickLogFileRadio : public PickFileRadio
= Dialog to edit display alarms.
=============================================================================*/
QString EditDisplayAlarmDlg::i18n_lbl_DisplayMethod() { return i18nc("@label:listbox", "Display method:"); }
QString EditDisplayAlarmDlg::i18n_lbl_DisplayMethod() { return i18nc("@label:listbox How to display alarms", "Display method:"); }
QString EditDisplayAlarmDlg::i18n_combo_Window() { return i18nc("@item:inlistbox", "Window"); }
QString EditDisplayAlarmDlg::i18n_combo_Notify() { return i18nc("@item:inlistbox", "Notification"); }
QString EditDisplayAlarmDlg::i18n_chk_ConfirmAck() { return i18nc("@option:check", "Confirm acknowledgment"); }
......@@ -677,6 +677,7 @@ void EditDisplayAlarmDlg::slotDisplayMethodChanged(int index)
const bool enable = (index == dWINDOW);
mConfirmAck->setEnabled(enable);
mFontColourButton->setEnabled(enable);
mSoundPicker->showFile(enable);
}
/******************************************************************************
......
......@@ -2244,6 +2244,7 @@ void* KAlarmApp::execAlarm(KAEvent& event, const KAAlarm& alarm, ExecAlarmFlags
{
// There isn't already a message for this event.
const int mdFlags = (flags & Reschedule ? 0 : MessageDisplay::NoReschedule) | MessageDisplay::AlwaysHide;
event.setNotify(false); // can't use notification system if audio only
disp = MessageDisplay::create(event, alarm, mdFlags);
}
else
......
......@@ -54,6 +54,7 @@ using namespace KCalUtils;
#include <KEditToolBar>
#include <KXMLGUIFactory>
#include <KToggleAction>
#include <KNotifyConfigWidget>
#include <KToolBarPopupAction>
#include <QAction>
......@@ -543,6 +544,7 @@ void MainWindow::initActions()
connect(act, &QAction::triggered, this, &MainWindow::slotQuit, Qt::QueuedConnection);
QAction* actionMenubar = KStandardAction::showMenubar(this, &MainWindow::slotShowMenubar, actions);
KStandardAction::keyBindings(this, &MainWindow::slotConfigureKeys, actions);
KStandardAction::configureNotifications(this, &MainWindow::slotConfigureNotifications, actions);
KStandardAction::configureToolbars(this, &MainWindow::slotConfigureToolbar, actions);
KStandardAction::preferences(this, &MainWindow::slotPreferences, actions);
mResourceSelector->initActions(actions);
......@@ -1122,6 +1124,14 @@ void MainWindow::slotConfigureKeys()
KShortcutsDialog::configure(actionCollection(), KShortcutsEditor::LetterShortcutsAllowed, this);
}
/******************************************************************************
* Called when the Configure Notifications menu item is selected.
*/
void MainWindow::slotConfigureNotifications()
{
KNotifyConfigWidget::configure(this);
}
/******************************************************************************
* Called when the Configure Toolbars menu item is selected.
*/
......
......@@ -105,6 +105,7 @@ private Q_SLOTS:
void slotPreferences();
void slotShowMenubar();
void slotConfigureKeys();
void slotConfigureNotifications();
void slotConfigureToolbar();
void slotNewToolbarConfig();
void slotQuit();
......
......@@ -33,7 +33,7 @@ bool MessageDisplay::mRedisplayed = false;
MessageDisplay* MessageDisplay::create(const KAEvent& event, const KAAlarm& alarm, int flags)
{
if (event.notify())
return new MessageNotification(event, alarm, flags);
return new MessageNotification(event, alarm, flags & ~AlwaysHide);
else
return new MessageWindow(event, alarm, flags);
}
......
......@@ -1144,11 +1144,12 @@ bool MessageDisplayHelper::activateAutoClose()
* Called when the display has been shown properly (in its correct position),
* to play sounds and reschedule the event.
*/
void MessageDisplayHelper::displayComplete()
void MessageDisplayHelper::displayComplete(bool audio)
{
delete mTempFile;
mTempFile = nullptr;
playAudio();
if (audio)
playAudio();
if (mRescheduleEvent)
alarmShowing(mEvent);
}
......
......@@ -88,7 +88,7 @@ public:
void initTexts();
const DisplayTexts& texts() const { return mTexts; }
bool activateAutoClose();
void displayComplete();
void displayComplete(bool audio);
bool alarmShowing(KAEvent&);
void playAudio();
EditAlarmDlg* createEdit();
......
......@@ -34,21 +34,21 @@ namespace
// Notification eventIds: these are the IDs contained in the '[Event/ID]'
// entries in kalarm.notifyrc.
const QString MessageId = QStringLiteral("Message");
const QString BeepId = QStringLiteral("MessageBeep");
const QString SpeakId = QStringLiteral("MessageSpeak");
const QString ErrorId = QStringLiteral("MessageError");
// Flags for the notification
//const KNotification::NotificationFlags NFLAGS = KNotification::CloseWhenWidgetActivated
const KNotification::NotificationFlags NFLAGS = KNotification::RaiseWidgetOnActivation;
// | KNotification::Persistent;
const KNotification::NotificationFlags NFLAGS = KNotification::RaiseWidgetOnActivation
| KNotification::Persistent;
// | KNotification::LoopSound
const QString NL = QStringLiteral("\n");
const QString SP = QStringLiteral(" ");
inline QString getNotifyEventId(const KAEvent& event)
{
return MessageId;
return event.beep() ? BeepId : event.speak() ? SpeakId : MessageId;
}
} // namespace
......@@ -145,7 +145,7 @@ MessageNotification::MessageNotification(const KAEvent& event, const KAAlarm& al
qCDebug(KALARM_LOG) << "MessageNotification():" << mEventId();
MNSessionManager::create();
setWidget(MainWindow::mainMainWindow());
if (!(flags & (NoInitView | AlwaysHide)))
if (!(flags & NoInitView))
MessageNotification::setUpDisplay(); // avoid calling virtual method from constructor
connect(this, QOverload<unsigned int>::of(&KNotification::activated), this, &MessageNotification::buttonActivated);
......@@ -154,8 +154,6 @@ MessageNotification::MessageNotification(const KAEvent& event, const KAAlarm& al
connect(mHelper, &MessageDisplayHelper::commandExited, this, &MessageNotification::commandCompleted);
mNotificationList.append(this);
if (mAlwaysHidden())
displayComplete(); // play audio, etc.
}
/******************************************************************************
......@@ -314,20 +312,11 @@ void MessageNotification::setUpDisplay()
}
/******************************************************************************
* Return the number of message notifications, optionally excluding always-hidden ones.
* Return the number of message notifications.
*/
int MessageNotification::notificationCount(bool excludeAlwaysHidden)
int MessageNotification::notificationCount()
{
int count = mNotificationList.count();
if (excludeAlwaysHidden)
{
for (MessageNotification* notif : qAsConst(mNotificationList))
{
if (notif->mAlwaysHidden())
--count;
}
}
return count;
return mNotificationList.count();
}
/******************************************************************************
......@@ -350,7 +339,7 @@ void MessageNotification::closeDisplay()
*/
void MessageNotification::showDisplay()
{
if (mInitialised && !mAlwaysHidden() && mHelper->activateAutoClose())
if (mInitialised && mHelper->activateAutoClose())
{
if (!mCommandInhibit && !mShown)
{
......@@ -359,7 +348,7 @@ void MessageNotification::showDisplay()
mShown = true;
}
if (!mDisplayComplete && !mErrorWindow() && mAlarmType() != KAAlarm::INVALID_ALARM)
displayComplete(); // play audio, etc.
mHelper->displayComplete(false); // reschedule
mDisplayComplete = true;
}
}
......@@ -382,13 +371,6 @@ void MessageNotification::repeat(const KAAlarm& alarm)
if (event.isValid())
{
mAlarmType() = alarm.type(); // store new alarm type for use if it is later deferred
if (mAlwaysHidden())
playAudio();
else
{
if (Preferences::modalMessages())
playAudio();
}
if (mHelper->alarmShowing(event))
ResourcesCalendar::updateEvent(event);
}
......@@ -574,15 +556,6 @@ void MessageNotification::saveProperties(KConfigGroup& config)
config.writeEntry("NotifyId", eventId());
}
/******************************************************************************
* Called when the notification has been displayed properly, to play sounds and
* reschedule the event.
*/
void MessageNotification::displayComplete()
{
mHelper->displayComplete();
}
/******************************************************************************
* Called when a button in the notification has been pressed.
* Button indexes start at 1.
......
......@@ -40,7 +40,7 @@ public:
void showDateTime(const KAEvent&, const KAAlarm&) override;
void cancelReminder(const KAEvent&, const KAAlarm&) override;
static void redisplayAlarms();
static int notificationCount(bool excludeAlwaysHidden = false);
static int notificationCount();
protected Q_SLOTS:
void textsChanged(MessageDisplayHelper::DisplayTexts::TextIds ids, const QString& change);
......@@ -62,7 +62,6 @@ private:
void setNotificationTitle(const QString&);
void setNotificationText();
void setNotificationButtons();
void displayComplete();
static QVector<MessageNotification*> mNotificationList; // list of notification instances
// Miscellaneous
......
......@@ -999,7 +999,7 @@ void MessageWindow::frameDrawn()
*/
void MessageWindow::displayComplete()
{
mHelper->displayComplete();
mHelper->displayComplete(true);
if (!mAlwaysHidden())
{
......
......@@ -32,11 +32,10 @@
namespace
{
QMap<Preferences::SoundType, int> varIndexes; // mapping from sound type to combo index
const QMap<Preferences::SoundType, int>& indexes(varIndexes);
const int NoneIndex = 0;
const int FileIndex = 2;
}
// Collect these widget labels together to ensure consistent wording and
// translations across different modules.
QString SoundPicker::i18n_label_Sound() { return i18nc("@label:listbox Listbox providing audio options", "Sound:"); }
......@@ -60,26 +59,26 @@ SoundPicker::SoundPicker(QWidget* parent)
label->setFixedSize(label->sizeHint());
// Sound type combo box
// The order of combo box entries must correspond with the 'Type' enum.
if (varIndexes.isEmpty())
{
varIndexes[Preferences::Sound_None] = 0;
varIndexes[Preferences::Sound_Beep] = 1;
varIndexes[Preferences::Sound_File] = 2;
varIndexes[Preferences::Sound_Speak] = 3;
}
mTypeCombo = new ComboBox(mTypeBox);
typeBoxLayout->addWidget(mTypeCombo);
mTypeCombo->addItem(i18n_combo_None()); // index None
mTypeCombo->addItem(i18n_combo_Beep()); // index Beep
mTypeCombo->addItem(i18n_combo_File()); // index PlayFile
mTypeCombo->addItem(i18n_combo_None(), Preferences::Sound_None); // index None
mTypeCombo->addItem(i18n_combo_Beep(), Preferences::Sound_Beep); // index Beep
mTypeCombo->addItem(i18n_combo_File(), Preferences::Sound_File); // index PlayFile
mFileShowing = true;
mSpeakShowing = !KPIMTextEdit::TextToSpeech::self()->isReady();
showSpeak(!mSpeakShowing); // index Speak (only displayed if appropriate)
connect(mTypeCombo, static_cast<void (ComboBox::*)(int)>(&ComboBox::activated), this, &SoundPicker::slotTypeSelected);
connect(mTypeCombo, static_cast<void (ComboBox::*)(int)>(&ComboBox::currentIndexChanged), this, &SoundPicker::changed);
label->setBuddy(mTypeCombo);
soundLayout->addWidget(mTypeBox);
mTypeBox->setWhatsThis(xi18nc("@info:whatsthis Combination of multiple whatsthis items",
"<para>Choose a sound to play when the message is displayed."
"<list><item><interface>%1</interface>: the message is displayed silently.</item>"
"<list><item><interface>%2</interface>: a simple beep is sounded.</item>"
"<list><item><interface>%3</interface>: an audio file is played. You will be prompted to choose the file and set play options. (Option not available if using notification.)</item>"
"<list><item><interface>%4</interface>: the message text is spoken. (Option requires working Qt text-to-speech installation.)</item>"
"</list></para>",
i18n_combo_None(), i18n_combo_Beep(), i18n_combo_File(), i18n_combo_Speak()));
// Sound file picker button
mFilePicker = new PushButton(this);
......@@ -92,7 +91,7 @@ SoundPicker::SoundPicker(QWidget* parent)
soundLayout->addWidget(mFilePicker);
// Initialise the file picker button state and tooltip
mTypeCombo->setCurrentIndex(indexes[Preferences::Sound_None]);
mTypeCombo->setCurrentIndex(NoneIndex);
mFilePicker->setEnabled(false);
}
......@@ -107,42 +106,45 @@ void SoundPicker::setReadOnly(bool readOnly)
mReadOnly = readOnly;
}
/******************************************************************************
* Show or hide the File option.
*/
void SoundPicker::showFile(bool show)
{
if (show != mFileShowing)
{
if (show)
mTypeCombo->insertItem(FileIndex, i18n_combo_File(), Preferences::Sound_File);
else
{
if (mTypeCombo->currentData().toInt() == Preferences::Sound_File)
mTypeCombo->setCurrentIndex(NoneIndex);
mTypeCombo->removeItem(FileIndex);
}
mFileShowing = show;
}
}
/******************************************************************************
* Show or hide the Speak option.
*/
void SoundPicker::showSpeak(bool show)
{
if (!KPIMTextEdit::TextToSpeech::self()->isReady())
show = false; // speech capability is not installed
if (show == mSpeakShowing)
return; // no change
if (!show && mTypeCombo->currentIndex() == indexes[Preferences::Sound_Speak])
mTypeCombo->setCurrentIndex(indexes[Preferences::Sound_None]);
if (mTypeCombo->count() == indexes[Preferences::Sound_Speak]+1)
mTypeCombo->removeItem(indexes[Preferences::Sound_Speak]); // precaution in case of mix-ups
QString whatsThis;
QString opt1 = xi18nc("@info:whatsthis", "<interface>%1</interface>: the message is displayed silently.", i18n_combo_None());
QString opt2 = xi18nc("@info:whatsthis", "<interface>%1</interface>: a simple beep is sounded.", i18n_combo_Beep());
QString opt3 = xi18nc("@info:whatsthis", "<interface>%1</interface>: an audio file is played. You will be prompted to choose the file and set play options.", i18n_combo_File());
if (show)
show = false; // speech capability is not installed or configured
if (show != mSpeakShowing)
{
mTypeCombo->addItem(i18n_combo_Speak());
QString opt4 = xi18nc("@info:whatsthis", "<interface>%1</interface>: the message text is spoken.", i18n_combo_Speak());
whatsThis = xi18nc("@info:whatsthis Combination of multiple whatsthis items",
"<para>Choose a sound to play when the message is displayed:"
"<list><item>%1</item>"
"<item>%2</item>"
"<item>%3</item>"
"<item>%4</item></list></para>", opt1, opt2, opt3, opt4);
// Note that 'Speak' is always the last option.
if (show)
mTypeCombo->addItem(i18n_combo_Speak(), Preferences::Sound_Speak);
else
{
if (mTypeCombo->currentData().toInt() == Preferences::Sound_Speak)
mTypeCombo->setCurrentIndex(NoneIndex);
mTypeCombo->removeItem(mTypeCombo->count() - 1);
}
mSpeakShowing = show;
}
else
whatsThis = xi18nc("@info:whatsthis Combination of multiple whatsthis items",
"<para>Choose a sound to play when the message is displayed:"
"<list><item>%1</item>"
"<item>%2</item>"
"<item>%3</item></list></para>", opt1, opt2, opt3);
mTypeBox->setWhatsThis(whatsThis);
mSpeakShowing = show;
}
/******************************************************************************
......@@ -150,11 +152,9 @@ void SoundPicker::showSpeak(bool show)
*/
Preferences::SoundType SoundPicker::sound() const
{
int current = mTypeCombo->currentIndex();
for (QMap<Preferences::SoundType, int>::ConstIterator it = indexes.constBegin(); it != indexes.constEnd(); ++it)
if (it.value() == current)
return it.key();
return Preferences::Sound_None;
if (mTypeCombo->currentIndex() < 0)
return Preferences::Sound_None;
return static_cast<Preferences::SoundType>(mTypeCombo->currentData().toInt());
}
/******************************************************************************
......@@ -163,7 +163,7 @@ Preferences::SoundType SoundPicker::sound() const
*/
QUrl SoundPicker::file() const
{
return (mTypeCombo->currentIndex() == indexes[Preferences::Sound_File]) ? mFile : QUrl();
return (mTypeCombo->currentData().toInt() == Preferences::Sound_File) ? mFile : QUrl();
}
/******************************************************************************
......@@ -172,7 +172,7 @@ QUrl SoundPicker::file() const
*/
float SoundPicker::volume(float& fadeVolume, int& fadeSeconds) const
{
if (mTypeCombo->currentIndex() == indexes[Preferences::Sound_File] && !mFile.isEmpty())
if (mTypeCombo->currentData().toInt() == Preferences::Sound_File && !mFile.isEmpty())
{
fadeVolume = mFadeVolume;
fadeSeconds = mFadeSeconds;
......@@ -192,7 +192,7 @@ float SoundPicker::volume(float& fadeVolume, int& fadeSeconds) const
*/
int SoundPicker::repeatPause() const
{
return mTypeCombo->currentIndex() == indexes[Preferences::Sound_File] && !mFile.isEmpty() ? mRepeatPause : -1;
return mTypeCombo->currentData().toInt() == Preferences::Sound_File && !mFile.isEmpty() ? mRepeatPause : -1;
}
/******************************************************************************
......@@ -207,7 +207,7 @@ void SoundPicker::set(Preferences::SoundType type, const QString& f, float volum
mFadeVolume = fadeVolume;
mFadeSeconds = fadeSeconds;
mRepeatPause = repeatPause;
mTypeCombo->setCurrentIndex(indexes[type]); // this doesn't trigger slotTypeSelected()
selectType(type); // this doesn't trigger slotTypeSelected()
mFilePicker->setEnabled(type == Preferences::Sound_File);
mTypeCombo->setToolTip(type == Preferences::Sound_File ? mFile.toDisplayString() : QString());
mLastType = type;
......@@ -218,15 +218,7 @@ void SoundPicker::set(Preferences::SoundType type, const QString& f, float volum
*/
void SoundPicker::slotTypeSelected(int id)
{
Preferences::SoundType newType = Preferences::Sound_None;
for (QMap<Preferences::SoundType, int>::ConstIterator it = indexes.constBegin(); it != indexes.constEnd(); ++it)
{
if (it.value() == id)
{
newType = it.key();
break;
}
}
const Preferences::SoundType newType = (id >= 0) ? static_cast<Preferences::SoundType>(mTypeCombo->itemData(id).toInt()) : Preferences::Sound_None;
if (newType == mLastType || mRevertType)
return;
if (mLastType == Preferences::Sound_File)
......@@ -284,7 +276,7 @@ void SoundPicker::slotPickFile()
mRevertType = true; // prevent sound dialog popping up twice
QTimer::singleShot(0, this, &SoundPicker::setLastType);
#else
mTypeCombo->setCurrentIndex(indexes[mLastType]);
selectType(mLastType);
#endif
mTypeCombo->setToolTip(QString());
}
......@@ -299,7 +291,7 @@ void SoundPicker::slotPickFile()
*/
void SoundPicker::setLastType()
{
mTypeCombo->setCurrentIndex(indexes[mLastType]);
selectType(mLastType);
mRevertType = false;
}
......@@ -328,4 +320,14 @@ bool SoundPicker::browseFile(QString& file, QString& defaultDir, const QString&
defaultDir, initialFile, filter, true, nullptr);
}
/******************************************************************************
* Select the item corresponding to a given sound type.
*/
void SoundPicker::selectType(Preferences::SoundType type)
{
int i = mTypeCombo->findData(type);
if (i >= 0)
mTypeCombo->setCurrentIndex(i);
}
// vim: et sw=4:
/*
* soundpicker.h - widget to select a sound file or a beep
* Program: kalarm
* SPDX-FileCopyrightText: 2002-2019 David Jarvie <djarvie@kde.org>
* SPDX-FileCopyrightText: 2002-2020 David Jarvie <djarvie@kde.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
......@@ -21,125 +21,135 @@ class PushButton;
class SoundPicker : public QFrame
{
Q_OBJECT
public:
/** Constructor.
* @param parent The parent object of this widget.
*/
explicit SoundPicker(QWidget* parent);
/** Initialises the widget's state.
* @param type The option to select.
* @param filename The full path or URL of the sound file to select.
* If the 'file' option is not initially selected,
* @p filename provides the default should 'file'
* later be selected by the user.
* @param volume The volume to play a sound file, or < 0 for no
* volume setting. If the 'file' option is not
* initially selected, @p volume provides the default
* should 'file' later be selected by the user.
* @param fadeVolume The initial volume to play a sound file if fading
* is to be used, or < 0 for no fading. If the
* 'file' option is not initially selected, @p
* fadeVolume provides the default should 'file'
* later be selected by the user.
* @param fadeSeconds The number of seconds over which the sound file
* volume should be faded, or 0 for no fading. If
* the 'file' option is not initially selected,
* @p fadeSeconds provides the default should
* 'file' later be selected by the user.
* @param repeatPause Number of seconds to pause between sound file
* repetitions, or -1 for no repetition. If the
* 'file' option is not initially selected,
* @p repeatPause provides the default should 'file'
* later be selected by the user.
*/
void set(Preferences::SoundType type, const QString& filename, float volume, float fadeVolume, int fadeSeconds, int repeatPause);
/** Returns true if the widget is read only for the user. */
bool isReadOnly() const { return mReadOnly; }
/** Sets whether the widget can be changed the user.
* @param readOnly True to set the widget read-only, false to set it read-write.
*/
void setReadOnly(bool readOnly);
/** Show or hide the 'speak' option.
* If it is to be hidden and it is currently selected, sound is turned off.
*/
void showSpeak(bool show);
/** Returns the selected option. */
Preferences::SoundType sound() const;
/** If the 'file' option is selected, returns the URL of the chosen file.
* Otherwise returns an empty URL.
*/
QUrl file() const;
/** Returns the volume and fade characteristics for playing a sound file.
* @param fadeVolume Receives the initial volume if the volume is to
* be faded, else -1.
* @param fadeSeconds Receives the number of seconds over which the
* volume is to be faded, else 0.
* @return Volume to play the sound file, or < 0 if the
* 'file' option is not selected.
*/
float volume(float& fadeVolume, int& fadeSeconds) const;
/** Returns pause in seconds between repetitions of the sound file,
* or -1 if no repeat or 'file' option is not selected.
*/
int repeatPause() const;
/** Returns the current file URL regardless of whether the 'file' option is selected. */
QUrl fileSetting() const { return mFile; }
/** Returns the current file repetition setting regardless of whether
* the 'file' option is selected.
*/
bool repeatPauseSetting() const { return mRepeatPause; }
/** Display a dialog to choose a sound file, initially highlighting
* @p initialFile if non-null.
* @param file Updated to URL selected, in human readable format,
* or empty if none selected.
* @param initialDir Initial directory to display if @p initialFile
* is null. If a file is chosen, this is updated to
* the directory containing the chosen file.
* @param initialFile Full path name or URL of file to be highlighted
* initially. If null, no file will be highlighted.
* @return true if @p file value can be used,
* false if the dialog was deleted while visible.