Pool Video Switch v2
Software video switch for distributed remote display in a lecture environment
toolbar.cpp
Go to the documentation of this file.
1 #include "../../shared/settings.h"
2 #include "../net/serverconnection.h"
3 #include "../vnc/vncwindow.h"
4 #include "../vnc/vncserver.h"
5 #include "../informationdialog/informationdialog.h"
6 #include "../clientapp/clientapp.h"
7 #include "../addons/addons.h"
8 
9 #include "toolbar.h"
10 #include "ui_toolbar.h"
11 
12 #include <QNetworkInterface>
13 #include <QScreen>
14 #include <QMenu>
15 #include <QMouseEvent>
16 #include <QMessageBox>
17 
28 Toolbar::Toolbar(const QByteArray& sessionName, QWidget *parent)
29  : QWidget(parent)
30  , _showTimer(this)
31  , _hideTimer(this)
32  , _hideCountdown(10)
33  , _blinkTimer(this)
34  , _beWatchedEye(":eye")
35 {
36  qDebug() << "sessionName - constructor";
37  init();
38 
39  clientApp->connectWindow()->connectToSession(sessionName, "");
40 }
41 
52 Toolbar::Toolbar(const bool autoConnect, QWidget *parent)
53  : QWidget(parent)
54  , _showTimer(this)
55  , _hideTimer(this)
56  , _hideCountdown(10)
57  , _blinkTimer(this)
58  , _beWatchedEye(":eye")
59 {
60  qDebug() << "auto - constructor!";
61  init();
62 
63 
64  if (autoConnect) {
65  // Try getting manager ip.
66  QString mgrIp = identifyMgrIP();
67  if (!mgrIp.isEmpty())
68  clientApp->connectWindow()->connectToSession("", mgrIp);
69  }
70 }
71 
84  : QWidget(parent), _showTimer(this), _hideTimer(this), _hideCountdown(10), _blinkTimer(this), _beWatchedEye(":eye")
85 {
86  init();
87 }
88 
90 {
91  this->close();
92  this->deleteLater();
93  qApp->quit();
94 }
95 
97 {
98  _ui = new Ui::Toolbar;
99  /* Initialize the GUI */
100  _ui->setupUi(this);
101 
102  /* Set window properties */
103  setWindowFlags(Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint | Qt::FramelessWindowHint);
104  setAttribute(Qt::WA_AlwaysShowToolTips);
105  setAttribute(Qt::WA_QuitOnClose, false);
106  setAttribute(Qt::WA_DeleteOnClose, false);
107 
108  /* Create the VNC Window */
109  _vnc = new VncWindow(nullptr);
110 
111  /* Create the connect window */
112  clientApp->connectWindow()->setAvailableRooms(myRooms());
113  // Connect the signals
114  connect(clientApp->connectWindow(), &ConnectWindow::disconnect, this, &Toolbar::onDoDisconnect);
115  connect(clientApp->connectWindow(), &ConnectWindow::connected, this, &Toolbar::onConnected);
116  connect(_ui->btnAttention, &QToolButton::toggled, this, &Toolbar::onBtnAttention);
117 
118  /* Setup menu */
120 
121  /* hide attention button while disconnected */
122  _ui->btnAttention->setVisible(false);
123  _ui->btnAttention->setMaximumWidth(30);
124 
125  /* Connect the signals from vnc server */
127 
128  /* React to screen geometry change */
129  connect(QGuiApplication::primaryScreen(), &QScreen::availableGeometryChanged, this, &Toolbar::setToolbarPosition);
130 
131  /* Detect task bars and set position */
132  const QRect availableScreen = QGuiApplication::primaryScreen()->availableGeometry();
133  setToolbarPosition(availableScreen);
134 
135  /* Setup show & hide timer */
136  _showTimer.setInterval(500);
137  _showTimer.setSingleShot(true);
138  connect(&_showTimer, &QTimer::timeout, this, &Toolbar::showBar);
139  _hideTimer.setInterval(50);
140  _hideTimer.setSingleShot(false);
141  connect(&_hideTimer, &QTimer::timeout, this, &Toolbar::hideBar);
142 
143  setVisible(true);
144  raise();
145  _hideTimer.start(); // initially show PVS and hide later
146 
147  /* Setup blink timer */
148  _blinkTimer.setInterval(500);
149  connect(&_blinkTimer, &QTimer::timeout, this, &Toolbar::cameraBlink);
150 }
151 
152 static QFrame* makeVerticalLine() {
153  auto *f = new QFrame();
154  f->setFrameShape(QFrame::HLine);
155  f->setFrameShadow(QFrame::Sunken);
156  return f;
157 }
158 
164 {
165  QList<QPushButton*> buttons;
166  QList<QAction*> menus;
167  auto settings = clientApp->getSettings();
168  AddonManager::loadFromPath(settings->value("addonConfigDir", "/opt/openslx/pvs2/addons").toString(), buttons, menus);
169  // Buttons
170  if (!buttons.isEmpty()) {
171  _ui->buttonContainer->addWidget(makeVerticalLine());
172  for (auto i : buttons) {
173  _ui->buttonContainer->addWidget(i);
174  i->setVisible(false);
175  }
176  _ui->buttonContainer->addWidget(makeVerticalLine());
177  }
178  // Menu
179  _menu = new QMenu(this);
180  _acnConnect = new QAction(tr("&Connect..."), this);
181  _acnDisconnect = new QAction(tr("&Disconnect"), this);
182  _acnDisconnect->setEnabled(false);
183  _acnInformation = new QAction(tr("&Information..."), this);
184  _acnAbout = new QAction(tr("&What's this?"), this);
185  _acnQuit = new QAction(tr("&Quit"), this);
186 
187  _menu->addAction(_acnConnect);
188  _menu->addAction(_acnDisconnect);
189  _menu->addSeparator();
190  for (auto i : menus) {
191  _menu->addAction(i);
192  i->setVisible(false);
193  }
194  _menu->addAction(_acnInformation);
195  _menu->addAction(_acnAbout);
196  _menu->addSeparator();
197  _menu->addAction(_acnQuit);
198  _ui->cmdMenu->setMenu(_menu);
199 
200  /* only add a "quit"-button when the configuration allows it. */
201  bool allow = settings->value("allowClientQuit").toBool();
202  _acnQuit->setVisible(allow);
203 
204  // Connect the signals
205  connect(_menu, &QMenu::aboutToHide, this, &Toolbar::delayedHideBar);
206  connect(_acnConnect, &QAction::triggered, clientApp->connectWindow(), &ConnectWindow::doShow);
207  connect(_acnDisconnect, &QAction::triggered, clientApp->connectWindow(), &ConnectWindow::DoDisconnect);
208  connect(_acnInformation, &QAction::triggered, this, &Toolbar::showInformationDialog);
209  connect(_acnAbout, &QAction::triggered, this, &Toolbar::showAboutDialog);
210  connect(_acnQuit, &QAction::triggered, this, &Toolbar::exit);
211 
212  // Delay until bar is visible
213  QTimer::singleShot(10, [=]() {
215  });
216 }
217 
223 {
225  _vnc->deleteLater();
226  delete _ui;
227 }
228 
229 /*
230  * Override
231  */
232 
239 void Toolbar::enterEvent(QEvent* e)
240 {
241  delayedShowBar();
242  QWidget::enterEvent(e);
243 }
244 
245 void Toolbar::mousePressEvent(QMouseEvent* e)
246 {
247  _lastDragPos = e->globalPos();
248 }
249 
250 void Toolbar::mouseMoveEvent(QMouseEvent* e)
251 {
252  const QPoint currentPos = e->globalPos();
253  const QPoint offset = currentPos - _lastDragPos;
254  _lastDragPos = currentPos;
255  move(x() + offset.x(), y());
256 }
257 
258 /*
259 * CFG to test this
260 * http://git.openslx.org/tm-scripts.git/plain/server/modules/pvs2-freiburg/etc/xdg/openslx/pvs2client.ini
261 *
262 */
263 
264 
265 /* returns a sorted list of available rooms.
266  * (Available means that this client is configured to be in that room) */
267 QList<Room> Toolbar::myRooms()
268 {
269 
270  QList<Room> myRooms;
271 
272  auto conf = clientApp->getSettings();
273 
274  if (!conf->contains("rooms")) {
275  qDebug() << "Invalid config file!";
276  return myRooms;
277  }
278 
279  QStringList roomNames = conf->value("rooms").toStringList();
280 
281  /* go through all rooms and check if this client is a member of the room. */
282  auto localAddresses = QNetworkInterface::allAddresses();
283  for (auto roomName : roomNames) {
284  conf->beginGroup(roomName);
285  if (conf->contains("name")) {
286  roomName = conf->value("name").toString();
287  }
288  if (!conf->contains("mgrIP")) {
289  qDebug() << "Room " << roomName << " has no mgrIP: Invalid config file!";
290  }
291  QString mgrIP = conf->value("mgrIP").toString();
292  int priority = conf->value("priority").toInt();
293 
294  if (mgrIP.length() != 0) {
295  foreach (const QHostAddress & address, localAddresses) {
296  int size = conf->beginReadArray("client");
297  for (int j = 0; j < size; ++j) {
298  conf->setArrayIndex(j);
299  QString ip = conf->value("ip").toString();
300  if (address != QHostAddress(QHostAddress::LocalHost)
301  && ip == address.toString() ) {
302  /* add this room to the list */
303  Room r(roomName, mgrIP, priority);
304  myRooms << r;
305  break;
306  }
307  }
308  conf->endArray();
309  }
310  }
311  conf->endGroup();
312  }
313  /* sort */
314  qStableSort(myRooms.begin(), myRooms.end(), qGreater<Room>());
315  return myRooms;
316 }
320 {
321  QList<Room> rooms = myRooms();
322  if (!rooms.empty()) {
323  return rooms.first().mgr;
324  } else {
325  return "";
326  }
327 }
328 
329 /*
330  * Slots
331  */
332 
338 {
339  static bool showEye = false;
340  if (!showEye) {
341  _ui->icon_cam->setPixmap(_beWatchedEye);
342  showEye = true;
343  } else {
344  _ui->icon_cam->setPixmap(QPixmap()); // set empty pixmap for blinking effect
345  showEye = false;
346  }
347 }
348 
355 {
356  if (port > 0) {
357  _blinkTimer.start();
358  _ui->lblStatus->setStyleSheet("color:red");
359  _ui->lblStatus->setText(tr("Streaming"));
360  showBar();
361  } else {
362  _blinkTimer.stop();
363  _ui->icon_cam->setPixmap(QPixmap());
364  _ui->lblStatus->setStyleSheet("color:green");
365  _ui->lblStatus->setText(tr("Online"));
366  delayedHideBar();
367  }
368 }
369 
375 {
376  if (connection != nullptr) {
377  disconnect(connection, &ServerConnection::disconnected, this, &Toolbar::onDisconnected);
378  }
379  _ui->lblStatus->setStyleSheet("color:red");
380  _ui->lblStatus->setText(tr("Offline"));
381 
382  this->_acnConnect->setEnabled(true);
383  this->_acnDisconnect->setEnabled(false);
384  _ui->btnAttention->setVisible(false);
385  onBtnAttention();
386  delayedHideBar();
388 }
389 
397 {
398  this->_acnConnect->setEnabled(false);
399  this->_acnDisconnect->setEnabled(true);
400 
401  _ui->btnAttention->setChecked(false);
402  _ui->lblStatus->setStyleSheet("color:green");
403  _ui->lblStatus->setText(tr("Online"));
404  /* connected, show button */
405  _ui->btnAttention->setVisible(true);
406  AddonManager::connectEvent(connection->isLocalConnection(), connection->getPeerAdress());
407  //
408  connect(connection, &ServerConnection::disconnected, this, &Toolbar::onDisconnected);
409  connect(connection, &ServerConnection::openVnc,
411  connect(connection, &ServerConnection::closeVnc, _vnc, &VncWindow::close);
414 }
415 
420 {
421  if (clientApp->connection() != nullptr)
422  clientApp->connection()->disconnectFromServer();
423 }
424 
426 {
427  _ui->btnAttention->setChecked(on);
428  if (on) {
429  showBar();
430  } else {
431  delayedHideBar();
432  }
433 }
434 
440 {
441  // Don't hide window if any menu is open or VNC Server is running from this client.
442  if (_ui->btnAttention->isChecked() || VncServer::instance()->isVncServerRunning()) {
443  _hideTimer.stop();
444  return;
445  }
446  // These don't qualify for hiding, but don't stop timer
447  if (_menu->isVisible() || this->underMouse())
448  return;
449  // Countdown
450  if (--_hideCountdown > 0)
451  return;
452  _hideTimer.stop();
453  move(x(), _yPosHidden);
454 }
455 
457 {
458  _showTimer.stop();
459  if (!_hideTimer.isActive()) {
460  _hideCountdown = 10;
461  _hideTimer.start();
462  }
463 }
464 
469 {
470  move(x(), _yPos);
471  delayedHideBar();
472 }
473 
475 {
476  _hideTimer.stop();
477  if (!_showTimer.isActive()) {
478  _showTimer.start();
479  }
480 }
481 
486 {
487  QMessageBox msgBox(
488  QMessageBox::NoIcon,
489  tr("About PVS Client"),
490  tr("The PVS - client is part of a software system for managing the "\
491  "virtual data traffic within the computer pools, between the tutor's "\
492  "and student's PCs. It has been developed to simplify the information "\
493  "traffic in seminars and general eLearning."),
494  QMessageBox::NoButton,
495  this,
496  Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint | Qt::WindowStaysOnTopHint);
497  msgBox.setIconPixmap(QIcon(":cam32.svg").pixmap(64, 64));
498  msgBox.exec();
499 }
500 
502 {
503  auto* d = new InformationDialog();
504  d->exec();
505  d->deleteLater();
506 }
507 
509 {
510  const bool on = clientApp->connection() != nullptr && _ui->btnAttention->isChecked();
511  if (on != _ui->btnAttention->isChecked()) {
512  _ui->btnAttention->setChecked(on);
513  return;
514  }
515  if (clientApp->connection() != nullptr) {
516  clientApp->connection()->sendAttention(on);
517  }
518 }
519 
520 void Toolbar::setToolbarPosition(const QRect &availableGeometry)
521 {
522  const QRect primaryScreen = QGuiApplication::primaryScreen()->geometry();
523  // set center position
524  const int centerPos = primaryScreen.left() + (primaryScreen.width() - this->width()) / 2;
525 
526  // detect system task bars
527  if (primaryScreen.height() > availableGeometry.height() && primaryScreen.y() < availableGeometry.y()) {
528  // system task bar already in top position, prefer to show toolbar on bottom
529  _yPos = primaryScreen.height() - this->height();
530  _yPosHidden = primaryScreen.height() - 2;
531  } else {
532  // no task bars at all or a bottom task bar, either way show our toolbar on top
533  _yPos = primaryScreen.top();
534  _yPosHidden = _yPos - this->height() + 2;
535  }
536  move(centerPos, _yPos);
537  delayedShowBar();
538 }
void mouseMoveEvent(QMouseEvent *event) override
Definition: toolbar.cpp:250
QString getPeerAdress() const
Toolbar(QWidget *parent=nullptr)
Constructor of the Toolbar.
Definition: toolbar.cpp:83
int _yPos
Definition: toolbar.h:58
Ui::Toolbar * _ui
Definition: toolbar.h:43
void stop()
VncServer::stop.
Definition: vncserver.cpp:139
void started(int port, const QString &ropass, const QString &rwpass)
static void initControls()
Definition: addons.cpp:131
void showBar()
This slot shows the toolbar.
Definition: toolbar.cpp:468
void DoDisconnect()
actually disconnects the connection
QAction * _acnConnect
Definition: toolbar.h:46
void showAboutDialog()
Toolbar::showAboutDialog.
Definition: toolbar.cpp:485
void initButtonsAndMenus()
This function should be called once from the main init() function which in turn should only be called...
Definition: toolbar.cpp:163
static QFrame * makeVerticalLine()
Definition: toolbar.cpp:152
void onServerAttentionChanged(bool on)
Definition: toolbar.cpp:425
QTimer _hideTimer
Definition: toolbar.h:51
static void connectEvent(bool isLocal, const QString &address)
Definition: addons.cpp:144
void delayedHideBar()
Definition: toolbar.cpp:456
static void disconnectEvent()
Definition: addons.cpp:156
QAction * _acnDisconnect
Definition: toolbar.h:45
void attentionChanged(bool state)
void delayedShowBar()
Definition: toolbar.cpp:474
static QString identifyMgrIP()
Identifies the responsible manager for this client by searching through the configuration file...
Definition: toolbar.cpp:319
~Toolbar() override
Destructor of the Toolbar.
Definition: toolbar.cpp:222
int _yPosHidden
Definition: toolbar.h:59
void disconnected(ServerConnection *connection)
QTimer _showTimer
Definition: toolbar.h:50
void hideBar()
This slot hides the toolbar.
Definition: toolbar.cpp:439
QAction * _acnQuit
Definition: toolbar.h:49
void cameraBlink()
A slot for changing the camera icon.
Definition: toolbar.cpp:337
void enterEvent(QEvent *e) override
This event is reimplemented to receive widget enter events.
Definition: toolbar.cpp:239
const QPixmap _beWatchedEye
Definition: toolbar.h:55
QAction * _acnInformation
Definition: toolbar.h:47
void running(const bool isRunning, const int clientId)
int _hideCountdown
Definition: toolbar.h:52
VncWindow * _vnc
Definition: toolbar.h:54
void onConnected(ServerConnection *connection)
A slot for the onConnected signal of the ConnectWindow.
Definition: toolbar.cpp:396
QAction * _acnAbout
Definition: toolbar.h:48
static void loadFromPath(const QString &path, QList< QPushButton * > &buttons, QList< QAction * > &menuEntries)
Definition: addons.cpp:53
void onDisconnected(ServerConnection *connection)
A slot for the onDisconnected signal of the ConnectWindow.
Definition: toolbar.cpp:374
void exit()
Definition: toolbar.cpp:89
void disconnect()
QPoint _lastDragPos
Definition: toolbar.h:56
void mousePressEvent(QMouseEvent *event) override
Definition: toolbar.cpp:245
void setToolbarPosition(const QRect &geometry)
Definition: toolbar.cpp:520
void onBtnAttention()
Definition: toolbar.cpp:508
void onDoDisconnect()
Definition: toolbar.cpp:419
#define clientApp
Definition: clientapp.h:12
void openVnc(const QString &host, int port, const QString &passwd, bool ro, bool fullscreen, const QString &caption, const int clientId, const QByteArray &rawThumb)
void connected(ServerConnection *connection)
QTimer _blinkTimer
Definition: toolbar.h:53
void showInformationDialog()
Definition: toolbar.cpp:501
QMenu * _menu
Definition: toolbar.h:44
void onVncServerIsRunning(int port)
A slot for the VncServerIsRunning signal.
Definition: toolbar.cpp:354
void init()
Definition: toolbar.cpp:96
static QList< Room > myRooms()
Definition: toolbar.cpp:267
Definition: room.h:6
void onVncViewerStartStop(bool started, int clientId)
This slot is triggered once the internal VNC viewer has started or stopped displaying a VNC stream...
void open(const QString &host, int port, const QString &passwd, bool ro, bool fullscreen, const QString &caption, const int clientId, const QByteArray &rawThumb)
Show the VNC client window and connect to the given VNC server.
Definition: vncwindow.cpp:186
bool isVncServerRunning() const
Definition: vncserver.h:36
static VncServer * instance()
VncServer::instance.
Definition: vncserver.cpp:25