<commit_before>/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company.  For licensing terms and
** conditions see http://www.qt.io/terms-conditions.  For further information
** use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, The Qt Company gives you certain additional
** rights.  These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "qmlprofilerclientmanager.h"
#include "qmlprofilertool.h"
#include "qmlprofilerplugin.h"

#include <qmldebug/qmldebugclient.h>
#include <qmldebug/qmlprofilertraceclient.h>

#include <utils/qtcassert.h>
#include <QPointer>
#include <QTimer>
#include <QMessageBox>

#include "qmlprofilermodelmanager.h"

using namespace QmlDebug;
using namespace Core;

namespace QmlProfiler {
namespace Internal {

class QmlProfilerClientManager::QmlProfilerClientManagerPrivate
{
public:
    QmlProfilerStateManager *profilerState;

    QmlDebugConnection *connection;
    QPointer<QmlProfilerTraceClient> qmlclientplugin;

    QTimer connectionTimer;
    int connectionAttempts;

    enum ConnectMode {
        TcpConnection, OstConnection
    };
    ConnectMode connectMode;
    QString tcpHost;
    quint64 tcpPort;
    QString ostDevice;
    QString sysroot;

    bool qmlDataReady;

    QmlProfilerModelManager *modelManager;
};

QmlProfilerClientManager::QmlProfilerClientManager(QObject *parent) :
    QObject(parent), d(new QmlProfilerClientManagerPrivate)
{
    setObjectName(QLatin1String("QML Profiler Connections"));

    d->profilerState = 0;

    d->connection = 0;
    d->connectionAttempts = 0;
    d->qmlDataReady = false;

    d->modelManager = 0;

    d->connectionTimer.setInterval(200);
    connect(&d->connectionTimer, SIGNAL(timeout()), SLOT(tryToConnect()));
}

QmlProfilerClientManager::~QmlProfilerClientManager()
{
    delete d->connection;
    delete d->qmlclientplugin.data();
    delete d;
}

void QmlProfilerClientManager::setModelManager(QmlProfilerModelManager *m)
{
    if (d->modelManager)
        disconnect(this,SIGNAL(dataReadyForProcessing()), d->modelManager, SLOT(complete()));
    d->modelManager = m;
    if (d->modelManager)
        connect(this,SIGNAL(dataReadyForProcessing()), d->modelManager, SLOT(complete()));
}

////////////////////////////////////////////////////////////////
// Interface
void QmlProfilerClientManager::setTcpConnection(QString host, quint64 port)
{
    d->connectMode = QmlProfilerClientManagerPrivate::TcpConnection;
    d->tcpHost = host;
    d->tcpPort = port;
}

void QmlProfilerClientManager::setOstConnection(QString ostDevice)
{
    d->connectMode = QmlProfilerClientManagerPrivate::OstConnection;
    d->ostDevice = ostDevice;
}

void QmlProfilerClientManager::clearBufferedData()
{
    if (d->qmlclientplugin)
        d->qmlclientplugin.data()->clearData();
}

void QmlProfilerClientManager::discardPendingData()
{
    clearBufferedData();
}

////////////////////////////////////////////////////////////////
// Internal
void QmlProfilerClientManager::connectClient(quint16 port)
{
    if (d->connection)
        delete d->connection;
    d->connection = new QmlDebugConnection;
    enableServices();
    connect(d->connection, SIGNAL(stateMessage(QString)), this, SLOT(logState(QString)));
    connect(d->connection, SIGNAL(errorMessage(QString)), this, SLOT(logState(QString)));
    connect(d->connection, SIGNAL(opened()), this, SLOT(qmlDebugConnectionOpened()));
    connect(d->connection, SIGNAL(closed()), this, SLOT(qmlDebugConnectionClosed()));
    d->connectionTimer.start();
    d->tcpPort = port;
}

void QmlProfilerClientManager::enableServices()
{
    QTC_ASSERT(d->profilerState, return);

    disconnectClientSignals();
    d->profilerState->setServerRecording(false); // false by default (will be set to true when connected)
    delete d->qmlclientplugin.data();
    d->qmlclientplugin = new QmlProfilerTraceClient(d->connection,
                                                    d->profilerState->recordingFeatures());
    connectClientSignals();
}

void QmlProfilerClientManager::connectClientSignals()
{
    QTC_ASSERT(d->profilerState, return);
    if (d->qmlclientplugin) {
        connect(d->qmlclientplugin.data(), SIGNAL(complete(qint64)),
                this, SLOT(qmlComplete(qint64)));
        connect(d->qmlclientplugin.data(),
                SIGNAL(rangedEvent(QmlDebug::Message,QmlDebug::RangeType,int,qint64,qint64,
                                   QString,QmlDebug::QmlEventLocation,qint64,qint64,qint64,
                                   qint64,qint64)),
                d->modelManager,
                SLOT(addQmlEvent(QmlDebug::Message,QmlDebug::RangeType,int,qint64,qint64,
                                 QString,QmlDebug::QmlEventLocation,qint64,qint64,qint64,qint64,
                                 qint64)));
        connect(d->qmlclientplugin.data(), SIGNAL(traceFinished(qint64,QList<int>)),
                d->modelManager->traceTime(), SLOT(increaseEndTime(qint64)));
        connect(d->qmlclientplugin.data(), SIGNAL(traceStarted(qint64,QList<int>)),
                d->modelManager->traceTime(), SLOT(decreaseStartTime(qint64)));
        connect(d->qmlclientplugin.data(), SIGNAL(enabledChanged()),
                d->qmlclientplugin.data(), SLOT(sendRecordingStatus()));
        // fixme: this should be unified for both clients
        connect(d->qmlclientplugin.data(), SIGNAL(recordingChanged(bool)),
                d->profilerState, SLOT(setServerRecording(bool)));
        connect(d->profilerState, SIGNAL(recordingFeaturesChanged(quint64)),
                d->qmlclientplugin.data(), SLOT(setFeatures(quint64)));
    }
}

void QmlProfilerClientManager::disconnectClientSignals()
{
    if (d->qmlclientplugin) {
        disconnect(d->qmlclientplugin.data(), SIGNAL(complete(qint64)),
                   this, SLOT(qmlComplete(qint64)));
        disconnect(d->qmlclientplugin.data(),
                   SIGNAL(rangedEvent(int,int,qint64,qint64,QStringList,QmlDebug::QmlEventLocation,
                                qint64,qint64,qint64,qint64,qint64)),
                   d->modelManager,
                   SLOT(addQmlEvent(int,int,qint64,qint64,QStringList,QmlDebug::QmlEventLocation,
                                    qint64,qint64,qint64,qint64,qint64)));
        disconnect(d->qmlclientplugin.data(), SIGNAL(traceFinished(qint64)),
                   d->modelManager->traceTime(), SLOT(increaseEndTime(qint64)));
        disconnect(d->qmlclientplugin.data(), SIGNAL(traceStarted(qint64)),
                   d->modelManager->traceTime(), SLOT(decreaseStartTime(qint64)));
        disconnect(d->qmlclientplugin.data(), SIGNAL(enabledChanged()),
                   d->qmlclientplugin.data(), SLOT(sendRecordingStatus()));
        // fixme: this should be unified for both clients
        disconnect(d->qmlclientplugin.data(), SIGNAL(recordingChanged(bool)),
                   d->profilerState, SLOT(setServerRecording(bool)));
        disconnect(d->profilerState, SIGNAL(recordingFeaturesChanged(quint64)),
                   d->qmlclientplugin.data(), SLOT(setFeatures(quint64)));
    }
}

void QmlProfilerClientManager::connectToClient()
{
    if (!d->connection || d->connection->isOpen() || d->connection->isConnecting())
        return;

    d->connection->connectToHost(d->tcpHost, d->tcpPort);
}

bool QmlProfilerClientManager::isConnected() const
{
    return d->connection && d->connection->isOpen();
}

void QmlProfilerClientManager::disconnectClient()
{
    // this might be actually be called indirectly by QDDConnectionPrivate::readyRead(), therefore allow
    // function to complete before deleting object
    if (d->connection) {
        d->connection->deleteLater();
        d->connection = 0;
    }
}

void QmlProfilerClientManager::tryToConnect()
{
    ++d->connectionAttempts;

    if (d->connection && d->connection->isOpen()) {
        d->connectionTimer.stop();
        d->connectionAttempts = 0;
    } else if (d->connectionAttempts == 50) {
        d->connectionTimer.stop();
        d->connectionAttempts = 0;

        QMessageBox *infoBox = QmlProfilerTool::requestMessageBox();
        infoBox->setIcon(QMessageBox::Critical);
        infoBox->setWindowTitle(tr("Qt Creator"));
        infoBox->setText(tr("Could not connect to the in-process QML profiler.\n"
                            "Do you want to retry?"));
        infoBox->setStandardButtons(QMessageBox::Retry |
                                    QMessageBox::Cancel |
                                    QMessageBox::Help);
        infoBox->setDefaultButton(QMessageBox::Retry);
        infoBox->setModal(true);

        connect(infoBox, SIGNAL(finished(int)),
                this, SLOT(retryMessageBoxFinished(int)));

        infoBox->show();
    } else {
        connectToClient();
    }
}

void QmlProfilerClientManager::qmlDebugConnectionOpened()
{
    logState(tr("Debug connection opened"));
    clientRecordingChanged();
}

void QmlProfilerClientManager::qmlDebugConnectionClosed()
{
    logState(tr("Debug connection closed"));
    disconnectClient();
    emit connectionClosed();
}

void QmlProfilerClientManager::logState(const QString &msg)
{
    QString state = QLatin1String("QML Profiler: ") + msg;
    if (QmlProfilerPlugin::debugOutput)
        qWarning() << state;
    QmlProfilerTool::logState(state);
}

void QmlProfilerClientManager::retryMessageBoxFinished(int result)
{
    QTC_ASSERT(!d->connection->isOpen(), return);
    if (d->connection->isConnecting())
        d->connection->disconnect();

    switch (result) {
    case QMessageBox::Retry: {
        d->connectionAttempts = 0;
        d->connectionTimer.start();
        break;
    }
    case QMessageBox::Help: {
        QmlProfilerTool::handleHelpRequest(QLatin1String("qthelp://org.qt-project.qtcreator/doc/creator-debugging-qml.html"));
        // fall through
    }
    default: {
        // The actual error message has already been logged.
        logState(tr("Failed to connect!"));
        emit connectionFailed();
        break;
    }
    }
}

void QmlProfilerClientManager::qmlComplete(qint64 maximumTime)
{
    d->modelManager->traceTime()->increaseEndTime(maximumTime);
    d->qmlDataReady = true;
    emit dataReadyForProcessing();
    // once complete is sent, reset the flags
    d->qmlDataReady = false;
}

void QmlProfilerClientManager::stopClientsRecording()
{
    if (d->qmlclientplugin)
        d->qmlclientplugin.data()->setRecording(false);
}

////////////////////////////////////////////////////////////////
// Profiler State
void QmlProfilerClientManager::registerProfilerStateManager( QmlProfilerStateManager *profilerState )
{
    if (d->profilerState) {
        disconnect(d->profilerState, SIGNAL(stateChanged()),
                   this, SLOT(profilerStateChanged()));
        disconnect(d->profilerState, SIGNAL(clientRecordingChanged()),
                   this, SLOT(clientRecordingChanged()));
        disconnect(d->profilerState, SIGNAL(serverRecordingChanged()),
                   this, SLOT(serverRecordingChanged()));
    }

    d->profilerState = profilerState;

    // connect
    if (d->profilerState) {
        connect(d->profilerState, SIGNAL(stateChanged()),
                this, SLOT(profilerStateChanged()));
        connect(d->profilerState, SIGNAL(clientRecordingChanged()),
                this, SLOT(clientRecordingChanged()));
        connect(d->profilerState, SIGNAL(serverRecordingChanged()),
                this, SLOT(serverRecordingChanged()));
    }
}

void QmlProfilerClientManager::profilerStateChanged()
{
    QTC_ASSERT(d->profilerState, return);
    switch (d->profilerState->currentState()) {
    case QmlProfilerStateManager::AppStopRequested :
        if (d->profilerState->serverRecording())
            stopClientsRecording();
        else
            d->profilerState->setCurrentState(QmlProfilerStateManager::AppReadyToStop);
        break;
    default:
        break;
    }
}

void QmlProfilerClientManager::clientRecordingChanged()
{
    QTC_ASSERT(d->profilerState, return);
    if (d->profilerState->currentState() == QmlProfilerStateManager::AppRunning) {
        if (d->qmlclientplugin)
            d->qmlclientplugin.data()->setRecording(d->profilerState->clientRecording());
    }
}

void QmlProfilerClientManager::serverRecordingChanged()
{
    if (d->profilerState->serverRecording())
        d->qmlDataReady = false;
}

} // namespace Internal
} // namespace QmlProfiler
<commit_msg>QmlProfiler: Don't try to disconnect connections that don't exist<commit_after>/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company.  For licensing terms and
** conditions see http://www.qt.io/terms-conditions.  For further information
** use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, The Qt Company gives you certain additional
** rights.  These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "qmlprofilerclientmanager.h"
#include "qmlprofilertool.h"
#include "qmlprofilerplugin.h"

#include <qmldebug/qmldebugclient.h>
#include <qmldebug/qmlprofilertraceclient.h>

#include <utils/qtcassert.h>
#include <QPointer>
#include <QTimer>
#include <QMessageBox>

#include "qmlprofilermodelmanager.h"

using namespace QmlDebug;
using namespace Core;

namespace QmlProfiler {
namespace Internal {

class QmlProfilerClientManager::QmlProfilerClientManagerPrivate
{
public:
    QmlProfilerStateManager *profilerState;

    QmlDebugConnection *connection;
    QPointer<QmlProfilerTraceClient> qmlclientplugin;

    QTimer connectionTimer;
    int connectionAttempts;

    enum ConnectMode {
        TcpConnection, OstConnection
    };
    ConnectMode connectMode;
    QString tcpHost;
    quint64 tcpPort;
    QString ostDevice;
    QString sysroot;

    bool qmlDataReady;

    QmlProfilerModelManager *modelManager;
};

QmlProfilerClientManager::QmlProfilerClientManager(QObject *parent) :
    QObject(parent), d(new QmlProfilerClientManagerPrivate)
{
    setObjectName(QLatin1String("QML Profiler Connections"));

    d->profilerState = 0;

    d->connection = 0;
    d->connectionAttempts = 0;
    d->qmlDataReady = false;

    d->modelManager = 0;

    d->connectionTimer.setInterval(200);
    connect(&d->connectionTimer, SIGNAL(timeout()), SLOT(tryToConnect()));
}

QmlProfilerClientManager::~QmlProfilerClientManager()
{
    delete d->connection;
    delete d->qmlclientplugin.data();
    delete d;
}

void QmlProfilerClientManager::setModelManager(QmlProfilerModelManager *m)
{
    if (d->modelManager)
        disconnect(this,SIGNAL(dataReadyForProcessing()), d->modelManager, SLOT(complete()));
    d->modelManager = m;
    if (d->modelManager)
        connect(this,SIGNAL(dataReadyForProcessing()), d->modelManager, SLOT(complete()));
}

////////////////////////////////////////////////////////////////
// Interface
void QmlProfilerClientManager::setTcpConnection(QString host, quint64 port)
{
    d->connectMode = QmlProfilerClientManagerPrivate::TcpConnection;
    d->tcpHost = host;
    d->tcpPort = port;
}

void QmlProfilerClientManager::setOstConnection(QString ostDevice)
{
    d->connectMode = QmlProfilerClientManagerPrivate::OstConnection;
    d->ostDevice = ostDevice;
}

void QmlProfilerClientManager::clearBufferedData()
{
    if (d->qmlclientplugin)
        d->qmlclientplugin.data()->clearData();
}

void QmlProfilerClientManager::discardPendingData()
{
    clearBufferedData();
}

////////////////////////////////////////////////////////////////
// Internal
void QmlProfilerClientManager::connectClient(quint16 port)
{
    if (d->connection)
        delete d->connection;
    d->connection = new QmlDebugConnection;
    enableServices();
    connect(d->connection, SIGNAL(stateMessage(QString)), this, SLOT(logState(QString)));
    connect(d->connection, SIGNAL(errorMessage(QString)), this, SLOT(logState(QString)));
    connect(d->connection, SIGNAL(opened()), this, SLOT(qmlDebugConnectionOpened()));
    connect(d->connection, SIGNAL(closed()), this, SLOT(qmlDebugConnectionClosed()));
    d->connectionTimer.start();
    d->tcpPort = port;
}

void QmlProfilerClientManager::enableServices()
{
    QTC_ASSERT(d->profilerState, return);

    disconnectClientSignals();
    d->profilerState->setServerRecording(false); // false by default (will be set to true when connected)
    delete d->qmlclientplugin.data();
    d->qmlclientplugin = new QmlProfilerTraceClient(d->connection,
                                                    d->profilerState->recordingFeatures());
    connectClientSignals();
}

void QmlProfilerClientManager::connectClientSignals()
{
    QTC_ASSERT(d->profilerState, return);
    if (d->qmlclientplugin) {
        connect(d->qmlclientplugin.data(), SIGNAL(complete(qint64)),
                this, SLOT(qmlComplete(qint64)));
        connect(d->qmlclientplugin.data(),
                SIGNAL(rangedEvent(QmlDebug::Message,QmlDebug::RangeType,int,qint64,qint64,
                                   QString,QmlDebug::QmlEventLocation,qint64,qint64,qint64,
                                   qint64,qint64)),
                d->modelManager,
                SLOT(addQmlEvent(QmlDebug::Message,QmlDebug::RangeType,int,qint64,qint64,
                                 QString,QmlDebug::QmlEventLocation,qint64,qint64,qint64,qint64,
                                 qint64)));
        connect(d->qmlclientplugin.data(), SIGNAL(traceFinished(qint64,QList<int>)),
                d->modelManager->traceTime(), SLOT(increaseEndTime(qint64)));
        connect(d->qmlclientplugin.data(), SIGNAL(traceStarted(qint64,QList<int>)),
                d->modelManager->traceTime(), SLOT(decreaseStartTime(qint64)));
        connect(d->qmlclientplugin.data(), SIGNAL(enabledChanged()),
                d->qmlclientplugin.data(), SLOT(sendRecordingStatus()));
        // fixme: this should be unified for both clients
        connect(d->qmlclientplugin.data(), SIGNAL(recordingChanged(bool)),
                d->profilerState, SLOT(setServerRecording(bool)));
        connect(d->profilerState, SIGNAL(recordingFeaturesChanged(quint64)),
                d->qmlclientplugin.data(), SLOT(setFeatures(quint64)));
    }
}

void QmlProfilerClientManager::disconnectClientSignals()
{
    if (d->qmlclientplugin) {
        disconnect(d->qmlclientplugin.data(), SIGNAL(complete(qint64)),
                   this, SLOT(qmlComplete(qint64)));
        disconnect(d->qmlclientplugin.data(),
                   SIGNAL(rangedEvent(int,int,qint64,qint64,QStringList,QmlDebug::QmlEventLocation,
                                qint64,qint64,qint64,qint64,qint64)),
                   d->modelManager,
                   SLOT(addQmlEvent(int,int,qint64,qint64,QStringList,QmlDebug::QmlEventLocation,
                                    qint64,qint64,qint64,qint64,qint64)));
        disconnect(d->qmlclientplugin.data(), SIGNAL(traceFinished(qint64)),
                   d->modelManager->traceTime(), SLOT(increaseEndTime(qint64)));
        disconnect(d->qmlclientplugin.data(), SIGNAL(traceStarted(qint64)),
                   d->modelManager->traceTime(), SLOT(decreaseStartTime(qint64)));
        disconnect(d->qmlclientplugin.data(), SIGNAL(enabledChanged()),
                   d->qmlclientplugin.data(), SLOT(sendRecordingStatus()));
        // fixme: this should be unified for both clients
        disconnect(d->qmlclientplugin.data(), SIGNAL(recordingChanged(bool)),
                   d->profilerState, SLOT(setServerRecording(bool)));
        disconnect(d->profilerState, SIGNAL(recordingFeaturesChanged(quint64)),
                   d->qmlclientplugin.data(), SLOT(setFeatures(quint64)));
    }
}

void QmlProfilerClientManager::connectToClient()
{
    if (!d->connection || d->connection->isOpen() || d->connection->isConnecting())
        return;

    d->connection->connectToHost(d->tcpHost, d->tcpPort);
}

bool QmlProfilerClientManager::isConnected() const
{
    return d->connection && d->connection->isOpen();
}

void QmlProfilerClientManager::disconnectClient()
{
    // this might be actually be called indirectly by QDDConnectionPrivate::readyRead(), therefore allow
    // function to complete before deleting object
    if (d->connection) {
        d->connection->deleteLater();
        d->connection = 0;
    }
}

void QmlProfilerClientManager::tryToConnect()
{
    ++d->connectionAttempts;

    if (d->connection && d->connection->isOpen()) {
        d->connectionTimer.stop();
        d->connectionAttempts = 0;
    } else if (d->connectionAttempts == 50) {
        d->connectionTimer.stop();
        d->connectionAttempts = 0;

        QMessageBox *infoBox = QmlProfilerTool::requestMessageBox();
        infoBox->setIcon(QMessageBox::Critical);
        infoBox->setWindowTitle(tr("Qt Creator"));
        infoBox->setText(tr("Could not connect to the in-process QML profiler.\n"
                            "Do you want to retry?"));
        infoBox->setStandardButtons(QMessageBox::Retry |
                                    QMessageBox::Cancel |
                                    QMessageBox::Help);
        infoBox->setDefaultButton(QMessageBox::Retry);
        infoBox->setModal(true);

        connect(infoBox, SIGNAL(finished(int)),
                this, SLOT(retryMessageBoxFinished(int)));

        infoBox->show();
    } else {
        connectToClient();
    }
}

void QmlProfilerClientManager::qmlDebugConnectionOpened()
{
    logState(tr("Debug connection opened"));
    clientRecordingChanged();
}

void QmlProfilerClientManager::qmlDebugConnectionClosed()
{
    logState(tr("Debug connection closed"));
    disconnectClient();
    emit connectionClosed();
}

void QmlProfilerClientManager::logState(const QString &msg)
{
    QString state = QLatin1String("QML Profiler: ") + msg;
    if (QmlProfilerPlugin::debugOutput)
        qWarning() << state;
    QmlProfilerTool::logState(state);
}

void QmlProfilerClientManager::retryMessageBoxFinished(int result)
{
    if (d->connection) {
        QTC_ASSERT(!d->connection->isOpen(), return);
        if (d->connection->isConnecting())
            d->connection->disconnect();
    }

    switch (result) {
    case QMessageBox::Retry: {
        d->connectionAttempts = 0;
        d->connectionTimer.start();
        break;
    }
    case QMessageBox::Help: {
        QmlProfilerTool::handleHelpRequest(QLatin1String("qthelp://org.qt-project.qtcreator/doc/creator-debugging-qml.html"));
        // fall through
    }
    default: {
        // The actual error message has already been logged.
        logState(tr("Failed to connect!"));
        emit connectionFailed();
        break;
    }
    }
}

void QmlProfilerClientManager::qmlComplete(qint64 maximumTime)
{
    d->modelManager->traceTime()->increaseEndTime(maximumTime);
    d->qmlDataReady = true;
    emit dataReadyForProcessing();
    // once complete is sent, reset the flags
    d->qmlDataReady = false;
}

void QmlProfilerClientManager::stopClientsRecording()
{
    if (d->qmlclientplugin)
        d->qmlclientplugin.data()->setRecording(false);
}

////////////////////////////////////////////////////////////////
// Profiler State
void QmlProfilerClientManager::registerProfilerStateManager( QmlProfilerStateManager *profilerState )
{
    if (d->profilerState) {
        disconnect(d->profilerState, SIGNAL(stateChanged()),
                   this, SLOT(profilerStateChanged()));
        disconnect(d->profilerState, SIGNAL(clientRecordingChanged()),
                   this, SLOT(clientRecordingChanged()));
        disconnect(d->profilerState, SIGNAL(serverRecordingChanged()),
                   this, SLOT(serverRecordingChanged()));
    }

    d->profilerState = profilerState;

    // connect
    if (d->profilerState) {
        connect(d->profilerState, SIGNAL(stateChanged()),
                this, SLOT(profilerStateChanged()));
        connect(d->profilerState, SIGNAL(clientRecordingChanged()),
                this, SLOT(clientRecordingChanged()));
        connect(d->profilerState, SIGNAL(serverRecordingChanged()),
                this, SLOT(serverRecordingChanged()));
    }
}

void QmlProfilerClientManager::profilerStateChanged()
{
    QTC_ASSERT(d->profilerState, return);
    switch (d->profilerState->currentState()) {
    case QmlProfilerStateManager::AppStopRequested :
        if (d->profilerState->serverRecording())
            stopClientsRecording();
        else
            d->profilerState->setCurrentState(QmlProfilerStateManager::AppReadyToStop);
        break;
    default:
        break;
    }
}

void QmlProfilerClientManager::clientRecordingChanged()
{
    QTC_ASSERT(d->profilerState, return);
    if (d->profilerState->currentState() == QmlProfilerStateManager::AppRunning) {
        if (d->qmlclientplugin)
            d->qmlclientplugin.data()->setRecording(d->profilerState->clientRecording());
    }
}

void QmlProfilerClientManager::serverRecordingChanged()
{
    if (d->profilerState->serverRecording())
        d->qmlDataReady = false;
}

} // namespace Internal
} // namespace QmlProfiler
<|endoftext|>


<commit_before><commit_msg>Resolves: #i120050# memory leak when SdrObject is removed from master page<commit_after><|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact:  Qt Software Information (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
**
**************************************************************************/

#include "profilehighlighter.h"

#include <QtCore/QRegExp>
#include <QtGui/QColor>
#include <QtGui/QTextDocument>
#include <QtGui/QTextEdit>

using namespace Qt4ProjectManager::Internal;

#define MAX_VARIABLES 48
const char *const variables[MAX_VARIABLES] = {
    "CONFIG",
    "DEFINES",
    "DEF_FILE",
    "DEPENDPATH",
    "DESTDIR",
    "DESTDIR_TARGET",
    "DISTFILES",
    "DLLDESTDIR",
    "FORMS",
    "HEADERS",
    "INCLUDEPATH",
    "LEXSOURCES",
    "LIBS",
    "MAKEFILE",
    "MOC_DIR",
    "OBJECTS",
    "OBJECTS_DIR",
    "OBJMOC",
    "POST_TARGETDEPS",
    "PRECOMPILED_HEADER",
    "PRE_TARGETDEPS",
    "QMAKE",
    "QMAKESPEC",
    "QT",
    "RCC_DIR",
    "RC_FILE",
    "REQUIRES",
    "RESOURCES",
    "RES_FILE",
    "SOURCES",
    "SRCMOC",
    "SUBDIRS",
    "TARGET",
    "TARGET_EXT",
    "TARGET_x",
    "TARGET_x.y.z",
    "TEMPLATE",
    "TRANSLATIONS",
    "UI_DIR",
    "UI_HEADERS_DIR",
    "UI_SOURCES_DIR",
    "VER_MAJ",
    "VER_MIN",
    "VER_PAT",
    "VERSION",
    "VPATH",
    "YACCSOURCES",
    0
};

#define MAX_FUNCTIONS 22
const char *const functions[MAX_FUNCTIONS] = {
    "basename",
    "CONFIG",
    "contains",
    "count",
    "dirname",
    "error",
    "exists",
    "find",
    "for",
    "include",
    "infile",
    "isEmpty",
    "join",
    "member",
    "message",
    "prompt",
    "quote",
    "sprintf",
    "system",
    "unique",
    "warning",
    0
};

struct KeywordHelper
{
    inline KeywordHelper(const QString &word) : needle(word) {}
    const QString needle;
};

static bool operator<(const KeywordHelper &helper, const char *kw)
{
    return helper.needle < QLatin1String(kw);
}

static bool operator<(const char *kw, const KeywordHelper &helper)
{
    return QLatin1String(kw) < helper.needle;
}

static bool isVariable(const QString &word)
{
    const char *const *start = &variables[0];
    const char *const *end = &variables[MAX_VARIABLES - 1];
    const char *const *kw = qBinaryFind(start, end, KeywordHelper(word));
    return *kw != 0;
}

static bool isFunction(const QString &word)
{
    const char *const *start = &functions[0];
    const char *const *end = &functions[MAX_FUNCTIONS - 1];
    const char *const *kw = qBinaryFind(start, end, KeywordHelper(word));
    return *kw != 0;
}

ProFileHighlighter::ProFileHighlighter(QTextDocument *document) :
    QSyntaxHighlighter(document)
{
}

void ProFileHighlighter::highlightBlock(const QString &text)
{
    if (text.isEmpty())
        return;

    QString buf;
    bool inCommentMode = false;

    QTextCharFormat emptyFormat;
    int i = 0;
    for (;;) {
        const QChar c = text.at(i);
        if (inCommentMode) {
            setFormat(i, 1, m_formats[ProfileCommentFormat]);
        } else {
            if (c.isLetter() || c == '_' || c == '.') {
                buf += c;
                setFormat(i - buf.length()+1, buf.length(), emptyFormat);
                if (!buf.isEmpty() && isFunction(buf))
                    setFormat(i - buf.length()+1, buf.length(), m_formats[ProfileFunctionFormat]);
                else if (!buf.isEmpty() && isVariable(buf))
                    setFormat(i - buf.length()+1, buf.length(), m_formats[ProfileVariableFormat]);
            } else if (c == '(') {
                if (!buf.isEmpty() && isFunction(buf))
                    setFormat(i - buf.length(), buf.length(), m_formats[ProfileFunctionFormat]);
                buf.clear();
            } else if (c == '#') {
                inCommentMode = true;
                setFormat(i, 1, m_formats[ProfileCommentFormat]);
                buf.clear();
            } else {
                if (!buf.isEmpty() && isVariable(buf))
                    setFormat(i - buf.length(), buf.length(), m_formats[ProfileVariableFormat]);
                buf.clear();
            }
        }
        i++;
        if (i >= text.length())
            break;
    }
}

<commit_msg>Add PKGCONFIG to highlighted variables.<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact:  Qt Software Information (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
**
**************************************************************************/

#include "profilehighlighter.h"

#include <QtCore/QRegExp>
#include <QtGui/QColor>
#include <QtGui/QTextDocument>
#include <QtGui/QTextEdit>

using namespace Qt4ProjectManager::Internal;

#define MAX_VARIABLES 49
const char *const variables[MAX_VARIABLES] = {
    "CONFIG",
    "DEFINES",
    "DEF_FILE",
    "DEPENDPATH",
    "DESTDIR",
    "DESTDIR_TARGET",
    "DISTFILES",
    "DLLDESTDIR",
    "FORMS",
    "HEADERS",
    "INCLUDEPATH",
    "LEXSOURCES",
    "LIBS",
    "MAKEFILE",
    "MOC_DIR",
    "OBJECTS",
    "OBJECTS_DIR",
    "OBJMOC",
    "PKGCONFIG",
    "POST_TARGETDEPS",
    "PRECOMPILED_HEADER",
    "PRE_TARGETDEPS",
    "QMAKE",
    "QMAKESPEC",
    "QT",
    "RCC_DIR",
    "RC_FILE",
    "REQUIRES",
    "RESOURCES",
    "RES_FILE",
    "SOURCES",
    "SRCMOC",
    "SUBDIRS",
    "TARGET",
    "TARGET_EXT",
    "TARGET_x",
    "TARGET_x.y.z",
    "TEMPLATE",
    "TRANSLATIONS",
    "UI_DIR",
    "UI_HEADERS_DIR",
    "UI_SOURCES_DIR",
    "VER_MAJ",
    "VER_MIN",
    "VER_PAT",
    "VERSION",
    "VPATH",
    "YACCSOURCES",
    0
};

#define MAX_FUNCTIONS 22
const char *const functions[MAX_FUNCTIONS] = {
    "basename",
    "CONFIG",
    "contains",
    "count",
    "dirname",
    "error",
    "exists",
    "find",
    "for",
    "include",
    "infile",
    "isEmpty",
    "join",
    "member",
    "message",
    "prompt",
    "quote",
    "sprintf",
    "system",
    "unique",
    "warning",
    0
};

struct KeywordHelper
{
    inline KeywordHelper(const QString &word) : needle(word) {}
    const QString needle;
};

static bool operator<(const KeywordHelper &helper, const char *kw)
{
    return helper.needle < QLatin1String(kw);
}

static bool operator<(const char *kw, const KeywordHelper &helper)
{
    return QLatin1String(kw) < helper.needle;
}

static bool isVariable(const QString &word)
{
    const char *const *start = &variables[0];
    const char *const *end = &variables[MAX_VARIABLES - 1];
    const char *const *kw = qBinaryFind(start, end, KeywordHelper(word));
    return *kw != 0;
}

static bool isFunction(const QString &word)
{
    const char *const *start = &functions[0];
    const char *const *end = &functions[MAX_FUNCTIONS - 1];
    const char *const *kw = qBinaryFind(start, end, KeywordHelper(word));
    return *kw != 0;
}

ProFileHighlighter::ProFileHighlighter(QTextDocument *document) :
    QSyntaxHighlighter(document)
{
}

void ProFileHighlighter::highlightBlock(const QString &text)
{
    if (text.isEmpty())
        return;

    QString buf;
    bool inCommentMode = false;

    QTextCharFormat emptyFormat;
    int i = 0;
    for (;;) {
        const QChar c = text.at(i);
        if (inCommentMode) {
            setFormat(i, 1, m_formats[ProfileCommentFormat]);
        } else {
            if (c.isLetter() || c == '_' || c == '.') {
                buf += c;
                setFormat(i - buf.length()+1, buf.length(), emptyFormat);
                if (!buf.isEmpty() && isFunction(buf))
                    setFormat(i - buf.length()+1, buf.length(), m_formats[ProfileFunctionFormat]);
                else if (!buf.isEmpty() && isVariable(buf))
                    setFormat(i - buf.length()+1, buf.length(), m_formats[ProfileVariableFormat]);
            } else if (c == '(') {
                if (!buf.isEmpty() && isFunction(buf))
                    setFormat(i - buf.length(), buf.length(), m_formats[ProfileFunctionFormat]);
                buf.clear();
            } else if (c == '#') {
                inCommentMode = true;
                setFormat(i, 1, m_formats[ProfileCommentFormat]);
                buf.clear();
            } else {
                if (!buf.isEmpty() && isVariable(buf))
                    setFormat(i - buf.length(), buf.length(), m_formats[ProfileVariableFormat]);
                buf.clear();
            }
        }
        i++;
        if (i >= text.length())
            break;
    }
}

<|endoftext|>


<commit_before>#include "ShaderResourceBuffer.h"
#include <assert.h>

using namespace Device;
using namespace Rendering::Buffer;
using namespace Rendering::View;

ShaderResourceBuffer::ShaderResourceBuffer()
	: _baseBuffer(), _srv()
{
}

ShaderResourceBuffer::~ShaderResourceBuffer()
{
	Destroy();
}

void ShaderResourceBuffer::Initialize(
	Device::DirectX& dx,
	uint stride, uint num, DXGI_FORMAT format,
	const void* sysMem, bool useMapWriteNoOverWrite,
	uint optionalBindFlag, D3D11_USAGE usage)
{
	D3D11_BUFFER_DESC desc;
	memset(&desc, 0, sizeof(D3D11_BUFFER_DESC));

	desc.Usage					= usage;
	desc.ByteWidth				= stride * num;
	desc.BindFlags				= D3D11_BIND_SHADER_RESOURCE | optionalBindFlag;
	desc.CPUAccessFlags			= useMapWriteNoOverWrite ? D3D11_CPU_ACCESS_WRITE : 0;
	desc.StructureByteStride	= stride;
	desc.MiscFlags				= (format == DXGI_FORMAT_UNKNOWN) ? D3D11_RESOURCE_MISC_BUFFER_STRUCTURED : 0;

	D3D11_SUBRESOURCE_DATA data;
	data.pSysMem = sysMem;

	_baseBuffer.SetBuffer(dx.CreateBuffer(desc, sysMem ? &data : nullptr));
	_srv.InitializeUsingBuffer(dx, _baseBuffer, num, format, false);
}

void ShaderResourceBuffer::Destroy()
{
	_srv.Destroy();
}
<commit_msg>Update ShaderResourceBuffer.cpp<commit_after>#include "ShaderResourceBuffer.h"
#include <assert.h>

using namespace Device;
using namespace Rendering::Buffer;
using namespace Rendering::View;

void ShaderResourceBuffer::Initialize(
	Device::DirectX& dx,
	uint stride, uint num, DXGI_FORMAT format,
	const void* sysMem, bool useMapWriteNoOverWrite,
	uint optionalBindFlag, D3D11_USAGE usage)
{
	D3D11_BUFFER_DESC desc;
	memset(&desc, 0, sizeof(D3D11_BUFFER_DESC));

	desc.Usage					= usage;
	desc.ByteWidth				= stride * num;
	desc.BindFlags				= D3D11_BIND_SHADER_RESOURCE | optionalBindFlag;
	desc.CPUAccessFlags			= useMapWriteNoOverWrite ? D3D11_CPU_ACCESS_WRITE : 0;
	desc.StructureByteStride	= stride;
	desc.MiscFlags				= (format == DXGI_FORMAT_UNKNOWN) ? D3D11_RESOURCE_MISC_BUFFER_STRUCTURED : 0;

	D3D11_SUBRESOURCE_DATA data;
	data.pSysMem = sysMem;

	_baseBuffer.SetBuffer(dx.CreateBuffer(desc, sysMem ? &data : nullptr));
	_srv.InitializeUsingBuffer(dx, _baseBuffer, num, format, false);
}
<|endoftext|>


<commit_before>//---------------------------------------------------------
// Copyright 2015 Ontario Institute for Cancer Research
// Written by Jared Simpson (jared.simpson@oicr.on.ca)
//---------------------------------------------------------
//
// nanopolish_variants -- tools for calling variants
//
#include <algorithm>
#include <map>
#include <iterator>
#include <iomanip>
#include "nanopolish_profile_hmm.h"
#include "nanopolish_variant.h"
#include "nanopolish_haplotype.h"
#include "nanopolish_model_names.h"

// return a new copy of the string with gap symbols removed
std::string remove_gaps(const std::string& str)
{
    std::string ret = str;
    ret.erase( std::remove(ret.begin(), ret.end(), '-'), ret.end());
    return ret;
}

// extract differences between the pair of strings
std::vector<Variant> extract_variants(const std::string& reference,
                                      const std::string& haplotype)
{
    AlnParam par = aln_param_nt2nt;
    par.band_width = std::max(20, abs(reference.size() - haplotype.size()) * 2);
    AlnAln* aln = aln_stdaln(reference.c_str(), haplotype.c_str(), &par, 1, 1);

    // Make aligned strings where gaps are padded with '-'
    std::string pad_ref(aln->out1);
    std::string pad_hap(aln->out2);

    assert(pad_ref.size() == pad_hap.size());

    //std::cout << "PR: " << pad_ref << "\n";
    //std::cout << "PH: " << pad_hap << "\n";

    // parse variants from the alignment
    std::vector<Variant> variants;

    // generate a map from padded bases to positions in the original reference sequence
    std::vector<size_t> ref_positions(pad_ref.size(), 0);
    size_t pos = 0;
    for(size_t i = 0; i < pad_ref.size(); ++i) {
        ref_positions[i] = pad_ref[i] != '-' ? pos : std::string::npos;
        pos += pad_ref[i] != '-';
    }

    // diff_start iterates over the places where these sequences are different
    size_t diff_start = 0;
    while(1) {

        // find the start point of the next difference between the strings
        while(diff_start < pad_ref.size() && pad_ref[diff_start] == pad_hap[diff_start]) {
            diff_start++;
        }

        // check for end of alignment
        if(diff_start == pad_ref.size())
            break;

        // find the end point of the difference
        bool is_indel = false;
        size_t diff_end = diff_start;
        while(diff_end < pad_ref.size() && pad_ref[diff_end] != pad_hap[diff_end]) {
            is_indel = is_indel || pad_ref[diff_end] == '-' || pad_hap[diff_end] == '-';
            diff_end++;
        }

        // If the difference is an indel, we include the previous matching reference base
        diff_start -= is_indel;

        Variant v;
        v.ref_name = "noctg";

        assert(ref_positions[diff_start] != std::string::npos);
        v.ref_position = ref_positions[diff_start];
        v.ref_seq = remove_gaps(pad_ref.substr(diff_start, diff_end - diff_start).c_str());
        v.alt_seq = remove_gaps(pad_hap.substr(diff_start, diff_end - diff_start).c_str());

        variants.push_back(v);
        diff_start = diff_end;
    }

    aln_free_AlnAln(aln);
    return variants;
}

void filter_variants_by_count(std::vector<Variant>& variants, int min_count)
{
    std::map<std::string, std::pair<Variant, int>> map;

    for(size_t i = 0; i < variants.size(); ++i) {
        std::string key = variants[i].key();
        auto iter = map.find(key);
        if(iter == map.end()) {
            map.insert(std::make_pair(key, std::make_pair(variants[i], 1)));
        } else {
            iter->second.second += 1;
        }
    }

    variants.clear();

    for(auto iter = map.begin(); iter != map.end(); ++iter) {
        Variant& v = iter->second.first;
        if(iter->second.second >= min_count) {
            v.add_info("BaseCalledReadsWithVariant", iter->second.second);
            variants.push_back(v);
        }
    }
}

void filter_out_non_snp_variants(std::vector<Variant>& variants)
{
    std::vector<Variant> tmp;
    for(size_t i = 0; i < variants.size(); ++i) {
        bool is_snp = variants[i].ref_seq.length() ==
                      variants[i].alt_seq.length();
        if(is_snp) {
            tmp.push_back(variants[i]);
        }
    }
    variants.swap(tmp);
}

std::vector<Variant> select_variants(const std::vector<Variant>& candidate_variants,
                                     Haplotype base_haplotype,
                                     const std::vector<HMMInputData>& input)
{
    // make a copy of the variant set to modify
    std::vector<Variant> all_variants = candidate_variants;

    // Calculate baseline probablilty
    std::vector<Variant> selected_variants;

    double base_lp = profile_hmm_score(base_haplotype.get_sequence(), input);

    while(!all_variants.empty()) {

        double best_variant_lp = -INFINITY;
        size_t best_variant_idx = 0;
        size_t best_supporting_reads = 0;

        std::vector<double> base_lp_by_read;
        for(size_t j = 0; j < input.size(); ++j) {
            double tmp = profile_hmm_score(base_haplotype.get_sequence(), input[j]);
            base_lp_by_read.push_back(tmp);
        }

        for(size_t i = 0; i < all_variants.size(); ++i) {

            // apply the variant to get a new haplotype
            Variant& v = all_variants[i];
            Haplotype derived = base_haplotype;
            derived.apply_variant(v);

            // score the haplotype
            double variant_lp = 0.0f;
            size_t supporting_reads = 0;
            #pragma omp parallel for
            for(size_t j = 0; j < input.size(); ++j) {
                double tmp = profile_hmm_score(derived.get_sequence(), input[j]);
                #pragma omp critical
                {
                    variant_lp += tmp;
                    supporting_reads += tmp > base_lp_by_read[j];
                }
            }

            if(variant_lp > best_variant_lp) {
                best_variant_lp = variant_lp;
                best_variant_idx = i;
                best_supporting_reads = supporting_reads;
            }
        }

        if(best_variant_lp - base_lp > 1.0) {
            // move the best variant from the all list to the selected list
            Variant& best_variant = all_variants[best_variant_idx];
            best_variant.add_info("TotalReads", input.size());
            best_variant.add_info("SupportingReads", best_supporting_reads);
            best_variant.add_info("SupportFraction", (double)best_supporting_reads / input.size());
            best_variant.quality = best_variant_lp - base_lp;
            selected_variants.push_back(best_variant);

            //printf("SELECTED %zu from %zu: \n\t", best_variant_idx, all_variants.size() + 1);

            // apply the variant to the base haplotype
            base_haplotype.apply_variant(selected_variants.back());
            base_lp = best_variant_lp;
        } else {
            // no variant improved upon the base haplotype, stop
            break;
        }
    }

    return selected_variants;
}

std::vector<Variant> select_variant_set(const std::vector<Variant>& candidate_variants,
                                        Haplotype base_haplotype,
                                        const std::vector<HMMInputData>& input,
                                        const uint32_t alignment_flags)
{
    size_t num_variants = candidate_variants.size();
    size_t num_haplotypes = 1 << num_variants;

    double base_lp = 0.0f;
    double base_lp_by_model_strand[6] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
    int read_counts[6] = { 0, 0, 0, 0, 0, 0 };

    std::vector<double> base_lp_by_read(input.size());

    #pragma omp parallel for
    for(size_t j = 0; j < input.size(); ++j) {

        double tmp = profile_hmm_score(base_haplotype.get_sequence(), input[j], alignment_flags);

        #pragma omp critical
        {
            base_lp_by_read[j] = tmp;
            base_lp += tmp;

            int mid = input[j].read->pore_model[input[j].strand].metadata.model_idx;
            int cid = 2 * mid + input[j].rc;
            base_lp_by_model_strand[cid] += tmp;
            read_counts[cid] += 1;
        }
    }

    double best_lp = -INFINITY;
    std::vector<Variant> best_variant_set;

    // The haplotype id is a bitmask indicating which variants
    // to apply to get the haplotype. We skip the empty
    // variant set.
    for(size_t hi = 1; hi < num_haplotypes; ++hi) {

        Haplotype current_haplotype = base_haplotype;
        std::vector<Variant> current_variant_set;

        for(size_t vi = 0; vi < num_variants; vi++) {
            // if bit vi is set in the haplotype id, apply this variant
            if( (hi & (1 << vi)) == 0) {
                continue;
            }

            current_variant_set.push_back(candidate_variants[vi]);
            current_haplotype.apply_variant(current_variant_set.back());
        }

        // score the haplotype
        double current_lp = 0.0f;
        double current_lp_by_model_strand[6] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
        size_t supporting_reads = 0;

        #pragma omp parallel for
        for(size_t j = 0; j < input.size(); ++j) {
            double tmp = profile_hmm_score(current_haplotype.get_sequence(), input[j], alignment_flags);

            #pragma omp critical
            {
                current_lp += tmp;
                supporting_reads += tmp > base_lp_by_read[j];
                int mid = input[j].read->pore_model[input[j].strand].metadata.model_idx;
                int cid = 2 * mid + input[j].rc;
                current_lp_by_model_strand[cid] += tmp;
            }
        }

        if(current_lp > best_lp && current_lp - base_lp > 1.0) {
            best_lp = current_lp;
            best_variant_set = current_variant_set;

            // Annotate variants
            for(size_t vi = 0; vi < best_variant_set.size(); ++vi) {
                Variant& v = best_variant_set[vi];
                v.add_info("TotalReads", input.size());
                v.add_info("SupportingReads", supporting_reads);
                v.add_info("SupportFraction", (double)supporting_reads / input.size());

                // Annotate variants with qualities from the three possible models
                std::string names[3] = { "Template", "Comp.P1", "Comp.P2" };

                for(int mid = 0; mid < 3; mid++) {
                    int cid = 2 * mid;
                    double s0 = current_lp_by_model_strand[cid] - base_lp_by_model_strand[cid];
                    int c0 = read_counts[cid];

                    double s1 = current_lp_by_model_strand[cid + 1] - base_lp_by_model_strand[cid + 1];
                    int c1 = read_counts[cid + 1];

                    std::stringstream ss;
                    ss << std::setprecision(4) << s0 / c0 << "," << s1 / c1;
                    v.add_info(names[mid], ss.str());
                }

                /*
                v.add_info("TemplateQuality", current_lp_by_strand[0] - base_lp_by_strand[0]);
                v.add_info("ComplementQuality", current_lp_by_strand[1] - base_lp_by_strand[1]);
                v.add_info("ForwardQuality", current_lp_by_rc[0] - base_lp_by_rc[0]);
                v.add_info("ReverseQuality", current_lp_by_rc[1] - base_lp_by_rc[1]);
                v.add_info("TAvgQuality", (current_lp_by_model[0] - base_lp_by_model[0]) / model_count[0]);
                v.add_info("C1AvgQuality", (current_lp_by_model[1] - base_lp_by_model[1]) / model_count[1]);
                v.add_info("C2AvgQuality", (current_lp_by_model[2] - base_lp_by_model[2]) / model_count[2]);
                */

                std::stringstream counts;
                std::ostream_iterator<int> rc_out(counts, ",");
                std::copy(std::begin(read_counts), std::end(read_counts), rc_out);
                std::string rc_str = counts.str();
                v.add_info("ReadCounts", rc_str.substr(0, rc_str.size() - 1));
                v.quality = best_lp - base_lp;
            }
        }

#ifdef DEBUG_HAPLOTYPE_SELECTION
        std::stringstream ss;
        for(size_t vi = 0; vi < current_variant_set.size(); ++vi) {
            const Variant& v = current_variant_set[vi];
            ss << (vi > 0 ? "," : "") << v.key();
        }
        fprintf(stderr, "haplotype: %zu variants: %s relative score: %.2lf\n", hi, ss.str().c_str(), current_lp - base_lp);
#endif
    }
    return best_variant_set;
}

<commit_msg>output all scores in VCF records (for debugging)<commit_after>//---------------------------------------------------------
// Copyright 2015 Ontario Institute for Cancer Research
// Written by Jared Simpson (jared.simpson@oicr.on.ca)
//---------------------------------------------------------
//
// nanopolish_variants -- tools for calling variants
//
#include <algorithm>
#include <map>
#include <iterator>
#include <iomanip>
#include "nanopolish_profile_hmm.h"
#include "nanopolish_variant.h"
#include "nanopolish_haplotype.h"
#include "nanopolish_model_names.h"

// return a new copy of the string with gap symbols removed
std::string remove_gaps(const std::string& str)
{
    std::string ret = str;
    ret.erase( std::remove(ret.begin(), ret.end(), '-'), ret.end());
    return ret;
}

// extract differences between the pair of strings
std::vector<Variant> extract_variants(const std::string& reference,
                                      const std::string& haplotype)
{
    AlnParam par = aln_param_nt2nt;
    par.band_width = std::max(20, abs(reference.size() - haplotype.size()) * 2);
    AlnAln* aln = aln_stdaln(reference.c_str(), haplotype.c_str(), &par, 1, 1);

    // Make aligned strings where gaps are padded with '-'
    std::string pad_ref(aln->out1);
    std::string pad_hap(aln->out2);

    assert(pad_ref.size() == pad_hap.size());

    //std::cout << "PR: " << pad_ref << "\n";
    //std::cout << "PH: " << pad_hap << "\n";

    // parse variants from the alignment
    std::vector<Variant> variants;

    // generate a map from padded bases to positions in the original reference sequence
    std::vector<size_t> ref_positions(pad_ref.size(), 0);
    size_t pos = 0;
    for(size_t i = 0; i < pad_ref.size(); ++i) {
        ref_positions[i] = pad_ref[i] != '-' ? pos : std::string::npos;
        pos += pad_ref[i] != '-';
    }

    // diff_start iterates over the places where these sequences are different
    size_t diff_start = 0;
    while(1) {

        // find the start point of the next difference between the strings
        while(diff_start < pad_ref.size() && pad_ref[diff_start] == pad_hap[diff_start]) {
            diff_start++;
        }

        // check for end of alignment
        if(diff_start == pad_ref.size())
            break;

        // find the end point of the difference
        bool is_indel = false;
        size_t diff_end = diff_start;
        while(diff_end < pad_ref.size() && pad_ref[diff_end] != pad_hap[diff_end]) {
            is_indel = is_indel || pad_ref[diff_end] == '-' || pad_hap[diff_end] == '-';
            diff_end++;
        }

        // If the difference is an indel, we include the previous matching reference base
        diff_start -= is_indel;

        Variant v;
        v.ref_name = "noctg";

        assert(ref_positions[diff_start] != std::string::npos);
        v.ref_position = ref_positions[diff_start];
        v.ref_seq = remove_gaps(pad_ref.substr(diff_start, diff_end - diff_start).c_str());
        v.alt_seq = remove_gaps(pad_hap.substr(diff_start, diff_end - diff_start).c_str());

        variants.push_back(v);
        diff_start = diff_end;
    }

    aln_free_AlnAln(aln);
    return variants;
}

void filter_variants_by_count(std::vector<Variant>& variants, int min_count)
{
    std::map<std::string, std::pair<Variant, int>> map;

    for(size_t i = 0; i < variants.size(); ++i) {
        std::string key = variants[i].key();
        auto iter = map.find(key);
        if(iter == map.end()) {
            map.insert(std::make_pair(key, std::make_pair(variants[i], 1)));
        } else {
            iter->second.second += 1;
        }
    }

    variants.clear();

    for(auto iter = map.begin(); iter != map.end(); ++iter) {
        Variant& v = iter->second.first;
        if(iter->second.second >= min_count) {
            v.add_info("BaseCalledReadsWithVariant", iter->second.second);
            variants.push_back(v);
        }
    }
}

void filter_out_non_snp_variants(std::vector<Variant>& variants)
{
    std::vector<Variant> tmp;
    for(size_t i = 0; i < variants.size(); ++i) {
        bool is_snp = variants[i].ref_seq.length() ==
                      variants[i].alt_seq.length();
        if(is_snp) {
            tmp.push_back(variants[i]);
        }
    }
    variants.swap(tmp);
}

std::vector<Variant> select_variants(const std::vector<Variant>& candidate_variants,
                                     Haplotype base_haplotype,
                                     const std::vector<HMMInputData>& input)
{
    // make a copy of the variant set to modify
    std::vector<Variant> all_variants = candidate_variants;

    // Calculate baseline probablilty
    std::vector<Variant> selected_variants;

    double base_lp = profile_hmm_score(base_haplotype.get_sequence(), input);

    while(!all_variants.empty()) {

        double best_variant_lp = -INFINITY;
        size_t best_variant_idx = 0;
        size_t best_supporting_reads = 0;

        std::vector<double> base_lp_by_read;
        for(size_t j = 0; j < input.size(); ++j) {
            double tmp = profile_hmm_score(base_haplotype.get_sequence(), input[j]);
            base_lp_by_read.push_back(tmp);
        }

        for(size_t i = 0; i < all_variants.size(); ++i) {

            // apply the variant to get a new haplotype
            Variant& v = all_variants[i];
            Haplotype derived = base_haplotype;
            derived.apply_variant(v);

            // score the haplotype
            double variant_lp = 0.0f;
            size_t supporting_reads = 0;
            #pragma omp parallel for
            for(size_t j = 0; j < input.size(); ++j) {
                double tmp = profile_hmm_score(derived.get_sequence(), input[j]);
                #pragma omp critical
                {
                    variant_lp += tmp;
                    supporting_reads += tmp > base_lp_by_read[j];
                }
            }

            if(variant_lp > best_variant_lp) {
                best_variant_lp = variant_lp;
                best_variant_idx = i;
                best_supporting_reads = supporting_reads;
            }
        }

        if(best_variant_lp - base_lp > 1.0) {
            // move the best variant from the all list to the selected list
            Variant& best_variant = all_variants[best_variant_idx];
            best_variant.add_info("TotalReads", input.size());
            best_variant.add_info("SupportingReads", best_supporting_reads);
            best_variant.add_info("SupportFraction", (double)best_supporting_reads / input.size());
            best_variant.quality = best_variant_lp - base_lp;
            selected_variants.push_back(best_variant);

            //printf("SELECTED %zu from %zu: \n\t", best_variant_idx, all_variants.size() + 1);

            // apply the variant to the base haplotype
            base_haplotype.apply_variant(selected_variants.back());
            base_lp = best_variant_lp;
        } else {
            // no variant improved upon the base haplotype, stop
            break;
        }
    }

    return selected_variants;
}

std::vector<Variant> select_variant_set(const std::vector<Variant>& candidate_variants,
                                        Haplotype base_haplotype,
                                        const std::vector<HMMInputData>& input,
                                        const uint32_t alignment_flags)
{
    size_t num_variants = candidate_variants.size();
    size_t num_haplotypes = 1 << num_variants;

    double base_lp = 0.0f;
    double base_lp_by_model_strand[6] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
    int read_counts[6] = { 0, 0, 0, 0, 0, 0 };

    std::vector<double> base_lp_by_read(input.size());

    #pragma omp parallel for
    for(size_t j = 0; j < input.size(); ++j) {

        double tmp = profile_hmm_score(base_haplotype.get_sequence(), input[j], alignment_flags);

        #pragma omp critical
        {
            base_lp_by_read[j] = tmp;
            base_lp += tmp;

            int mid = input[j].read->pore_model[input[j].strand].metadata.model_idx;
            int cid = 2 * mid + input[j].rc;
            base_lp_by_model_strand[cid] += tmp;
            read_counts[cid] += 1;
        }
    }

    double best_lp = -INFINITY;
    std::vector<Variant> best_variant_set;

    // The haplotype id is a bitmask indicating which variants
    // to apply to get the haplotype. We skip the empty
    // variant set.
    for(size_t hi = 1; hi < num_haplotypes; ++hi) {

        Haplotype current_haplotype = base_haplotype;
        std::vector<Variant> current_variant_set;

        for(size_t vi = 0; vi < num_variants; vi++) {
            // if bit vi is set in the haplotype id, apply this variant
            if( (hi & (1 << vi)) == 0) {
                continue;
            }

            current_variant_set.push_back(candidate_variants[vi]);
            current_haplotype.apply_variant(current_variant_set.back());
        }

        // score the haplotype
        double current_lp = 0.0f;
        double current_lp_by_model_strand[6] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
        size_t supporting_reads = 0;
        std::vector<double> relative_lp_by_read(input.size(), 0.0f);

        #pragma omp parallel for
        for(size_t j = 0; j < input.size(); ++j) {
            double tmp = profile_hmm_score(current_haplotype.get_sequence(), input[j], alignment_flags);

            #pragma omp critical
            {
                current_lp += tmp;
                supporting_reads += tmp > base_lp_by_read[j];
                int mid = input[j].read->pore_model[input[j].strand].metadata.model_idx;
                int cid = 2 * mid + input[j].rc;
                current_lp_by_model_strand[cid] += tmp;
                relative_lp_by_read[j] = tmp - base_lp_by_read[j];
            }
        }

        if(current_lp > best_lp && current_lp - base_lp > 1.0) {
            best_lp = current_lp;
            best_variant_set = current_variant_set;

            // Annotate variants
            for(size_t vi = 0; vi < best_variant_set.size(); ++vi) {
                Variant& v = best_variant_set[vi];
                v.add_info("TotalReads", input.size());
                v.add_info("SupportingReads", supporting_reads);
                v.add_info("SupportFraction", (double)supporting_reads / input.size());

                // Annotate variants with qualities from the three possible models
                std::string names[3] = { "Template", "Comp.P1", "Comp.P2" };

                for(int mid = 0; mid < 3; mid++) {
                    int cid = 2 * mid;
                    double s0 = current_lp_by_model_strand[cid] - base_lp_by_model_strand[cid];
                    int c0 = read_counts[cid];

                    double s1 = current_lp_by_model_strand[cid + 1] - base_lp_by_model_strand[cid + 1];
                    int c1 = read_counts[cid + 1];

                    std::stringstream ss;
                    ss << std::setprecision(4) << s0 / c0 << "," << s1 / c1;
                    v.add_info(names[mid], ss.str());
                }

                /*
                v.add_info("TemplateQuality", current_lp_by_strand[0] - base_lp_by_strand[0]);
                v.add_info("ComplementQuality", current_lp_by_strand[1] - base_lp_by_strand[1]);
                v.add_info("ForwardQuality", current_lp_by_rc[0] - base_lp_by_rc[0]);
                v.add_info("ReverseQuality", current_lp_by_rc[1] - base_lp_by_rc[1]);
                v.add_info("TAvgQuality", (current_lp_by_model[0] - base_lp_by_model[0]) / model_count[0]);
                v.add_info("C1AvgQuality", (current_lp_by_model[1] - base_lp_by_model[1]) / model_count[1]);
                v.add_info("C2AvgQuality", (current_lp_by_model[2] - base_lp_by_model[2]) / model_count[2]);
                */

                std::stringstream counts;
                std::ostream_iterator<int> rc_out(counts, ",");
                std::copy(std::begin(read_counts), std::end(read_counts), rc_out);
                std::string rc_str = counts.str();
                v.add_info("ReadCounts", rc_str.substr(0, rc_str.size() - 1));

                std::stringstream scores;
                std::ostream_iterator<float> scores_out(scores, ",");
                std::copy(std::begin(relative_lp_by_read), std::end(relative_lp_by_read), scores_out);
                std::string scores_str = scores.str();
                v.add_info("Scores", scores_str.substr(0, scores_str.size() - 1));

                v.quality = best_lp - base_lp;
            }
        }

#ifdef DEBUG_HAPLOTYPE_SELECTION
        std::stringstream ss;
        for(size_t vi = 0; vi < current_variant_set.size(); ++vi) {
            const Variant& v = current_variant_set[vi];
            ss << (vi > 0 ? "," : "") << v.key();
        }
        fprintf(stderr, "haplotype: %zu variants: %s relative score: %.2lf\n", hi, ss.str().c_str(), current_lp - base_lp);
#endif
    }
    return best_variant_set;
}

<|endoftext|>


<commit_before>/*
    pluginloader.cpp - Kopete Plugin Loader

    Copyright (c) 2002 by Duncan Mac-Vicar Prett       <duncan@kde.org>

    Portions of this code based in Noatun plugin code:
    Copyright (c) 2000-2002 The Noatun Developers

    Kopete    (c) 2002 by the Kopete developers  <kopete-devel@kde.org>

    *************************************************************************
    *                                                                       *
    * This program is free software; you can redistribute it and/or modify  *
    * it under the terms of the GNU General Public License as published by  *
    * the Free Software Foundation; either version 2 of the License, or     *
    * (at your option) any later version.                                   *
    *                                                                       *
    *************************************************************************
*/

#include "pluginloader.h"

#include <qapplication.h>
#include <qdir.h>
#include <qfile.h>

#include <kdebug.h>
#include <kglobal.h>
#include <klocale.h>
#include <knotifyclient.h>
#include <kparts/componentfactory.h>
#include <ksimpleconfig.h>
#include <kstaticdeleter.h>
#include <kstddirs.h>
#include <kurl.h>

#include "kopeteplugin.h"

class KopeteLibraryInfo;

// Put the static deleter in its anonymous namespace
namespace
{
	KStaticDeleter<LibraryLoader> sd;
}

bool operator ==(const KopeteLibraryInfo &a, const KopeteLibraryInfo &b)
{
	// Feels like cheating, doesn't it?
	return a.specfile == b.specfile;
}

LibraryLoader* LibraryLoader::s_pluginLoader = 0L;

LibraryLoader* LibraryLoader::pluginLoader()
{
	if( !s_pluginLoader )
		sd.setObject( s_pluginLoader, new LibraryLoader() );

	return s_pluginLoader;
}

LibraryLoader::LibraryLoader()
: QObject( qApp )
{
}

LibraryLoader::~LibraryLoader()
{
	QDictIterator<KopetePlugin> i( mLibHash );
	for( ; i.current(); ++i )
	{
		if( getInfo( i.currentKey() ).type != "protocol" );
			remove( i.current() );
	}

	i.toFirst();
	for( ; i.current(); ++i )
	{
		remove( i.current() );
	}
}

QPtrList<KopetePlugin> LibraryLoader::plugins() const
{
	QPtrList<KopetePlugin> list;
	QDictIterator<KopetePlugin> i( mLibHash );
	for( ; i.current(); ++i )
		list.append( i.current() );

	return list;
}

QValueList<KopeteLibraryInfo> LibraryLoader::loaded() const
{
	QValueList<KopeteLibraryInfo> items;

	QDictIterator<KopetePlugin> i( mLibHash );
	for( ; i.current(); ++i )
	{
		if( mLibHash[ i.currentKey() ] )
			items.append( getInfo( i.currentKey() ) );
	}

	return items;
}

bool LibraryLoader::loadAll()
{
	KConfig *config=KGlobal::config();
	config->setGroup("");
	QStringList modules = config->readListEntry("Modules");

	// Session management...
/*
	for(QStringList::ConstIterator i=modules.begin(); i!=modules.end(); ++i)
	{
		KopeteLibraryInfo info=getInfo(*i);
		if (!info.type.contains("sm"))
			continue;
		loadPlugin( *i );
	}
*/
	// load all the protocols in the first
	for(QStringList::ConstIterator i=modules.begin(); i!=modules.end(); ++i)
	{
		KopeteLibraryInfo info=getInfo(*i);
		if (!info.type.contains("protocol"))
			continue;

		if ( !loadPlugin( *i ) )
			kdDebug() << "[LibraryLoader] loading " << (*i) << " failed!" << endl;
	}

	// load all misc plugins
	for(QStringList::ConstIterator i=modules.begin(); i!=modules.end(); ++i)
	{
		KopeteLibraryInfo info=getInfo(*i);
		if (!info.type.contains("other"))
			continue;

		if ( !loadPlugin( *i ) )
			kdDebug() << "[LibraryLoader] loading " << (*i) << " failed!" << endl;
	}

	return true;
}

KopeteLibraryInfo LibraryLoader::getInfo(const QString &spec) const
{
	QMap<QString, KopeteLibraryInfo>::iterator cached = m_cachedInfo.find(spec);
	if (cached != m_cachedInfo.end() )
		return *cached;

	KopeteLibraryInfo info;
	QString specPath = ( spec[ 0 ] == '/' ) ? spec : KGlobal::dirs()->findResource( "appdata", spec );
	if( !QFile::exists( specPath ) )
		return info;

	KSimpleConfig file( specPath );
	if( spec.find( '/' ) >= 0 )
		info.specfile = KURL( spec ).fileName();
	else
		info.specfile = spec;

	info.filename = file.readEntry( "Filename" );
	info.author   = file.readEntry( "Author" );
	info.site     = file.readEntry( "Site" );
	info.email    = file.readEntry( "Email" );
	info.type     = file.readEntry( "Type" );
	info.name     = file.readEntry( "Name" );
	info.comment  = file.readEntry( "Comment" );
	info.license  = file.readEntry( "License" );
	info.icon     = file.readEntry( "Icon" );

	m_cachedInfo[ spec ] = info;
	return info;
}

bool LibraryLoader::isLoaded( const QString &spec ) const
{
	KopetePlugin *p = mLibHash[ spec ];
	return p;
}

void LibraryLoader::setModules(const QStringList &mods)
{
	KConfig *config=KGlobal::config();
	config->setGroup("");
	config->writeEntry("Modules", mods);
	KGlobal::config()->sync();
}

QValueList<KopeteLibraryInfo> LibraryLoader::available() const
{
	QValueList<KopeteLibraryInfo> items;
	QStringList files=KGlobal::dirs()->findAllResources("appdata", "*.plugin", false, true);
	for (QStringList::Iterator i=files.begin(); i!=files.end(); ++i)
		items.append(getInfo(*i));

	return items;
}

bool LibraryLoader::loadPlugin( const QString &spec )
{
	KopetePlugin *plugin = mLibHash[ spec ];
	if( !plugin )
	{
		KopeteLibraryInfo info = getInfo( spec );
		if( info.specfile != spec )
			return false;

		// Get the library loader instance
		KLibLoader *loader = KLibLoader::self();

		KLibrary *lib = loader->library( QFile::encodeName( info.filename) );
		if( !lib )
		{
			kdDebug() << "LibraryLoader::loadPlugin: Error while loading plugin: " << loader->lastErrorMessage() << endl;
			return false;
		}
		plugin = KParts::ComponentFactory::createInstanceFromFactory<KopetePlugin> ( lib->factory(), this );
		mLibHash.insert( spec, plugin );

		connect( plugin, SIGNAL( destroyed( QObject * ) ),
			SLOT( slotPluginDestroyed( QObject * ) ) );

		// Automatically load the i18n catalogue for the plugin
		KGlobal::locale()->insertCatalogue( info.filename );

		plugin->init();

		m_addressBookFields.insert( plugin, plugin->addressBookFields() );

		kdDebug() << "LibraryLoader::loadPlugin: Successfully loaded plugin '" << spec << "'."<< endl;
		emit pluginLoaded( plugin );
		return true;
	}
	else
	{
		kdDebug() << "LibraryLoader::loadPlugin: Plugin '" << spec << "' is already loaded!" << endl;
		return false;
	}
}

bool LibraryLoader::remove( const QString &spec )
{
	KopetePlugin *plugin = mLibHash[ spec ];
	if( !plugin )
		return false;

	remove( plugin );
	return true;
}

bool LibraryLoader::remove( KopetePlugin *p )
{
	if( !p )
		return false;

	// Added by Duncan 20/01/2002
	// We need to call unload function for the plugin
	p->unload();
	delete p;

	return false;
}

void LibraryLoader::slotPluginDestroyed( QObject *o )
{
	m_addressBookFields.remove( static_cast<KopetePlugin *>( o ) );

	QDictIterator<KopetePlugin> it( mLibHash );
	for( ; it.current() && it.current() == o; ++it )
	{
		mLibHash.remove( it.currentKey() );
		break;
	}

	// FIXME: Most likely most data structures here leak and are bound
	// to cause crashes. Find and identify those.
}

QStringList LibraryLoader::addressBookFields( KopetePlugin *p ) const
{
	if( m_addressBookFields.contains( p ) )
		return m_addressBookFields[ p ];
	else
		return QStringList();
}

KopetePlugin * LibraryLoader::searchByName(const QString &name)
{
	for( QDictIterator<KopetePlugin> i( mLibHash ); i.current(); ++i )
	{
		if (getInfo(i.currentKey()).name==name)
			return (*i);
	}
	return 0L;
}

QString LibraryLoader::pluginIcon( const QString &pluginId ) const
{
	QDictIterator<KopetePlugin> i( mLibHash );
	for( ; i.current(); ++i )
	{
		if( i.currentKey() == pluginId );
			return getInfo( i.currentKey() ).icon;
	}

	return QString::null;
}

#include <pluginloader.moc>

// vim: set noet ts=4 sts=4 sw=4:

<commit_msg>Thanks Andy, for spotting this one!<commit_after>/*
    pluginloader.cpp - Kopete Plugin Loader

    Copyright (c) 2002 by Duncan Mac-Vicar Prett       <duncan@kde.org>

    Portions of this code based in Noatun plugin code:
    Copyright (c) 2000-2002 The Noatun Developers

    Kopete    (c) 2002 by the Kopete developers  <kopete-devel@kde.org>

    *************************************************************************
    *                                                                       *
    * This program is free software; you can redistribute it and/or modify  *
    * it under the terms of the GNU General Public License as published by  *
    * the Free Software Foundation; either version 2 of the License, or     *
    * (at your option) any later version.                                   *
    *                                                                       *
    *************************************************************************
*/

#include "pluginloader.h"

#include <qapplication.h>
#include <qdir.h>
#include <qfile.h>

#include <kdebug.h>
#include <kglobal.h>
#include <klocale.h>
#include <knotifyclient.h>
#include <kparts/componentfactory.h>
#include <ksimpleconfig.h>
#include <kstaticdeleter.h>
#include <kstddirs.h>
#include <kurl.h>

#include "kopeteplugin.h"

class KopeteLibraryInfo;

// Put the static deleter in its anonymous namespace
namespace
{
	KStaticDeleter<LibraryLoader> sd;
}

bool operator ==(const KopeteLibraryInfo &a, const KopeteLibraryInfo &b)
{
	// Feels like cheating, doesn't it?
	return a.specfile == b.specfile;
}

LibraryLoader* LibraryLoader::s_pluginLoader = 0L;

LibraryLoader* LibraryLoader::pluginLoader()
{
	if( !s_pluginLoader )
		sd.setObject( s_pluginLoader, new LibraryLoader() );

	return s_pluginLoader;
}

LibraryLoader::LibraryLoader()
: QObject( qApp )
{
}

LibraryLoader::~LibraryLoader()
{
	QDictIterator<KopetePlugin> i( mLibHash );
	for( ; i.current(); ++i )
	{
		if( getInfo( i.currentKey() ).type != "protocol" )
			remove( i.current() );
	}

	i.toFirst();
	for( ; i.current(); ++i )
	{
		remove( i.current() );
	}
}

QPtrList<KopetePlugin> LibraryLoader::plugins() const
{
	QPtrList<KopetePlugin> list;
	QDictIterator<KopetePlugin> i( mLibHash );
	for( ; i.current(); ++i )
		list.append( i.current() );

	return list;
}

QValueList<KopeteLibraryInfo> LibraryLoader::loaded() const
{
	QValueList<KopeteLibraryInfo> items;

	QDictIterator<KopetePlugin> i( mLibHash );
	for( ; i.current(); ++i )
	{
		if( mLibHash[ i.currentKey() ] )
			items.append( getInfo( i.currentKey() ) );
	}

	return items;
}

bool LibraryLoader::loadAll()
{
	KConfig *config=KGlobal::config();
	config->setGroup("");
	QStringList modules = config->readListEntry("Modules");

	// Session management...
/*
	for(QStringList::ConstIterator i=modules.begin(); i!=modules.end(); ++i)
	{
		KopeteLibraryInfo info=getInfo(*i);
		if (!info.type.contains("sm"))
			continue;
		loadPlugin( *i );
	}
*/
	// load all the protocols in the first
	for(QStringList::ConstIterator i=modules.begin(); i!=modules.end(); ++i)
	{
		KopeteLibraryInfo info=getInfo(*i);
		if (!info.type.contains("protocol"))
			continue;

		if ( !loadPlugin( *i ) )
			kdDebug() << "[LibraryLoader] loading " << (*i) << " failed!" << endl;
	}

	// load all misc plugins
	for(QStringList::ConstIterator i=modules.begin(); i!=modules.end(); ++i)
	{
		KopeteLibraryInfo info=getInfo(*i);
		if (!info.type.contains("other"))
			continue;

		if ( !loadPlugin( *i ) )
			kdDebug() << "[LibraryLoader] loading " << (*i) << " failed!" << endl;
	}

	return true;
}

KopeteLibraryInfo LibraryLoader::getInfo(const QString &spec) const
{
	QMap<QString, KopeteLibraryInfo>::iterator cached = m_cachedInfo.find(spec);
	if (cached != m_cachedInfo.end() )
		return *cached;

	KopeteLibraryInfo info;
	QString specPath = ( spec[ 0 ] == '/' ) ? spec : KGlobal::dirs()->findResource( "appdata", spec );
	if( !QFile::exists( specPath ) )
		return info;

	KSimpleConfig file( specPath );
	if( spec.find( '/' ) >= 0 )
		info.specfile = KURL( spec ).fileName();
	else
		info.specfile = spec;

	info.filename = file.readEntry( "Filename" );
	info.author   = file.readEntry( "Author" );
	info.site     = file.readEntry( "Site" );
	info.email    = file.readEntry( "Email" );
	info.type     = file.readEntry( "Type" );
	info.name     = file.readEntry( "Name" );
	info.comment  = file.readEntry( "Comment" );
	info.license  = file.readEntry( "License" );
	info.icon     = file.readEntry( "Icon" );

	m_cachedInfo[ spec ] = info;
	return info;
}

bool LibraryLoader::isLoaded( const QString &spec ) const
{
	KopetePlugin *p = mLibHash[ spec ];
	return p;
}

void LibraryLoader::setModules(const QStringList &mods)
{
	KConfig *config=KGlobal::config();
	config->setGroup("");
	config->writeEntry("Modules", mods);
	KGlobal::config()->sync();
}

QValueList<KopeteLibraryInfo> LibraryLoader::available() const
{
	QValueList<KopeteLibraryInfo> items;
	QStringList files=KGlobal::dirs()->findAllResources("appdata", "*.plugin", false, true);
	for (QStringList::Iterator i=files.begin(); i!=files.end(); ++i)
		items.append(getInfo(*i));

	return items;
}

bool LibraryLoader::loadPlugin( const QString &spec )
{
	KopetePlugin *plugin = mLibHash[ spec ];
	if( !plugin )
	{
		KopeteLibraryInfo info = getInfo( spec );
		if( info.specfile != spec )
			return false;

		// Get the library loader instance
		KLibLoader *loader = KLibLoader::self();

		KLibrary *lib = loader->library( QFile::encodeName( info.filename) );
		if( !lib )
		{
			kdDebug() << "LibraryLoader::loadPlugin: Error while loading plugin: " << loader->lastErrorMessage() << endl;
			return false;
		}
		plugin = KParts::ComponentFactory::createInstanceFromFactory<KopetePlugin> ( lib->factory(), this );
		mLibHash.insert( spec, plugin );

		connect( plugin, SIGNAL( destroyed( QObject * ) ),
			SLOT( slotPluginDestroyed( QObject * ) ) );

		// Automatically load the i18n catalogue for the plugin
		KGlobal::locale()->insertCatalogue( info.filename );

		plugin->init();

		m_addressBookFields.insert( plugin, plugin->addressBookFields() );

		kdDebug() << "LibraryLoader::loadPlugin: Successfully loaded plugin '" << spec << "'."<< endl;
		emit pluginLoaded( plugin );
		return true;
	}
	else
	{
		kdDebug() << "LibraryLoader::loadPlugin: Plugin '" << spec << "' is already loaded!" << endl;
		return false;
	}
}

bool LibraryLoader::remove( const QString &spec )
{
	KopetePlugin *plugin = mLibHash[ spec ];
	if( !plugin )
		return false;

	remove( plugin );
	return true;
}

bool LibraryLoader::remove( KopetePlugin *p )
{
	if( !p )
		return false;

	// Added by Duncan 20/01/2002
	// We need to call unload function for the plugin
	p->unload();
	delete p;

	return false;
}

void LibraryLoader::slotPluginDestroyed( QObject *o )
{
	m_addressBookFields.remove( static_cast<KopetePlugin *>( o ) );

	QDictIterator<KopetePlugin> it( mLibHash );
	for( ; it.current() && it.current() == o; ++it )
	{
		mLibHash.remove( it.currentKey() );
		break;
	}

	// FIXME: Most likely most data structures here leak and are bound
	// to cause crashes. Find and identify those.
}

QStringList LibraryLoader::addressBookFields( KopetePlugin *p ) const
{
	if( m_addressBookFields.contains( p ) )
		return m_addressBookFields[ p ];
	else
		return QStringList();
}

KopetePlugin * LibraryLoader::searchByName(const QString &name)
{
	for( QDictIterator<KopetePlugin> i( mLibHash ); i.current(); ++i )
	{
		if (getInfo(i.currentKey()).name==name)
			return (*i);
	}
	return 0L;
}

QString LibraryLoader::pluginIcon( const QString &pluginId ) const
{
	QDictIterator<KopetePlugin> i( mLibHash );
	for( ; i.current(); ++i )
	{
		if( i.currentKey() == pluginId );
			return getInfo( i.currentKey() ).icon;
	}

	return QString::null;
}

#include <pluginloader.moc>

// vim: set noet ts=4 sts=4 sw=4:

<|endoftext|>