swift
audionotificationcomponent.cpp
1 // SPDX-FileCopyrightText: Copyright (C) 2019 swift Project Community / Contributors
2 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3 
5 
6 #include <QCheckBox>
7 #include <QComboBox>
8 #include <QFileDialog>
9 #include <QPointer>
10 #include <QToolButton>
11 #include <QtGlobal>
12 
13 #include "ui_audionotificationcomponent.h"
14 
16 #include "gui/guiapplication.h"
19 #include "misc/sequence.h"
20 
21 using namespace swift::core;
22 using namespace swift::core::context;
23 using namespace swift::misc;
24 using namespace swift::misc::aviation;
25 using namespace swift::misc::audio;
26 using namespace swift::misc::physical_quantities;
27 
28 namespace swift::gui::components
29 {
30  CAudioNotificationComponent::CAudioNotificationComponent(QWidget *parent)
31  : QFrame(parent), ui(new Ui::CAudioNotificationComponent)
32  {
33  ui->setupUi(this);
34 
35  // deferred init, because in a distributed swift system
36  // it takes a moment until the settings are sychronized
37  // this is leading to undesired "save settings" messages and played sounds
38  QPointer<CAudioNotificationComponent> myself(this);
39  QTimer::singleShot(2500, this, [=] {
40  if (!myself || !sGui || sGui->isShuttingDown()) { return; }
41  this->init();
42  });
43  }
44 
45  void CAudioNotificationComponent::init()
46  {
47  if (!sGui || sGui->isShuttingDown()) { return; }
48  this->reloadSettings();
49 
50  // checkboxes for notifications
51  bool c = connect(ui->cb_SetupAudioPTTClickDown, &QCheckBox::toggled, this,
52  &CAudioNotificationComponent::onNotificationsToggled, Qt::QueuedConnection);
53  Q_ASSERT(c);
54  c = connect(ui->cb_SetupAudioPTTClickUp, &QCheckBox::toggled, this,
55  &CAudioNotificationComponent::onNotificationsToggled, Qt::QueuedConnection);
56  Q_ASSERT(c);
57  c = connect(ui->cb_SetupAudioNotificationTextMessageFrequency, &QCheckBox::toggled, this,
58  &CAudioNotificationComponent::onNotificationsToggled, Qt::QueuedConnection);
59  Q_ASSERT(c);
60  c = connect(ui->cb_SetupAudioNotificationTextMessagePrivate, &QCheckBox::toggled, this,
61  &CAudioNotificationComponent::onNotificationsToggled, Qt::QueuedConnection);
62  Q_ASSERT(c);
63  c = connect(ui->cb_SetupAudioNotificationTextMessageSupervisor, &QCheckBox::toggled, this,
64  &CAudioNotificationComponent::onNotificationsToggled, Qt::QueuedConnection);
65  Q_ASSERT(c);
66  c = connect(ui->cb_SetupAudioNotificationTextMessageUnicom, &QCheckBox::toggled, this,
67  &CAudioNotificationComponent::onNotificationsToggled, Qt::QueuedConnection);
68  Q_ASSERT(c);
69  c = connect(ui->cb_SetupAudioNotificationTextCallsignMentioned, &QCheckBox::toggled, this,
70  &CAudioNotificationComponent::onNotificationsToggled, Qt::QueuedConnection);
71  Q_ASSERT(c);
72  c = connect(ui->cb_SetupAfvBlocked, &QCheckBox::toggled, this,
73  &CAudioNotificationComponent::onNotificationsToggled, Qt::QueuedConnection);
74  Q_ASSERT(c);
75  c = connect(ui->cb_SetupAfvClicked, &QCheckBox::toggled, this,
76  &CAudioNotificationComponent::onNotificationsToggled, Qt::QueuedConnection);
77  Q_ASSERT(c);
78  c = connect(ui->cb_SetupAudioNotificationLogin, &QCheckBox::toggled, this,
79  &CAudioNotificationComponent::onNotificationsToggled, Qt::QueuedConnection);
80  Q_ASSERT(c);
81  c = connect(ui->cb_SetupAudioNotificationLogoff, &QCheckBox::toggled, this,
82  &CAudioNotificationComponent::onNotificationsToggled, Qt::QueuedConnection);
83  Q_ASSERT(c);
84  c = connect(ui->pb_SoundReset, &QPushButton::released, this,
85  &CAudioNotificationComponent::resetNotificationSoundsDir, Qt::QueuedConnection);
86  Q_ASSERT(c);
87  c = connect(ui->pb_SoundDir, &QPushButton::released, this,
88  &CAudioNotificationComponent::selectNotificationSoundsDir, Qt::QueuedConnection);
89  Q_ASSERT(c);
90 
91  // volumes
92  c = connect(ui->sb_NotificationValueVolume, qOverload<int>(&QSpinBox::valueChanged), this,
93  &CAudioNotificationComponent::onNotificationVolumeChanged);
94  Q_ASSERT(c);
95  }
96 
98 
99  void CAudioNotificationComponent::reloadSettings()
100  {
101  const CSettings as(m_audioSettings.getThreadLocal());
102 
103  ui->cb_SetupAudioPTTClickDown->setChecked(as.isNotificationFlagSet(CNotificationSounds::PTTClickKeyDown));
104  ui->cb_SetupAudioPTTClickUp->setChecked(as.isNotificationFlagSet(CNotificationSounds::PTTClickKeyUp));
105 
106  ui->cb_SetupAudioNotificationTextMessageFrequency->setChecked(
107  as.isNotificationFlagSet(CNotificationSounds::NotificationTextMessageFrequency));
108  ui->cb_SetupAudioNotificationTextMessagePrivate->setChecked(
109  as.isNotificationFlagSet(CNotificationSounds::NotificationTextMessagePrivate));
110  ui->cb_SetupAudioNotificationTextMessageSupervisor->setChecked(
111  as.isNotificationFlagSet(CNotificationSounds::NotificationTextMessageSupervisor));
112  ui->cb_SetupAudioNotificationTextMessageUnicom->setChecked(
113  as.isNotificationFlagSet(CNotificationSounds::NotificationTextMessageUnicom));
114  ui->cb_SetupAudioNotificationTextCallsignMentioned->setChecked(
115  as.isNotificationFlagSet(CNotificationSounds::NotificationTextCallsignMentioned));
116 
117  ui->cb_SetupAfvBlocked->setChecked(as.isNotificationFlagSet(CNotificationSounds::AFVBlocked));
118  ui->cb_SetupAfvClicked->setChecked(as.isNotificationFlagSet(CNotificationSounds::AFVClicked));
119 
120  ui->cb_SetupAudioNotificationLogin->setChecked(
121  as.isNotificationFlagSet(CNotificationSounds::NotificationLogin));
122  ui->cb_SetupAudioNotificationLogoff->setChecked(
123  as.isNotificationFlagSet(CNotificationSounds::NotificationLogoff));
124 
125  ui->le_SoundDir->setText(as.getNotificationSoundDirectory());
126  ui->sb_NotificationValueVolume->setValue(as.getNotificationVolume());
127  }
128 
129  void CAudioNotificationComponent::onNotificationVolumeChanged(int volume)
130  {
131  volume = qMax(25, qMin(100, volume));
132  CSettings as(m_audioSettings.getThreadLocal());
133  if (as.getNotificationVolume() == volume) { return; }
134  as.setNotificationVolume(volume);
135  m_audioSettings.set(as);
136  }
137 
138  CNotificationSounds::NotificationFlag CAudioNotificationComponent::checkBoxToFlag(const QCheckBox *cb) const
139  {
140  if (!cb) { return CNotificationSounds::NoNotifications; }
141 
142  if (cb == ui->cb_SetupAudioPTTClickDown) { return CNotificationSounds::PTTClickKeyDown; }
143  if (cb == ui->cb_SetupAudioPTTClickUp) { return CNotificationSounds::PTTClickKeyUp; }
144 
145  if (cb == ui->cb_SetupAudioNotificationTextCallsignMentioned)
146  {
147  return CNotificationSounds::NotificationTextCallsignMentioned;
148  }
149  if (cb == ui->cb_SetupAudioNotificationTextMessageFrequency)
150  {
151  return CNotificationSounds::NotificationTextMessageFrequency;
152  }
153  if (cb == ui->cb_SetupAudioNotificationTextMessagePrivate)
154  {
155  return CNotificationSounds::NotificationTextMessagePrivate;
156  }
157  if (cb == ui->cb_SetupAudioNotificationTextMessageSupervisor)
158  {
159  return CNotificationSounds::NotificationTextMessageSupervisor;
160  }
161  if (cb == ui->cb_SetupAudioNotificationTextMessageUnicom)
162  {
163  return CNotificationSounds::NotificationTextMessageUnicom;
164  }
165 
166  if (cb == ui->cb_SetupAfvBlocked) { return CNotificationSounds::AFVBlocked; }
167  if (cb == ui->cb_SetupAfvClicked) { return CNotificationSounds::AFVClicked; }
168 
169  if (cb == ui->cb_SetupAudioNotificationLogin) { return CNotificationSounds::NotificationLogin; }
170  if (cb == ui->cb_SetupAudioNotificationLogoff) { return CNotificationSounds::NotificationLogoff; }
171 
172  return CNotificationSounds::NoNotifications;
173  }
174 
175  void CAudioNotificationComponent::onNotificationsToggled(bool checked)
176  {
177  if (!sGui || sGui->isShuttingDown() || !sGui->getIContextAudio()) { return; }
178  CSettings as(m_audioSettings.getThreadLocal());
179 
180  as.setNotificationFlag(CNotificationSounds::PTTClickKeyDown, ui->cb_SetupAudioPTTClickDown->isChecked());
181  as.setNotificationFlag(CNotificationSounds::PTTClickKeyUp, ui->cb_SetupAudioPTTClickUp->isChecked());
182 
183  as.setNotificationFlag(CNotificationSounds::NotificationTextMessageFrequency,
184  ui->cb_SetupAudioNotificationTextMessageFrequency->isChecked());
185  as.setNotificationFlag(CNotificationSounds::NotificationTextMessagePrivate,
186  ui->cb_SetupAudioNotificationTextMessagePrivate->isChecked());
187  as.setNotificationFlag(CNotificationSounds::NotificationTextMessageSupervisor,
188  ui->cb_SetupAudioNotificationTextMessageSupervisor->isChecked());
189  as.setNotificationFlag(CNotificationSounds::NotificationTextMessageUnicom,
190  ui->cb_SetupAudioNotificationTextMessageUnicom->isChecked());
191  as.setNotificationFlag(CNotificationSounds::NotificationTextCallsignMentioned,
192  ui->cb_SetupAudioNotificationTextCallsignMentioned->isChecked());
193 
194  as.setNotificationFlag(CNotificationSounds::AFVBlocked, ui->cb_SetupAfvBlocked->isChecked());
195  as.setNotificationFlag(CNotificationSounds::AFVClicked, ui->cb_SetupAfvClicked->isChecked());
196 
197  as.setNotificationFlag(CNotificationSounds::NotificationLogin, ui->cb_SetupAudioNotificationLogin->isChecked());
198  as.setNotificationFlag(CNotificationSounds::NotificationLogoff,
199  ui->cb_SetupAudioNotificationLogoff->isChecked());
200 
201  const CStatusMessage msg = m_audioSettings.set(as);
202  CLogMessage(this).preformatted(msg);
203 
204  const QCheckBox *sender = qobject_cast<const QCheckBox *>(QObject::sender());
205  if (checked && sGui && sGui->getCContextAudioBase() && sender)
206  {
207  const CNotificationSounds::NotificationFlag f = this->checkBoxToFlag(sender);
208  sGui->getCContextAudioBase()->playNotification(f, false, as.getNotificationVolume());
209  }
210  }
211 
212  void CAudioNotificationComponent::selectNotificationSoundsDir()
213  {
214  CSettings s = m_audioSettings.get();
215  const QString dir =
216  QFileDialog::getExistingDirectory(this, QStringLiteral("Open directory"), s.getNotificationSoundDirectory(),
217  QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
218  const QDir d(dir);
219  if (d.exists())
220  {
222  ui->le_SoundDir->setText(s.getNotificationSoundDirectory());
223  const CStatusMessage m = m_audioSettings.setAndSave(s);
224  CLogMessage::preformatted(m);
225  }
226  }
227 
228  void CAudioNotificationComponent::resetNotificationSoundsDir()
229  {
230  CSettings s = m_audioSettings.get();
232  const CStatusMessage m = m_audioSettings.setAndSave(s);
233  CLogMessage::preformatted(m);
234  ui->le_SoundDir->clear();
235  }
236 
237 } // namespace swift::gui::components
const context::IContextAudio * getIContextAudio() const
Direct access to contexts if a CCoreFacade has been initialized.
bool isShuttingDown() const
Is application shutting down?
const context::CContextAudioBase * getCContextAudioBase() const
Direct access to contexts if a CCoreFacade has been initialized.
void playNotification(swift::misc::audio::CNotificationSounds::NotificationFlag notification, bool considerSettings, int volume=-1)
Notification sounds.
CStatusMessage setAndSave(const T &value, qint64 timestamp=0)
Write and save in the same step. Must be called from the thread in which the owner lives.
Definition: valuecache.h:417
CStatusMessage set(const T &value, qint64 timestamp=0)
Write a new value. Must be called from the thread in which the owner lives.
Definition: valuecache.h:411
const T & getThreadLocal() const
Read the current value.
Definition: valuecache.h:400
T get() const
Get a copy of the current value.
Definition: valuecache.h:408
Class for emitting a log message.
Definition: logmessage.h:27
static void preformatted(const CStatusMessage &statusMessage)
Sends a verbatim, preformatted message to the log.
Streamable status message, e.g.
Value object encapsulating information of audio related settings.
Definition: audiosettings.h:25
void setNotificationSoundDirectory(const QString &dir)
Directory.
const QString & getNotificationSoundDirectory() const
Notification directory.
Definition: audiosettings.h:87
SWIFT_GUI_EXPORT swift::gui::CGuiApplication * sGui
Single instance of GUI application object.
Backend services of the swift project, like dealing with the network or the simulators.
Definition: actionbind.cpp:7
High level reusable GUI components.
Definition: aboutdialog.cpp:13
Free functions in swift::misc.
auto singleShot(int msec, QObject *target, F &&task)
Starts a single-shot timer which will call a task in the thread of the given object when it times out...
Definition: threadutils.h:30