<commit_before>/* This file is part of Strigi Desktop Search
 *
 * Copyright (C) 2006 Jos van den Oever <jos@vandenoever.info>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */
#include "dlgfilters.h"
#include "dlglistindexedfiles.h"
#include "simplesearchgui.h"
#include "searchtabs.h"
#include "histogram.h"
#include "searchview.h"
#include <QtGui/QListWidget>
#include <QtGui/QListWidgetItem>
#include <QtGui/QLineEdit>
#include <QtGui/QVBoxLayout>
#include <QtGui/QStackedWidget>
#include <QtGui/QLabel>
#include <QtGui/QDockWidget>
#include <QtGui/QPushButton>
#include <QtGui/QFileDialog>
#include <QtGui/QComboBox>
#include <QtGui/QMenu>
#include <QtGui/QMenuBar>
#include <QtGui/QAction>
#include <QtCore/QString>
#include <QtCore/QDebug>
#include <QtCore/QCoreApplication>
#include <QtCore/QProcess>
#include <QtCore/QTimer>
#include <string>
#include <map>
#include <vector>
using namespace std;

SimpleSearchGui::SimpleSearchGui (QWidget * parent, Qt::WFlags flags)
    : QMainWindow (parent, flags)
{
    mainview = new QStackedWidget();

    QWidget* statuswidget = new QWidget();
    QVBoxLayout *statuslayout = new QVBoxLayout;
    statuslayout->setMargin(0);
    statusview = new QLabel();
    statusview->setAlignment(Qt::AlignTop);
    statusview->setMargin(25);
    indexing = false;
    running = false;
    starting = true;
    indexeddirs = new QListWidget();
    indexeddirs->setSelectionMode(QAbstractItemView::ExtendedSelection);
    adddir = new QPushButton("add directory");
    removedir = new QPushButton("remove directory");
    toggleindexing = new QPushButton("start indexing");
    toggledaemon = new QPushButton("stop daemon");
    statuslayout->addWidget(statusview);
    QHBoxLayout *hlayout = new QHBoxLayout;
    hlayout->addWidget(toggledaemon);
    hlayout->addWidget(toggleindexing);
    statuslayout->addLayout(hlayout);

    histogram = new Histogram();
    histogram->setOrientation(Qt::Vertical);
    fieldnames = new QComboBox();
    fieldnames->addItems(strigi.getFieldNames());
    fieldnames->setCurrentIndex(fieldnames->findText("system.last_modified_time"));
    histogram->setFieldName("mtime");
/*    vector<string> backends = ClientInterface::getBackEnds();
    if (backends.size() > 1) {
        backendsList = new QComboBox();
        for (uint i = 0; i< backends.size(); ++i) {
            QString backend = backends[i].c_str();
            backendsList->insertItem(i, backend);
        }
        statuslayout->addWidget(backendsList);
    } else {*/
        backendsList = 0;
//    }
    statuslayout->addWidget(indexeddirs);
    hlayout = new QHBoxLayout;
    hlayout->addWidget(adddir);
    hlayout->addWidget(removedir);
    statuslayout->addLayout(hlayout);
    statuswidget->setLayout(statuslayout);

    tabs = new SearchTabs();
    tabs->addTab("kde", "kde");
    tabs->addTab("msg", "mimetype:message/*");
    tabs->addTab("irc", "path:*konversation*log");
    tabs->addTab("mail", "mimetype:text/x-mail");
    tabs->addTab("audio", "mimetype:audio/*");
    tabs->addTab("other",
        "-kde -mimetype:message/* -mimetype:text/x-mail -mimetype:audio/*");
    tabs->addTab("all", "");
    mainview->addWidget(tabs);
    mainview->addWidget(statuswidget);
    asyncstrigi.updateStatus();
    mainview->setCurrentIndex(1);

    queryfield = new QLineEdit();
    QVBoxLayout *layout = new QVBoxLayout;
    layout->addWidget(mainview);
    layout->addWidget(queryfield);

    QVBoxLayout* histlayout = new QVBoxLayout();
    QDockWidget* histwidget = new QDockWidget();
    histwidget->setFeatures(QDockWidget::NoDockWidgetFeatures);
    QWidget* histw = new QWidget();
    histw->setLayout(histlayout);
    histwidget->setWidget(histw);
    histlayout->addWidget(fieldnames);
    histlayout->addWidget(histogram);
    addDockWidget(Qt::LeftDockWidgetArea, histwidget);

    centralview = new QWidget();
    centralview->setLayout(layout);
    setCentralWidget(centralview);

    createActions();
    createMenus();

    connect(queryfield, SIGNAL(textChanged(const QString&)),
        this, SLOT(query(const QString&)));
    connect(toggleindexing, SIGNAL(clicked()),
        this, SLOT(toggleIndexing()));
    connect(toggledaemon, SIGNAL(clicked()),
        this, SLOT(toggleDaemon()));
    connect(adddir, SIGNAL(clicked()),
        this, SLOT(addDirectory()));
    connect(removedir, SIGNAL(clicked()),
        this, SLOT(removeDirectory()));
    queryfield->setFocus(Qt::ActiveWindowFocusReason);

    connect(&asyncstrigi,SIGNAL(statusUpdated(const QMap<QString, QString>& )),
        this, SLOT(updateStatus(const QMap<QString, QString>& )));
    connect(tabs->getSearchView(), SIGNAL(gotHits(const QString&)),
        histogram, SLOT(setQuery(const QString&)));
    connect(fieldnames, SIGNAL(currentIndexChanged(const QString&)),
        histogram, SLOT(setFieldName(const QString&)));

    QTimer *timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(updateStatus()));
    timer->start(2000);
    asyncstrigi.updateStatus();
}
void
SimpleSearchGui::createMenus() {
    fileMenu = menuBar()->addMenu(tr("&File"));
    fileMenu->addAction(fileExitAct);

    editMenu = menuBar()->addMenu(tr("&Edit"));
    editMenu->addAction(editFiltersAct);
    editMenu->addAction(editListIndexedFilesAct);
}
void
SimpleSearchGui::createActions() {
    fileExitAct = new QAction(tr("&Exit"), this);
    fileExitAct->setShortcut(tr("Ctrl+Q"));
    fileExitAct->setStatusTip(tr("Quit the program"));
    connect(fileExitAct, SIGNAL(triggered()), this, SLOT(close()));

    editFiltersAct = new QAction(tr("Edit Filters"), this);
    editFiltersAct->setStatusTip(tr("Edit filename filters"));
    connect(editFiltersAct, SIGNAL(triggered()), this, SLOT(editFilters()));

    editListIndexedFilesAct = new QAction(tr("List indexed files"), this);
    editListIndexedFilesAct->setStatusTip(tr("Show files indexed by strigi"));
    connect(editListIndexedFilesAct, SIGNAL(triggered()), this, SLOT(editListIndexedFiles()));
}
void
SimpleSearchGui::query(const QString& item) {
    QString query = item.trimmed();
    if (query.length() == 0) {
        tabs->setQuery(QString());
        asyncstrigi.updateStatus();
        mainview->setCurrentIndex(1);
    } else {
        mainview->setCurrentIndex(0);
        tabs->setQuery(query);
    }
}
void
SimpleSearchGui::updateStatus() {
    if (statusview->isVisible()) {
        asyncstrigi.updateStatus();
    }
    if (fieldnames->count() == 0) {
        fieldnames->addItems(strigi.getFieldNames());
        fieldnames->setCurrentIndex(fieldnames->findText("system.last_modified_time"));
    }
}
void
SimpleSearchGui::updateStatus(const QMap<QString, QString>& s) {
//    static bool first = true;
    static bool attemptedstart = false;
//    if (!first && !statusview->isVisible()) return;
//    first = false;
    QMap<QString, QString> status (s);
    if (status.size() == 0) {
        running = false;
        editFiltersAct->setEnabled(false);
        editListIndexedFilesAct->setEnabled(false);
        status["Status"] = "Daemon is not running";
    } else {
        attemptedstart = true;
        starting = false;
        running = true;
        editFiltersAct->setEnabled(true);
        editListIndexedFilesAct->setEnabled(true);
        if (indexeddirs->count() == 0) {
            updateDirectories();
        }
    }
    toggleindexing->setEnabled(running);
    adddir->setEnabled(running);
    removedir->setEnabled(running);
    queryfield->setEnabled(running);
    toggledaemon->setText((running)?"stop daemon":"start daemon");
    toggledaemon->setEnabled(true);
    if (backendsList) {
        backendsList->setEnabled(!running);
    }
    bool idxng = status["Status"] == "indexing";
    if (idxng != indexing) {
        indexing = idxng;
        toggleindexing->setText((indexing)?"stop indexing":"start indexing");
    }

    QMap<QString,QString>::const_iterator i;
    QString text;
    for (i = status.begin(); i != status.end(); ++i) {
        text += i.key();
        text += ":\t";
        text += i.value();
        text += '\n';
    }
    statusview->setText(text);
}
void
SimpleSearchGui::startDaemon() {
    toggledaemon->setEnabled(false);
    starting = true;
    // try to start the daemon
    QFileInfo exe = QCoreApplication::applicationDirPath()
    + "/../../daemon/strigidaemon";
    QStringList args;
    if (backendsList) {
        args += backendsList->currentText();
    }
    if (exe.exists()) {
        // start not installed version
        QProcess::startDetached(exe.absoluteFilePath(), args);
    } else {
        exe = QCoreApplication::applicationDirPath()+"/strigidaemon";
        if (exe.exists()) {
            QProcess::startDetached(exe.absoluteFilePath(), args);
        } else {
            // start installed version
            QProcess::startDetached("strigidaemon");
        }
    }
}
void
SimpleSearchGui::toggleDaemon() {
    if (running) {
        strigi.stopDaemon();
        indexeddirs->clear();
    } else {
        startDaemon();
    }
}
void
SimpleSearchGui::toggleIndexing() {
    if (indexing) {
        strigi.stopIndexing();
    } else {
        strigi.startIndexing();
    }
}
void
SimpleSearchGui::addDirectory() {
    // open file dialog
    QString dir = QFileDialog::getExistingDirectory (this);
    if (dir.size() <= 0) return;
    for (int i=0; i<indexeddirs->count(); ++i) {
        QString text = indexeddirs->item(i)->text();
        if (dir.startsWith(text)) {
            return;
        }
        if (text.startsWith(dir)) {
            indexeddirs->takeItem(i);
            i = 0;
        }
    }
    indexeddirs->addItem(dir);
    setDirectories();
}
void
SimpleSearchGui::removeDirectory() {
    QList<QListWidgetItem*> items = indexeddirs->selectedItems();

    if (items.size() == 0)
        return;

    for (QList<QListWidgetItem*>::iterator iter = items.begin(); iter != items.end(); iter++)
    {
        int row = indexeddirs->row (*iter);
        indexeddirs->takeItem (row);
    }
    setDirectories();
}
void
SimpleSearchGui::setDirectories() {
    QStringList s;
    for (int i=0; i<indexeddirs->count(); ++i) {
        QString text = indexeddirs->item(i)->text();
        s.append(text);
    }
    strigi.setIndexedDirectories(s);
    updateDirectories();
}
void
SimpleSearchGui::updateDirectories() {
    indexeddirs->clear();
    indexeddirs->addItems(strigi.getIndexedDirectories());
}
void
SimpleSearchGui::editFilters() {
    QList<QPair<bool,QString> > filters;
    filters = strigi.getFilters();

    DlgFilters dlg(filters);
    if (dlg.exec() && filters != dlg.getFilters()) {
        strigi.setFilters(dlg.getFilters());
    }
}
void
SimpleSearchGui::editListIndexedFiles() {
    QStringList files = strigi.getIndexedFiles();
    DlgListIndexedFiles dlg(files);
    dlg.exec();
}
<commit_msg>load the fieldnames even if the daemon is started later<commit_after>/* This file is part of Strigi Desktop Search
 *
 * Copyright (C) 2006 Jos van den Oever <jos@vandenoever.info>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */
#include "dlgfilters.h"
#include "dlglistindexedfiles.h"
#include "simplesearchgui.h"
#include "searchtabs.h"
#include "histogram.h"
#include "searchview.h"
#include <QtGui/QListWidget>
#include <QtGui/QListWidgetItem>
#include <QtGui/QLineEdit>
#include <QtGui/QVBoxLayout>
#include <QtGui/QStackedWidget>
#include <QtGui/QLabel>
#include <QtGui/QDockWidget>
#include <QtGui/QPushButton>
#include <QtGui/QFileDialog>
#include <QtGui/QComboBox>
#include <QtGui/QMenu>
#include <QtGui/QMenuBar>
#include <QtGui/QAction>
#include <QtCore/QString>
#include <QtCore/QDebug>
#include <QtCore/QCoreApplication>
#include <QtCore/QProcess>
#include <QtCore/QTimer>
#include <string>
#include <map>
#include <vector>
using namespace std;

SimpleSearchGui::SimpleSearchGui (QWidget * parent, Qt::WFlags flags)
    : QMainWindow (parent, flags)
{
    mainview = new QStackedWidget();

    QWidget* statuswidget = new QWidget();
    QVBoxLayout *statuslayout = new QVBoxLayout;
    statuslayout->setMargin(0);
    statusview = new QLabel();
    statusview->setAlignment(Qt::AlignTop);
    statusview->setMargin(25);
    indexing = false;
    running = false;
    starting = true;
    indexeddirs = new QListWidget();
    indexeddirs->setSelectionMode(QAbstractItemView::ExtendedSelection);
    adddir = new QPushButton("add directory");
    removedir = new QPushButton("remove directory");
    toggleindexing = new QPushButton("start indexing");
    toggledaemon = new QPushButton("stop daemon");
    statuslayout->addWidget(statusview);
    QHBoxLayout *hlayout = new QHBoxLayout;
    hlayout->addWidget(toggledaemon);
    hlayout->addWidget(toggleindexing);
    statuslayout->addLayout(hlayout);

    histogram = new Histogram();
    histogram->setOrientation(Qt::Vertical);
    fieldnames = new QComboBox();
    fieldnames->addItems(strigi.getFieldNames());
    fieldnames->setCurrentIndex(fieldnames->findText("system.last_modified_time"));
    histogram->setFieldName("mtime");
/*    vector<string> backends = ClientInterface::getBackEnds();
    if (backends.size() > 1) {
        backendsList = new QComboBox();
        for (uint i = 0; i< backends.size(); ++i) {
            QString backend = backends[i].c_str();
            backendsList->insertItem(i, backend);
        }
        statuslayout->addWidget(backendsList);
    } else {*/
        backendsList = 0;
//    }
    statuslayout->addWidget(indexeddirs);
    hlayout = new QHBoxLayout;
    hlayout->addWidget(adddir);
    hlayout->addWidget(removedir);
    statuslayout->addLayout(hlayout);
    statuswidget->setLayout(statuslayout);

    tabs = new SearchTabs();
    tabs->addTab("kde", "kde");
    tabs->addTab("msg", "mimetype:message/*");
    tabs->addTab("irc", "path:*konversation*log");
    tabs->addTab("mail", "mimetype:text/x-mail");
    tabs->addTab("audio", "mimetype:audio/*");
    tabs->addTab("other",
        "-kde -mimetype:message/* -mimetype:text/x-mail -mimetype:audio/*");
    tabs->addTab("all", "");
    mainview->addWidget(tabs);
    mainview->addWidget(statuswidget);
    asyncstrigi.updateStatus();
    mainview->setCurrentIndex(1);

    queryfield = new QLineEdit();
    QVBoxLayout *layout = new QVBoxLayout;
    layout->addWidget(mainview);
    layout->addWidget(queryfield);

    QVBoxLayout* histlayout = new QVBoxLayout();
    QDockWidget* histwidget = new QDockWidget();
    histwidget->setFeatures(QDockWidget::NoDockWidgetFeatures);
    QWidget* histw = new QWidget();
    histw->setLayout(histlayout);
    histwidget->setWidget(histw);
    histlayout->addWidget(fieldnames);
    histlayout->addWidget(histogram);
    addDockWidget(Qt::LeftDockWidgetArea, histwidget);

    centralview = new QWidget();
    centralview->setLayout(layout);
    setCentralWidget(centralview);

    createActions();
    createMenus();

    connect(queryfield, SIGNAL(textChanged(const QString&)),
        this, SLOT(query(const QString&)));
    connect(toggleindexing, SIGNAL(clicked()),
        this, SLOT(toggleIndexing()));
    connect(toggledaemon, SIGNAL(clicked()),
        this, SLOT(toggleDaemon()));
    connect(adddir, SIGNAL(clicked()),
        this, SLOT(addDirectory()));
    connect(removedir, SIGNAL(clicked()),
        this, SLOT(removeDirectory()));
    queryfield->setFocus(Qt::ActiveWindowFocusReason);

    connect(&asyncstrigi,SIGNAL(statusUpdated(const QMap<QString, QString>& )),
        this, SLOT(updateStatus(const QMap<QString, QString>& )));
    connect(tabs->getSearchView(), SIGNAL(gotHits(const QString&)),
        histogram, SLOT(setQuery(const QString&)));
    connect(fieldnames, SIGNAL(currentIndexChanged(const QString&)),
        histogram, SLOT(setFieldName(const QString&)));

    QTimer *timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(updateStatus()));
    timer->start(2000);
    asyncstrigi.updateStatus();
}
void
SimpleSearchGui::createMenus() {
    fileMenu = menuBar()->addMenu(tr("&File"));
    fileMenu->addAction(fileExitAct);

    editMenu = menuBar()->addMenu(tr("&Edit"));
    editMenu->addAction(editFiltersAct);
    editMenu->addAction(editListIndexedFilesAct);
}
void
SimpleSearchGui::createActions() {
    fileExitAct = new QAction(tr("&Exit"), this);
    fileExitAct->setShortcut(tr("Ctrl+Q"));
    fileExitAct->setStatusTip(tr("Quit the program"));
    connect(fileExitAct, SIGNAL(triggered()), this, SLOT(close()));

    editFiltersAct = new QAction(tr("Edit Filters"), this);
    editFiltersAct->setStatusTip(tr("Edit filename filters"));
    connect(editFiltersAct, SIGNAL(triggered()), this, SLOT(editFilters()));

    editListIndexedFilesAct = new QAction(tr("List indexed files"), this);
    editListIndexedFilesAct->setStatusTip(tr("Show files indexed by strigi"));
    connect(editListIndexedFilesAct, SIGNAL(triggered()), this, SLOT(editListIndexedFiles()));
}
void
SimpleSearchGui::query(const QString& item) {
    QString query = item.trimmed();
    if (query.length() == 0) {
        tabs->setQuery(QString());
        asyncstrigi.updateStatus();
        mainview->setCurrentIndex(1);
    } else {
        mainview->setCurrentIndex(0);
        tabs->setQuery(query);
    }
}
void
SimpleSearchGui::updateStatus() {
    if (statusview->isVisible()) {
        asyncstrigi.updateStatus();
    }
    if (fieldnames->count() == 0) {
        fieldnames->addItems(strigi.getFieldNames());
        fieldnames->setCurrentIndex(
            fieldnames->findText("system.last_modified_time"));
    }
}
void
SimpleSearchGui::updateStatus(const QMap<QString, QString>& s) {
//    static bool first = true;
    static bool attemptedstart = false;
//    if (!first && !statusview->isVisible()) return;
//    first = false;
    QMap<QString, QString> status (s);
    if (status.size() == 0) {
        running = false;
        editFiltersAct->setEnabled(false);
        editListIndexedFilesAct->setEnabled(false);
        status["Status"] = "Daemon is not running";
    } else {
        attemptedstart = true;
        starting = false;
        running = true;
        editFiltersAct->setEnabled(true);
        editListIndexedFilesAct->setEnabled(true);
        if (indexeddirs->count() == 0) {
            updateDirectories();
        }
    }
    toggleindexing->setEnabled(running);
    adddir->setEnabled(running);
    removedir->setEnabled(running);
    queryfield->setEnabled(running);
    toggledaemon->setText((running)?"stop daemon":"start daemon");
    toggledaemon->setEnabled(true);
    if (backendsList) {
        backendsList->setEnabled(!running);
    }
    bool idxng = status["Status"] == "indexing";
    if (idxng != indexing) {
        indexing = idxng;
        toggleindexing->setText((indexing)?"stop indexing":"start indexing");
    }

    QMap<QString,QString>::const_iterator i;
    QString text;
    for (i = status.begin(); i != status.end(); ++i) {
        text += i.key();
        text += ":\t";
        text += i.value();
        text += '\n';
    }
    statusview->setText(text);
}
void
SimpleSearchGui::startDaemon() {
    toggledaemon->setEnabled(false);
    starting = true;
    // try to start the daemon
    QFileInfo exe = QCoreApplication::applicationDirPath()
    + "/../../daemon/strigidaemon";
    QStringList args;
    if (backendsList) {
        args += backendsList->currentText();
    }
    if (exe.exists()) {
        // start not installed version
        QProcess::startDetached(exe.absoluteFilePath(), args);
    } else {
        exe = QCoreApplication::applicationDirPath()+"/strigidaemon";
        if (exe.exists()) {
            QProcess::startDetached(exe.absoluteFilePath(), args);
        } else {
            // start installed version
            QProcess::startDetached("strigidaemon");
        }
    }
}
void
SimpleSearchGui::toggleDaemon() {
    if (running) {
        strigi.stopDaemon();
        indexeddirs->clear();
    } else {
        startDaemon();
    }
}
void
SimpleSearchGui::toggleIndexing() {
    if (indexing) {
        strigi.stopIndexing();
    } else {
        strigi.startIndexing();
    }
}
void
SimpleSearchGui::addDirectory() {
    // open file dialog
    QString dir = QFileDialog::getExistingDirectory (this);
    if (dir.size() <= 0) return;
    for (int i=0; i<indexeddirs->count(); ++i) {
        QString text = indexeddirs->item(i)->text();
        if (dir.startsWith(text)) {
            return;
        }
        if (text.startsWith(dir)) {
            indexeddirs->takeItem(i);
            i = 0;
        }
    }
    indexeddirs->addItem(dir);
    setDirectories();
}
void
SimpleSearchGui::removeDirectory() {
    QList<QListWidgetItem*> items = indexeddirs->selectedItems();

    if (items.size() == 0)
        return;

    for (QList<QListWidgetItem*>::iterator iter = items.begin(); iter != items.end(); iter++)
    {
        int row = indexeddirs->row (*iter);
        indexeddirs->takeItem (row);
    }
    setDirectories();
}
void
SimpleSearchGui::setDirectories() {
    QStringList s;
    for (int i=0; i<indexeddirs->count(); ++i) {
        QString text = indexeddirs->item(i)->text();
        s.append(text);
    }
    strigi.setIndexedDirectories(s);
    updateDirectories();
}
void
SimpleSearchGui::updateDirectories() {
    indexeddirs->clear();
    indexeddirs->addItems(strigi.getIndexedDirectories());
}
void
SimpleSearchGui::editFilters() {
    QList<QPair<bool,QString> > filters;
    filters = strigi.getFilters();

    DlgFilters dlg(filters);
    if (dlg.exec() && filters != dlg.getFilters()) {
        strigi.setFilters(dlg.getFilters());
    }
}
void
SimpleSearchGui::editListIndexedFiles() {
    QStringList files = strigi.getIndexedFiles();
    DlgListIndexedFiles dlg(files);
    dlg.exec();
}
<|endoftext|>


<commit_before>#include "FtpDataTransfer.h"
#include <QSslKey>

FtpDataTransfer::FtpDataTransfer(TransferMode clientMode, TransferMode serverMode, QObject *parent) :
	QObject(parent),
	clientMode(clientMode),
	serverMode(serverMode),
	clientSocket(0),
	serverSocket(0),
	clientListen(QHostAddress::Any),
	serverListen(QHostAddress::Any),
	connected(0),
	disconnected(0),
	clientSsl(false),
	serverSsl(false),
	clientBufferSize(32768),
	serverBufferSize(32768),
	clientReady(false),
	serverReady(false),
	clientDone(false),
	serverDone(false)
{
	connect(&clientServer, SIGNAL(clientConnected(QSslSocket*)), this, SLOT(clientConnectedPassive(QSslSocket*)));
	connect(&serverServer, SIGNAL(clientConnected(QSslSocket*)), this, SLOT(serverConnectedActive(QSslSocket*)));
}

FtpDataTransfer::~FtpDataTransfer()
{
	clientSocket = 0;
	serverSocket = 0;
}

void FtpDataTransfer::setClient(QHostAddress host, quint16 port)
{
	clientAddress = host;
	clientPort = port;
}

void FtpDataTransfer::setClient(QString host, quint16 port)
{
	setClient(QHostAddress(host), port);
}

void FtpDataTransfer::setClientListenAddress(QHostAddress address)
{
	clientListen = address;
}

void FtpDataTransfer::setServer(QHostAddress host, quint16 port)
{
	serverAddress = host;
	serverPort = port;
}

void FtpDataTransfer::setServer(QString host, quint16 port)
{
	setServer(QHostAddress(host), port);
}

void FtpDataTransfer::setServerListenAddress(QHostAddress address)
{
	serverListen = address;
}

void FtpDataTransfer::setUseSsl(bool clientSsl, bool serverSsl, QSslCertificate cert, QSslKey key)
{
	this->clientSsl = clientSsl;
	this->serverSsl = serverSsl;

	if(clientSsl)
	{
		certificate = cert;
		privateKey = key;
	}
}

void FtpDataTransfer::setClientReadBufferSize(quint32 size)
{
	clientBufferSize = size;
}

void FtpDataTransfer::setServerReadBufferSize(quint32 size)
{
	serverBufferSize = size;
}

QHostAddress FtpDataTransfer::clientServerAddress()
{
	return clientServer.serverAddress();
}

quint16 FtpDataTransfer::clientServerPort()
{
	return clientServer.serverPort();
}

QHostAddress FtpDataTransfer::serverServerAddress()
{
	return serverServer.serverAddress();
}

quint16 FtpDataTransfer::serverServerPort()
{
	return serverServer.serverPort();
}

void FtpDataTransfer::start()
{
	if(clientMode == Active)
	{
		clientSocket = new QSslSocket(this);
		clientSocket->setReadBufferSize(clientBufferSize);

//		connect(clientSocket, SIGNAL(readyRead()), this, SLOT(forwardFromClientToServer()));
//		connect(clientSocket, SIGNAL(bytesWritten(qint64)), this, SLOT(forwardFromServerToClient()));
//		connect(clientSocket, SIGNAL(disconnected()), this, SLOT(clientDisconnected()));

//		if(clientSsl)
//		{
//			connect(clientSocket, SIGNAL(encrypted()), this, SLOT(clientConnectedActive()));

//			clientSocket->setLocalCertificate(certificate);
//			clientSocket->setPrivateKey(privateKey);

//			clientSocket->connectToHostEncrypted(clientAddress.toString(), clientPort);

//			// Do not forget that in FTP the server is ALWAYS TLS server and client is ALWAYS TLS client
//			// Even when client is listening
////			clientSocket->connectToHost(clientAddress, clientPort);
//		} else {

			connect(clientSocket, SIGNAL(connected()), this, SLOT(clientConnectedActive()));

			clientSocket->connectToHost(clientAddress, clientPort);
//		}
	} else {
		clientServer.listen(clientListen);
	}

	if(serverMode == Passive)
	{
		serverSocket = new QSslSocket(this);
		serverSocket->setReadBufferSize(serverBufferSize);

//		connect(serverSocket, SIGNAL(readyRead()), this, SLOT(forwardFromServerToClient()));
//		connect(serverSocket, SIGNAL(bytesWritten(qint64)), this, SLOT(forwardFromClientToServer()));
//		connect(serverSocket, SIGNAL(disconnected()), this, SLOT(serverDisconnected()));

		qDebug() << "Connecting to" << serverAddress << serverPort;

		if(serverSsl)
		{
			connect(serverSocket, SIGNAL(encrypted()), this, SLOT(serverConnectedPassive()));

//			serverSocket->setLocalCertificate(certificate);
//			serverSocket->setPrivateKey(privateKey);
			serverSocket->setPeerVerifyMode(QSslSocket::VerifyNone);
			serverSocket->setProtocol(QSsl::AnyProtocol);

			// Here we act like client
			serverSocket->connectToHostEncrypted(serverAddress.toString(), serverPort);
		} else {
			connect(serverSocket, SIGNAL(connected()), this, SLOT(serverConnectedPassive()));

			serverSocket->connectToHost(serverAddress, serverPort);
		}
	} else {
		serverServer.listen(serverListen);
	}
}

void FtpDataTransfer::clientConnectedActive()
{
	if(!clientSsl || clientSocket->isEncrypted())
	{
		qDebug() << "Client connected active, ok";

		connect(clientSocket, SIGNAL(readyRead()), this, SLOT(forwardFromClientToServer()));
		connect(clientSocket, SIGNAL(bytesWritten(qint64)), this, SLOT(forwardFromServerToClient()));
		connect(clientSocket, SIGNAL(disconnected()), this, SLOT(clientDisconnected()));

		clientReady = true;

		if(serverDone && !buffer.isEmpty())
		{
			clientSocket->write(buffer);
			buffer.clear();
			clientSocket->disconnectFromHost();
		}
	} else {
		qDebug() << "Client connected active, engage ssl";

		connect(clientSocket, SIGNAL(encrypted()), this, SLOT(clientConnectedActive()));

		clientSocket->setLocalCertificate(certificate);
		clientSocket->setPrivateKey(privateKey);
		clientSocket->setProtocol(QSsl::AnyProtocol);
		clientSocket->startServerEncryption();
	//	clientSocket->waitForEncrypted(1000); // I just don't know... those fucking signals are not working
	}
}

void FtpDataTransfer::serverConnectedPassive()
{
	if(!serverSsl || serverSocket->isEncrypted())
	{
		qDebug() << "Server connected, ok";

		connect(serverSocket, SIGNAL(readyRead()), this, SLOT(forwardFromServerToClient()));
		connect(serverSocket, SIGNAL(bytesWritten(qint64)), this, SLOT(forwardFromClientToServer()));
		connect(serverSocket, SIGNAL(disconnected()), this, SLOT(serverDisconnected()));

		serverReady = true;

		if(clientDone && !buffer.isEmpty())
		{
			serverSocket->write(buffer);
			buffer.clear();
			serverSocket->disconnectFromHost();
		}
	} else {
		qDebug() << "Server connected, engage ssl";

		connect(serverSocket, SIGNAL(encrypted()), this, SLOT(serverConnectedPassive()));

		serverSocket->startClientEncryption();
	}
}

void FtpDataTransfer::clientConnectedPassive(QSslSocket *client)
{
//	if(client)
//		clientSocket = client;

//	if(!client || !useSsl)
//	{
//		connect(clientSocket, SIGNAL(readyRead()), this, SLOT(forwardFromClientToServer()));
//		connect(clientSocket, SIGNAL(bytesWritten(qint64)), this, SLOT(forwardFromServerToClient()));
//		connect(clientSocket, SIGNAL(disconnected()), this, SLOT(clientDisconnected()));
//	}

//	qDebug() << "Client connected to passive server" << clientSocket->peerAddress();

//	if(useSsl && !clientSocket->isEncrypted())
//	{
//		connect(clientSocket, SIGNAL(encrypted()), this, SLOT(clientConnected()));

//		clientSocket->setLocalCertificate(certificate);
//		clientSocket->setPrivateKey(privateKey);
//		clientSocket->startServerEncryption();
//	}

	clientSocket = client;

	clientSocket->setReadBufferSize(clientBufferSize);

	connect(clientSocket, SIGNAL(readyRead()), this, SLOT(forwardFromClientToServer()));
	connect(clientSocket, SIGNAL(bytesWritten(qint64)), this, SLOT(forwardFromServerToClient()));
	connect(clientSocket, SIGNAL(disconnected()), this, SLOT(clientDisconnected()));
	connect(clientSocket, SIGNAL(encrypted()), this, SLOT(clientConnectedActive()));
	connect(clientSocket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(sslErrors(QList<QSslError>)));
	connect(clientSocket, SIGNAL(peerVerifyError(QSslError)), this, SLOT(peerVerifyError(QSslError)));
	connect(clientSocket, SIGNAL(modeChanged(QSslSocket::SslMode)), this, SLOT(modeChange(QSslSocket::SslMode)));

	if(!clientSsl || clientSocket->isEncrypted())
	{
		qDebug() << "Client connected passive, ok";
		clientReady = true;

		if(serverDone && !buffer.isEmpty())
		{
			clientSocket->write(buffer);
			buffer.clear();
			clientSocket->disconnectFromHost();
		}
	} else {
		qDebug() << "Client connected passive, engage ssl";

		clientSocket->setLocalCertificate(certificate);
		clientSocket->setPrivateKey(privateKey);
		clientSocket->setProtocol(QSsl::AnyProtocol);
		clientSocket->setPeerVerifyMode(QSslSocket::VerifyNone);

		QList<QSslError> ignoreErrors;
		ignoreErrors << QSslError(QSslError::SelfSignedCertificate);
		clientSocket->ignoreSslErrors(ignoreErrors);

		clientSocket->startServerEncryption();

//		clientSocket->waitForEncrypted(1000);// FIXME AAAA
	}
}

void FtpDataTransfer::serverConnectedActive(QSslSocket *server)
{
//	if(server)
//		serverSocket = server;

//	if(!server || !useSsl)
//	{
//		connect(serverSocket, SIGNAL(readyRead()), this, SLOT(forwardFromServerToClient()));
//		connect(serverSocket, SIGNAL(bytesWritten(qint64)), this, SLOT(forwardFromClientToServer()));
//		connect(serverSocket, SIGNAL(disconnected()), this, SLOT(serverDisconnected()));
//	}

//	qDebug() << "Server connected to passive server" << serverSocket->peerAddress() << server;

//	if(useSsl && internalSsl && server)
//	{
//		connect(clientSocket, SIGNAL(encrypted()), this, SLOT(serverConnected()));

//		serverSocket->setLocalCertificate(certificate);
//		serverSocket->setPrivateKey(privateKey);
//		serverSocket->startServerEncryption();
//	}

	serverSocket = server;

	serverSocket->setReadBufferSize(serverBufferSize);

	if(!serverSsl || serverSocket->isEncrypted())
	{
		qDebug() << "Server active connected, ok";

		connect(serverSocket, SIGNAL(readyRead()), this, SLOT(forwardFromServerToClient()));
		connect(serverSocket, SIGNAL(bytesWritten(qint64)), this, SLOT(forwardFromClientToServer()));
		connect(serverSocket, SIGNAL(disconnected()), this, SLOT(serverDisconnected()));

		serverReady = true;

		if(clientDone && !buffer.isEmpty())
		{
			serverSocket->write(buffer);
			buffer.clear();
			serverSocket->disconnectFromHost();
		}
	} else {
		qDebug() << "Server active connected, engage ssl";

		connect(serverSocket, SIGNAL(encrypted()), this, SLOT(serverConnectedPassive()));

//		serverSocket->setLocalCertificate(certificate);
//		serverSocket->setPrivateKey(privateKey);
		serverSocket->setPeerVerifyMode(QSslSocket::VerifyNone);
		serverSocket->setProtocol(QSsl::AnyProtocol);
		serverSocket->startClientEncryption();

		//qDebug() << serverSocket->waitForEncrypted(1000); // FIXME aaaaa
		qDebug() << serverSocket->sslErrors();

		//qDebug() << serverSocket->waitForEncrypted();
	}
}

void FtpDataTransfer::forwardFromServerToClient()
{
	if(!clientSocket && serverSocket)
	{
		if(serverSocket->bytesAvailable())
			buffer.append(serverSocket->read(serverBufferSize));

	} else if(clientSocket && !serverSocket) {
		if(!buffer.isEmpty() && clientReady)
		{
			clientSocket->write(buffer);
			buffer.clear();
		}

	} else if(clientReady) {
		if(!buffer.isEmpty())
		{
			clientSocket->write(buffer);
			buffer.clear();
		}

		clientSocket->write(serverSocket->read(serverBufferSize));
	} else {
		buffer.append(serverSocket->read(serverBufferSize));
	}
}

void FtpDataTransfer::forwardFromClientToServer()
{
	if(!serverSocket && clientSocket)
	{
		if(clientSocket->bytesAvailable())
			buffer.append(clientSocket->read(clientBufferSize));

	} else if(serverSocket && !clientSocket) {
		if(!buffer.isEmpty() && serverReady)
		{
			serverSocket->write(buffer);
			buffer.clear();
		}

	} else if(serverReady) {
		if(!buffer.isEmpty())
		{
			serverSocket->write(buffer);
			buffer.clear();
		}

		serverSocket->write(clientSocket->read(clientBufferSize));
	} else {
		buffer.append(clientSocket->read(clientBufferSize));
	}
}

void FtpDataTransfer::clientDisconnected()
{
	qDebug() << "Client disconnected";

	if(serverSocket && serverReady)
		serverSocket->disconnectFromHost();

	clientReady = false;
	clientDone = true;

	if(++disconnected == 2)
		emit transferFinished();
}

void FtpDataTransfer::serverDisconnected()
{
	qDebug() << "Server disconnected";

	if(clientSocket && clientReady)
		clientSocket->disconnectFromHost();

	serverReady = false;
	serverDone = true;

	if(++disconnected == 2)
		emit transferFinished();
}

void FtpDataTransfer::sslErrors(const QList<QSslError> &errors)
{
	qDebug() << "SSL errors occured:" << errors;
}

void FtpDataTransfer::peerVerifyError(const QSslError &error)
{
	QSslCertificate cert = error.certificate();

	qDebug() << "Peer verify error occured:" << (int)error.error() << error
		 << cert.issuerInfo(QSslCertificate::CommonName)
		    << cert.subjectInfo(QSslCertificate::CommonName);
	clientSocket->ignoreSslErrors();
	qDebug() << "Ignoring error";
}

void  FtpDataTransfer::modeChange(QSslSocket::SslMode mode)
{
	qDebug() << "Client ssl mode changed to" << mode;
}
<commit_msg>FTP: send buffer contents even if it is empty and the other side has already disconnected<commit_after>#include "FtpDataTransfer.h"
#include <QSslKey>

FtpDataTransfer::FtpDataTransfer(TransferMode clientMode, TransferMode serverMode, QObject *parent) :
	QObject(parent),
	clientMode(clientMode),
	serverMode(serverMode),
	clientSocket(0),
	serverSocket(0),
	clientListen(QHostAddress::Any),
	serverListen(QHostAddress::Any),
	connected(0),
	disconnected(0),
	clientSsl(false),
	serverSsl(false),
	clientBufferSize(32768),
	serverBufferSize(32768),
	clientReady(false),
	serverReady(false),
	clientDone(false),
	serverDone(false)
{
	connect(&clientServer, SIGNAL(clientConnected(QSslSocket*)), this, SLOT(clientConnectedPassive(QSslSocket*)));
	connect(&serverServer, SIGNAL(clientConnected(QSslSocket*)), this, SLOT(serverConnectedActive(QSslSocket*)));
}

FtpDataTransfer::~FtpDataTransfer()
{
	clientSocket = 0;
	serverSocket = 0;
}

void FtpDataTransfer::setClient(QHostAddress host, quint16 port)
{
	clientAddress = host;
	clientPort = port;
}

void FtpDataTransfer::setClient(QString host, quint16 port)
{
	setClient(QHostAddress(host), port);
}

void FtpDataTransfer::setClientListenAddress(QHostAddress address)
{
	clientListen = address;
}

void FtpDataTransfer::setServer(QHostAddress host, quint16 port)
{
	serverAddress = host;
	serverPort = port;
}

void FtpDataTransfer::setServer(QString host, quint16 port)
{
	setServer(QHostAddress(host), port);
}

void FtpDataTransfer::setServerListenAddress(QHostAddress address)
{
	serverListen = address;
}

void FtpDataTransfer::setUseSsl(bool clientSsl, bool serverSsl, QSslCertificate cert, QSslKey key)
{
	this->clientSsl = clientSsl;
	this->serverSsl = serverSsl;

	if(clientSsl)
	{
		certificate = cert;
		privateKey = key;
	}
}

void FtpDataTransfer::setClientReadBufferSize(quint32 size)
{
	clientBufferSize = size;
}

void FtpDataTransfer::setServerReadBufferSize(quint32 size)
{
	serverBufferSize = size;
}

QHostAddress FtpDataTransfer::clientServerAddress()
{
	return clientServer.serverAddress();
}

quint16 FtpDataTransfer::clientServerPort()
{
	return clientServer.serverPort();
}

QHostAddress FtpDataTransfer::serverServerAddress()
{
	return serverServer.serverAddress();
}

quint16 FtpDataTransfer::serverServerPort()
{
	return serverServer.serverPort();
}

void FtpDataTransfer::start()
{
	if(clientMode == Active)
	{
		clientSocket = new QSslSocket(this);
		clientSocket->setReadBufferSize(clientBufferSize);

//		connect(clientSocket, SIGNAL(readyRead()), this, SLOT(forwardFromClientToServer()));
//		connect(clientSocket, SIGNAL(bytesWritten(qint64)), this, SLOT(forwardFromServerToClient()));
//		connect(clientSocket, SIGNAL(disconnected()), this, SLOT(clientDisconnected()));

//		if(clientSsl)
//		{
//			connect(clientSocket, SIGNAL(encrypted()), this, SLOT(clientConnectedActive()));

//			clientSocket->setLocalCertificate(certificate);
//			clientSocket->setPrivateKey(privateKey);

//			clientSocket->connectToHostEncrypted(clientAddress.toString(), clientPort);

//			// Do not forget that in FTP the server is ALWAYS TLS server and client is ALWAYS TLS client
//			// Even when client is listening
////			clientSocket->connectToHost(clientAddress, clientPort);
//		} else {

			connect(clientSocket, SIGNAL(connected()), this, SLOT(clientConnectedActive()));

			clientSocket->connectToHost(clientAddress, clientPort);
//		}
	} else {
		clientServer.listen(clientListen);
	}

	if(serverMode == Passive)
	{
		serverSocket = new QSslSocket(this);
		serverSocket->setReadBufferSize(serverBufferSize);

//		connect(serverSocket, SIGNAL(readyRead()), this, SLOT(forwardFromServerToClient()));
//		connect(serverSocket, SIGNAL(bytesWritten(qint64)), this, SLOT(forwardFromClientToServer()));
//		connect(serverSocket, SIGNAL(disconnected()), this, SLOT(serverDisconnected()));

		qDebug() << "Connecting to" << serverAddress << serverPort;

		if(serverSsl)
		{
			connect(serverSocket, SIGNAL(encrypted()), this, SLOT(serverConnectedPassive()));

//			serverSocket->setLocalCertificate(certificate);
//			serverSocket->setPrivateKey(privateKey);
			serverSocket->setPeerVerifyMode(QSslSocket::VerifyNone);
			serverSocket->setProtocol(QSsl::AnyProtocol);

			// Here we act like client
			serverSocket->connectToHostEncrypted(serverAddress.toString(), serverPort);
		} else {
			connect(serverSocket, SIGNAL(connected()), this, SLOT(serverConnectedPassive()));

			serverSocket->connectToHost(serverAddress, serverPort);
		}
	} else {
		serverServer.listen(serverListen);
	}
}

void FtpDataTransfer::clientConnectedActive()
{
	if(!clientSsl || clientSocket->isEncrypted())
	{
		qDebug() << "Client connected active, ok";

		connect(clientSocket, SIGNAL(readyRead()), this, SLOT(forwardFromClientToServer()));
		connect(clientSocket, SIGNAL(bytesWritten(qint64)), this, SLOT(forwardFromServerToClient()));
		connect(clientSocket, SIGNAL(disconnected()), this, SLOT(clientDisconnected()));

		clientReady = true;

		if(serverDone)
		{
			clientSocket->write(buffer);
			buffer.clear();
			clientSocket->disconnectFromHost();
		}
	} else {
		qDebug() << "Client connected active, engage ssl";

		connect(clientSocket, SIGNAL(encrypted()), this, SLOT(clientConnectedActive()));

		clientSocket->setLocalCertificate(certificate);
		clientSocket->setPrivateKey(privateKey);
		clientSocket->setProtocol(QSsl::AnyProtocol);
		clientSocket->startServerEncryption();
	//	clientSocket->waitForEncrypted(1000); // I just don't know... those fucking signals are not working
	}
}

void FtpDataTransfer::serverConnectedPassive()
{
	if(!serverSsl || serverSocket->isEncrypted())
	{
		qDebug() << "Server connected, ok";

		connect(serverSocket, SIGNAL(readyRead()), this, SLOT(forwardFromServerToClient()));
		connect(serverSocket, SIGNAL(bytesWritten(qint64)), this, SLOT(forwardFromClientToServer()));
		connect(serverSocket, SIGNAL(disconnected()), this, SLOT(serverDisconnected()));

		serverReady = true;

		if(clientDone)
		{
			serverSocket->write(buffer);
			buffer.clear();
			serverSocket->disconnectFromHost();
		}
	} else {
		qDebug() << "Server connected, engage ssl";

		connect(serverSocket, SIGNAL(encrypted()), this, SLOT(serverConnectedPassive()));

		serverSocket->startClientEncryption();
	}
}

void FtpDataTransfer::clientConnectedPassive(QSslSocket *client)
{
//	if(client)
//		clientSocket = client;

//	if(!client || !useSsl)
//	{
//		connect(clientSocket, SIGNAL(readyRead()), this, SLOT(forwardFromClientToServer()));
//		connect(clientSocket, SIGNAL(bytesWritten(qint64)), this, SLOT(forwardFromServerToClient()));
//		connect(clientSocket, SIGNAL(disconnected()), this, SLOT(clientDisconnected()));
//	}

//	qDebug() << "Client connected to passive server" << clientSocket->peerAddress();

//	if(useSsl && !clientSocket->isEncrypted())
//	{
//		connect(clientSocket, SIGNAL(encrypted()), this, SLOT(clientConnected()));

//		clientSocket->setLocalCertificate(certificate);
//		clientSocket->setPrivateKey(privateKey);
//		clientSocket->startServerEncryption();
//	}

	clientSocket = client;

	clientSocket->setReadBufferSize(clientBufferSize);

	connect(clientSocket, SIGNAL(readyRead()), this, SLOT(forwardFromClientToServer()));
	connect(clientSocket, SIGNAL(bytesWritten(qint64)), this, SLOT(forwardFromServerToClient()));
	connect(clientSocket, SIGNAL(disconnected()), this, SLOT(clientDisconnected()));
	connect(clientSocket, SIGNAL(encrypted()), this, SLOT(clientConnectedActive()));
	connect(clientSocket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(sslErrors(QList<QSslError>)));
	connect(clientSocket, SIGNAL(peerVerifyError(QSslError)), this, SLOT(peerVerifyError(QSslError)));
	connect(clientSocket, SIGNAL(modeChanged(QSslSocket::SslMode)), this, SLOT(modeChange(QSslSocket::SslMode)));

	if(!clientSsl || clientSocket->isEncrypted())
	{
		qDebug() << "Client connected passive, ok";
		clientReady = true;

		if(serverDone)
		{
			clientSocket->write(buffer);
			buffer.clear();
			clientSocket->disconnectFromHost();
		}
	} else {
		qDebug() << "Client connected passive, engage ssl";

		clientSocket->setLocalCertificate(certificate);
		clientSocket->setPrivateKey(privateKey);
		clientSocket->setProtocol(QSsl::AnyProtocol);
		clientSocket->setPeerVerifyMode(QSslSocket::VerifyNone);

		QList<QSslError> ignoreErrors;
		ignoreErrors << QSslError(QSslError::SelfSignedCertificate);
		clientSocket->ignoreSslErrors(ignoreErrors);

		clientSocket->startServerEncryption();

//		clientSocket->waitForEncrypted(1000);// FIXME AAAA
	}
}

void FtpDataTransfer::serverConnectedActive(QSslSocket *server)
{
//	if(server)
//		serverSocket = server;

//	if(!server || !useSsl)
//	{
//		connect(serverSocket, SIGNAL(readyRead()), this, SLOT(forwardFromServerToClient()));
//		connect(serverSocket, SIGNAL(bytesWritten(qint64)), this, SLOT(forwardFromClientToServer()));
//		connect(serverSocket, SIGNAL(disconnected()), this, SLOT(serverDisconnected()));
//	}

//	qDebug() << "Server connected to passive server" << serverSocket->peerAddress() << server;

//	if(useSsl && internalSsl && server)
//	{
//		connect(clientSocket, SIGNAL(encrypted()), this, SLOT(serverConnected()));

//		serverSocket->setLocalCertificate(certificate);
//		serverSocket->setPrivateKey(privateKey);
//		serverSocket->startServerEncryption();
//	}

	serverSocket = server;

	serverSocket->setReadBufferSize(serverBufferSize);

	if(!serverSsl || serverSocket->isEncrypted())
	{
		qDebug() << "Server active connected, ok";

		connect(serverSocket, SIGNAL(readyRead()), this, SLOT(forwardFromServerToClient()));
		connect(serverSocket, SIGNAL(bytesWritten(qint64)), this, SLOT(forwardFromClientToServer()));
		connect(serverSocket, SIGNAL(disconnected()), this, SLOT(serverDisconnected()));

		serverReady = true;

		if(clientDone)
		{
			serverSocket->write(buffer);
			buffer.clear();
			serverSocket->disconnectFromHost();
		}
	} else {
		qDebug() << "Server active connected, engage ssl";

		connect(serverSocket, SIGNAL(encrypted()), this, SLOT(serverConnectedPassive()));

//		serverSocket->setLocalCertificate(certificate);
//		serverSocket->setPrivateKey(privateKey);
		serverSocket->setPeerVerifyMode(QSslSocket::VerifyNone);
		serverSocket->setProtocol(QSsl::AnyProtocol);
		serverSocket->startClientEncryption();

		//qDebug() << serverSocket->waitForEncrypted(1000); // FIXME aaaaa
		qDebug() << serverSocket->sslErrors();

		//qDebug() << serverSocket->waitForEncrypted();
	}
}

void FtpDataTransfer::forwardFromServerToClient()
{
	if(!clientSocket && serverSocket)
	{
		if(serverSocket->bytesAvailable())
			buffer.append(serverSocket->read(serverBufferSize));

	} else if(clientSocket && !serverSocket) {
		if(!buffer.isEmpty() && clientReady)
		{
			clientSocket->write(buffer);
			buffer.clear();
		}

	} else if(clientReady) {
		if(!buffer.isEmpty())
		{
			clientSocket->write(buffer);
			buffer.clear();
		}

		clientSocket->write(serverSocket->read(serverBufferSize));
	} else {
		buffer.append(serverSocket->read(serverBufferSize));
	}
}

void FtpDataTransfer::forwardFromClientToServer()
{
	if(!serverSocket && clientSocket)
	{
		if(clientSocket->bytesAvailable())
			buffer.append(clientSocket->read(clientBufferSize));

	} else if(serverSocket && !clientSocket) {
		if(!buffer.isEmpty() && serverReady)
		{
			serverSocket->write(buffer);
			buffer.clear();
		}

	} else if(serverReady) {
		if(!buffer.isEmpty())
		{
			serverSocket->write(buffer);
			buffer.clear();
		}

		serverSocket->write(clientSocket->read(clientBufferSize));
	} else {
		buffer.append(clientSocket->read(clientBufferSize));
	}
}

void FtpDataTransfer::clientDisconnected()
{
	qDebug() << "Client disconnected";

	if(serverSocket && serverReady)
		serverSocket->disconnectFromHost();

	clientReady = false;
	clientDone = true;

	if(++disconnected == 2)
		emit transferFinished();
}

void FtpDataTransfer::serverDisconnected()
{
	qDebug() << "Server disconnected";

	if(clientSocket && clientReady)
		clientSocket->disconnectFromHost();

	serverReady = false;
	serverDone = true;

	if(++disconnected == 2)
		emit transferFinished();
}

void FtpDataTransfer::sslErrors(const QList<QSslError> &errors)
{
	qDebug() << "SSL errors occured:" << errors;
}

void FtpDataTransfer::peerVerifyError(const QSslError &error)
{
	QSslCertificate cert = error.certificate();

	qDebug() << "Peer verify error occured:" << (int)error.error() << error
		 << cert.issuerInfo(QSslCertificate::CommonName)
		    << cert.subjectInfo(QSslCertificate::CommonName);
	clientSocket->ignoreSslErrors();
	qDebug() << "Ignoring error";
}

void  FtpDataTransfer::modeChange(QSslSocket::SslMode mode)
{
	qDebug() << "Client ssl mode changed to" << mode;
}
<|endoftext|>


<commit_before>#ifndef STAN_MATH_OPENCL_EVENT_CONCAT_CL_HPP
#define STAN_MATH_OPENCL_EVENT_CONCAT_CL_HPP
#ifdef STAN_OPENCL

#include <stan/math/opencl/matrix_cl.hpp>
#include <CL/cl.hpp>
#include <type_traits>
#include <vector>

namespace stan {
namespace math {

/**
 * Template check for if type has event stack
 * @tparam Type to check.
 * @return enum with false value if type does not have an event stack.
 */
template <typename T>
struct has_event_stack {
  enum { value = false };
};

/**
 * Template check for if type has event stack
 * @tparam Type to check.
 * @return enum with false value if type does not have an event stack.
 */
template <>
struct has_event_stack<matrix_cl> {
  enum { value = true };
};

/**
 * Template check for if type has event stack
 * @tparam Type to check.
 * @return enum with true value if type does not have an event stack.
 */
template <>
struct has_event_stack<std::vector<cl::Event>> {
  enum { value = true };
};

/**
 * Helper template that enables function if type has event stack.
 * @tparam Type to check.
 * @return None, will fail compilation and pass to next template ala SFINAE.
 */
template <typename T>
using enable_if_has_event_stack
    = std::enable_if_t<has_event_stack<T>::value, int>;

/**
 * Helper template that enables function if type does not have event stack.
 * @tparam Type to check.
 * @return None, will fail compilation and pass to next template ala SFINAE.
 */
template <typename T>
using enable_if_no_event_stack
    = std::enable_if_t<!has_event_stack<T>::value, int>;

/**
 * Ends the recurstion to extract the event stack.
 * @return An empty event vector.
 */
inline const void event_concat_cl() {
}

/**
 * Ends the recursion to extract the event stack.
 * @param v1 Events on the OpenCL event stack.
 * @return returns input vector.
 */
inline const std::vector<cl::Event>& event_concat_cl(
    const std::vector<cl::Event>& v1) {
  return v1;
}

/**
 * Ends the recursion to extract the event stack.
 * @param A OpenCL matrix holding the events.
 * @return The event stack for the matrix.
 */
inline const std::vector<cl::Event>& event_concat_cl(const matrix_cl& A) {
  return A.events();
}

/**
 * Ends the recurstion to extract the event stack.
 * @param throwaway_val A value that does not have an event stack.
 * @tparam T checks if either has an event stack and if not then fails
 * compilation.
 * @return An empty event vector.
 */
template <typename T, enable_if_no_event_stack<T> = 0>
inline const std::vector<cl::Event> event_concat_cl(const T& throwaway_val) {
  const std::vector<cl::Event> vec_concat;
  return vec_concat;
}

/**
 * Passes over an argument without an event stack.
 * @param throwaway_val A value that does not have an event stack.
 * @param args variadic arcs passed down to the next recursion.
 * @tparam T checks if either has an event stack and if not then fails
 * compilation.
 * @tparam Args Types for variadic.
 * @return An empty event vector.
 */
template <typename T, enable_if_no_event_stack<T> = 0, typename... Args>
inline const std::vector<cl::Event> event_concat_cl(const T& throwaway_val,
                                                    const Args... args) {
  return event_concat_cl(args...);
}

/**
 * Gets the event stack from a vector of events and other arguments.
 * @param v1 A event stack to roll up.
 * @param args variadic arcs passed down to the next recursion.
 * @tparam Args Types for variadic.
 * @return Vector of OpenCL events
 */
template <typename... Args>
inline const std::vector<cl::Event> event_concat_cl(
    const std::vector<cl::Event>& v1, const Args... args) {
  std::vector<cl::Event> vec_concat = event_concat_cl(args...);
  vec_concat.insert(vec_concat.end(), v1.begin(), v1.end());
  return vec_concat;
}

/**
 * Get the event stack from a matrix_cl.
 * @param A matrix holding an event stack.
 * @param args variadic arcs passed down to the next recursion.
 * @tparam Args Types for variadic.
 * @return Vector of OpenCL events
 */
template <typename... Args>
inline const std::vector<cl::Event> event_concat_cl(const matrix_cl& A,
                                                    const Args... args) {
  return event_concat_cl(A.events(), args...);
}

/**
 * Recursion when called from within matrix_cl.
 * @param A A pointer to a matrix_cl type, this is called from within a
 * matrix_cl.
 * @param args variadic arcs passed down to the next recursion.
 * @tparam Args Types for variadic.
 * @return Vector of OpenCL events
 */
template <typename... Args>
inline const std::vector<cl::Event> event_concat_cl(const matrix_cl* const& A,
                                                    const Args... args) {
  return event_concat_cl(A->events(), args...);
}
}  // namespace math
}  // namespace stan

#endif
#endif
<commit_msg>[Jenkins] auto-formatting by clang-format version 5.0.0-3~16.04.1 (tags/RELEASE_500/final)<commit_after>#ifndef STAN_MATH_OPENCL_EVENT_CONCAT_CL_HPP
#define STAN_MATH_OPENCL_EVENT_CONCAT_CL_HPP
#ifdef STAN_OPENCL

#include <stan/math/opencl/matrix_cl.hpp>
#include <CL/cl.hpp>
#include <type_traits>
#include <vector>

namespace stan {
namespace math {

/**
 * Template check for if type has event stack
 * @tparam Type to check.
 * @return enum with false value if type does not have an event stack.
 */
template <typename T>
struct has_event_stack {
  enum { value = false };
};

/**
 * Template check for if type has event stack
 * @tparam Type to check.
 * @return enum with false value if type does not have an event stack.
 */
template <>
struct has_event_stack<matrix_cl> {
  enum { value = true };
};

/**
 * Template check for if type has event stack
 * @tparam Type to check.
 * @return enum with true value if type does not have an event stack.
 */
template <>
struct has_event_stack<std::vector<cl::Event>> {
  enum { value = true };
};

/**
 * Helper template that enables function if type has event stack.
 * @tparam Type to check.
 * @return None, will fail compilation and pass to next template ala SFINAE.
 */
template <typename T>
using enable_if_has_event_stack
    = std::enable_if_t<has_event_stack<T>::value, int>;

/**
 * Helper template that enables function if type does not have event stack.
 * @tparam Type to check.
 * @return None, will fail compilation and pass to next template ala SFINAE.
 */
template <typename T>
using enable_if_no_event_stack
    = std::enable_if_t<!has_event_stack<T>::value, int>;

/**
 * Ends the recurstion to extract the event stack.
 * @return An empty event vector.
 */
inline const void event_concat_cl() {}

/**
 * Ends the recursion to extract the event stack.
 * @param v1 Events on the OpenCL event stack.
 * @return returns input vector.
 */
inline const std::vector<cl::Event>& event_concat_cl(
    const std::vector<cl::Event>& v1) {
  return v1;
}

/**
 * Ends the recursion to extract the event stack.
 * @param A OpenCL matrix holding the events.
 * @return The event stack for the matrix.
 */
inline const std::vector<cl::Event>& event_concat_cl(const matrix_cl& A) {
  return A.events();
}

/**
 * Ends the recurstion to extract the event stack.
 * @param throwaway_val A value that does not have an event stack.
 * @tparam T checks if either has an event stack and if not then fails
 * compilation.
 * @return An empty event vector.
 */
template <typename T, enable_if_no_event_stack<T> = 0>
inline const std::vector<cl::Event> event_concat_cl(const T& throwaway_val) {
  const std::vector<cl::Event> vec_concat;
  return vec_concat;
}

/**
 * Passes over an argument without an event stack.
 * @param throwaway_val A value that does not have an event stack.
 * @param args variadic arcs passed down to the next recursion.
 * @tparam T checks if either has an event stack and if not then fails
 * compilation.
 * @tparam Args Types for variadic.
 * @return An empty event vector.
 */
template <typename T, enable_if_no_event_stack<T> = 0, typename... Args>
inline const std::vector<cl::Event> event_concat_cl(const T& throwaway_val,
                                                    const Args... args) {
  return event_concat_cl(args...);
}

/**
 * Gets the event stack from a vector of events and other arguments.
 * @param v1 A event stack to roll up.
 * @param args variadic arcs passed down to the next recursion.
 * @tparam Args Types for variadic.
 * @return Vector of OpenCL events
 */
template <typename... Args>
inline const std::vector<cl::Event> event_concat_cl(
    const std::vector<cl::Event>& v1, const Args... args) {
  std::vector<cl::Event> vec_concat = event_concat_cl(args...);
  vec_concat.insert(vec_concat.end(), v1.begin(), v1.end());
  return vec_concat;
}

/**
 * Get the event stack from a matrix_cl.
 * @param A matrix holding an event stack.
 * @param args variadic arcs passed down to the next recursion.
 * @tparam Args Types for variadic.
 * @return Vector of OpenCL events
 */
template <typename... Args>
inline const std::vector<cl::Event> event_concat_cl(const matrix_cl& A,
                                                    const Args... args) {
  return event_concat_cl(A.events(), args...);
}

/**
 * Recursion when called from within matrix_cl.
 * @param A A pointer to a matrix_cl type, this is called from within a
 * matrix_cl.
 * @param args variadic arcs passed down to the next recursion.
 * @tparam Args Types for variadic.
 * @return Vector of OpenCL events
 */
template <typename... Args>
inline const std::vector<cl::Event> event_concat_cl(const matrix_cl* const& A,
                                                    const Args... args) {
  return event_concat_cl(A->events(), args...);
}
}  // namespace math
}  // namespace stan

#endif
#endif
<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////////
// oxygenwidgetexplorer.cpp
// print widget's and parent's information on mouse click
// -------------------
//
// Copyright (c) 2010 Hugo Pereira Da Costa <hugo.pereira@free.fr>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//////////////////////////////////////////////////////////////////////////////

#include "oxygenwidgetexplorer.h"

#include <QtCore/QTextStream>
#include <QApplication>
#include <QtGui/QMouseEvent>
#include <QtGui/QPainter>

namespace Oxygen
{

    //________________________________________________
    WidgetExplorer::WidgetExplorer( QObject* parent ):
        QObject( parent ),
        _enabled( false ),
        _drawWidgetRects( false )
    {

        _eventTypes.insert( QEvent::Enter, "Enter" );
        _eventTypes.insert( QEvent::Leave, "Leave" );

        _eventTypes.insert( QEvent::HoverMove, "HoverMove" );
        _eventTypes.insert( QEvent::HoverEnter, "HoverEnter" );
        _eventTypes.insert( QEvent::HoverLeave, "HoverLeave" );

        _eventTypes.insert( QEvent::MouseMove, "MouseMove" );
        _eventTypes.insert( QEvent::MouseButtonPress, "MouseButtonPress" );
        _eventTypes.insert( QEvent::MouseButtonRelease, "MouseButtonRelease" );

        _eventTypes.insert( QEvent::FocusIn, "FocusIn" );
        _eventTypes.insert( QEvent::FocusOut, "FocusOut" );

        // _eventTypes.insert( QEvent::Paint, "Paint" );

    }

    //________________________________________________
    void WidgetExplorer::setEnabled( bool value )
    {
        if( value == _enabled ) return;
        _enabled = value;

        qApp->removeEventFilter( this );
        if( _enabled )  qApp->installEventFilter( this );
    }

    //________________________________________________
    bool WidgetExplorer::eventFilter( QObject* object, QEvent* event )
    {

        if( object->isWidgetType() )
        {
            QString type( _eventTypes[event->type()] );
            if( !type.isEmpty() )
            {
                QTextStream( stdout ) << "Oxygen::WidgetExplorer::eventFilter - widget: " << object << " (" << object->metaObject()->className() << ")";
                QTextStream( stdout ) << " type: " << type  << endl;
            }
        }

        switch( event->type() )
        {
            case QEvent::Paint:
            if( _drawWidgetRects )
            {
                QWidget* widget( qobject_cast<QWidget*>( object ) );
                if( !widget ) return false;

                QPainter painter( widget );
                painter.setRenderHints(QPainter::Antialiasing);
                painter.setBrush( Qt::NoBrush );
                painter.setPen( Qt::red );
                painter.drawRect( widget->rect() );
                painter.end();
            }
            break;

            case QEvent::MouseButtonPress:
            {

                // cast event and check button
                QMouseEvent* mouseEvent( static_cast<QMouseEvent*>( event ) );
                if( mouseEvent->button() != Qt::LeftButton ) break;

                // case widget and check (should not be necessary)
                QWidget* widget( qobject_cast<QWidget*>(object) );
                if( !widget ) return false;

                QTextStream( stdout )
                    << "Oxygen::WidgetExplorer::eventFilter -"
                    << " event: " << event << " type: " << eventType( event->type() )
                    << " widget: " << widgetInformation( widget )
                    << endl;

                // print parent information
                QWidget* parent( widget->parentWidget() );
                while( parent )
                {
                    QTextStream( stdout ) << "    parent: " << widgetInformation( parent ) << endl;
                    parent = parent->parentWidget();
                }
                QTextStream( stdout ) << "" << endl;

            }
            break;

            default: break;

        }

        // always return false to go on with normal chain
        return false;

    }

    //________________________________________________
    QString WidgetExplorer::eventType( const QEvent::Type& type ) const
    {
        switch( type )
        {
            case QEvent::MouseButtonPress: return "MouseButtonPress";
            case QEvent::MouseButtonRelease: return "MouseButtonRelease";
            case QEvent::MouseMove: return "MouseMove";
            default: return "Unknown";
        }
    }

    //________________________________________________
    QString WidgetExplorer::widgetInformation( const QWidget* widget ) const
    {

        QRect r( widget->geometry() );
        QString className( widget->metaObject()->className() );
        QString out;
        QTextStream( &out ) << widget << " (" << className << ")"
            << " position: " << r.x() << "," << r.y()
            << " size: " << r.width() << "," << r.height()
            << " hover: " << widget->testAttribute( Qt::WA_Hover );
        return out;
    }

}
<commit_msg>Unuse QTextStream::endl, which doesn't exist in Qt6<commit_after>//////////////////////////////////////////////////////////////////////////////
// oxygenwidgetexplorer.cpp
// print widget's and parent's information on mouse click
// -------------------
//
// Copyright (c) 2010 Hugo Pereira Da Costa <hugo.pereira@free.fr>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//////////////////////////////////////////////////////////////////////////////

#include "oxygenwidgetexplorer.h"

#include <QtCore/QTextStream>
#include <QApplication>
#include <QtGui/QMouseEvent>
#include <QtGui/QPainter>

namespace Oxygen
{

    //________________________________________________
    WidgetExplorer::WidgetExplorer( QObject* parent ):
        QObject( parent ),
        _enabled( false ),
        _drawWidgetRects( false )
    {

        _eventTypes.insert( QEvent::Enter, "Enter" );
        _eventTypes.insert( QEvent::Leave, "Leave" );

        _eventTypes.insert( QEvent::HoverMove, "HoverMove" );
        _eventTypes.insert( QEvent::HoverEnter, "HoverEnter" );
        _eventTypes.insert( QEvent::HoverLeave, "HoverLeave" );

        _eventTypes.insert( QEvent::MouseMove, "MouseMove" );
        _eventTypes.insert( QEvent::MouseButtonPress, "MouseButtonPress" );
        _eventTypes.insert( QEvent::MouseButtonRelease, "MouseButtonRelease" );

        _eventTypes.insert( QEvent::FocusIn, "FocusIn" );
        _eventTypes.insert( QEvent::FocusOut, "FocusOut" );

        // _eventTypes.insert( QEvent::Paint, "Paint" );

    }

    //________________________________________________
    void WidgetExplorer::setEnabled( bool value )
    {
        if( value == _enabled ) return;
        _enabled = value;

        qApp->removeEventFilter( this );
        if( _enabled )  qApp->installEventFilter( this );
    }

    //________________________________________________
    bool WidgetExplorer::eventFilter( QObject* object, QEvent* event )
    {

        if( object->isWidgetType() )
        {
            QString type( _eventTypes[event->type()] );
            if( !type.isEmpty() )
            {
                QTextStream( stdout ) << "Oxygen::WidgetExplorer::eventFilter - widget: " << object << " (" << object->metaObject()->className() << ")";
                QTextStream( stdout ) << " type: " << type  << '\n';
            }
        }

        switch( event->type() )
        {
            case QEvent::Paint:
            if( _drawWidgetRects )
            {
                QWidget* widget( qobject_cast<QWidget*>( object ) );
                if( !widget ) return false;

                QPainter painter( widget );
                painter.setRenderHints(QPainter::Antialiasing);
                painter.setBrush( Qt::NoBrush );
                painter.setPen( Qt::red );
                painter.drawRect( widget->rect() );
                painter.end();
            }
            break;

            case QEvent::MouseButtonPress:
            {

                // cast event and check button
                QMouseEvent* mouseEvent( static_cast<QMouseEvent*>( event ) );
                if( mouseEvent->button() != Qt::LeftButton ) break;

                // case widget and check (should not be necessary)
                QWidget* widget( qobject_cast<QWidget*>(object) );
                if( !widget ) return false;

                QTextStream( stdout )
                    << "Oxygen::WidgetExplorer::eventFilter -"
                    << " event: " << event << " type: " << eventType( event->type() )
                    << " widget: " << widgetInformation( widget )
                    << '\n';

                // print parent information
                QWidget* parent( widget->parentWidget() );
                while( parent )
                {
                    QTextStream( stdout ) << "    parent: " << widgetInformation( parent ) << '\n';
                    parent = parent->parentWidget();
                }
                QTextStream( stdout ) << "\n";

            }
            break;

            default: break;

        }

        // always return false to go on with normal chain
        return false;

    }

    //________________________________________________
    QString WidgetExplorer::eventType( const QEvent::Type& type ) const
    {
        switch( type )
        {
            case QEvent::MouseButtonPress: return "MouseButtonPress";
            case QEvent::MouseButtonRelease: return "MouseButtonRelease";
            case QEvent::MouseMove: return "MouseMove";
            default: return "Unknown";
        }
    }

    //________________________________________________
    QString WidgetExplorer::widgetInformation( const QWidget* widget ) const
    {

        QRect r( widget->geometry() );
        QString className( widget->metaObject()->className() );
        QString out;
        QTextStream( &out ) << widget << " (" << className << ")"
            << " position: " << r.x() << "," << r.y()
            << " size: " << r.width() << "," << r.height()
            << " hover: " << widget->testAttribute( Qt::WA_Hover );
        return out;
    }

}
<|endoftext|>


<commit_before>// Copyright (c) 2013, Manuel Blum
// All rights reserved.

#include <Eigen/Dense>
#include <gtest/gtest.h>

#include "nn.h"

TEST(nn, sigmoid1)
{
    matrix_t X(3,3);
    matrix_t s(3,3);
    X << -2, -1.5, -1, -0.5, 0, 0.5, 1, 1.5, 2;
    s <<  0.1192, 0.1824, 0.2689, 0.3775, 0.5, 0.6225, 0.7311, 0.8176, 0.8808;
    matrix_t Y = NeuralNet::sigmoid(X);
    ASSERT_NEAR((Y.array()-s.array()).maxCoeff(), 0.0, 1e-4);
}

TEST(nn, sigmoid2)
{
    matrix_t X = matrix_t::Random(100,200) * 2;
    matrix_t Y = NeuralNet::sigmoid(X);
    ASSERT_EQ(X.rows(), Y.rows());
    ASSERT_EQ(X.cols(), Y.cols());

    for (int i=0; i<X.rows(); ++i)
    {
        for (int j=0; j<X.cols(); ++j)
        {
            ASSERT_NEAR(Y(i,j), 1/(1+exp(-X(i,j))), 1e-7);
        }
    }
}

TEST(nn, sigmoid_gradient1)
{
    matrix_t X(3,3);
    matrix_t s(3,3);
    X << -2, -1.5, -1, -0.5, 0, 0.5, 1, 1.5, 2;
    s <<  0.105, 0.1491, 0.1966, 0.2350, 0.25, 0.2350, 0.1966, 0.1491, 0.1050;
    matrix_t sig = NeuralNet::sigmoid(X);
    matrix_t Y = NeuralNet::sigmoid_gradient(sig);
    ASSERT_NEAR((Y.array()-s.array()).maxCoeff(), 0.0, 1e-4);
}

TEST(nn, sigmoid_gradient2)
{
    matrix_t X = matrix_t::Random(100,200) * 2;
    matrix_t sig = NeuralNet::sigmoid(X);
    matrix_t Y = NeuralNet::sigmoid_gradient(sig);
    ASSERT_EQ(X.rows(), Y.rows());
    ASSERT_EQ(X.cols(), Y.cols());

    for (int i=0; i<X.rows(); ++i)
    {
        for (int j=0; j<X.cols(); ++j)
        {
            double sigmoid = 1/(1+exp(-X(i,j)));
            ASSERT_NEAR(Y(i,j), sigmoid*(1-sigmoid), 1e-9);
        }
    }
}

// compare analytical with numerical gradients
TEST(nn, gradient)
{
    Eigen::VectorXi topo(4);
    topo << 3, 10, 10, 2;
    NeuralNet nn(topo);
    nn.init_weights(0.5);
    int m = 100;
    matrix_t X = matrix_t::Random(m,3);
    matrix_t Y = matrix_t::Random(m,2);
    Y *= 0.5+0.5;
    double lambda = 0.01;
    double e = 1e-4;
    ASSERT_EQ(nn.layer[0].size, topo(0));

    for (int i=1; i<nn.layer.size(); ++i)
    {
        ASSERT_EQ(nn.layer[i].W.rows(), nn.layer[i].size);
        ASSERT_EQ(nn.layer[i].W.cols(), nn.layer[i-1].size);
        ASSERT_EQ(nn.layer[i].b.rows(), nn.layer[i].size);
        ASSERT_EQ(nn.layer[i].size, topo(i));

        for (int j=0; j<nn.layer[i].W.rows(); ++j)
        {
            for (int k=0; k<nn.layer[i].W.cols(); ++k)
            {
                double w = nn.layer[i].W(j,k);
                nn.layer[i].W(j,k) = w - e;
                double j1 = nn.loss(X, Y, lambda);
                nn.layer[i].W(j,k) = w + e;
                double j2 = nn.loss(X, Y, lambda);
                nn.layer[i].W(j,k) = w;
                nn.loss(X, Y, lambda);
                ASSERT_NEAR((j2-j1)/(2*e), nn.layer[i].dEdW(j,k), 1e-9);
            }
        }

        for (int j=0; j<nn.layer[i].b.rows(); ++j)
        {
            double b = nn.layer[i].b(j);
            nn.layer[i].b(j) = b - e;
            double j1 = nn.loss(X, Y, lambda);
            nn.layer[i].b(j) = b + e;
            double j2 = nn.loss(X, Y, lambda);
            nn.layer[i].b(j) = b;
            nn.loss(X, Y, lambda);
            ASSERT_NEAR((j2-j1)/(2*e), nn.layer[i].dEdb(j), 1e-9);
        }
    }
}

TEST(nn, readwrite)
{
    Eigen::VectorXi topo(4);
    topo << 3, 10, 10, 2;
    NeuralNet nn(topo);
    nn.init_weights(0.5);
    nn.write("testnet.nn");
    NeuralNet nnclone("testnet.nn");
    ASSERT_EQ(topo.size(), nnclone.layer.size());

    for (int i=0; i<topo.size(); ++i)
    {
        ASSERT_EQ(topo(i), nnclone.layer[i].size);
    }

    for (int i=1; i<nn.layer.size(); ++i)
    {
        for (int j=0; j<nn.layer[i].W.rows(); ++j)
        {
            for (int k=0; k<nn.layer[i].W.cols(); ++k)
            {
                ASSERT_NEAR(nn.layer[i].W(j,k), nnclone.layer[i].W(j,k), 1e-12);
            }
        }

        for (int j=0; j<nn.layer[i].b.rows(); ++j)
        {
            ASSERT_NEAR(nn.layer[i].b(j), nnclone.layer[i].b(j), 1e-12);
        }
    }
}

TEST(nn, testfunction)
{
    srand((unsigned int) time(NULL));
    Eigen::VectorXi topo(4);
    topo << 2, 10, 10, 1;
    NeuralNet nn(topo);
    matrix_t X = matrix_t::Random(1000,2);
    matrix_t Y = matrix_t::Random(1000,1);

    for (int i=0; i<X.rows(); ++i)
    {
        Y(i,0) = (X(i,0) * X(i,1) + 1.2)*0.4;
    }

    double lambda = 0.01, err;

    for (int i=0; i<300; ++i)
    {
        err = nn.loss(X, Y, lambda);
        nn.rprop();
    }

    ASSERT_LE(err, 0.01);
    nn.write("testnet.nn");
    NeuralNet nnclone("testnet.nn");
    ASSERT_NEAR(nn.loss(X, Y, lambda), nnclone.loss(X, Y, lambda), 1e-12);
}
<commit_msg>Fixing another bug that caused target values to be out of range<commit_after>// Copyright (c) 2013, Manuel Blum
// All rights reserved.

#include <Eigen/Dense>
#include <gtest/gtest.h>

#include "nn.h"

TEST(nn, sigmoid1)
{
    matrix_t X(3,3);
    matrix_t s(3,3);
    X << -2, -1.5, -1, -0.5, 0, 0.5, 1, 1.5, 2;
    s <<  0.1192, 0.1824, 0.2689, 0.3775, 0.5, 0.6225, 0.7311, 0.8176, 0.8808;
    matrix_t Y = NeuralNet::sigmoid(X);
    ASSERT_NEAR((Y.array()-s.array()).maxCoeff(), 0.0, 1e-4);
}

TEST(nn, sigmoid2)
{
    matrix_t X = matrix_t::Random(100,200) * 2;
    matrix_t Y = NeuralNet::sigmoid(X);
    ASSERT_EQ(X.rows(), Y.rows());
    ASSERT_EQ(X.cols(), Y.cols());

    for (int i=0; i<X.rows(); ++i)
    {
        for (int j=0; j<X.cols(); ++j)
        {
            ASSERT_NEAR(Y(i,j), 1/(1+exp(-X(i,j))), 1e-7);
        }
    }
}

TEST(nn, sigmoid_gradient1)
{
    matrix_t X(3,3);
    matrix_t s(3,3);
    X << -2, -1.5, -1, -0.5, 0, 0.5, 1, 1.5, 2;
    s <<  0.105, 0.1491, 0.1966, 0.2350, 0.25, 0.2350, 0.1966, 0.1491, 0.1050;
    matrix_t sig = NeuralNet::sigmoid(X);
    matrix_t Y = NeuralNet::sigmoid_gradient(sig);
    ASSERT_NEAR((Y.array()-s.array()).maxCoeff(), 0.0, 1e-4);
}

TEST(nn, sigmoid_gradient2)
{
    matrix_t X = matrix_t::Random(100,200) * 2;
    matrix_t sig = NeuralNet::sigmoid(X);
    matrix_t Y = NeuralNet::sigmoid_gradient(sig);
    ASSERT_EQ(X.rows(), Y.rows());
    ASSERT_EQ(X.cols(), Y.cols());

    for (int i=0; i<X.rows(); ++i)
    {
        for (int j=0; j<X.cols(); ++j)
        {
            double sigmoid = 1/(1+exp(-X(i,j)));
            ASSERT_NEAR(Y(i,j), sigmoid*(1-sigmoid), 1e-9);
        }
    }
}

// compare analytical with numerical gradients
TEST(nn, gradient)
{
    Eigen::VectorXi topo(4);
    topo << 3, 10, 10, 2;
    NeuralNet nn(topo);
    nn.init_weights(0.5);
    int m = 100;
    matrix_t X = matrix_t::Random(m,3);
    matrix_t Y = matrix_t::Random(m,2);
    Y = Y.array() * 0.4 + 0.5;
    ASSERT_GE(Y.minCoeff(), 0.1);
    ASSERT_LE(Y.maxCoeff(), 0.9);
    double lambda = 0.01;
    double e = 1e-4;
    ASSERT_EQ(nn.layer[0].size, topo(0));

    for (int i=1; i<nn.layer.size(); ++i)
    {
        ASSERT_EQ(nn.layer[i].W.rows(), nn.layer[i].size);
        ASSERT_EQ(nn.layer[i].W.cols(), nn.layer[i-1].size);
        ASSERT_EQ(nn.layer[i].b.rows(), nn.layer[i].size);
        ASSERT_EQ(nn.layer[i].size, topo(i));

        for (int j=0; j<nn.layer[i].W.rows(); ++j)
        {
            for (int k=0; k<nn.layer[i].W.cols(); ++k)
            {
                double w = nn.layer[i].W(j,k);
                nn.layer[i].W(j,k) = w - e;
                double j1 = nn.loss(X, Y, lambda);
                nn.layer[i].W(j,k) = w + e;
                double j2 = nn.loss(X, Y, lambda);
                nn.layer[i].W(j,k) = w;
                nn.loss(X, Y, lambda);
                ASSERT_NEAR((j2-j1)/(2*e), nn.layer[i].dEdW(j,k), 1e-9);
            }
        }

        for (int j=0; j<nn.layer[i].b.rows(); ++j)
        {
            double b = nn.layer[i].b(j);
            nn.layer[i].b(j) = b - e;
            double j1 = nn.loss(X, Y, lambda);
            nn.layer[i].b(j) = b + e;
            double j2 = nn.loss(X, Y, lambda);
            nn.layer[i].b(j) = b;
            nn.loss(X, Y, lambda);
            ASSERT_NEAR((j2-j1)/(2*e), nn.layer[i].dEdb(j), 1e-9);
        }
    }
}

TEST(nn, readwrite)
{
    Eigen::VectorXi topo(4);
    topo << 3, 10, 10, 2;
    NeuralNet nn(topo);
    nn.init_weights(0.5);
    nn.write("testnet.nn");
    NeuralNet nnclone("testnet.nn");
    ASSERT_EQ(topo.size(), nnclone.layer.size());

    for (int i=0; i<topo.size(); ++i)
    {
        ASSERT_EQ(topo(i), nnclone.layer[i].size);
    }

    for (int i=1; i<nn.layer.size(); ++i)
    {
        for (int j=0; j<nn.layer[i].W.rows(); ++j)
        {
            for (int k=0; k<nn.layer[i].W.cols(); ++k)
            {
                ASSERT_NEAR(nn.layer[i].W(j,k), nnclone.layer[i].W(j,k), 1e-12);
            }
        }

        for (int j=0; j<nn.layer[i].b.rows(); ++j)
        {
            ASSERT_NEAR(nn.layer[i].b(j), nnclone.layer[i].b(j), 1e-12);
        }
    }
}

TEST(nn, testfunction)
{
    srand((unsigned int) time(NULL));
    Eigen::VectorXi topo(4);
    topo << 2, 10, 10, 1;
    NeuralNet nn(topo);
    matrix_t X = matrix_t::Random(1000,2);
    matrix_t Y = matrix_t::Random(1000,1);

    for (int i=0; i<X.rows(); ++i)
    {
        Y(i,0) = (X(i,0) * X(i,1) + 1.2)*0.4;
    }

    double lambda = 0.01, err;

    for (int i=0; i<300; ++i)
    {
        err = nn.loss(X, Y, lambda);
        nn.rprop();
    }

    ASSERT_LE(err, 0.01);
    nn.write("testnet.nn");
    NeuralNet nnclone("testnet.nn");
    ASSERT_NEAR(nn.loss(X, Y, lambda), nnclone.loss(X, Y, lambda), 1e-12);
}
<|endoftext|>


<commit_before>/*
 *	Manipulator.cpp
 *	Nashoba Robotics 2011
 *
 *	Copyright 2011 Nick Alberts
 *	All Rights Reserved
 */

#include "Manipulator.h"

Manipulator::Manipulator( Joystick &joy ):
	joystick( joy )
{

}

void Manipulator::Run( void* ) throw ()
{
	// TODO: resolve issue of getting state of robot in Manipulator thread and object

	//claw.Grab();
	//claw.ClawTest();

	while ( RobotBase::getInstance().IsOperatorControl() )
	{

		if (joystick.GetRawButton(8))
		{
			arm.SimpleUpperArm( joystick.GetY() );
		}
		if (joystick.GetRawButton(2))
		{
			claw.Grab();
		}
		if (joystick.GetRawButton(1))
		{
			claw.Release();
		}
		if (joystick.GetRawButton(3))
		{
			claw.RotateUp();
		}
		if (joystick.GetRawButton(4))
		{
			claw.RotateDown();
		}
		if (joystick.GetRawButton(5))
		{
			arm.SetLowerArm(true);
		}
		if (joystick.GetRawButton(6))
		{
			arm.SetLowerArm(false);
		}
		if (joystick.GetRawButton(10))
		{
			arm.SetLowerArm(true);
			arm.SetUpperArm(-1953);
		}
		if (joystick.GetRawButton(7))
		{
			arm.SetLowerArm(false);
			arm.SetUpperArm(-800);
		}
		if(joystick.GetRawButton(11))
		{
			arm.SetLowerArm(false);
			arm.SetUpperArm(-50);
		}
		if (joystick.GetRawButton(9))
		{
			GoDown();
		}
		arm.encoderValue = arm.armEncoder.Get();

		/*
		/*
		claw.clawServoBottom1.SetRaw(0);
		claw.clawServoTop4.SetRaw(0);
		claw.clawServoTop3.SetRaw(0);
		claw.clawServoBottom2.SetRaw(0);
		Wait(4.0f);

		claw.clawServoBottom1.SetRaw(255);
		claw.clawServoBottom2.SetRaw(1);
		claw.clawServoTop4.SetRaw(255);
		claw.clawServoTop3.SetRaw(1);
		Wait(4.0f);
		/*
		printf("A\n");

		Wait(4.0f);

		claw.clawServoBottom1.Set(0.0f);
		claw.clawServoBottom2.Set(1.0f);
		claw.clawServoTop4.Set(0.0f);
		claw.clawServoTop3.Set(1.0f);

		printf("B\n");

		Wait(1.0f);

		/*
		if (joystick.GetRawButton(2))
		{
			if (arm.lowerArm)
			{
				arm.SetLowerArm(true);
			}
			if ( ! arm.lowerArm)
			{
				arm.SetLowerArm(false);
			}
		}

		/*
		claw.ClawTest();
		//claw.SimpleGripper( joystick.GetY() );
		*/

		/*
		claw.clawServoBottom1.Set( ((joystick.GetY())+1.0f )/2.0f );
		claw.clawServoBottom2.Set( 1.0f-((joystick.GetY())+1.0f)/2.0f);
		claw.clawServoTop4.Set( 1.0f-((joystick.GetX())+1.0f)/2.0f);
		claw.clawServoTop3.Set( ((joystick.GetX())+1.0f )/2.0f );Wait(0.05);
		Wait(0.05);
		/*
		dashboard.AddFloat(((joystick.GetY())+1.0f )/2.0f);
		dashboard.AddFloat(((joystick.GetX())+1.0f )/2.0f);
		dashboard.AddFloat(1.0f-((joystick.GetX())+1.0f)/2.0f);
		dashboard.AddFloat(1.0f-((joystick.GetY())+1.0f)/2.0f);
		*/
		//printf("%x\n",arm.armSolenoidRaise.GetAll());
		printf("%f",arm.armMotor.Get());
		Wait(0.05);
	}
}

void Manipulator::GoDown()
{
	arm.SetLowerArm(false);
	Wait(1.5f);
	arm.SetUpperArm(-70);
}

<commit_msg>Removed extraneous comments and debugging, added spaces<commit_after>/*
 *	Manipulator.cpp
 *	Nashoba Robotics 2011
 *
 *	Copyright 2011 Nick Alberts
 *	All Rights Reserved
 */

#include "Manipulator.h"

Manipulator::Manipulator( Joystick &joy ):
	joystick( joy )
{

}

void Manipulator::Run( void* ) throw ()
{
	// TODO: resolve issue of getting state of robot in Manipulator thread and object

	//claw.Grab();
	//claw.ClawTest();

	while ( RobotBase::getInstance().IsOperatorControl() )
	{

		if ( joystick.GetRawButton( 8 ) )
			arm.SimpleUpperArm( joystick.GetY() );

		if ( joystick.GetRawButton( 2 ) )
			claw.Grab();

		if ( joystick.GetRawButton( 1 ) )
			claw.Release();

		if ( joystick.GetRawButton( 3 ) )
			claw.RotateUp();

		if ( joystick.GetRawButton( 4 ) )
			claw.RotateDown();

		if ( joystick.GetRawButton( 5 ) )
			arm.SetLowerArm( true );

		if ( joystick.GetRawButton( 6 ) )
			arm.SetLowerArm( false );

		if ( joystick.GetRawButton( 10 ) )
		{
			arm.SetLowerArm( true );
			arm.SetUpperArm( -1953 );
		}

		if ( joystick.GetRawButton( 7 ) )
		{
			arm.SetLowerArm( false );
			arm.SetUpperArm( -800 );
		}

		if ( joystick.GetRawButton( 11 ) )
		{
			arm.SetLowerArm( false );
			arm.SetUpperArm( -50 );
		}

		if ( joystick.GetRawButton( 9 ) )
			GoDown();

		arm.encoderValue = arm.armEncoder.Get();

		Wait(0.05);
	}
}

void Manipulator::GoDown()
{
	arm.SetLowerArm( false );
	Wait( 1.5f );
	arm.SetUpperArm( -70 );
}

<|endoftext|>