/*
# Copyright (c) 2009, 2010 - 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/
# -----------------------------------------------------------------------------
# pvsClientGUI.cpp
# - main loop for pvs client GUI.
# - draws toolbar and system tray icon.
# - uses DBUS to communicate with pvs client.
# -----------------------------------------------------------------------------
*/
#include "pvsgui.h"
PVSGUI::PVSGUI(QWidget *parent) :
QWidget(parent)
{
setupUi(this);
_menu = new QMenu(this);
_hostMenu = new QMenu(tr("Connect"), this);
_hosts = new QHash<QString, QAction*> ();
_vncViewer = new ClientVNCViewer();
_chatDialog = new ClientChatDialog();
_configDialog = new ClientConfigDialog();
_infoDialog = new ClientInfoDialog();
_aboutDialog = new AboutDialog();
_hostMenu->setEnabled(false);
hostButton->setEnabled(false);
setupMenu();
if (QSystemTrayIcon::isSystemTrayAvailable())
{
qDebug("[%s] System tray available.", metaObject()->className());
_trayIcon = new QSystemTrayIcon(QIcon(":cam_off32.svg"), this);
_trayIcon->setContextMenu(_menu);
_trayIcon->setVisible(true);
_chatDialog->setTrayIcon(_trayIcon);
}
else
_trayIcon = NULL;
// connect to D-Bus and get interface
QDBusConnection dbus = QDBusConnection::sessionBus();
dbus.registerObject("/", this);
dbus.registerService("org.openslx.pvsgui");
_ifaceDBus = new OrgOpenslxPvsInterface("org.openslx.pvs", "/", dbus, this);
_ifaceDBus->start(); // start pvs if not running
// get available hosts
QDBusPendingReply<QStringList> reply0 = _ifaceDBus->getAvailableHosts();
reply0.waitForFinished();
QStringList hosts = reply0.value();
if (reply0.isValid() && !hosts.isEmpty())
foreach (QString host, hosts)
addHost(host);
// already connected?
QDBusPendingReply<QString> reply1 = _ifaceDBus->isConnected();
reply1.waitForFinished();
QString host = reply1.value();
if (reply1.isValid() && host != "")
connected(host);
else
disconnected();
if (dbus.isConnected())
qDebug("[%s] Connection to DBus successful!", metaObject()->className());
// TODO: perhaps this can go if fadi does his work
// check if vnc is allowed and setup checkbox
QFile file(QDir::toNativeSeparators(QDir::homePath() + "/.pvs/.allow"));
if (file.open(QIODevice::ReadOnly | QIODevice::Text))
{
QTextStream in(&file);
QString line = in.readLine();
if (line == "1")
vncCheckBox->setChecked(true);
file.close();
}
// listen on port 29481 for incoming file transfers
_serverSocket = new QTcpServer();
_serverSocket->listen(QHostAddress::Any, 29481);
connect(_serverSocket, SIGNAL(newConnection()), this, SLOT(receiveFile()));
// signals & slots - menu
connect(_disconnectAction, SIGNAL(triggered()), this, SLOT(pvsDisconnect()));
connect(_startChatAction, SIGNAL(triggered()), _chatDialog, SLOT(open()));
connect(_sendFileAction, SIGNAL(triggered()), this, SLOT(sendFile()));
connect(_configAction, SIGNAL(triggered()), _configDialog, SLOT(open()));
connect(_showInfoAction, SIGNAL(triggered()), _infoDialog, SLOT(open()));
connect(_aboutAction, SIGNAL(triggered()), _aboutDialog, SLOT(open()));
connect(_quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
connect(_configDialog, SIGNAL(configChanged()), this, SLOT(updateConfig()));
// signals & slots - toolbar
connect(_menu, SIGNAL(aboutToHide()), this, SLOT(hide()));
connect(_hostMenu, SIGNAL(aboutToHide()), this, SLOT(hide()));
connect(_hostMenu, SIGNAL(triggered(QAction*)), this,
SLOT(pvsConnect(QAction*)));
connect(vncCheckBox, SIGNAL(stateChanged(int)), this,
SLOT(setVncAllow(int)));
// signals & slots - dbus
connect(_ifaceDBus, SIGNAL(showMessage(QString, QString, bool)), this,
SLOT(showMessage(QString, QString, bool)));
connect(_ifaceDBus, SIGNAL(connected(QString)), this,
SLOT(connected(QString)));
connect(_ifaceDBus, SIGNAL(disconnected()), this, SLOT(disconnected()));
connect(_ifaceDBus, SIGNAL(addHost(QString)), this, SLOT(addHost(QString)));
connect(_ifaceDBus, SIGNAL(delHost(QString)), this, SLOT(delHost(QString)));
connect(_ifaceDBus, SIGNAL(incomingMulticastTransferNew(qulonglong, QString, QString, qulonglong)), SLOT(incomingMulticastFile(qulonglong, QString, QString, qulonglong)));
// show toolbar
setWindowFlags(Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint);
setAttribute(Qt::WA_AlwaysShowToolTips);
updateConfig();
setVisible(true);
hide();
}
PVSGUI::~PVSGUI()
{
_ifaceDBus->quit();
}
////////////////////////////////////////////////////////////////////////////////
// Public
void PVSGUI::updateConfig()
{
if (_settings.value("Display/location").isNull())
setLocation(POSITION_TOP_CENTER);
else
setLocation(_settings.value("Display/location").toInt());
}
////////////////////////////////////////////////////////////////////////////////
// Protected
void PVSGUI::leaveEvent(QEvent * e)
{
if (!_menu->isVisible() && !_hostMenu->isVisible())
hide(true);
QWidget::leaveEvent(e);
}
void PVSGUI::enterEvent(QEvent * e)
{
hide(false);
QWidget::enterEvent(e);
}
void PVSGUI::mousePressEvent(QMouseEvent *event)
{
QApplication::setOverrideCursor(QCursor(Qt::ClosedHandCursor));
_clickPoint = event->pos();
}
void PVSGUI::mouseReleaseEvent(QMouseEvent *event)
{
QApplication::setOverrideCursor(QCursor(Qt::ArrowCursor));
}
void PVSGUI::mouseMoveEvent(QMouseEvent *event)
{
if (event->globalX() - _clickPoint.x() >= 0 && event->globalX()
- _clickPoint.x() + width() <= QApplication::desktop()->width())
{
move(event->globalX() - _clickPoint.x(), y());
}
}
////////////////////////////////////////////////////////////////////////////////
// Private
void PVSGUI::setupMenu()
{
// setup actions
_disconnectAction = new QAction(tr("&Disconnect"), this);
_startChatAction = new QAction(tr("C&hat"), this);
_sendFileAction = new QAction(tr("&Send File"), this);
_configAction = new QAction(tr("&Config"), this);
_showInfoAction = new QAction(tr("&Information"), this);
_aboutAction = new QAction(tr("&About"), this);
_quitAction = new QAction(tr("&Quit"), this);
// setup menu
_menu->addMenu(_hostMenu);
_menu->addAction(_disconnectAction);
_menu->addAction(_showInfoAction);
_menu->addSeparator();
_menu->addAction(_startChatAction);
_menu->addAction(_sendFileAction);
_menu->addSeparator();
_menu->addAction(_configAction);
_menu->addAction(_aboutAction);
_menu->addSeparator();
_menu->addAction(_quitAction);
pvsButton->setMenu(_menu);
hostButton->setMenu(_hostMenu);
}
void PVSGUI::setLocation(int location)
{
_location = location;
switch (_location)
{
case POSITION_TOP_LEFT:
move(0, 0);
break;
case POSITION_TOP_CENTER:
move((QApplication::desktop()->width() - width()) / 2, 0);
break;
case POSITION_TOP_RIGHT:
move(QApplication::desktop()->width() - width(), 0);
break;
case POSITION_BOTTOM_LEFT:
move(0, QApplication::desktop()->height() - height());
break;
case POSITION_BOTTOM_CENTER:
move((QApplication::desktop()->width() - width()) / 2,
QApplication::desktop()->height() - height());
break;
case POSITION_BOTTOM_RIGHT:
move(QApplication::desktop()->width() - width(),
QApplication::desktop()->height() - height());
break;
default:
break;
}
}
void PVSGUI::hide(bool b)
{
if (b)
{
if (_location <= POSITION_TOP_RIGHT)
move(x(), 2 - height());
else
move(x(), QApplication::desktop()->height() - 2);
}
else
{
if (_location <= POSITION_TOP_RIGHT)
move(x(), 0);
else
move(x(), QApplication::desktop()->height() - height());
}
}
void PVSGUI::hide()
{
if (!_menu->isVisible() && !_hostMenu->isVisible())
hide(true);
}
void PVSGUI::pvsConnect(QAction *action)
{
QString host = action->text();
action->setChecked(false); // we set it manually
// already connected?
if (host == hostButton->text())
{
action->setChecked(true);
return;
}
// ask user for passwd
bool ok = false;
QString passwd = QInputDialog::getText(0, tr("PVS Connection"), tr(
"Please enter password (If not needed leave blank):"),
QLineEdit::Password, QString(), &ok);
if (ok)
{
_ifaceDBus->pvsConnect(host, passwd); // send via dbus
_passwd = passwd; // TODO: we have to ask the backend for passwd!
qDebug("[%s] Host '%s' send via DBus.", metaObject()->className(),
qPrintable(host));
}
}
void PVSGUI::pvsDisconnect()
{
QMessageBox::StandardButton result = QMessageBox::question(0, tr(
"PVS Connection"), tr("Are you sure you want to disconnect?"),
QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok);
if (result == QMessageBox::Ok)
_ifaceDBus->pvsDisconnect();
}
void PVSGUI::showMessage(QString title, QString msg, bool useDialog)
{
if (!isVisible())
return;
// show balloon message if supported, otherwise show message dialog
if (!useDialog && _trayIcon && QSystemTrayIcon::supportsMessages())
_trayIcon->showMessage(title, msg, QSystemTrayIcon::Information, 10000);
else
QMessageBox::about(0, title, msg);
}
void PVSGUI::connected(QString host)
{
statusLabel->setText(
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\"><html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">p, li { white-space: pre-wrap; }</style></head><body style=\" font-family:'DejaVu Sans'; font-size:9pt; font-weight:400; font-style:normal;\"><p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" color:#00aa00;\">Online</span></p></body></html>");
showMessage(tr("PVS connection"), tr("Connected to ") + host);
if (_hosts->contains(host))
_hosts->value(host)->setChecked(true);
hostButton->setText(host);
_disconnectAction->setEnabled(true);
_startChatAction->setEnabled(true);
_sendFileAction->setEnabled(true);
_showInfoAction->setEnabled(true);
_infoDialog->setHost(host);
_infoDialog->setPasswd(_passwd);
if (_trayIcon)
{
_trayIcon->setIcon(QIcon(":cam_on32.svg"));
_trayIcon->setToolTip(tr("Connected to ") + host);
}
}
void PVSGUI::disconnected()
{
statusLabel->setText(
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\"><html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">p, li { white-space: pre-wrap; }</style></head><body style=\" font-family:'DejaVu Sans'; font-size:9pt; font-weight:400; font-style:normal;\"><p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" color:#ff0000;\">Offline</span></p></body></html>");
showMessage(tr("PVS connection"), tr("Disconnected"));
if (_hosts->contains(hostButton->text()))
_hosts->value(hostButton->text())->setChecked(false);
hostButton->setText("-");
_disconnectAction->setEnabled(false);
_startChatAction->setEnabled(false);
_sendFileAction->setEnabled(false);
_showInfoAction->setEnabled(false);
_passwd = "";
if (_trayIcon)
{
_trayIcon->setIcon(QIcon(":cam_off32.svg"));
_trayIcon->setToolTip(tr("Disconnected"));
}
_vncViewer->close();
}
void PVSGUI::addHost(QString host)
{
// avoid duplicates
if (_hosts->contains(host))
return;
QAction *action = _hostMenu->addAction(host);
action->setCheckable(true);
_hosts->insert(host, action);
if (!_hosts->isEmpty())
{
_hostMenu->setEnabled(true);
hostButton->setEnabled(true);
}
if (hostButton->text() == "-")
showMessage(tr("PVS Connection"), tr("New host available: ") + host);
}
void PVSGUI::delHost(QString host)
{
if (_hosts->contains(host))
{
_hostMenu->removeAction(_hosts->value(host));
_hosts->remove(host);
}
if (_hosts->isEmpty())
{
_hostMenu->setEnabled(false);
hostButton->setEnabled(false);
}
}
// TODO: perhaps this can go if fadi does his work
void PVSGUI::setVncAllow(int i)
{
QFile file(QDir::toNativeSeparators(QDir::homePath() + "/.pvs/.allow"));
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
return;
QTextStream out(&file);
if (i == 0)
out << 0;
else
out << 1;
file.close();
}
void PVSGUI::sendFile()
{
ClientFileSendDialog *d = new ClientFileSendDialog();
d->open();
}
void PVSGUI::receiveFile()
{
QTcpSocket *socket = _serverSocket->nextPendingConnection();
ClientFileReceiveDialog *d = new ClientFileReceiveDialog(socket);
d->open();
}
void PVSGUI::incomingMulticastFile(qulonglong transferID, QString sender, QString basename, qulonglong size)
{
ClientFileReceiveDialog *d = new ClientFileReceiveDialog(sender, transferID, basename, size, _ifaceDBus, this);
d->open();
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// Main
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
app.setOrganizationName("openslx");
app.setOrganizationDomain("openslx.org");
app.setApplicationName("pvsgui");
// use system locale as language to translate gui
QTranslator translator;
translator.load(":pvsgui");
app.installTranslator(&translator);
PVSGUI pvsgui;
return app.exec();
}