summaryrefslogblamecommitdiffstats
path: root/src/server/connectionframe/connectionframe.cpp
blob: 875e0311b109ac20d94f2d885d46b491bbc5991e (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
















                                                                               
                                     
                          

                  
                
 
                             
                                                                         
                                                                             

                           
                                                                         

                                                                                



                                                                             
                                     
                                                                          
                                                                                                                    

                                   
                                                                         




                                                                                                                  
  
                           
                                                         


                                                                                        
                                                         

                                                                                        
                                  
                                                                             

                                                                                        
 
                                                                  
 

                                            





                                         
                                                                                        
                                                                                                             
                                                        



                              
                           
                                              


                                             

         



































                                                                    
                                 
                             



                                   
                              


                                       

 


















                                                                




                                

                                                   





                                                                         

 
   



                                                      


                                                  
                                                                                      
                                                                                                                            
                                                                                                
                                                                                                
                                                                                 
                         
                                   
                       


                                                            
                                 
                                    

 


                                                                  

                                        








                                                                                                                                      

 










                                                          
                                           

 




                                                                                           


                                                           
                                                

                                                                                          
                                                                                                
                                              
                        


                                                


         



                                 





                                                                     



                             





                                                                  



                               

                                                         
                                                 
                          
                


                                                                               







                                                           



                                   


                                                                       
                                                      


                        



                                      





                                                               



                               

                                                    


                                             
                                     
                                     
                       
         
 







                                                                                                                               
                               
                                                                                         


                        



                      
                                                           





                                                                   
                                                 

 



                                

                                                 
                                    
                       
                               
                                 

 



                             




                                             
                                 

 



                                                             
                                        
 
                              
                                    
                                  
                                                                   


                                                         
                                                                
                 
                                                                                             
                                      
                 



                                                          
                                                  
 

                                                        

                                                 
                                      
                                                         
                              
                                                 



                                                              
                                           




                                                                 
                                 
                                                           
                
                                                   
         

 
  


        



                                            
                                            
 
                            



                                    

                           
                           

 




                                   
                                                                         


                                  
                       
 
 
/*
# Copyright (c) 2009 - OpenSLX Project, Computer Center University of Freiburg
#
# This program is free software distributed under the GPL version 2.
# See http://openslx.org/COPYING
#
# If you have any feedback please consult http://openslx.org/feedback and
# send your suggestions, praise, or complaints to feedback@openslx.org
#
# General information about OpenSLX can be found at http://openslx.org/
# -----------------------------------------------------------------------------
# src/gui/connectionFrame.cpp
# -----------------------------------------------------------------------------
*/


#include "connectionframe.h"
#include "../mainwindow/mainwindow.h"
#include "../net/client.h"
#include <QImage>
#include <cassert>
#include <cmath>

static QString style_student(
    "QLabel{ background-color: #FFF; border-radius: 2px; color: black;} \
	QGroupBox { background-color: #AAA; margin: 2px; border-radius: 4px}"
);
static QString style_tutor(
    "QLabel{ background-color: #FFF; border-radius: 2px; color: black;} \
	QGroupBox { background-color: #70C670; margin: 2px; border-radius: 4px}"
);
static QString style_attention(
    "QLabel{ background-color: #FFF; border-radius: 2px; color: black;} \
	QGroupBox { background-color: #C88; margin: 2px; border-radius: 4px}"
);
static QString style_selectedStudent(
    "QLabel{ background-color: #FFF; border-radius: 2px; color: black; } \
		QGroupBox { background-color: #ccebff; margin: 0px; border-radius: 4px; border: 4px solid #6C8CF0;}"
);
static QString style_selectedTutor(
    "QLabel{ background-color: #FFF; border-radius: 2px; color: black;} \
		QGroupBox { background-color: #9f9; margin: 0px;  border-radius: 4px; border: 4px solid #6C8CF0;}"
);
static QString style_selectedAttention(
    "QLabel{ background-color: #FFF; border-radius: 2px; color: black;} \
		QGroupBox { background-color: #E99; margin: 0px;  border-radius: 4px; border: 4px solid #6C8CF0;}"
);
static QString style_exam (
    "QLabel{ background-color: #919191; color: black; } \
		QGroupBox { background-color: #d35400; margin: 1px; border-radius: 4px}"
);
static QString style_exam_selected (
    "QLabel{ background-color: #919191; color: black; } \
		QGroupBox { background-color: #cc743a; margin: 1px; border-radius: 4px}"
);
static QString style_disconnected(
    "QLabel{ background-color: #919191; border-radius: 2px; color: black; } \
		QGroupBox { background-color: #7F7F7F; margin: 1px; border-radius: 4px}"
);

static QIcon *term = NULL, *cam = NULL, *eye = NULL, *lock = NULL;

bool ConnectionFrame::paintDisabled = false;

/**
 * Initialize frame for connected client.
 * @param parent
 * @param width
 * @param height
 */
ConnectionFrame::ConnectionFrame(MainWindow* main, QWidget *parent, bool fromRoomplan) :
	QGroupBox(parent), _client(NULL), _timerId(0), _timerCounter(0), _isSelected(false), _isTutor(false),
	_isFromRoomplan(fromRoomplan), _mainWindow(main)
{

	//defines the ui-stuff
	// load icons first
	if (term == NULL) {
		term = new QIcon(":terminal");
		cam = new QIcon(":cf_cam");
		eye = new QIcon(":cf_eye");
		lock = new QIcon(":cf_lock");
	}

	_mainLayout = new QBoxLayout(QBoxLayout::TopToBottom, this);
	_mainLayout->setSpacing(1);
	_mainLayout->setMargin(3);
	_mainLayout->setAlignment(Qt::AlignHCenter);
	this->setStyleSheet(style_student);

	_iconLayout = new QBoxLayout(QBoxLayout::RightToLeft, NULL);
	_iconLayout->setSpacing(1);
	_iconLayout->setMargin(3);

	_lblUserName = new QLabel("Test", this);
	_lblUserName->setAlignment(Qt::AlignHCenter);

	_lblHostName = new QLabel("PC", this);
	_lblHostName->setAlignment(Qt::AlignHCenter);

	_lblExamMode = new QLabel(tr("EXAM-MODE"), this);
	_lblExamMode->setAlignment(Qt::AlignHCenter);
	_lblExamMode->setVisible(false);

	_icoCam = addIcon(cam);
	_icoEye = addIcon(eye);
	_icoLock = addIcon(lock);

	_iconLayout->addWidget(_icoCam);
	_iconLayout->addWidget(_icoEye);
	_iconLayout->addWidget(_icoLock);
	_iconLayout->addStretch();

	_mainLayout->addLayout(_iconLayout);
	_mainLayout->addStretch();
	_mainLayout->addWidget(_lblExamMode);
	_mainLayout->addStretch();
	_mainLayout->addWidget(_lblUserName);
	_mainLayout->addWidget(_lblHostName);
	this->setLayout(_mainLayout);
	this->updateAppearance();
	this->updateLabels();
}

ConnectionFrame::~ConnectionFrame()
{
	if (_client != NULL) {
		_client->deleteLater();
	}
	_iconLayout->deleteLater();
}

void ConnectionFrame::setGridPosition(const QPoint& pos)
{
	_gridPosition = pos;
	updateGeometry();
}

void ConnectionFrame::setGridPosition(int x, int y)
{
	setGridPosition(QPoint(x, y));
}

void ConnectionFrame::updateGeometry()
{
	const QRect rect = _mainWindow->calcFrameGeometry(this);
	setGeometry(rect);
	if (this->_client == NULL)
		showDefaultThumb();
}

/**
 * Add icon to connection frame.
 * @param icon
 * @return Pointer to new Icon.
 */
QLabel* ConnectionFrame::addIcon(const QIcon* icon)
{
	QLabel *label = new QLabel(this);
	label->setPixmap(icon->pixmap(24, 24, QIcon::Normal, QIcon::On));
	label->setAttribute(Qt::WA_TranslucentBackground);
	label->hide();
	_icons.append(label);
	return label;
}

/**
 * Assign client to connectionFrame.
 * Set hostName, userName and tutor status to display.
 * @param client
 */
void ConnectionFrame::assignClient(Client* client)
{
	assert(_client == NULL);
	connect( client, SIGNAL(disconnected()), this, SLOT(onClientDisconnected()) );
	connect( client, SIGNAL(thumbUpdated(Client*, const QImage&)), this, SLOT(onThumbUpdated(Client*, const QImage&)) );
	connect( client, SIGNAL(vncServerStateChange(Client*)), this, SLOT(updateAppearance()));
	connect( client, SIGNAL(vncClientStateChange(Client*)), this, SLOT(updateAppearance()));
	connect( client, SIGNAL(stateChanged()), this, SLOT(updateAppearance()));
	_client = client;
	_computerId = client->ip();
	updateLabels();
	showDefaultThumb();
	if (_timerId == 0)
		_timerId = startTimer(1000 + qrand() % 150);
	this->updateAppearance();
	_client->setTutor(_isTutor);
}

/**
 * Show default thumg instead of remote screen in connectionFrame.
 */
void ConnectionFrame::showDefaultThumb()
{
	_remoteScreen = term->pixmap(_desiredThumbSize, QIcon::Normal, QIcon::On).toImage();
	this->update();
}

void ConnectionFrame::calcDesiredThumbSize(const QSize &frameSize)
{
	const int width = frameSize.width() - 10;
	const int height = frameSize.height() - 12 - _lblHostName->height() - (_lblUserName->isHidden() ? 0 : _lblUserName->height());
	_desiredThumbSize = QSize(width, height);
}

void ConnectionFrame::updateLabels()
{
	_lblHostName->setText(_computerId);
	if (_client == NULL) {
		_lblUserName->setText(QString());
		_lblUserName->hide();
	} else {
		_lblHostName->setToolTip(_client->host());
		_lblUserName->setText(_client->name());
		_lblUserName->show();
	}
	calcDesiredThumbSize(this->size());
}

/**
 * Handle mouse release event on frame.
 * Check if frame was clicked or moved, if not moved enough, the event is handled as click.
 * @param event
 */
void ConnectionFrame::mouseReleaseEvent(QMouseEvent* event)
{
	event->accept();
	if (event->button() == Qt::LeftButton) {
		QApplication::setOverrideCursor(QCursor(Qt::OpenHandCursor));
		// Only recognize a move if the distance is larger than _startDragDistance
		if ((this->pos() - _previousPosition).manhattanLength() > _startDragDistance ) {
			emit frameMoved(this);
		} else {
			move(_previousPosition);
			emit clicked(this);
		}
	}
}

/**
 * Handle if mouse reaches frame.
 * @param event
 */
void ConnectionFrame::enterEvent(QEvent* event)
{
	QApplication::setOverrideCursor(QCursor(Qt::OpenHandCursor));
	event->accept();
}

/**
 * Handle mouse leaves frame.
 * @param event
 */
void ConnectionFrame::leaveEvent(QEvent* event)
{
	QApplication::setOverrideCursor(QCursor(Qt::ArrowCursor));
	event->accept();
}

/**
 * Handle mouse press on frame.
 * @param event
 */
void ConnectionFrame::mousePressEvent(QMouseEvent *event)
{
	if (event->button() == Qt::RightButton) {
		// Menu...
	} else {
		_clickPoint = event->pos();
		_previousPosition  = this->pos();
		QApplication::setOverrideCursor(QCursor(Qt::ClosedHandCursor));
	}
	// On click, the window has to be on the top-level.
	activateWindow();
	raise();
	update();
	event->accept();
}

/**
 * Hanle mouse movement over frame.
 * @param event
 */
void ConnectionFrame::mouseMoveEvent(QMouseEvent *event)
{
	QApplication::setOverrideCursor(QCursor(Qt::ClosedHandCursor));
	move(mapToParent(event->pos() - _clickPoint));
	event->accept();
}

/**
 * Handle double click event on frame.
 * @param event
 */
void ConnectionFrame::mouseDoubleClickEvent(QMouseEvent* event)
{
	emit doubleClicked(this);
	event->accept();
}

/**
 * Draw remote screen in frame.
 * @param event
 */
void ConnectionFrame::paintEvent(QPaintEvent *event)
{
	if (ConnectionFrame::paintDisabled) {
		return;
	}
	QGroupBox::paintEvent(event);
	if (_remoteScreen.isNull()) {
		return;
	}

	if (!_desiredThumbSize.isEmpty()) {
		if (abs(100 - ((_remoteScreen.width() * 100) / _desiredThumbSize.width())) > 5
				&& abs(100 - ((_remoteScreen.height() * 100) / _desiredThumbSize.height())) > 5) {
			qDebug() << "Rescale thumb" << _remoteScreen.size() << "to" << _desiredThumbSize;
			_remoteScreen = _remoteScreen.scaled(_desiredThumbSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
		}
	}

	QPainter painter(this);
	painter.drawImage((this->width() - _remoteScreen.width()) / 2, 4, _remoteScreen);
	event->accept();
}

/**
 * Handle timer event.
 * @param event
 */
void ConnectionFrame::timerEvent(QTimerEvent* /* event */ )
{
	if (_client == NULL)
		return;
	++_timerCounter;
	if (_client->isActiveVncServer() && _timerCounter % 5 != 0)
		return;
	_client->requestThumb(_desiredThumbSize);
}

/**
 * Set frame as selected or not.
 * @param selected
 */
void ConnectionFrame::setSelection(bool selected)
{
	if (_isSelected == selected)
		return;
	_isSelected = selected;
	this->updateAppearance();
}

/**
 * Set tutor status of frame.
 * @param b
 */
void ConnectionFrame::setTutor(bool b)
{
	if (_isTutor != b && _client != NULL)
		_client->setTutor(b);
	_isTutor = b;
	this->updateAppearance();
}

/**
 * Update appearence of frame.
 * Check tutor status, vnc status and set background or icon.
 */
void ConnectionFrame::updateAppearance()
{
	if (_client == NULL) {
		// Unconnected Frame
		if (_isSelected) {
			this->setStyleSheet(style_selectedStudent);
		} else if (_isTutor) {
			this->setStyleSheet(style_tutor);
		} else {
			this->setStyleSheet(style_disconnected);
		}
		for (QList<QLabel*>::iterator it(_icons.begin()); it != _icons.end(); ++it) {
			(**it).hide();
		}
		return;
	}
	_icoCam->setVisible(_client->isActiveVncServer());
	_icoEye->setVisible(_client->isActiveVncClient());
	_icoLock->setVisible(_client->isLocked());


	_lblExamMode->setVisible(_client->isExamMode());
	// Normal client, no special stuff active

	if (_isSelected && _isTutor) {
		this->setStyleSheet(style_selectedTutor);
	} else if (_isTutor) {
		this->setStyleSheet(style_tutor);
	} else if (_isSelected && _client->wantsAttention()) {
		this->setStyleSheet(style_selectedAttention);
	} else if (_client->wantsAttention()) {
		this->setStyleSheet(style_attention);
	} else if (_client->isExamMode()) {
		if (_isSelected) {
			this->setStyleSheet(style_exam_selected);
		} else {
			this->setStyleSheet(style_exam);
		}
	} else if (_isSelected) {
		this->setStyleSheet(style_selectedStudent);
	} else {
		this->setStyleSheet(style_student);
	}
}

/*
 * Slots
 */

/**
 * Handle if client was disconnected.
 * Kill timer and set appearence to default.
 */
void ConnectionFrame::onClientDisconnected()
{
	if (_timerId != 0) {
		killTimer(_timerId);
		_timerId = 0;
	}
	_client = NULL;
	updateLabels();
	updateAppearance();
	showDefaultThumb();
}

/**
 * Update thumb of specific client.
 * @param client
 * @param thumb
 */
void ConnectionFrame::onThumbUpdated(Client* client, const QImage& thumb)
{
	assert(client == _client);
	_remoteScreen = thumb;
	this->update();
}