/* # 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 (); _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 reply0 = _ifaceDBus->getAvailableHosts(); reply0.waitForFinished(); QStringList hosts = reply0.value(); if (reply0.isValid() && !hosts.isEmpty()) foreach (QString host, hosts) addHost(host); // already connected? QDBusPendingReply 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()); if (!_settings.value("Multicast/interface").isNull()) _ifaceDBus->setMulticastInterface(_settings.value("Multicast/interface").toString()); } //////////////////////////////////////////////////////////////////////////////// // 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( "

Online

"); 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( "

Offline

"); 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(); }