19 #include <QSvgRenderer>
22 #include <QMessageBox>
23 #include <QCloseEvent>
24 #include <QDialogButtonBox>
27 #include "../serverapp/serverapp.h"
28 #include "../clicklabel/clicklabel.h"
29 #include "../sessionnamewindow/sessionnamewindow.h"
30 #include "../connectionframe/connectionframe.h"
31 #include "../helpwindow/helpwindow.h"
32 #include "../reloadroomwindow/reloadroomwindow.h"
34 #include "../net/listenserver.h"
35 #include "../net/client.h"
36 #include "../net/discoverylistener.h"
38 #include "../../shared/settings.h"
39 #include "../util/platform/screensaver.h"
41 #include "ui_mainwindow.h"
43 #define sStrTutorNdef MainWindow::tr("No tutor defined.")
44 #define sStrTutorOffline MainWindow::tr("Tutor is offline.")
45 #define sStrSourceNdef MainWindow::tr("Please select a projection source.")
46 #define sStrSourceOffline MainWindow::tr("The projection source is offline.")
47 #define sStrDestNdef MainWindow::tr("Please select a projection destination.")
48 #define sStrDestOffline MainWindow::tr("The projection destination is offline.")
49 #define sStrSourceDestSame MainWindow::tr("Selected projection target is tutor.")
50 #define sStrNoDestAv MainWindow::tr("No projection destination available.")
60 , _mode(
Mode::Multicast)
62 qDebug() <<
"MainWindow(parent)";
72 setWindowFlags(Qt::FramelessWindowHint);
85 ui->frmRoom->setStyleSheet(
"background-color:#444");
88 ui->action_Exit->setStatusTip(tr(
"Exit"));
89 ui->action_Lock->setStatusTip(tr(
"Lock or Unlock all Clients"));
98 _dropMarker->setStyleSheet(
"background-color: #448; border-radius: 2px;");
127 <<
ui->action_DeleteClient
128 <<
ui->action_StudentToTutor
129 <<
ui->action_StudentToTutorExclusive
130 <<
ui->action_SetAsTutor
131 <<
ui->action_TutorToStudent
132 <<
ui->action_LockSingle
134 <<
ui->action_TutorToAll
135 <<
ui->action_StopProjection;
143 setAttribute(Qt::WA_QuitOnClose);
144 setUnifiedTitleAndToolBarOnMac(
true);
145 this->showMaximized();
162 int examClientCount = 0;
167 Client* c = frame->client();
170 examClientCount += b ? 1 : 0;
175 serverApp->setExam(examClientCount * 2 >= clientCount && clientCount > 0);
177 qDebug() <<
"isExam is " << e;
178 ui->action_TutorToAll->setVisible(!e);
179 ui->action_StudentToTutor->setVisible(!e);
180 ui->action_StudentToTutorExclusive->setVisible(!e);
181 ui->action_TutorToStudent->setVisible(!e);
182 ui->action_StopProjection->setVisible(!e);
188 if (clientCount == 0) {
213 const int dx = a.x() - b.x();
214 const int dy = a.y() - b.y();
215 const int sum = dx * dx + dy * dy;
234 const bool pickFirstOne = ( preferredPixels == QPoint(-1, -1) );
235 const QSize& clientSize =
serverApp->getCurrentRoom()->clientSize;
236 #define GRID(X,Y) (grid[((X) * _tilesY) + (Y)])
243 if (frame == toIgnore) {
continue; }
245 const QPoint p = frame->getGridPosition();
247 for (
int x = p.x(); x < p.x() + clientSize.width(); x++) {
248 for (
int y = p.y(); y < p.y() + clientSize.height(); y++) {
254 QList<QPoint> freePositions;
256 for (
int x = 0; x <=
_tilesX - clientSize.width(); x++) {
257 for (
int y = 0; y <= _tilesY - clientSize.height(); y++) {
261 for (dx = 0; dx < clientSize.width(); dx++) {
262 for (dy = 0; dy < clientSize.height(); dy++) {
263 if (
GRID(x + dx, y + dy)) {
271 freePositions << QPoint(x, y);
281 if (freePositions.isEmpty() && toIgnore !=
nullptr) {
285 int min_distance = 10000000;
286 QPoint bestPosition = QPoint(0, 0);
288 for (QPoint freePos : freePositions) {
290 const int dist =
distance(freePosPx, preferredPixels);
291 if (dist < min_distance) {
293 bestPosition = freePos;
315 if (gridPosition ==
nullptr) {
318 cf->setGridPosition(*gridPosition);
320 cf->setComputerId(computerId);
357 if (frame->client() !=
nullptr) {
358 if (frame->client()->id() == id)
359 return frame->client();
374 if ((frame !=
nullptr) && (frame->isTutor()))
389 if ((frame !=
nullptr) && (frame->isSelected()))
406 QMessageBox::StandardButton ret = QMessageBox::question(
this, tr(
"Question"), tr(
"Are you sure you want to exit?"),
407 QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
408 if (ret == QMessageBox::Yes) {
409 QApplication::exit(0);
421 QMainWindow::changeEvent(e);
433 float aspectRoom = float(gridSize.height()) /
float(gridSize.width());
434 float aspectFrame = float(frameSize.height()) /
float(frameSize.width());
436 if (aspectRoom / aspectFrame < 0.8f) {
439 if ( aspectFrame / aspectRoom < 0.8f) {
452 if (
ui->frmRoom->size().width() < 100 ||
ui->frmRoom->size().height() < 100) {
462 QPoint bounds = frame->getGridPosition();
463 while (bounds.x() + clientSize.width() > newGridSize.width()) {
464 newGridSize += QSize(1, 0);
466 while (bounds.y() + clientSize.height() > newGridSize.height()) {
467 newGridSize += QSize(0, 1);
477 newGridSize += QSize(0, 1);
481 newGridSize += QSize(1, 0);
484 this->
_tilesX = newGridSize.width();
485 this->
_tilesY = newGridSize.height();
486 const int maxX =
_tilesX - clientSize.width();
487 const int maxY =
_tilesY - clientSize.height();
490 for (
auto * frame : _clientFrames) {
491 const QPoint gp = frame->getGridPosition();
492 if ( gp.x() > maxX || gp.y() > maxY ) {
498 for (
auto * frame : _clientFrames) {
499 frame->updateGeometry();
504 int w =
ui->frmRoom->width() - 5;
505 int h =
ui->frmRoom->height() - 5;
506 ui->imageLabel->hide();
507 ui->imageLabel->setScaledContents(
true);
508 ui->imageLabel->setPixmap(QPixmap::fromImage(*_backgroundImage).scaled(w, h, Qt::IgnoreAspectRatio));
509 ui->imageLabel->show();
511 ui->imageLabel->clear();
521 const bool somethingSelected = (selected !=
nullptr);
522 const bool selectedOnline = (selected !=
nullptr && selected->
client() !=
nullptr);
523 const bool tutorOnline = (tutor !=
nullptr && tutor->
client() !=
nullptr);
525 ui->action_DeleteClient->setEnabled(somethingSelected && !selectedOnline);
526 ui->action_SetAsTutor->setEnabled(somethingSelected);
527 ui->action_LockSingle->setEnabled(selectedOnline && selected != tutor);
529 ui->action_StudentToTutorExclusive->setEnabled(selectedOnline && tutorOnline && selected != tutor);
530 ui->action_StudentToTutor->setEnabled(selectedOnline && tutorOnline && selected != tutor);
531 ui->action_TutorToStudent->setEnabled(selectedOnline && tutorOnline && selected != tutor);
533 ui->action_TutorToAll->setEnabled(tutorOnline);
547 const QPoint pos(
ui->frmRoom->mapFrom(
this, e->pos()));
548 if (pos.x() < 0 || pos.y() < 0)
550 const QSize frame(
ui->frmRoom->size());
551 if (frame.width() > pos.x() && frame.height() > pos.y()) {
573 if (frame->client() !=
nullptr) {
574 frame->client()->lockScreen(lock);
575 frame->client()->removeAttention();
588 QPoint slot =
closestFreeSlot(connectionFrame->pos(), connectionFrame);
592 ui->imageLabel->lower();
604 const QPoint preferredPixels = connectionFrame->pos();
617 if (current == frame)
622 if (current !=
nullptr) {
643 bool haveAdditionalClient =
false;
644 for (QMutableListIterator<ConnectionFrame*> it(
_clientFrames); it.hasNext(); ) {
645 if (!it.next()->isFromRoomplan()) {
646 haveAdditionalClient =
true;
650 if (!haveAdditionalClient)
653 QMessageBox::StandardButton ret = QMessageBox::question(
this,
654 tr(
"Question"), tr(
"Do you want to delete and disconnect any clients\n"
655 "not belonging to the current room layout?"),
656 QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
657 if (ret != QMessageBox::Yes)
661 for (QMutableListIterator<ConnectionFrame*> it(
_clientFrames); it.hasNext(); ) {
702 QList<QString> keyList =
serverApp->getRooms().keys();
703 for (
const auto & it : keyList) {
724 if (room !=
nullptr) {
732 const QString& computerId = it.key();
733 const QPoint& pos = it.value();
737 if (computerId == room->
tutorIP) {
738 qDebug() <<
"set computer with id " << computerId <<
" as tutor per configuration";
748 qDebug() <<
"imgPath is " << imgPath;
751 qDebug() <<
"set background image path: " << imgPath;
752 if (imgPath.endsWith(
"svg")) {
754 QSize s = QGuiApplication::screenAt(geometry().center())->size();
755 QSvgRenderer renderer(imgPath);
759 renderer.render(&painter);
775 if (roomToReload.isEmpty()) {
776 QMessageBox::critical(
this,
"Warning", tr(
"No item selected, please select room!"), 0, 1);
779 QMessageBox::StandardButton ret = QMessageBox::question(
this, tr(
"Warning"),
780 tr(
"Are you sure you want to reload the room?\n"
781 "Note that all clients will be deleted."),
782 QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
783 if (ret == QMessageBox::Yes) {
789 frame->deleteLater();
791 _clientFrames.clear();
806 return ui->frmRoom->size().width() /
_tilesX;
811 return ui->frmRoom->size().height() /
_tilesY;
817 const QSize& clientSize =
serverApp->getCurrentRoom()->clientSize;
820 return QRect(pos.x() * w, pos.y() * h, w * clientSize.width(), h * clientSize.height());
838 ui->action_Lock->setChecked(
false);
841 QMessageBox::critical(
this, tr(
"Projection"),
sStrTutorNdef);
845 QMessageBox::critical(
this, tr(
"Projection"),
sStrNoDestAv);
855 if (frame->client() !=
nullptr)
870 ui->action_Lock->setChecked(
false);
873 QMessageBox::critical(
this, tr(
"Projection"),
sStrDestNdef);
875 QMessageBox::critical(
this, tr(
"Projection"),
sStrTutorNdef);
888 if (c->client() !=
nullptr) {
895 if (destinationClient->desiredProjectionSource() == sourceClient->id() ) {
896 destinationClient->stopVncClient();
898 destinationClient->setDesiredProjectionSource(sourceClient->id());
904 if (c->client() !=
nullptr && c->client()->desiredProjectionSource() == sourceClient->id()) {
908 if (numClients == 0) {
910 sourceClient->stopVncServer();
940 QMessageBox::critical(
this, tr(
"Projection"),
sStrTutorNdef);
948 const bool wasLocked =
ui->action_Lock->isChecked();
949 ui->action_Lock->setChecked(
false);
961 if (f->client() ==
nullptr)
963 if (source != f->client() && dest != f->client()) {
964 f->client()->setDesiredProjectionSource(
NO_SOURCE);
967 f->client()->lockScreen(
true);
969 }
else if (wasLocked) {
970 f->client()->lockScreen(exclusive);
991 ui->action_Lock->setChecked(
false);
1011 QMessageBox::critical(
this, tr(
"Selection"), tr(
"No client is selected."));
1017 if (client ==
nullptr) {
1018 QMessageBox::critical(
this, tr(
"Selection"), tr(
"The selected client is not connected."));
1021 bool newState = !client->
isLocked();
1026 if (frame->client() ==
nullptr)
1028 if (frame->client()->isLocked())
1031 ui->action_Lock->setChecked(
false);
1053 if (selected ==
nullptr) {
1054 QMessageBox::critical(
this, tr(
"Selection"), tr(
"No client is selected."));
1059 if (selected->
client() !=
nullptr) {
1063 if (selected == tutor)
1066 if (tutor !=
nullptr) {
1102 QString check = request->
name;
1107 Client *c = frame->client();
1112 if (c->
ip() == request->
ip) {
1116 if (c->
name() == check) {
1118 check = request->
name +
" (" + QString::number(++addnum) +
")";
1122 }
while (inuse && addnum < 100);
1126 request->
name = check;
1148 if (frame->computerId() == client->
ip()) {
1154 if (existing !=
nullptr) {
1181 if (frame->client() ==
nullptr)
1183 if (frame->client()->desiredProjectionSource() == client->
id()) {
1184 frame->client()->startVncClient(client);
1195 if (frame->client() !=
nullptr) {
1196 if (frame->client()->desiredProjectionSource() == client->
id()) {
1197 frame->client()->setDesiredProjectionSource(
NO_SOURCE);
1198 frame->client()->stopVncClient();
1200 frame->client()->lockScreen(
true);
1206 ||
ui->action_Lock->isChecked());
1224 if (client !=
nullptr) {
1240 bool serverHasWatchers =
false;
1242 if (frame->client() !=
nullptr)
1243 if (frame->client()->desiredProjectionSource() == client->
projectionSource()) {
1244 serverHasWatchers =
true;
1248 if (!serverHasWatchers) {
1264 a->setDisabled(
true);
1275 a->setEnabled(
true);
1285 if (frame ==
nullptr) {
1286 QMessageBox::critical(
this, tr(
"Selection"), tr(
"No client is selected."));
1289 if (frame->
client() !=
nullptr) {
1290 QMessageBox::critical(
this, tr(
"Selection"), tr(
"This client is still connected."));
1293 QMessageBox::StandardButton ret = QMessageBox::question(
this, tr(
"Warning"), tr(
"Are you sure you want to delete the selected client?"),
1294 QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
1295 if (ret == QMessageBox::Yes) {
1297 frame->deleteLater();
void setExamMode(bool mode)
QRect calcFrameGeometry(ConnectionFrame *frame) const
MainWindow(QWidget *parent=nullptr)
Initialize MainWindow and ListenServer.
void enableButtons()
EnableButtons.
bool isFromRoomplan() const
void onReloadRoomCancel()
void tellClientCurrentSituation(Client *client)
Tells the new client the current situation in class room.
void reset(bool lock=false)
reset
QTimer * _buttonLockTimer
void authenticating(Client *client, ClientLogin *request)
void authenticated(Client *client)
static const qint64 BUTTON_BLOCK_TIME
void mouseReleaseEvent(QMouseEvent *e) override
Handle Mouse Release Event.
void onFrameDropped(ConnectionFrame *frame)
Place frame to from user specified position.
QPoint closestFreeSlot(const QPoint &preferredPixels, const ConnectionFrame *toIgnore)
: find the closest available frame.
void setTutor(bool b)
Set tutor status of frame.
void onFrameMoving(ConnectionFrame *frame)
void allowSaverAndStandby(bool allow)
Whether we want to allow the screen saver to activate or the screen to enter standby.
QDialogButtonBox * buttonBox() const
void clientCountChanged()
this function determines if the number of clients in exam mode comprise more than 50%...
ClickLabel * _sessionNameLabel
ConnectionFrame * createFrame(const QString &computerId=QString(), const QPoint *gridPosition=nullptr, bool fromRoomplan=false)
Create new Frame.
int getTileHeightPx() const
void setGridPosition(int x, int y)
SessionNameWindow * _sessionNameWindow
QImage * _backgroundImage
void changeEvent(QEvent *e) override
Change Event.
void disableButtons()
DisableButtons.
QString currentRoom() const
void placeFrameInFreeSlot(ConnectionFrame *frame, QPoint preferred=QPoint(-1,-1))
void onVncClientStateChange(Client *client)
Handle VNC client state change.
void onClientAuthenticated(Client *client)
New client was authenticated, make several checks.
void onButtonExit()
On button exit, close application.
int getTileWidthPx() const
QMap< QString, QPoint > clientPositions
ReloadRoomWindow * _reloadWindow
void closeEvent(QCloseEvent *e) override
Handle closeEvent.
void onButtonTutorToAll()
Handle projection from tutor to all.
void startVncClient(const Client *to)
QList< QAction * > _lockingButtons
void onButtonStudentToTutor()
Handle projection from one student to tutor.
ConnectionFrame * getSelectedFrame()
Return the Frame, which is currently selected by user.
void show(const QString &name)
const QPoint & getGridPosition() const
void onVncServerStateChange(Client *client)
Handle if VNC Server State has changed.
void setDesiredProjectionSource(int id)
#define sStrSourceOffline
void onButtonStudentToTutorExclusive()
Handle projection from one student to tutor, lock everyone else.
bool isActiveVncClient() const
void onSessionNameUpdate()
Update session name.
void addRoom(const QString &roomName)
const QString & name() const
int projectionSource() const
Class for clickable part on sessionName.
void onButtonLockSingle()
void setSelection(bool selected)
Set frame as selected or not.
static int distance(QPoint a, QPoint b)
Squared euclidean distance (why is this not implemented in QPoint?)
bool isActiveVncServer() const
void vncOneOnOne(bool exclusive)
ConnectionFrame * getTutorFrame()
Return the Frame, which is currently beeing Tutor.
void resizeEvent(QResizeEvent *e) override
Resize event.
void frameMoved(ConnectionFrame *frame)
void onSessionNameClick()
Show session name, after it was clicked on.
void startVncServerIfNecessary(int from)
MainWindow::startVncServerIfNecessary.
void vncClientStateChange(Client *client)
void onButtonSetAsTutor()
Handle button to set specific client as tutor.
void updateContextButtonStates()
AspectStatus checkAspectRatio(const QSize &frameSize, const QSize &gridSize)
check the difference in the aspect ratio between the frame size and the grid size.
Class for representing the clients of current session, with a specific frame displaying username and ...
void clicked(ConnectionFrame *frame)
void vncServerStateChange(Client *client)
void onClientConnected(Client *client)
Handle from ListenServer signaled new client connection.
Class for listing on new client connection.
void onFrameClicked(ConnectionFrame *frame)
Mark given frame after it was clicked on.
Client * getClientFromId(int id)
Returns connected client which belongs to given id.
#define sStrSourceDestSame
void assignClient(Client *client)
Assign client to connectionFrame.
void onClientAuthenticating(Client *client, ClientLogin *request)
Authenticate new Client client.
void newClient(Client *client)
void forceUnlockAndScreenOn()
Disable the screen saver (only if password locking is disabled!), power screen on if it's in standby...
int desiredProjectionSource() const
enum MainWindow::Mode _mode
void onButtonStopProjection()
Handle Button StopProjection.
void onButtonLock(bool checked)
Handle button to lock or unlock screens of client(s).
QList< ConnectionFrame * > _clientFrames
void frameMoving(ConnectionFrame *frame)
void onButtonHelp()
Display popup which explains possible actions about the buttons.
void onButtonTutorToStudent()
Handle the projection from Tutor to specific student.
void onButtonReloadRoomConfig()