summaryrefslogblamecommitdiffstats
path: root/src/pvsgui.cpp
blob: 7e256829047a708d7f5356630425b14f24cae762 (plain) (tree)


















                                                                                
                   
                   
                    





                                 



                                                                   











                                               



                                                                   


                                                         
                                                                                



                                                                                    
 

                                                                   
                                                         
                             




                                                                                          

                                                                
                             








                                                                            



                                     



                                                                  



                        





                                                                               
                                                                              













                                                                                 








                                                                                
                                                                                                                                                                               

                   
                                                                                                        
                                            












                                                                                
                                         
        
                                                                 
 
 






                                         

































                                                                  











































                                                                                

                                                         








                                                             
                                  

                                                          




                                       
                                                      

                                   
                                                    




                                   



                         
                                            





                                                             
                                            





                                                                    






































                                                                          
                                                                  
 


























                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      










                                                                   





                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       


















































                                                                             












                                                                     





                                                                                                                   




                                                                                





                                                                    



                                                                                             













                                                               

                                

                         
 








                                                     
                                             























                                                                                 
 


















                                                           
                  


                                 


                      
/*
 # 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 <getopt.h>
#include "pvsgui.h"
#include "version.h"

PVSGUI::PVSGUI(QWidget *parent) :
    QWidget(parent)
{
    setupUi(this);

    // stop running pvs
    qDebug("[%s] Stopping pvs daemon.", metaObject()->className());
    QProcess::execute("pvs -c stop");

    _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);

    _trayIcon = new QSystemTrayIcon(QIcon(":cam_off32.svg"), this);
    _trayIcon->setContextMenu(_menu);
    _trayIcon->setVisible(true);
    _chatDialog->setTrayIcon(_trayIcon);

    // connect to D-Bus and get interface
    QDBusConnection dbus = QDBusConnection::sessionBus();
    _ifaceDBus = new OrgOpenslxPvsInterface("org.openslx.pvs", "/", dbus, this);
    if (dbus.isConnected())
        qDebug("[%s] Connection to DBus successful.", metaObject()->className());
    else
        qDebug("[%s] ERROR: Could not connect to DBus!", metaObject()->className());

    // start pvs daemon
    qDebug("[%s] Starting pvs daemon.", metaObject()->className());
    QDBusPendingReply<bool> reply0 = _ifaceDBus->start();
    reply0.waitForFinished();
    if (reply0.isValid() && reply0.value())
        qDebug("[%s] Connection to PVS daemon successful.", metaObject()->className());
    else
        qDebug("[%s] ERROR: Could not connect to PVS daemon!", metaObject()->className());

    // ask if restricted mode is on
    QDBusPendingReply<bool> reply1 = _ifaceDBus->isRestricted();
    reply1.waitForFinished();
    _restricted = reply1.value();

    setupMenu();

    // get available hosts
    QDBusPendingReply<QStringList> reply2 = _ifaceDBus->getAvailableHosts();
    reply2.waitForFinished();
    QStringList hosts = reply2.value();
    if (reply2.isValid() && !hosts.isEmpty())
        foreach (QString host, hosts)
                addHost(host);

    // already connected?
    QDBusPendingReply<QString> reply3 = _ifaceDBus->isConnected();
    reply3.waitForFinished();
    QString host = reply3.value();
    if (reply3.isValid() && host != "")
        connected(host);
    else
        disconnected();

    // 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(_showAction, SIGNAL(toggled(bool)), this, SLOT(setVisible(bool)));
    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*)));

    // 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 | Qt::FramelessWindowHint);
    setAttribute(Qt::WA_AlwaysShowToolTips);
}

PVSGUI::~PVSGUI()
{
    _ifaceDBus->quit();
}

////////////////////////////////////////////////////////////////////////////////
// Public

void PVSGUI::updateConfig()
{
    if (_settings.value("Display/location").isNull())
        setPosition(POSITION_TOP_CENTER);
    else
        setPosition(_settings.value("Display/location").toInt());
}


void PVSGUI::setVisible(bool visible)
{
    QWidget::setVisible(visible);
    _showAction->setChecked(isVisible());
}

void PVSGUI::setPosition(int position)
{
    _position = position;
    switch (_position)
    {
    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:
        updateConfig();
    }
}

void PVSGUI::hide()
{
    if (!_menu->isVisible() && !_hostMenu->isVisible())
        hide(true);
}

////////////////////////////////////////////////////////////////////////////////
// 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
    _showAction = new QAction(tr("Show &toolbar"), this);
    _showAction->setCheckable(true);
    _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->addAction(_showAction);
    if (!_restricted) _menu->addMenu(_hostMenu);
    if (!_restricted) _menu->addAction(_disconnectAction);
    _menu->addAction(_showInfoAction);
    _menu->addSeparator();
    _menu->addAction(_startChatAction);
    _menu->addAction(_sendFileAction);
    _menu->addSeparator();
    if (!_restricted) _menu->addAction(_configAction);
    _menu->addAction(_aboutAction);
    _menu->addSeparator();
    if (!_restricted) _menu->addAction(_quitAction);

    pvsButton->setMenu(_menu);
    hostButton->setMenu(_hostMenu);
}

void PVSGUI::hide(bool b)
{
    if (b)
    {
        if (_position <= POSITION_TOP_RIGHT)
            move(x(), 2 - height());
        else
            move(x(), QApplication::desktop()->height() - 2);
    }
    else
    {
        if (_position <= POSITION_TOP_RIGHT)
            move(x(), 0);
        else
            move(x(), QApplication::desktop()->height() - height());
    }
}

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 (!_settings.value("Display/showmsgs").toBool()) 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);
    }

    // try to disable screensaver
    if (QProcess::execute("xscreensaver-command -exit") == 0)
    	qDebug("xscreensaver disabled");
    else
    	qDebug("xscreensaver NOT disabled");

    if (QProcess::execute("gnome-screensaver-command --exit") == 0)
    	qDebug("gnome-screensaver disabled");
    else
    	qDebug("gnome-screensaver NOT disabled");
}

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

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

void printHelp()
{
    QTextStream qout(stdout);
    qout << QObject::tr("Usage: pvsgui [OPTIONS]...") << endl;
    qout << QObject::tr("Start the Pool Video Switch GUI.") << endl;
    qout << QObject::tr("Options:") << endl << endl;
    qout << "-b or --toolbar" << "\t\t" << QObject::tr("Start with toolbar.") << endl;
    qout << "-p or --position" << "\t" << QObject::tr("Set toolbar position (0-5)") << endl;
    qout << "-h or --help" << "\t\t" << QObject::tr("Show this help text and quit.") << endl;
    qout << "-v or --version" << "\t\t" << QObject::tr("Show version and quit.") << endl;
    qout << endl;
    qout.flush();
    exit(0);
}

void printVersion()
{
    QTextStream qout(stdout);
    qout << QObject::tr("Version: ") << VERSION_STRING << endl;
    qout << endl;
    qout.flush();
    exit(0);
}

int main(int argc, char *argv[])
{
    bool visible = false;
    int position = -1;

    // parse command line arguments
    int opt = 0;
    int longIndex = 0;
    static const char *optString = "hvp:b?";
    static const struct option longOpts[] =
    {
    	{ "help", no_argument, NULL, 'h' },
    	{ "version", no_argument, NULL, 'v' },
    	{ "position", required_argument, NULL, 'p' },
    	{ "toolbar", no_argument, NULL, 'b' }
    };

	opt = getopt_long( argc, argv, optString, longOpts, &longIndex );
	while( opt != -1 )
	{
		switch( opt )
		{
		case 'h':
			printHelp();
			break;
		case 'v':
			printVersion();
			break;
		case 'p':
			position = atoi(optarg);
			break;
		case 'b':
			visible = true;
			break;
        case '?':
        	exit(1);
		}
		opt = getopt_long( argc, argv, optString, longOpts, &longIndex );
	}


    QtSingleApplication app(argc, argv);
    app.setQuitOnLastWindowClosed(false);
    app.setOrganizationName("openslx");
    app.setOrganizationDomain("openslx.org");
    app.setApplicationName("pvsgui");

    // only one instance should be allowed
    if (app.sendMessage(""))
    {
        qDebug("[PVSGUI] ERROR: Already running. Exiting");
        return 0;
    }

    // use system locale as language to translate gui
    QTranslator translator;
    translator.load(":pvsgui");
    app.installTranslator(&translator);

    PVSGUI pvsgui;
    pvsgui.setPosition(position);
    pvsgui.setVisible(visible);
    pvsgui.hide();

    return app.exec();
}