<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (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 http://www.qtsoftware.com/contact.
**
**************************************************************************/

#include "trkutils.h"

#include <QtCore/QCoreApplication>
#include <QtCore/QFile>
#include <QtCore/QStringList>

#include <QtNetwork/QLocalServer>
#include <QtNetwork/QLocalSocket>

#ifdef Q_OS_UNIX

#include <signal.h>

void signalHandler(int)
{
    qApp->exit(1);
}

#endif

using namespace trk;

struct TrkOptions {
    TrkOptions() : verbose(1) {}

    int verbose;
    QString serverName;
    QString dumpName;
};

// Format of the replay source is something like
// ---IDE------------------------------------------------------
//  Command: 0x05 Support Mask
// [05 02]
//---TRK------------------------------------------------------
//  Command: 0x80 Acknowledge
//    Error: 0x0
// [80 02 00 7E 00 4F 5F 01 00 00 00 0F 1F 00 00 00
//  00 00 00 01 00 11 00 03 00 00 00 00 00 03 00 00...]

struct Inferior
{
    Inferior();
    uint pid;
    uint tid;
    uint codeseg;
    uint dataseg;

    uint registers[RegisterCount];
};

Inferior::Inferior()
{
    pid = 0x000008F5;
    tid = 0x000008F6;

    codeseg = 0x786A4000;
    dataseg = 0x00400000;

    registers[0]  = 0x00000000;
    registers[1]  = 0xC92D7FBC;
    registers[2]  = 0x00000000;
    registers[3]  = 0x00600000;
    registers[4]  = 0x00000000;
    registers[5]  = 0x786A7970;
    registers[6]  = 0x00000000;
    registers[7]  = 0x00000000;
    registers[8]  = 0x00000012;
    registers[9]  = 0x00000040;
    registers[10] = 0xC82AF210;
    registers[11] = 0x00000000;
    registers[12] = 0xC8000548;
    registers[13] = 0x00403ED0;
    registers[14] = 0x786A6BD8;
    registers[15] = 0x786A4CC8;
    registers[16] = 0x68000010; // that's reg 25 on chip?
}

class TrkServer : public QObject
{
    Q_OBJECT

public:
    TrkServer();
    ~TrkServer();

    void setServerName(const QString &name) { m_serverName = name; }
    void setMemoryDumpName(const QString &source) { m_memoryDumpName = source; }
    void setVerbose(int v) { m_verbose = v; }
    void startServer();

private slots:
    void handleConnection();
    void readFromAdapter();
    void writeToAdapter(byte command, byte token, const QByteArray &data);

    void handleAdapterMessage(const TrkResult &result);

private:
    void logMessage(const QString &msg, bool force = 0);
    byte nextNotificationToken();

    QString m_serverName;
    QString m_memoryDumpName;

    QByteArray m_adapterReadBuffer;

    QByteArray m_memoryData;
    QLocalServer m_server;
    int m_lastSent;
    QLocalSocket *m_adapterConnection;
    Inferior m_inferior;
    byte m_notificationToken;
    int m_verbose;
};

TrkServer::TrkServer() : m_verbose(1)
{
    m_adapterConnection = 0;
    m_notificationToken = 0;
}

TrkServer::~TrkServer()
{
    logMessage("Shutting down.\n");
    m_server.close();
}

void TrkServer::startServer()
{
    QFile file(m_memoryDumpName);
    file.open(QIODevice::ReadOnly);
    m_memoryData = file.readAll();
    file.close();

    logMessage(QString("Read %1 bytes of data from %2")
        .arg(m_memoryData.size()).arg(m_memoryDumpName));

    m_lastSent = 0;
    if (!m_server.listen(m_serverName)) {
        logMessage(QString("Error: Unable to start the TRK server %1: %2.")
            .arg(m_serverName).arg(m_server.errorString()), true);
        return;
    }

    logMessage("The TRK server '" + m_serverName + "'is running. Run the adapter now.", true);
    connect(&m_server, SIGNAL(newConnection()), this, SLOT(handleConnection()));
}

void TrkServer::logMessage(const QString &msg, bool force)
{
    if (m_verbose || force)
        qDebug("TRKSERVER: %s", qPrintable(msg));
}

void TrkServer::handleConnection()
{
    m_adapterConnection = m_server.nextPendingConnection();
    connect(m_adapterConnection, SIGNAL(disconnected()),
            m_adapterConnection, SLOT(deleteLater()));
    connect(m_adapterConnection, SIGNAL(readyRead()),
            this, SLOT(readFromAdapter()));
}

void TrkServer::readFromAdapter()
{
    QByteArray packet = m_adapterConnection->readAll();
    m_adapterReadBuffer.append(packet);

    logMessage("trk: -> " + stringFromArray(packet));

    if (packet != m_adapterReadBuffer)
        logMessage("buffer: " + stringFromArray(m_adapterReadBuffer));

    while (!m_adapterReadBuffer.isEmpty())
        handleAdapterMessage(extractResult(&m_adapterReadBuffer));
}

void TrkServer::writeToAdapter(byte command, byte token, const QByteArray &data)
{
    QByteArray msg = frameMessage(command, token, data);
    logMessage("trk: <- " + stringFromArray(msg));
    m_adapterConnection->write(msg);
}

void TrkServer::handleAdapterMessage(const TrkResult &result)
{
    QByteArray data;
    data.append(char(0x00));  // No error
    switch (result.code) {
        case 0x00: { // Ping
            m_notificationToken = 0;
            writeToAdapter(0x80, 0x00, data);
            break;
        }
        case 0x01: { // Connect
            writeToAdapter(0x80, result.token, data);
            break;
        }
        case 0x10: { // Read Memory
            const char *p = result.data.data();
            byte option = p[0];
            Q_UNUSED(option);
            ushort len = extractShort(p + 1);
            uint addr = extractInt(p + 3);
            //qDebug() << "MESSAGE: " << result.data.toHex();
            qDebug() << "ADDR: " << hexNumber(addr) << " " << hexNumber(len);
            if (addr < m_inferior.codeseg
                || addr + len >= m_inferior.codeseg + m_memoryData.size()) {
                qDebug() << "ADDRESS OUTSIDE CODESEG: " << hexNumber(addr)
                    << hexNumber(m_inferior.codeseg);
                for (int i = 0; i != len / 4; ++i)
                    appendInt(&data, 0xDEADBEEF);
                writeToAdapter(0x80, result.token, data);
                break;
            }
            for (int i = 0; i != len; ++i)
                appendByte(&data, m_memoryData[addr - m_inferior.codeseg + i]);
            writeToAdapter(0x80, result.token, data);
            break;
        }
        case 0x12: { // Read Registers
            data.clear();
            for (int i = 0; i < RegisterCount; ++i)
                appendInt(&data, m_inferior.registers[i], BigEndian);
            writeToAdapter(0x80, result.token, data);
            break;
        }
        case 0x18: { // Continue
            writeToAdapter(0x80, result.token, data); // ACK Package

            if (1) { // Fake "Stop"
                QByteArray note;
                appendInt(&note, 0); // FIXME: use proper address
                appendInt(&note, m_inferior.pid);
                appendInt(&note, m_inferior.tid);
                appendByte(&note, 0x00);
                appendByte(&note, 0x00);
                writeToAdapter(0x90, nextNotificationToken(), note);
            }

            break;
        }
        case 0x19: { // Step
            const char *p = result.data.data();
            //byte option = *p;
            uint startaddr = extractInt(p + 1);
            uint endaddr = extractInt(p + 5);
            uint pid = extractInt(p + 9);
            //uint tid = extractInt(p + 13);
            if (startaddr != m_inferior.registers[RegisterPC])
                logMessage("addr mismatch:" + hexNumber(startaddr) + " " +
                    hexNumber(m_inferior.registers[RegisterPC]));
            if (pid != m_inferior.pid)
                logMessage("pid mismatch:" + hexNumber(pid) + " " +
                    hexNumber(m_inferior.pid));
            writeToAdapter(0x80, result.token, data);

            // Fake "step"
            m_inferior.registers[RegisterPC] = endaddr;

            if (1) { // Fake "Stop"
                QByteArray note;
                appendInt(&note, 0); // FIXME: use proper address
                appendInt(&note, m_inferior.pid);
                appendInt(&note, m_inferior.tid);
                appendByte(&note, 0x00);
                appendByte(&note, 0x00);
                writeToAdapter(0x90, nextNotificationToken(), note);
            }
            break;
        }
        case 0x40: { // Create Item
            appendInt(&data, m_inferior.pid, BigEndian);
            appendInt(&data, m_inferior.tid, BigEndian);
            appendInt(&data, m_inferior.codeseg, BigEndian);
            appendInt(&data, m_inferior.dataseg, BigEndian);
            writeToAdapter(0x80, result.token, data);
            break;
        }
        case 0x41: { // Delete Item
            writeToAdapter(0x80, result.token, data);

            // A Process?
            // Command: 0xA1 Notify Deleted
            //[A1 02 00 00 00 00 00 00 00 00 01 B5]
            QByteArray note; // FIXME
            appendByte(&note, 0);
            appendByte(&note, 0);
            appendInt(&note, 0);
            appendInt(&note, m_inferior.pid);
            writeToAdapter(0xA1, nextNotificationToken(), note);
            break;
        }
        default:
            data[0] = 0x10; // Command not supported
            writeToAdapter(0xff, result.token, data);
            break;
    }

}

byte TrkServer::nextNotificationToken()
{
    ++m_notificationToken;
    if (m_notificationToken == 0)
        ++m_notificationToken;
    return m_notificationToken;
}

static bool readTrkArgs(const QStringList &args, TrkOptions *o)
{
    int argNumber = 0;
    const QStringList::const_iterator cend = args.constEnd();
    QStringList::const_iterator it = args.constBegin();
    for (++it; it != cend; ++it) {
        if (it->startsWith(QLatin1Char('-'))) {
            if (*it == QLatin1String("-v")) {
                o->verbose++;
            } else if (*it == QLatin1String("-q")) {
                o->verbose = 0;
            }
        } else {
            switch (argNumber++) {
            case 0:
                o->serverName = *it;
                break;
            case 1:
                o->dumpName = *it;
                break;
            }
        }
    }
    return !o->dumpName.isEmpty();
}

int main(int argc, char *argv[])
{
#ifdef Q_OS_UNIX
    signal(SIGUSR1, signalHandler);
#endif

    QCoreApplication app(argc, argv);
    TrkOptions options;
    if (!readTrkArgs(app.arguments(), &options)) {
        qWarning("Usage: %s [-v|-q] <trkservername> <replaysource>\n"
                 "Options: -v verbose\n"
                 "         -q quiet\n", argv[0]);
        return 1;
    }

    TrkServer server;
    server.setServerName(options.serverName);
    server.setMemoryDumpName(options.dumpName);
    server.setVerbose(options.verbose);
    server.startServer();

    return app.exec();
}

#include "trkserver.moc"
<commit_msg>Trk: Improve error handling.<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (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 http://www.qtsoftware.com/contact.
**
**************************************************************************/

#include "trkutils.h"

#include <QtCore/QCoreApplication>
#include <QtCore/QFile>
#include <QtCore/QStringList>

#include <QtNetwork/QLocalServer>
#include <QtNetwork/QLocalSocket>

#ifdef Q_OS_UNIX

#include <signal.h>

void signalHandler(int)
{
    qApp->exit(1);
}

#endif

using namespace trk;

struct TrkOptions {
    TrkOptions() : verbose(1) {}

    int verbose;
    QString serverName;
    QString dumpName;
};

// Format of the replay source is something like
// ---IDE------------------------------------------------------
//  Command: 0x05 Support Mask
// [05 02]
//---TRK------------------------------------------------------
//  Command: 0x80 Acknowledge
//    Error: 0x0
// [80 02 00 7E 00 4F 5F 01 00 00 00 0F 1F 00 00 00
//  00 00 00 01 00 11 00 03 00 00 00 00 00 03 00 00...]

struct Inferior
{
    Inferior();
    uint pid;
    uint tid;
    uint codeseg;
    uint dataseg;

    uint registers[RegisterCount];
};

Inferior::Inferior()
{
    pid = 0x000008F5;
    tid = 0x000008F6;

    codeseg = 0x786A4000;
    dataseg = 0x00400000;

    registers[0]  = 0x00000000;
    registers[1]  = 0xC92D7FBC;
    registers[2]  = 0x00000000;
    registers[3]  = 0x00600000;
    registers[4]  = 0x00000000;
    registers[5]  = 0x786A7970;
    registers[6]  = 0x00000000;
    registers[7]  = 0x00000000;
    registers[8]  = 0x00000012;
    registers[9]  = 0x00000040;
    registers[10] = 0xC82AF210;
    registers[11] = 0x00000000;
    registers[12] = 0xC8000548;
    registers[13] = 0x00403ED0;
    registers[14] = 0x786A6BD8;
    registers[15] = 0x786A4CC8;
    registers[16] = 0x68000010; // that's reg 25 on chip?
}

class TrkServer : public QObject
{
    Q_OBJECT

public:
    TrkServer();
    ~TrkServer();

    void setServerName(const QString &name) { m_serverName = name; }
    void setMemoryDumpName(const QString &source) { m_memoryDumpName = source; }
    void setVerbose(int v) { m_verbose = v; }
    bool startServer();

private slots:
    void handleConnection();
    void readFromAdapter();
    void writeToAdapter(byte command, byte token, const QByteArray &data);

    void handleAdapterMessage(const TrkResult &result);

private:
    void logMessage(const QString &msg, bool force = 0);
    byte nextNotificationToken();

    QString m_serverName;
    QString m_memoryDumpName;

    QByteArray m_adapterReadBuffer;

    QByteArray m_memoryData;
    QLocalServer m_server;
    int m_lastSent;
    QLocalSocket *m_adapterConnection;
    Inferior m_inferior;
    byte m_notificationToken;
    int m_verbose;
};

TrkServer::TrkServer() : m_verbose(1)
{
    m_adapterConnection = 0;
    m_notificationToken = 0;
}

TrkServer::~TrkServer()
{
    logMessage("Shutting down.\n");
    m_server.close();
}

bool TrkServer::startServer()
{
    QFile file(m_memoryDumpName);
    if (!file.open(QIODevice::ReadOnly)) {
        logMessage(QString::fromLatin1("Unable to read %1: %2").arg(m_memoryDumpName, file.errorString()), true);
        return false;
    }
    m_memoryData = file.readAll();
    file.close();

    logMessage(QString("Read %1 bytes of data from %2")
        .arg(m_memoryData.size()).arg(m_memoryDumpName), true);

    m_lastSent = 0;
    if (!m_server.listen(m_serverName)) {
        logMessage(QString("Error: Unable to start the TRK server %1: %2.")
            .arg(m_serverName).arg(m_server.errorString()), true);
        return false;
    }

    logMessage("The TRK server '" + m_serverName + "'is running. Run the adapter now.", true);
    connect(&m_server, SIGNAL(newConnection()), this, SLOT(handleConnection()));
    return true;
}

void TrkServer::logMessage(const QString &msg, bool force)
{
    if (m_verbose || force)
        qDebug("TRKSERVER: %s", qPrintable(msg));
}

void TrkServer::handleConnection()
{
    m_adapterConnection = m_server.nextPendingConnection();
    connect(m_adapterConnection, SIGNAL(disconnected()),
            m_adapterConnection, SLOT(deleteLater()));
    connect(m_adapterConnection, SIGNAL(readyRead()),
            this, SLOT(readFromAdapter()));
}

void TrkServer::readFromAdapter()
{
    QByteArray packet = m_adapterConnection->readAll();
    m_adapterReadBuffer.append(packet);

    logMessage("trk: -> " + stringFromArray(packet));

    if (packet != m_adapterReadBuffer)
        logMessage("buffer: " + stringFromArray(m_adapterReadBuffer));

    while (!m_adapterReadBuffer.isEmpty())
        handleAdapterMessage(extractResult(&m_adapterReadBuffer));
}

void TrkServer::writeToAdapter(byte command, byte token, const QByteArray &data)
{
    QByteArray msg = frameMessage(command, token, data);
    logMessage("trk: <- " + stringFromArray(msg));
    m_adapterConnection->write(msg);
}

void TrkServer::handleAdapterMessage(const TrkResult &result)
{
    QByteArray data;
    data.append(char(0x00));  // No error
    switch (result.code) {
        case 0x00: { // Ping
            m_notificationToken = 0;
            writeToAdapter(0x80, 0x00, data);
            break;
        }
        case 0x01: { // Connect
            writeToAdapter(0x80, result.token, data);
            break;
        }
        case 0x10: { // Read Memory
            const char *p = result.data.data();
            byte option = p[0];
            Q_UNUSED(option);
            ushort len = extractShort(p + 1);
            uint addr = extractInt(p + 3);
            //qDebug() << "MESSAGE: " << result.data.toHex();
            qDebug() << "ADDR: " << hexNumber(addr) << " " << hexNumber(len);
            if (addr < m_inferior.codeseg
                || addr + len >= m_inferior.codeseg + m_memoryData.size()) {
                qDebug() << "ADDRESS OUTSIDE CODESEG: " << hexNumber(addr)
                    << hexNumber(m_inferior.codeseg);
                for (int i = 0; i != len / 4; ++i)
                    appendInt(&data, 0xDEADBEEF);
                writeToAdapter(0x80, result.token, data);
                break;
            }
            for (int i = 0; i != len; ++i)
                appendByte(&data, m_memoryData[addr - m_inferior.codeseg + i]);
            writeToAdapter(0x80, result.token, data);
            break;
        }
        case 0x12: { // Read Registers
            data.clear();
            for (int i = 0; i < RegisterCount; ++i)
                appendInt(&data, m_inferior.registers[i], BigEndian);
            writeToAdapter(0x80, result.token, data);
            break;
        }
        case 0x18: { // Continue
            writeToAdapter(0x80, result.token, data); // ACK Package

            if (1) { // Fake "Stop"
                QByteArray note;
                appendInt(&note, 0); // FIXME: use proper address
                appendInt(&note, m_inferior.pid);
                appendInt(&note, m_inferior.tid);
                appendByte(&note, 0x00);
                appendByte(&note, 0x00);
                writeToAdapter(0x90, nextNotificationToken(), note);
            }

            break;
        }
        case 0x19: { // Step
            const char *p = result.data.data();
            //byte option = *p;
            uint startaddr = extractInt(p + 1);
            uint endaddr = extractInt(p + 5);
            uint pid = extractInt(p + 9);
            //uint tid = extractInt(p + 13);
            if (startaddr != m_inferior.registers[RegisterPC])
                logMessage("addr mismatch:" + hexNumber(startaddr) + " " +
                    hexNumber(m_inferior.registers[RegisterPC]));
            if (pid != m_inferior.pid)
                logMessage("pid mismatch:" + hexNumber(pid) + " " +
                    hexNumber(m_inferior.pid));
            writeToAdapter(0x80, result.token, data);

            // Fake "step"
            m_inferior.registers[RegisterPC] = endaddr;

            if (1) { // Fake "Stop"
                QByteArray note;
                appendInt(&note, 0); // FIXME: use proper address
                appendInt(&note, m_inferior.pid);
                appendInt(&note, m_inferior.tid);
                appendByte(&note, 0x00);
                appendByte(&note, 0x00);
                writeToAdapter(0x90, nextNotificationToken(), note);
            }
            break;
        }
        case 0x40: { // Create Item
            appendInt(&data, m_inferior.pid, BigEndian);
            appendInt(&data, m_inferior.tid, BigEndian);
            appendInt(&data, m_inferior.codeseg, BigEndian);
            appendInt(&data, m_inferior.dataseg, BigEndian);
            writeToAdapter(0x80, result.token, data);
            break;
        }
        case 0x41: { // Delete Item
            writeToAdapter(0x80, result.token, data);

            // A Process?
            // Command: 0xA1 Notify Deleted
            //[A1 02 00 00 00 00 00 00 00 00 01 B5]
            QByteArray note; // FIXME
            appendByte(&note, 0);
            appendByte(&note, 0);
            appendInt(&note, 0);
            appendInt(&note, m_inferior.pid);
            writeToAdapter(0xA1, nextNotificationToken(), note);
            break;
        }
        default:
            data[0] = 0x10; // Command not supported
            writeToAdapter(0xff, result.token, data);
            break;
    }

}

byte TrkServer::nextNotificationToken()
{
    ++m_notificationToken;
    if (m_notificationToken == 0)
        ++m_notificationToken;
    return m_notificationToken;
}

static bool readTrkArgs(const QStringList &args, TrkOptions *o)
{
    int argNumber = 0;
    const QStringList::const_iterator cend = args.constEnd();
    QStringList::const_iterator it = args.constBegin();
    for (++it; it != cend; ++it) {
        if (it->startsWith(QLatin1Char('-'))) {
            if (*it == QLatin1String("-v")) {
                o->verbose++;
            } else if (*it == QLatin1String("-q")) {
                o->verbose = 0;
            }
        } else {
            switch (argNumber++) {
            case 0:
                o->serverName = *it;
                break;
            case 1:
                o->dumpName = *it;
                break;
            }
        }
    }
    return !o->dumpName.isEmpty();
}

int main(int argc, char *argv[])
{
#ifdef Q_OS_UNIX
    signal(SIGUSR1, signalHandler);
#endif

    QCoreApplication app(argc, argv);
    TrkOptions options;
    if (!readTrkArgs(app.arguments(), &options)) {
        qWarning("Usage: %s [-v|-q] <trkservername> <replaysource>\n"
                 "Options: -v verbose\n"
                 "         -q quiet\n", argv[0]);
        return 1;
    }

    TrkServer server;
    server.setServerName(options.serverName);
    server.setMemoryDumpName(options.dumpName);
    server.setVerbose(options.verbose);
    if (!server.startServer())
        return -1;

    return app.exec();
}

#include "trkserver.moc"
<|endoftext|>


<commit_before>#include "config/Base.hh"

#include "distances/Euclidean.hh"

#include "containers/PointCloud.hh"
#include "containers/DataDescriptors.hh"

#include "tests/Base.hh"

#include <iostream>
#include <string>
#include <vector>

using namespace aleph;

template <class D> void eccentricityTest()
{
  ALEPH_TEST_BEGIN( "Eccentricity test" );

  auto pc = load<double>( CMAKE_SOURCE_DIR + std::string( "/tests/input/Iris_comma_separated.txt" ) );
  auto e  = eccentricities<D>( pc );

  ALEPH_ASSERT_THROW( e.empty() == false );
  ALEPH_ASSERT_THROW( e.size()  == pc.size() );

  ALEPH_TEST_END();
}

int main()
{
  std::cerr << "-- Euclidean distance\n";

  eccentricityTest<distances::Euclidean<double> >();
}
<commit_msg>Extended eccentricity test<commit_after>#include "config/Base.hh"

#include "distances/Euclidean.hh"

#include "containers/PointCloud.hh"
#include "containers/DataDescriptors.hh"

#include "tests/Base.hh"

#include <iostream>
#include <iterator>
#include <string>
#include <vector>

#include <cmath>

using namespace aleph;

std::vector<double> eccentricities1Euclidean = { 2.89079980416499,2.92938125424666,3.03641983689583,2.9621727303441,2.92929541313731,2.78705043697625,3.00602715597502,2.8356746106249,3.1373108792989,2.88701630933734,2.86529976759286,2.84126021185023,2.98522430007638,3.39123238649493,3.19483936246115,3.1337014835966,3.01260481744661,2.86805628876277,2.7979536274294,2.88954147893703,2.71306352350348,2.84120141277709,3.3362862387173,2.66715124686446,2.72665726890308,2.79976852903545,2.74652913581179,2.82290483495452,2.87035491460546,2.86651939236302,2.83533038097471,2.77334415186149,3.05451006705864,3.11804356416122,2.88701630933734,3.02718807256835,2.95881428992775,2.88701630933734,3.18248503470553,2.81932709558314,2.95185464618982,3.3012992406306,3.17206200994729,2.75134649646765,2.6964284226437,2.93496451471652,2.86202324080246,3.01392571947907,2.86361870791345,2.887876772943,2.25210981624465,1.98512518050107,2.22746828456605,2.06886133885497,2.00615773108091,1.94520613495742,2.02291842913504,2.31223098752768,2.04205581494509,2.06744085792057,2.39397607950724,1.89835739861966,2.10542320720528,1.94672340807722,1.98132245022511,2.064855598057,1.96659337777104,1.9495229263458,2.11266343543384,1.99819636135933,2.04616553157592,1.91727190637452,2.09222422433019,1.97790012609079,1.95547714086482,2.01741835159988,2.16200700729576,2.17088900883612,1.90872975252756,2.03899524868891,2.05313241230174,2.07671946279796,1.92853794674744,2.10725672425492,2.02954017351314,2.00145923145597,2.09349202211143,2.07505815822128,1.92596797654544,2.00175141894978,2.01277077432431,1.92721872317531,1.937498872848,2.30437405125727,1.93860121574396,1.91643906296722,1.90486515310751,1.91168528955325,2.2819233419764,1.90787144992946,2.88569024639774,2.18061648043976,2.83758488737405,2.37657898289289,2.61941662819479,3.56065886078822,2.33380495257112,3.15346857309184,2.64681560466341,3.22648403277086,2.22207743224167,2.26147462958443,2.48846372584116,2.23921550054667,2.37402053213599,2.39187689849027,2.34093891793156,3.82029521693236,3.91546616857478,2.22918241718016,2.71143603019124,2.1752503389485,3.67806596357303,2.07206551693359,2.59780194308357,2.90770716199425,2.01994415413271,2.036083682264,2.45916815198835,2.76464216367847,3.08321021435105,3.68792107059849,2.49383774441842,2.10251707257203,2.40689422435585,3.33293597247376,2.61261436224734,2.3308243191516,2.01122902482044,2.48572105721239,2.62695720495105,2.4561754939334,2.18061648043976,2.79894792696815,2.7528270066953,2.40633037809812,2.17849941999448,2.23753954254663,2.46512342412505,2.1243706113791 };
std::vector<double> eccentricities2Euclidean = { 3.442518457951,3.46298522472543,3.59301173576337,3.49080697451654,3.47977010734905,3.2135753712441,3.54617164465192,3.38654199245582,3.63406108919484,3.42629051113105,3.35434047168739,3.37702038292141,3.52145803136523,3.89861513873837,3.60273969824817,3.48001915703539,3.48338915425767,3.41484992349591,3.18772646254348,3.39956860008247,3.17655998421773,3.35382368846863,3.8717437931764,3.14294978218446,3.19359776219026,3.30304909641582,3.26610879590173,3.35418146994663,3.41072817249728,3.39478030707929,3.35956346370576,3.2549244742902,3.51503437631365,3.53986817080335,3.42629051113105,3.57986964380921,3.44934776443315,3.42629051113105,3.69693566800037,3.36303434416005,3.50736368231183,3.71005840025913,3.69942337849202,3.23530524062259,3.12096139034112,3.4642748158886,3.3623007995518,3.55902608401044,3.36901568216396,3.44546078195646,2.61240629816012,2.34742412017939,2.65535936048839,2.30081145106098,2.41520185491814,2.27678135387071,2.41972450222472,2.47108613096886,2.41933875263469,2.26683332720633,2.5430952269495,2.19784743176894,2.32172349774903,2.35691889267889,2.15805467956676,2.39304547943968,2.28939584461345,2.19590528028875,2.45677295111562,2.22141096302928,2.45139416115266,2.17663348621979,2.53923873106357,2.35697546303167,2.27502380939922,2.35926542240023,2.5774923213594,2.65854596850735,2.28636538345617,2.20723054225576,2.25740263725076,2.26436157301199,2.16471707158234,2.57855256555559,2.31919526272944,2.32244124432317,2.50034664263444,2.39530095534291,2.1743351474263,2.24324170194238,2.29654813433843,2.31430335090282,2.192046228223,2.46341226756708,2.22,2.18107007376349,2.18818037038388,2.23451709921107,2.44613981611845,2.17960241022684,3.39483922054246,2.63762519450104,3.39391612546136,2.91945200337324,3.18475535428809,4.06364368516729,2.55666449369747,3.67483332955387,3.17935003839883,3.721934980625,2.72629174276464,2.80028569970994,3.04985245544764,2.65505806590616,2.80135681411704,2.90837870069678,2.89254213452458,4.26575511095828,4.39011009732862,2.63142546920866,3.26472050871127,2.57047336755963,4.16462883500239,2.55674271942512,3.14871402321646,3.43305500489967,2.48526323220164,2.50436951480141,3.0192935155982,3.27267474705324,3.60558825528743,4.11630902630014,3.05063927726632,2.58879637412189,2.87086514254269,3.83193597719656,3.11461073009132,2.87135275900866,2.45199238715512,3.02718791399983,3.17939197541501,2.94441844852256,2.63762519450104,3.35761820342933,3.28564554793524,2.92677296693816,2.66215451592628,2.77354165884223,2.94833286225736,2.58954307423787 };

template <class InputIterator1, class InputIterator2> bool moreOrLessEqual( InputIterator1 begin1, InputIterator1 end1,
                                                                            InputIterator2 begin2, InputIterator2 end2 )
{
  auto n = std::distance( begin1, end1 );
  auto m = std::distance( begin2, end2 );

  if( n != m )
    return false;

  auto it1 = begin1;
  auto it2 = begin2;

  for( ; it1 != end1 && it2 != end2; ++it1, ++it2 )
  {
    // TODO: This precision is sufficient for me, but maybe it makes sense to
    // change it?
    if( std::abs( *it1 - *it2 ) >= 1e-4 )
      return false;
  }

  return true;
}

template <class D> void eccentricityTest()
{
  ALEPH_TEST_BEGIN( "Eccentricity test" );

  auto pc = load<double>( CMAKE_SOURCE_DIR + std::string( "/tests/input/Iris_comma_separated.txt" ) );
  auto e1  = eccentricities<D>( pc );
  auto e2  = eccentricities<D>( pc, 2 );

  ALEPH_ASSERT_THROW( e1.empty() == false );
  ALEPH_ASSERT_THROW( e1.size()  == pc.size() );
  ALEPH_ASSERT_THROW( e1.size()  == e2.size() );

  ALEPH_ASSERT_THROW( moreOrLessEqual( e1.begin(), e1.end(), eccentricities1Euclidean.begin(), eccentricities1Euclidean.end() ) );
  ALEPH_ASSERT_THROW( moreOrLessEqual( e2.begin(), e2.end(), eccentricities2Euclidean.begin(), eccentricities2Euclidean.end() ) );

  ALEPH_TEST_END();
}

int main()
{
  std::cerr << "-- Euclidean distance\n";

  eccentricityTest<distances::Euclidean<double> >();
}
<|endoftext|>


<commit_before>#include "engpar_selector.h"
#include "../engpar.h"
#include <set>
#include <PCU.h>
namespace engpar {

  void getCavity(agi::Ngraph* g, agi::GraphEdge* edge, agi::Migration* plan,
                 Cavity& cav, Peers& peers) {
    agi::PinIterator* pitr = g->pins(edge);
    agi::lid_t deg = g->degree(edge);
    agi::GraphVertex* vtx;
    typedef std::map<agi::part_t, int> Peer_Map;
    Peer_Map peerMap;
    for (agi::lid_t i =0;i<deg;i++) {
      vtx = g->iterate(pitr);
      if (g->owner(vtx)==PCU_Comm_Self()) {
        if(!plan->has(vtx)) {
          cav.push_back(vtx);
        }
      }
      else
	peerMap[g->owner(vtx)]++;
    }
    g->destroy(pitr);

    int max =0;
    Peer_Map::iterator itr;
    for (itr = peerMap.begin(); itr != peerMap.end(); itr++)
      if (itr->second > max)
	max = itr->second;
    for (itr = peerMap.begin(); itr != peerMap.end(); itr++)
      if (itr->second == max)
	peers.insert(itr->first);

  }

  wgt_t addCavity(agi::Ngraph* g, Cavity& cav,
                  part_t peer, agi::Migration* plan,
                  int target_dimension) {
    Cavity::iterator itr;
    wgt_t w=0.0;
    std::set<agi::GraphEdge*> target_edges;
    for (itr = cav.begin();itr!=cav.end();itr++) {
      plan->insert(std::make_pair(*itr,peer));
      if (target_dimension==-1)
        w+= g->weight(*itr);
      else {
        agi::EdgeIterator* eitr = g->edges(*itr,target_dimension);
        agi::GraphEdge* e;
        while ((e=g->iterate(eitr)))
          target_edges.insert(e);
        g->destroy(eitr);
      }
    }
    std::set<agi::GraphEdge*>::iterator sitr;
    for (sitr = target_edges.begin();sitr!=target_edges.end();++sitr) {
      agi::GraphEdge* e = *sitr;
      if (!g->isResidentOn(e,peer))
        w+=g->weight(e);
    }
    return w;
  }

  typedef std::pair<agi::GraphVertex*,agi::GraphVertex*> Connection;
  typedef std::map<Connection,int> Connection_Count;
  void getCavityConnections(agi::Ngraph* g,agi::etype con, int minCon, Cavity cav,
                            Connection_Count& conns) {
    for (unsigned int i=0;i<cav.size();i++) {
      agi::GraphVertex* u = cav[i];
      agi::GraphIterator* gitr = g->adjacent(u,con);
      agi::GraphVertex* v;
      std::map<agi::GraphVertex*, int> occ;
      while ((v = g->iterate(gitr))) {
        if (v==u) continue;
        occ[v]++;
      }
      g->destroy(gitr);
      std::map<agi::GraphVertex*, int>::iterator itr;
      for (itr=occ.begin();itr!=occ.end();itr++) {
        if (itr->second>=minCon) {
          agi::GraphVertex* v = itr->first;
          if (u<v)
            conns[std::make_pair(u,v)]++;
          else
            conns[std::make_pair(v,u)]++;
        }
      }
    }
  }

  //Returns true if the cavity isn't fully connected to the part
  //  In the example of a mesh, full connectivity is having a face connection
  bool isPartiallyConnected(agi::Ngraph* g,agi::etype con, int minCon,
                            agi::Migration* plan, Cavity cav) {
    Connection_Count conns;
    getCavityConnections(g,con,minCon,cav,conns);
    Connection_Count::iterator itr;
    for (itr=conns.begin();itr!=conns.end();itr++) {
      if (itr->second==2)
        continue;
      if (!plan->has(itr->first.first) && !plan->has(itr->first.second))
        return false;
    }
    return true;
  }

  wgt_t Selector::select(Targets* targets, agi::Migration* plan,
                         wgt_t planW, unsigned int cavSize,int target_dimension) {
    q->startIteration();
    Queue::iterator itr;
    for (itr = q->begin();itr!=q->end();itr++) {
      //Create Cavity and peers
      Cavity cav;
      Peers peers;
      getCavity(g,q->get(itr),plan,cav,peers);
      //For each peer of cavity
      Peers::iterator pitr;
      bool sent = false;
      for (pitr = peers.begin();pitr!=peers.end();pitr++) {
        part_t peer = *pitr;
        if (targets->has(peer) &&
            sending[*pitr]<targets->get(peer) &&
            cav.size()< cavSize) {
          //  addCavity to plan
          wgt_t w = addCavity(g,cav,peer,plan,target_dimension);
          planW+=w;
          sending[peer]+=w;
          sent=true;
          break;
        }
      }
      if (!sent && in->minConnectivity > 1 &&
          isPartiallyConnected(g,in->connectivityType,in->minConnectivity,plan,cav)) {
        wgt_t w = addCavity(g,cav,*peers.begin(),plan,target_dimension);
        planW+=w;
        sending[*peers.begin()]+=w;
        sent=true;
      }
      if (!sent) {
        q->addElement(q->get(itr));
      }
    }
    return planW;

  }
  void Selector::insertInteriorEdges(agi::GraphVertex* vtx, agi::part_t dest,
                                     EdgeSet& edges, int dim) {

    agi::EdgeIterator* eitr = g->edges(vtx,dim);
    agi::GraphEdge* e;
    while ((e = g->iterate(eitr))) {
      if (!g->isResidentOn(e,dest))
        edges.insert(e);
    }
    g->destroy(eitr);
  }
  void Selector::tempInsertInteriorEdges(agi::GraphVertex* vtx, agi::part_t dest,
                                         EdgeSet& tmpEdges, int dim,
                                         const EdgeSet& edges) {
    agi::EdgeIterator* eitr = g->edges(vtx,dim);
    agi::GraphEdge* e;
    while ((e = g->iterate(eitr))) {
      if (edges.find(e)!=edges.end())
        continue;
      if (!g->isResidentOn(e,dest))
        tmpEdges.insert(e);
    }
    g->destroy(eitr);
  }

  double Selector::weight(const EdgeSet& edges) {
    EdgeSet::const_iterator itr;
    double w=0;
    for (itr=edges.begin();itr!=edges.end();itr++)
      w+=g->weight(*itr);

    return w;
  }
  struct Migr {
    Migr(int i) :
      id(i), edge_types(0) {}
    void addWeight(double w) {ws[edge_types++]=w;}
    int id;
    double ws[5];
    int edge_types;
  };
  struct CompareMigr {
    //sort by part first completed edge type weights
    bool operator()(const Migr& a, const Migr& b) const {
      if( a.ws[0] < b.ws[0] )
        return true;
      if (a.ws[0]==b.ws[0])
        return a.id<b.id;
      return false;
    }
  };

  void Selector::calculatePlanWeights(agi::Migration* plan, std::unordered_map<int,double>& vtx_weight, PeerEdgeSet* peerEdges, std::unordered_set<part_t>& neighbors) {
    agi::Migration::iterator itr;
    for(itr = plan->begin();itr!=plan->end();itr++) {
      agi::GraphVertex* vtx = *itr;
      const int dest = plan->get(vtx);
      neighbors.insert(dest);
      for (unsigned int i=0;i<completed_dimensions->size();i++) {
        if (completed_dimensions->at(i)!=-1)
          insertInteriorEdges(vtx, dest, peerEdges[i][dest],
                              completed_dimensions->at(i));
        else
          vtx_weight[dest]+=g->weight(vtx);
      }
    }

  }

  void Selector::sendPlanWeight(std::unordered_map<int,double>& vtx_weight, PeerEdgeSet* peerEdges, std::unordered_set<part_t>& neighbors) {
    std::unordered_set<part_t>::iterator sitr;
    for (sitr = neighbors.begin();sitr!=neighbors.end();sitr++) {
      const int dest = *sitr;
      for (unsigned int i=0;i<completed_dimensions->size();i++) {
        double w;
        if (completed_dimensions->at(i)!=-1)
          w = weight(peerEdges[i][dest]);
        else
          w = vtx_weight[dest];
        PCU_COMM_PACK(dest, w);
      }
    }
    delete [] peerEdges;

  }

  void Selector::receiveIncomingWeight(MigrComm& incoming) {
    double w;
    while (PCU_Comm_Receive()) {
      Migr migr(PCU_Comm_Sender());
      for (unsigned int i=0;i<completed_dimensions->size();i++) {
        PCU_COMM_UNPACK(w);
        migr.addWeight(w);
      }
      incoming.insert(migr);
    }

  }
  bool Selector::determineAvailability(Ws& avail) {
    bool isAvail = true;
    for (unsigned int i=0;i<completed_dimensions->size();i++) {
      double totW = getWeight(g,completed_dimensions->at(i),in->countGhosts);
      avail[i] = completed_weights->at(i) - totW;
      if (avail[i]<0)
        isAvail=false;
    }
    return isAvail;
  }

  void Selector::acceptWeight(MigrComm& incoming, bool& isAvail, Ws& avail, Midd& accept) {
    MigrComm::iterator in;
    for (in=incoming.begin();in!=incoming.end();in++) {
      const int nbor = (*in).id;
      if(isAvail) {
        bool hasSpace= true;
        for (unsigned int i=0;i<completed_dimensions->size();i++)
          if ((*in).ws[i] > avail[i])
            hasSpace=false;
        accept[nbor] = new double[completed_dimensions->size()];
        if( hasSpace ) {
          for (unsigned int i=0;i<completed_dimensions->size();i++)
            isAvail = (avail[i]-=accept[nbor][i] = (*in).ws[i])>0;
        } else {
          for (unsigned int i=0;i<completed_dimensions->size();i++)
            isAvail = (avail[i] -=accept[nbor][i] = avail[i])>0;
        }
      } else {
        accept[nbor] = new double[completed_dimensions->size()];
        for (unsigned int i=0;i<completed_dimensions->size();i++)
          accept[nbor][i] = 0;
      }
    }
  }

  void Selector::sendAcceptedWeights(Midd& accept) {
    Midd::iterator acc;
    for (acc=accept.begin();acc!=accept.end();acc++) {
      for (unsigned int i=0;i<completed_dimensions->size();i++)
        PCU_COMM_PACK(acc->first, acc->second[i]);
      delete [] acc->second;
    }
  }

  void Selector::gatherCapacities(Midd* capacity) {
    double w;
    while (PCU_Comm_Receive()) {
      int nbor = PCU_Comm_Sender();
      capacity->insert(std::make_pair(nbor,
                                      new double[completed_dimensions->size()]));
      for (unsigned int i=0;i<completed_dimensions->size();i++) {
        PCU_COMM_UNPACK(w);
        (*capacity)[nbor][i] = w;
      }
    }
  }
  //return  map<int neighbor, pair<double vtxW, double edgeW> > where
  //  neighbor is a neighbor's part id
  //  vtxW is the vtx weight capacity of neighbor
  //  edgeW is the edge weight capacity of neighbor
  Midd* Selector::trim(Targets*, agi::Migration* plan) {
    //compute the weight of the vertices and edges being sent to each peer
    std::unordered_set<part_t> neighbors;
    PeerEdgeSet* peerEdges = new PeerEdgeSet[completed_dimensions->size()];
    std::unordered_map<int,double> vtx_weight;
    calculatePlanWeights(plan,vtx_weight,peerEdges,neighbors);

    //send vtx and edge weight
    PCU_Comm_Begin();
    sendPlanWeight(vtx_weight,peerEdges,neighbors);
    PCU_Comm_Send();
    MigrComm incoming;
    receiveIncomingWeight(incoming);

    Ws avail = new double[completed_dimensions->size()];
    bool isAvail=determineAvailability(avail);

    Midd accept;
    acceptWeight(incoming,isAvail,avail,accept);

    PCU_Barrier();
    delete [] avail;

    PCU_Comm_Begin();
    sendAcceptedWeights(accept);
    PCU_Comm_Send();
    Midd* capacity = new Midd;
    gatherCapacities(capacity);

    return capacity;
  }

  void Selector::combineSets(EdgeSet& edges,const EdgeSet& tempEdges) {
    EdgeSet::const_iterator itr;
    for (itr=tempEdges.begin();itr!=tempEdges.end();itr++)
      edges.insert(*itr);

  }

  void Selector::cancel(agi::Migration*& plan, Midd* capacity) {
    typedef std::pair<agi::GraphVertex*, int> PlanPair;
    std::vector<PlanPair > keep; //temporary plan container
    keep.reserve(plan->size());

    //Plan is a vector so this iterates over the plan in the order they were
    //    selected in.
    PeerEdgeSet* peerEdges = new PeerEdgeSet[completed_dimensions->size()];
    std::unordered_map<int,double> vtx_weight;
    agi::Migration::iterator pitr;
    for(pitr = plan->begin();pitr!=plan->end();pitr++) {
      agi::GraphVertex* v = *pitr;
      int dest = plan->get(v);
      bool isSpace=true;
      EdgeSet* tmpEdges = new EdgeSet[completed_dimensions->size()];

      for (unsigned int i=0;i<completed_dimensions->size();i++) {
        if (completed_dimensions->at(i)!=-1) {
          tempInsertInteriorEdges(v, dest, tmpEdges[i],
                                  completed_dimensions->at(i),
                                  peerEdges[i][dest]);
          if(weight(peerEdges[i][dest])+weight(tmpEdges[i])>(*capacity)[dest][i])
            isSpace=false;
        }
        else {
          if (vtx_weight[dest]+ g->weight(v) > (*capacity)[dest][i])
            isSpace = false;
        }
      }
      if (isSpace) {
        keep.push_back(PlanPair(v,dest));
        for (unsigned int i=0;i<completed_dimensions->size();i++) {
          if (completed_dimensions->at(i)!=-1)
            combineSets(peerEdges[i][dest],tmpEdges[i]);
          else
            vtx_weight[dest]+=g->weight(v);
        }
      }
      delete [] tmpEdges;
    }
    Midd::iterator acc;
    for (acc=capacity->begin();acc!=capacity->end();acc++) {
      delete [] acc->second;
    }
    delete capacity;
    delete [] peerEdges;
    plan->clear();
    for(size_t i=0; i < keep.size(); i++)
      plan->insert(keep[i]);
  }

  Selector* makeSelector(DiffusiveInput* in,Queue* q,
                         std::vector<int>* cd,
                         std::vector<double>* cw ) {
    return new Selector(in,q,cd,cw);
  }
}
<commit_msg>Make selection of part to send to require a stronger connectivity<commit_after>#include "engpar_selector.h"
#include "../engpar.h"
#include <set>
#include <PCU.h>
namespace engpar {

  void getCavity(agi::Ngraph* g, agi::GraphEdge* edge, agi::Migration* plan,
                 Cavity& cav, Peers& peers) {
    agi::PinIterator* pitr = g->pins(edge);
    agi::lid_t deg = g->degree(edge);
    agi::GraphVertex* vtx;
    typedef std::map<agi::part_t, std::unordered_set<agi::GraphEdge*> > Peer_Map;
    Peer_Map peerMap;
    std::set<agi::GraphEdge*> edgesOfCavity;
    for (agi::lid_t i =0;i<deg;i++) {
      vtx = g->iterate(pitr);
      if (g->owner(vtx)==PCU_Comm_Self()) {
        if(!plan->has(vtx)) {
          cav.push_back(vtx);
          agi::GraphEdge* e;
          agi::EdgeIterator* eitr = g->edges(vtx);
          while ((e=g->iterate(eitr)))
            edgesOfCavity.insert(e);
          g->destroy(eitr);
        }
      }
    }
    g->destroy(pitr);
    std::set<agi::GraphEdge*>::iterator sitr;
    for (sitr = edgesOfCavity.begin(); sitr != edgesOfCavity.end(); sitr++) {
      agi::GraphVertex* v;
      agi::PinIterator* pitr = g->pins(*sitr);
      while ((v = g->iterate(pitr))) {
        if (g->owner(v)!=PCU_Comm_Self())
          peerMap[g->owner(v)].insert(*sitr);
      }
    }
    while (peers.size()!=peerMap.size()) {
      unsigned int max =0;
      Peer_Map::iterator itr;
      for (itr = peerMap.begin(); itr != peerMap.end(); itr++)
        if (itr->second.size() > max)
          max = itr->second.size();
      if (max<2&&peers.size()>0)
        break;
      for (itr = peerMap.begin(); itr != peerMap.end(); itr++)
        if (itr->second.size() == max) {
          peers.insert(itr->first);
          itr->second.clear();
        }
    }
  }

  wgt_t addCavity(agi::Ngraph* g, Cavity& cav,
                  part_t peer, agi::Migration* plan,
                  int target_dimension) {
    Cavity::iterator itr;
    wgt_t w=0.0;
    std::set<agi::GraphEdge*> target_edges;
    for (itr = cav.begin();itr!=cav.end();itr++) {
      plan->insert(std::make_pair(*itr,peer));
      if (target_dimension==-1)
        w+= g->weight(*itr);
      else {
        agi::EdgeIterator* eitr = g->edges(*itr,target_dimension);
        agi::GraphEdge* e;
        while ((e=g->iterate(eitr)))
          target_edges.insert(e);
        g->destroy(eitr);
      }
    }
    std::set<agi::GraphEdge*>::iterator sitr;
    for (sitr = target_edges.begin();sitr!=target_edges.end();++sitr) {
      agi::GraphEdge* e = *sitr;
      if (!g->isResidentOn(e,peer))
        w+=g->weight(e);
    }
    return w;
  }

  typedef std::pair<agi::GraphVertex*,agi::GraphVertex*> Connection;
  typedef std::map<Connection,int> Connection_Count;
  void getCavityConnections(agi::Ngraph* g,agi::etype con, int minCon, Cavity cav,
                            Connection_Count& conns) {
    for (unsigned int i=0;i<cav.size();i++) {
      agi::GraphVertex* u = cav[i];
      agi::GraphIterator* gitr = g->adjacent(u,con);
      agi::GraphVertex* v;
      std::map<agi::GraphVertex*, int> occ;
      while ((v = g->iterate(gitr))) {
        if (v==u) continue;
        occ[v]++;
      }
      g->destroy(gitr);
      std::map<agi::GraphVertex*, int>::iterator itr;
      for (itr=occ.begin();itr!=occ.end();itr++) {
        if (itr->second>=minCon) {
          agi::GraphVertex* v = itr->first;
          if (u<v)
            conns[std::make_pair(u,v)]++;
          else
            conns[std::make_pair(v,u)]++;
        }
      }
    }
  }

  //Returns true if the cavity isn't fully connected to the part
  //  In the example of a mesh, full connectivity is having a face connection
  bool isPartiallyConnected(agi::Ngraph* g,agi::etype con, int minCon,
                            agi::Migration* plan, Cavity cav) {
    Connection_Count conns;
    getCavityConnections(g,con,minCon,cav,conns);
    Connection_Count::iterator itr;
    for (itr=conns.begin();itr!=conns.end();itr++) {
      if (itr->second==2)
        continue;
      if (!plan->has(itr->first.first) && !plan->has(itr->first.second))
        return false;
    }
    return true;
  }

  wgt_t Selector::select(Targets* targets, agi::Migration* plan,
                         wgt_t planW, unsigned int cavSize,int target_dimension) {
    q->startIteration();
    Queue::iterator itr;
    for (itr = q->begin();itr!=q->end();itr++) {
      //Create Cavity and peers
      Cavity cav;
      Peers peers;
      getCavity(g,q->get(itr),plan,cav,peers);
      //For each peer of cavity
      Peers::iterator pitr;
      bool sent = false;
      for (pitr = peers.begin();pitr!=peers.end();pitr++) {
        part_t peer = *pitr;
        if (targets->has(peer) &&
            sending[*pitr]<targets->get(peer) &&
            cav.size()< cavSize) {
          //  addCavity to plan
          wgt_t w = addCavity(g,cav,peer,plan,target_dimension);
          planW+=w;
          sending[peer]+=w;
          sent=true;
          break;
        }
      }
      if (!sent && in->minConnectivity > 1 &&
          isPartiallyConnected(g,in->connectivityType,in->minConnectivity,plan,cav)) {
        wgt_t w = addCavity(g,cav,*peers.begin(),plan,target_dimension);
        planW+=w;
        sending[*peers.begin()]+=w;
        sent=true;
      }
      if (!sent) {
        q->addElement(q->get(itr));
      }
    }
    return planW;

  }
  void Selector::insertInteriorEdges(agi::GraphVertex* vtx, agi::part_t dest,
                                     EdgeSet& edges, int dim) {

    agi::EdgeIterator* eitr = g->edges(vtx,dim);
    agi::GraphEdge* e;
    while ((e = g->iterate(eitr))) {
      if (!g->isResidentOn(e,dest))
        edges.insert(e);
    }
    g->destroy(eitr);
  }
  void Selector::tempInsertInteriorEdges(agi::GraphVertex* vtx, agi::part_t dest,
                                         EdgeSet& tmpEdges, int dim,
                                         const EdgeSet& edges) {
    agi::EdgeIterator* eitr = g->edges(vtx,dim);
    agi::GraphEdge* e;
    while ((e = g->iterate(eitr))) {
      if (edges.find(e)!=edges.end())
        continue;
      if (!g->isResidentOn(e,dest))
        tmpEdges.insert(e);
    }
    g->destroy(eitr);
  }

  double Selector::weight(const EdgeSet& edges) {
    EdgeSet::const_iterator itr;
    double w=0;
    for (itr=edges.begin();itr!=edges.end();itr++)
      w+=g->weight(*itr);

    return w;
  }
  struct Migr {
    Migr(int i) :
      id(i), edge_types(0) {}
    void addWeight(double w) {ws[edge_types++]=w;}
    int id;
    double ws[5];
    int edge_types;
  };
  struct CompareMigr {
    //sort by part first completed edge type weights
    bool operator()(const Migr& a, const Migr& b) const {
      if( a.ws[0] < b.ws[0] )
        return true;
      if (a.ws[0]==b.ws[0])
        return a.id<b.id;
      return false;
    }
  };

  void Selector::calculatePlanWeights(agi::Migration* plan, std::unordered_map<int,double>& vtx_weight, PeerEdgeSet* peerEdges, std::unordered_set<part_t>& neighbors) {
    agi::Migration::iterator itr;
    for(itr = plan->begin();itr!=plan->end();itr++) {
      agi::GraphVertex* vtx = *itr;
      const int dest = plan->get(vtx);
      neighbors.insert(dest);
      for (unsigned int i=0;i<completed_dimensions->size();i++) {
        if (completed_dimensions->at(i)!=-1)
          insertInteriorEdges(vtx, dest, peerEdges[i][dest],
                              completed_dimensions->at(i));
        else
          vtx_weight[dest]+=g->weight(vtx);
      }
    }

  }

  void Selector::sendPlanWeight(std::unordered_map<int,double>& vtx_weight, PeerEdgeSet* peerEdges, std::unordered_set<part_t>& neighbors) {
    std::unordered_set<part_t>::iterator sitr;
    for (sitr = neighbors.begin();sitr!=neighbors.end();sitr++) {
      const int dest = *sitr;
      for (unsigned int i=0;i<completed_dimensions->size();i++) {
        double w;
        if (completed_dimensions->at(i)!=-1)
          w = weight(peerEdges[i][dest]);
        else
          w = vtx_weight[dest];
        PCU_COMM_PACK(dest, w);
      }
    }
    delete [] peerEdges;

  }

  void Selector::receiveIncomingWeight(MigrComm& incoming) {
    double w;
    while (PCU_Comm_Receive()) {
      Migr migr(PCU_Comm_Sender());
      for (unsigned int i=0;i<completed_dimensions->size();i++) {
        PCU_COMM_UNPACK(w);
        migr.addWeight(w);
      }
      incoming.insert(migr);
    }

  }
  bool Selector::determineAvailability(Ws& avail) {
    bool isAvail = true;
    for (unsigned int i=0;i<completed_dimensions->size();i++) {
      double totW = getWeight(g,completed_dimensions->at(i),in->countGhosts);
      avail[i] = completed_weights->at(i) - totW;
      if (avail[i]<0)
        isAvail=false;
    }
    return isAvail;
  }

  void Selector::acceptWeight(MigrComm& incoming, bool& isAvail, Ws& avail, Midd& accept) {
    MigrComm::iterator in;
    for (in=incoming.begin();in!=incoming.end();in++) {
      const int nbor = (*in).id;
      if(isAvail) {
        bool hasSpace= true;
        for (unsigned int i=0;i<completed_dimensions->size();i++)
          if ((*in).ws[i] > avail[i])
            hasSpace=false;
        accept[nbor] = new double[completed_dimensions->size()];
        if( hasSpace ) {
          for (unsigned int i=0;i<completed_dimensions->size();i++)
            isAvail = (avail[i]-=accept[nbor][i] = (*in).ws[i])>0;
        } else {
          for (unsigned int i=0;i<completed_dimensions->size();i++)
            isAvail = (avail[i] -=accept[nbor][i] = avail[i])>0;
        }
      } else {
        accept[nbor] = new double[completed_dimensions->size()];
        for (unsigned int i=0;i<completed_dimensions->size();i++)
          accept[nbor][i] = 0;
      }
    }
  }

  void Selector::sendAcceptedWeights(Midd& accept) {
    Midd::iterator acc;
    for (acc=accept.begin();acc!=accept.end();acc++) {
      for (unsigned int i=0;i<completed_dimensions->size();i++)
        PCU_COMM_PACK(acc->first, acc->second[i]);
      delete [] acc->second;
    }
  }

  void Selector::gatherCapacities(Midd* capacity) {
    double w;
    while (PCU_Comm_Receive()) {
      int nbor = PCU_Comm_Sender();
      capacity->insert(std::make_pair(nbor,
                                      new double[completed_dimensions->size()]));
      for (unsigned int i=0;i<completed_dimensions->size();i++) {
        PCU_COMM_UNPACK(w);
        (*capacity)[nbor][i] = w;
      }
    }
  }
  //return  map<int neighbor, pair<double vtxW, double edgeW> > where
  //  neighbor is a neighbor's part id
  //  vtxW is the vtx weight capacity of neighbor
  //  edgeW is the edge weight capacity of neighbor
  Midd* Selector::trim(Targets*, agi::Migration* plan) {
    //compute the weight of the vertices and edges being sent to each peer
    std::unordered_set<part_t> neighbors;
    PeerEdgeSet* peerEdges = new PeerEdgeSet[completed_dimensions->size()];
    std::unordered_map<int,double> vtx_weight;
    calculatePlanWeights(plan,vtx_weight,peerEdges,neighbors);

    //send vtx and edge weight
    PCU_Comm_Begin();
    sendPlanWeight(vtx_weight,peerEdges,neighbors);
    PCU_Comm_Send();
    MigrComm incoming;
    receiveIncomingWeight(incoming);

    Ws avail = new double[completed_dimensions->size()];
    bool isAvail=determineAvailability(avail);

    Midd accept;
    acceptWeight(incoming,isAvail,avail,accept);

    PCU_Barrier();
    delete [] avail;

    PCU_Comm_Begin();
    sendAcceptedWeights(accept);
    PCU_Comm_Send();
    Midd* capacity = new Midd;
    gatherCapacities(capacity);

    return capacity;
  }

  void Selector::combineSets(EdgeSet& edges,const EdgeSet& tempEdges) {
    EdgeSet::const_iterator itr;
    for (itr=tempEdges.begin();itr!=tempEdges.end();itr++)
      edges.insert(*itr);

  }

  void Selector::cancel(agi::Migration*& plan, Midd* capacity) {
    typedef std::pair<agi::GraphVertex*, int> PlanPair;
    std::vector<PlanPair > keep; //temporary plan container
    keep.reserve(plan->size());

    //Plan is a vector so this iterates over the plan in the order they were
    //    selected in.
    PeerEdgeSet* peerEdges = new PeerEdgeSet[completed_dimensions->size()];
    std::unordered_map<int,double> vtx_weight;
    agi::Migration::iterator pitr;
    for(pitr = plan->begin();pitr!=plan->end();pitr++) {
      agi::GraphVertex* v = *pitr;
      int dest = plan->get(v);
      bool isSpace=true;
      EdgeSet* tmpEdges = new EdgeSet[completed_dimensions->size()];

      for (unsigned int i=0;i<completed_dimensions->size();i++) {
        if (completed_dimensions->at(i)!=-1) {
          tempInsertInteriorEdges(v, dest, tmpEdges[i],
                                  completed_dimensions->at(i),
                                  peerEdges[i][dest]);
          if(weight(peerEdges[i][dest])+weight(tmpEdges[i])>(*capacity)[dest][i])
            isSpace=false;
        }
        else {
          if (vtx_weight[dest]+ g->weight(v) > (*capacity)[dest][i])
            isSpace = false;
        }
      }
      if (isSpace) {
        keep.push_back(PlanPair(v,dest));
        for (unsigned int i=0;i<completed_dimensions->size();i++) {
          if (completed_dimensions->at(i)!=-1)
            combineSets(peerEdges[i][dest],tmpEdges[i]);
          else
            vtx_weight[dest]+=g->weight(v);
        }
      }
      delete [] tmpEdges;
    }
    Midd::iterator acc;
    for (acc=capacity->begin();acc!=capacity->end();acc++) {
      delete [] acc->second;
    }
    delete capacity;
    delete [] peerEdges;
    plan->clear();
    for(size_t i=0; i < keep.size(); i++)
      plan->insert(keep[i]);
  }

  Selector* makeSelector(DiffusiveInput* in,Queue* q,
                         std::vector<int>* cd,
                         std::vector<double>* cw ) {
    return new Selector(in,q,cd,cw);
  }
}
<|endoftext|>


<commit_before>#include <boost/shared_ptr.hpp>
#include <boost/foreach.hpp>
#define forEach BOOST_FOREACH
#include <ros/ros.h>
#include "planner_modules_pr2/tidyup_planning_scene_updater.h"
#include "planner_modules_pr2/navigation_modules.h"

using namespace planner_modules_pr2;

int main(int argc, char** argv)
{
	ros::init(argc, argv, "robot_near_test");

	ros::NodeHandle nh;
	ros::Publisher error_scene_publisher = nh.advertise<moveit_msgs::PlanningScene>("/modules_test/failed_scene", 1, true);

	vector<geometry_msgs::Pose2D> robot_poses;
	{
		robot_poses.push_back(geometry_msgs::Pose2D());
		geometry_msgs::Pose2D& robot_pose = robot_poses.back();
		robot_pose.x = 4.2;
		robot_pose.y = 6.85;
		robot_pose.theta = -M_PI_2;
	}
	{
		robot_poses.push_back(geometry_msgs::Pose2D());
		geometry_msgs::Pose2D& robot_pose = robot_poses.back();
		robot_pose.x = 1.3;
		robot_pose.y = 6.35;
		robot_pose.theta = -M_PI;
	}
//	{
//		robot_poses.push_back(geometry_msgs::Pose2D());
//		geometry_msgs::Pose2D& robot_pose = robot_poses.back();
//		robot_pose.x = 4.2;
//		robot_pose.y = 7.85;
//		robot_pose.theta = M_PI_2;
//	}
//	{
//		robot_poses.push_back(geometry_msgs::Pose2D());
//		geometry_msgs::Pose2D& robot_pose = robot_poses.back();
//		robot_pose.x = 3.7;
//		robot_pose.y = 7.85;
//		robot_pose.theta = M_PI_2;
//	}

	double torso_height = 0.2;

	::navigation_init(0, NULL);

	int test_count = 0;
	int success_count = 0;

	forEach(const geometry_msgs::Pose2D& start_pose, robot_poses)
	{
		forEach(const geometry_msgs::Pose2D& goal_pose, robot_poses)
		{
			if (hypot(start_pose.x-goal_pose.x, start_pose.y-goal_pose.y) < 0.0001)
				continue;
			TidyupPlanningSceneUpdaterPtr psu = TidyupPlanningSceneUpdater::instance();
			planning_scene::PlanningScenePtr scene = psu->getEmptyScene();
			psu->updateArmToSidePosition(scene, "right_arm");
			psu->updateArmToSidePosition(scene, "left_arm");
			psu->updateRobotPose2D(scene, start_pose, torso_height);
			//psu->visualize(scene);
			nav_msgs::GetPlan srv;
			srv.request.goal.pose.position.x = goal_pose.x;
			srv.request.goal.pose.position.y = goal_pose.y;
			srv.request.goal.pose.position.z = 0;
			srv.request.goal.pose.orientation = tf::createQuaternionMsgFromYaw(goal_pose.theta);
			srv.request.goal.header.frame_id = scene->getPlanningFrame();
			test_count++;
			bool result = navigation::compute_value(scene, srv) < modules::INFINITE_COST;
			if (result != true)
			{
				ROS_ERROR_STREAM("navigation test failed...");
				ROS_ERROR_STREAM("start: \n"<<start_pose);
				ROS_ERROR_STREAM("goal: \n"<<goal_pose);
			}
			else
			{
				success_count++;
			}
		}
	}
	if (success_count==test_count)
	{
		ROS_INFO_STREAM(success_count<<" navigation tests successful.");
	}
	else
	{
		ROS_ERROR_STREAM("only "<<success_count<<" of "<<test_count<<" navigation tests successful!");
	}

	ros::spin();
	return 0;
}

<commit_msg>enabled more testing locations<commit_after>#include <boost/shared_ptr.hpp>
#include <boost/foreach.hpp>
#define forEach BOOST_FOREACH
#include <ros/ros.h>
#include "planner_modules_pr2/tidyup_planning_scene_updater.h"
#include "planner_modules_pr2/navigation_modules.h"

using namespace planner_modules_pr2;

int main(int argc, char** argv)
{
	ros::init(argc, argv, "robot_near_test");

	ros::NodeHandle nh;
	ros::Publisher error_scene_publisher = nh.advertise<moveit_msgs::PlanningScene>("/modules_test/failed_scene", 1, true);

	vector<geometry_msgs::Pose2D> robot_poses;
	{
		robot_poses.push_back(geometry_msgs::Pose2D());
		geometry_msgs::Pose2D& robot_pose = robot_poses.back();
		robot_pose.x = 4.2;
		robot_pose.y = 6.85;
		robot_pose.theta = -M_PI_2;
	}
	{
		robot_poses.push_back(geometry_msgs::Pose2D());
		geometry_msgs::Pose2D& robot_pose = robot_poses.back();
		robot_pose.x = 1.3;
		robot_pose.y = 6.35;
		robot_pose.theta = -M_PI;
	}
	{
		robot_poses.push_back(geometry_msgs::Pose2D());
		geometry_msgs::Pose2D& robot_pose = robot_poses.back();
		robot_pose.x = 4.2;
		robot_pose.y = 7.85;
		robot_pose.theta = M_PI_2;
	}
	{
		robot_poses.push_back(geometry_msgs::Pose2D());
		geometry_msgs::Pose2D& robot_pose = robot_poses.back();
		robot_pose.x = 3.7;
		robot_pose.y = 7.85;
		robot_pose.theta = M_PI_2;
	}

	double torso_height = 0.2;

	::navigation_init(0, NULL);

	int test_count = 0;
	int success_count = 0;

	forEach(const geometry_msgs::Pose2D& start_pose, robot_poses)
	{
		forEach(const geometry_msgs::Pose2D& goal_pose, robot_poses)
		{
			if (hypot(start_pose.x-goal_pose.x, start_pose.y-goal_pose.y) < 0.0001)
				continue;
			TidyupPlanningSceneUpdaterPtr psu = TidyupPlanningSceneUpdater::instance();
			planning_scene::PlanningScenePtr scene = psu->getEmptyScene();
			psu->updateArmToSidePosition(scene, "right_arm");
			psu->updateArmToSidePosition(scene, "left_arm");
			psu->updateRobotPose2D(scene, start_pose, torso_height);
			//psu->visualize(scene);
			nav_msgs::GetPlan srv;
			srv.request.goal.pose.position.x = goal_pose.x;
			srv.request.goal.pose.position.y = goal_pose.y;
			srv.request.goal.pose.position.z = 0;
			srv.request.goal.pose.orientation = tf::createQuaternionMsgFromYaw(goal_pose.theta);
			srv.request.goal.header.frame_id = scene->getPlanningFrame();
			test_count++;
			bool result = navigation::compute_value(scene, srv) < modules::INFINITE_COST;
			if (result != true)
			{
				ROS_ERROR_STREAM("navigation test failed...");
				ROS_ERROR_STREAM("start: \n"<<start_pose);
				ROS_ERROR_STREAM("goal: \n"<<goal_pose);
			}
			else
			{
				success_count++;
			}
		}
	}
	if (success_count==test_count)
	{
		ROS_INFO_STREAM(success_count<<" navigation tests successful.");
	}
	else
	{
		ROS_ERROR_STREAM("only "<<success_count<<" of "<<test_count<<" navigation tests successful!");
	}

	ros::spin();
	return 0;
}

<|endoftext|>


<commit_before>#include "JNIRhodes.h"

#include "gapikey.h"

#include <common/rhoparams.h>

#undef DEFAULT_LOGCATEGORY
#define DEFAULT_LOGCATEGORY "MapView"

RHO_GLOBAL void mapview_create(rho_param *p)
{
#ifdef GOOGLE_API_KEY
    jclass clsMapView = getJNIClass(RHODES_JAVA_CLASS_MAPVIEW);
    if (!clsMapView) return;
    jmethodID midCreate = getJNIClassStaticMethod(clsMapView, "create", "(Ljava/lang/String;Ljava/util/Map;)V");
    if (!midCreate) return;

    if (p->type != RHO_PARAM_HASH) {
        RAWLOG_ERROR("create: wrong input parameter (expect Hash)");
        return;
    }

    JNIEnv *env = jnienv();
    jobject paramsObj = RhoValueConverter(env).createObject(p);
    env->CallStaticVoidMethod(clsMapView, midCreate, env->NewStringUTF(GOOGLE_API_KEY), paramsObj);
#else
    RHO_NOT_IMPLEMENTED;
#endif
}

<commit_msg>Add alert when Google API key was not specified<commit_after>#include "JNIRhodes.h"

#include "gapikey.h"

#include <common/rhoparams.h>

#undef DEFAULT_LOGCATEGORY
#define DEFAULT_LOGCATEGORY "MapView"

extern "C" void alert_show_popup(char *);

RHO_GLOBAL void mapview_create(rho_param *p)
{
#ifdef GOOGLE_API_KEY
    jclass clsMapView = getJNIClass(RHODES_JAVA_CLASS_MAPVIEW);
    if (!clsMapView) return;
    jmethodID midCreate = getJNIClassStaticMethod(clsMapView, "create", "(Ljava/lang/String;Ljava/util/Map;)V");
    if (!midCreate) return;

    if (p->type != RHO_PARAM_HASH) {
        RAWLOG_ERROR("create: wrong input parameter (expect Hash)");
        return;
    }

    JNIEnv *env = jnienv();
    jobject paramsObj = RhoValueConverter(env).createObject(p);
    env->CallStaticVoidMethod(clsMapView, midCreate, env->NewStringUTF(GOOGLE_API_KEY), paramsObj);
#else
    alert_show_popup("Google API key problem");
#endif
}

<|endoftext|>


<commit_before>#ifndef SJTU_LCTREE_HPP
#define SJTU_LCTREE_HPP

#include "LCTNode.hpp"
#include "TBase.hpp"

namespace sjtu{

template<class T, class A, class M>
class LCTree : public TBase<T, A, M>{
private:

protected:
	LCTNode<T, A, M>* access(LCTNode<T, A, M> *u);
	void setRoot(LCTNode<T, A, M> *u);

};

#include "source/LCTree.cpp"

/*

add(u, v) {
	add v into aaaTree of u;
}

del(u, v) {
	delete v in aaaTree of u;
}

*/

template<class T, class A, class M>
void LCTree<T, A, M>::rotate(LCTNode<T, A, M> *u, int c) {
	LCTNode<T, A, M> *v = u->father;
	v->child[c ^ 1] = u->child[c];
	if (u->child[c] != nullptr) {
		u->child[c]->father = v;
	}
	u->father = v->father;
	if (v->father->child[0] == v) {
		u->father->child[0] = u;
	} else if (v->father->child[1] == v) {
		u->father->child[1] = u;
	}
	v->father = u;
	u->child[c] = v;
}

template<class T, class A, class M>
void LCTree<T, A, M>::zig(LCTNode<T, A, M> *u) {
	LCTree<T, A, M>::rotate(u, 0);
}

template<class T, class A, class M>
void LCTree<T, A, M>::zag(LCTNode<T, A, M> *u) {
	LCTree<T, A, M>::rotate(u, 1);
}

template<class T, class A, class M>
LCTNode<T, A, M>* LCTree<T, A, M>::getSplayRoot(LCTNode<T, A, M> *u) {
	while (!LCTree<T, A, M>::isSplayRoot(u)) {
		u = u->father;
	}
	return u;
}

template<class T, class A, class M>
void LCTree<T, A, M>::splay(LCTNode<T, A, M> *u) {
	LCTNode<T, A, M> uRoot = LCTree<T, A, M>::getSplayRoot(u);
	del(uRoot->father, uRoot);

	while (!isSplayRoot(u)) {
		LCTNode<T, A, M> *v = u->father;
		if (isSplayRoot(v)) {
			v->update();
			u->update();
			if (v->child[0] == u) {
				LCTree<T, A, M>::zig(u);
			} else {
				LCTree<T, A, M>::zag(u);
			}
		} else {
			LCTNode<T, A, M> *w = v->father;
			w->update();
			v->update();
			u->update();
			if (w->child[0] == v) {
				if (v->child[0] == u) {
					LCTree<T, A, M>::zig(v);
					LCTree<T, A, M>::zig(u);
				} else {
					LCTree<T, A, M>::zag(u);
					LCTree<T, A, M>::zig(u);
				}
			} else {
				if (v->child[1] == u) {
					LCTree<T, A, M>::zag(v);
					LCTree<T, A, M>::zag(u);
				} else {
					LCTree<T, A, M>::zig(u);
					LCTree<T, A, M>::zag(u);
				}
			}
		}
	}
	LCTree<T, A, M>::update(u);
	add(u->father, u);
}

template<class T, class A, class M>
LCTNode<T, A, M>* LCTree<T, A, M>::access(LCTNode<T, A, M> *u) {
	LCTNode<T, A, M>* v = nullptr;
	for ( ; u != nullptr; u = u->father) {
		LCTree<T, A, M>::splay(u);
		LCTree<T, A, M>::del(u, v);
		LCTree<T, A, M>::add(u, u->child[1]);
		if (u->child[1] != nullptr) {
			u->sum -= u->child[1]->sum;
		}
		u->child[1] = v;
		u->sum += v->sum;

		v = u;
		v->update();
	}
	return v;
}

template<class T, class A, class M>
void LCTree<T, A, M>::setRoot(LCTNode<T, A, M> *u) {
	LCTree<T, A, M>::access(u)->reverse ^= true;
	LCTree<T, A, M>::splay(u);
}

template<class T, class A, class M>
void LCTree<T, A, M>::link(LCTNode<T, A, M> *u, LCTNode<T, A, M> *v) {
	LCTree<T, A, M>::setRoot(u);
	for (LCTNode<T, A, M> *vv = v; vv != nullptr; vv = vv->father) {
		vv->sum += u->sum;
	}
	u->father = v;
	LCTree<T, A, M>::access(u);
}

template<class T, class A, class M>
void LCTree<T, A, M>::cut(LCTNode<T, A, M> *u, LCTNode<T, A, M> *v) {
	LCTree<T, A, M>::setRoot(u);
	LCTree<T, A, M>::access(v);
	LCTree<T, A, M>::splay(v);
	v->child[0]->father = nullptr;
	v->child[0] = nullptr;
	update(v);
}

template<class T, class A, class B>
void LCTree<T, A, M>::modifyChain(LCTNode<T, A, M> *u, LCTNode<T, A, M> *v, T value) {
	LCTree<T, A, M>::setRoot(u);
	LCTree<T, A, M>::access(v);
	LCTree<T, A, M>::splay(v);
	v->makeTagChain(value);
}

template<class T, class A, class B>
T LCTree<T, A, M>::queryChain(LCTNode<T, A, M> *u, LCTNode<T, A, M> *v) {
	LCTree<T, A, M>::setRoot(u);
	LCTree<T, A, M>::access(v);
	LCTree<T, A, M>::splay(v);
	return v->sumChain;
}

template<class T, class A, class B>
void LCTree<T, A, M>::modifySubtree(LCTNode<T, A, M> *u, T value) {
	LCTree<T, A, M>::access(u);
	LCTree<T, A, M>::splay(u);
	u->makeTagSubtree(value);
	u->update();
	LCTree<T, A, M>::splay(u);
}

template<class T, class A, class B>
void LCTree<T, A, M>::querySubtree(LCTNode<T, A, M> *u) {
	LCTree<T, A, M>::access(u);
	LCTree<T, A, M>::splay(u);
	return u->sumSubtree;
}

}

#endif
<commit_msg>some changes<commit_after>#ifndef SJTU_LCTREE_HPP
#define SJTU_LCTREE_HPP

#include "LCTNode.hpp"
#include "TBase.hpp"

namespace sjtu{

template<class T, class A, class M>
class LCTree : public TBase<T, A, M>{
private:

protected:
	LCTNode<T, A, M>* access(LCTNode<T, A, M> *u);
	void setRoot(LCTNode<T, A, M> *u);

};

#include "source/LCTree.cpp"

/*

add(u, v) {
	add v into aaaTree of u;
}

del(u, v) {
	delete v in aaaTree of u;
}

*/

template<class T, class A, class M>
void LCTree<T, A, M>::rotate(LCTNode<T, A, M> *u, int c) {
	LCTNode<T, A, M> *v = u->father;
	v->child[c ^ 1] = u->child[c];
	if (u->child[c] != nullptr) {
		u->child[c]->father = v;
	}
	u->father = v->father;
	if (v->father->child[0] == v) {
		u->father->child[0] = u;
	} else if (v->father->child[1] == v) {
		u->father->child[1] = u;
	}
	v->father = u;
	u->child[c] = v;
}

template<class T, class A, class M>
void LCTree<T, A, M>::zig(LCTNode<T, A, M> *u) {
	LCTree<T, A, M>::rotate(u, 0);
}

template<class T, class A, class M>
void LCTree<T, A, M>::zag(LCTNode<T, A, M> *u) {
	LCTree<T, A, M>::rotate(u, 1);
}

template<class T, class A, class M>
LCTNode<T, A, M>* LCTree<T, A, M>::getSplayRoot(LCTNode<T, A, M> *u) {
	while (!LCTree<T, A, M>::isSplayRoot(u)) {
		u = u->father;
	}
	return u;
}

template<class T, class A, class M>
void LCTree<T, A, M>::splay(LCTNode<T, A, M> *u) {
	LCTNode<T, A, M> uRoot = LCTree<T, A, M>::getSplayRoot(u);
	del(uRoot->father, uRoot);

	u->clearTag();
	while (!isSplayRoot(u)) {
		LCTNode<T, A, M> *v = u->father;
		if (isSplayRoot(v)) {
			v->clearTag();
			u->clearTag();
			if (v->child[0] == u) {
				LCTree<T, A, M>::zig(u);
			} else {
				LCTree<T, A, M>::zag(u);
			}
		} else {
			LCTNode<T, A, M> *w = v->father;
			w->clearTag();
			v->clearTag();
			u->clearTag();
			if (w->child[0] == v) {
				if (v->child[0] == u) {
					LCTree<T, A, M>::zig(v);
					LCTree<T, A, M>::zig(u);
				} else {
					LCTree<T, A, M>::zag(u);
					LCTree<T, A, M>::zig(u);
				}
			} else {
				if (v->child[1] == u) {
					LCTree<T, A, M>::zag(v);
					LCTree<T, A, M>::zag(u);
				} else {
					LCTree<T, A, M>::zig(u);
					LCTree<T, A, M>::zag(u);
				}
			}
		}
	}
	LCTree<T, A, M>::update(u);
	add(u->father, u);
}

template<class T, class A, class M>
LCTNode<T, A, M>* LCTree<T, A, M>::access(LCTNode<T, A, M> *u) {
	LCTNode<T, A, M>* v = nullptr;
	for ( ; u != nullptr; u = u->father) {
		LCTree<T, A, M>::splay(u);
		LCTree<T, A, M>::del(u, v);
		LCTree<T, A, M>::add(u, u->child[1]);

		u->child[1] = v;

		v = u;
		v->update();
	}
	return v;
}

template<class T, class A, class M>
void LCTree<T, A, M>::setRoot(LCTNode<T, A, M> *u) {
	LCTree<T, A, M>::access(u)->reverse ^= true;
	LCTree<T, A, M>::splay(u);
}

template<class T, class A, class M>
void LCTree<T, A, M>::link(LCTNode<T, A, M> *u, LCTNode<T, A, M> *v) {
	LCTree<T, A, M>::setRoot(u);
	for (LCTNode<T, A, M> *vv = v; vv != nullptr; vv = vv->father) {
		vv->sum += u->sum;
	}
	u->father = v;
	LCTree<T, A, M>::access(u);
}

template<class T, class A, class M>
void LCTree<T, A, M>::cut(LCTNode<T, A, M> *u, LCTNode<T, A, M> *v) {
	LCTree<T, A, M>::setRoot(u);
	LCTree<T, A, M>::access(v);
	LCTree<T, A, M>::splay(v);
	v->child[0]->father = nullptr;
	v->child[0] = nullptr;
	v->update();
}

template<class T, class A, class B>
void LCTree<T, A, M>::modifyChain(LCTNode<T, A, M> *u, LCTNode<T, A, M> *v, T value) {
	LCTree<T, A, M>::setRoot(u);
	LCTree<T, A, M>::access(v);
	LCTree<T, A, M>::splay(v);
	v->makeTagChain(value);
	v->clearTag();
}

template<class T, class A, class B>
T LCTree<T, A, M>::queryChain(LCTNode<T, A, M> *u, LCTNode<T, A, M> *v) {
	LCTree<T, A, M>::setRoot(u);
	LCTree<T, A, M>::access(v);
	LCTree<T, A, M>::splay(v);
	return v->sumChain;
}

template<class T, class A, class B>
void LCTree<T, A, M>::modifySubtree(LCTNode<T, A, M> *u, T value) {
	LCTree<T, A, M>::access(u);
	LCTree<T, A, M>::splay(u);
	u->makeTagSubtree(value);
	u->clearTag();
	u->update();
	LCTree<T, A, M>::splay(u);
}

template<class T, class A, class B>
void LCTree<T, A, M>::querySubtree(LCTNode<T, A, M> *u) {
	LCTree<T, A, M>::access(u);
	LCTree<T, A, M>::splay(u);
	return u->sumSubtree;
}

}

#endif
<|endoftext|>


<commit_before>#pragma once

#include "alcpp/System.hpp"

#include "alcpp/event/EventQueue.hpp"
#include "alcpp/event/EventSource.hpp"
#include "alcpp/event/Event.hpp"

#include "alcpp/util/ToIntegral.hpp"
<commit_msg>updated header<commit_after>#pragma once

#include "alcpp/System.hpp"

#include "alcpp/event/EventQueue.hpp"
#include "alcpp/event/EventSource.hpp"
#include "alcpp/event/Event.hpp"

#include "alcpp/input/KeyboardState.hpp"
#include "alcpp/input/MouseState.hpp"

#include "alcpp/util/ToIntegral.hpp"
<|endoftext|>


<commit_before>/*
  This file is part of KOrganizer.

  Copyright (C) 2004 Reinhold Kainhofer <reinhold@kainhofer.com>
	large parts of code taken from KOEditorGeneralJournal.cpp:
  Copyright (c) 2001 Cornelius Schumacher <schumacher@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.

  This program 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 General Public License for more details.

  You should have received a copy of the GNU General Public License along
  with this program; if not, write to the Free Software Foundation, Inc.,
  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

  As a special exception, permission is given to link this program
  with any edition of Qt, and distribute the resulting executable,
  without including the source code for Qt in the source distribution.
*/

#include "koeditorgeneraljournal.h"
#include "koprefs.h"
#include "koeditorgeneral.h"
#include "koglobals.h"

#include <libkdepim/categoryselectdialog.h>

#include <kcal/journal.h>

#include <ktextedit.h>
#include <kdateedit.h>
#include <ktimeedit.h>
#include <kglobal.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <kdebug.h>
#include <KSqueezedTextLabel>

#include <q3groupbox.h>
#include <QDateTime>
#include <QCheckBox>
#include <QLabel>
#include <QLayout>
#include <QHBoxLayout>
#include <QBoxLayout>
#include <QPushButton>

KOEditorGeneralJournal::KOEditorGeneralJournal( QObject *parent ) : QObject( parent )
{
}

KOEditorGeneralJournal::~KOEditorGeneralJournal()
{
}

void KOEditorGeneralJournal::initTitle( QWidget *parent, QBoxLayout *topLayout )
{
  QHBoxLayout *hbox = new QHBoxLayout();
  topLayout->addItem( hbox );

  QString whatsThis = i18n("Sets the title of this journal.");
  QLabel *summaryLabel = new QLabel( i18n("T&itle:"), parent );
  summaryLabel->setWhatsThis( whatsThis );
  QFont f = summaryLabel->font();
  f.setBold( true );
  summaryLabel->setFont( f );
  hbox->addWidget( summaryLabel );

  mSummaryEdit = new FocusLineEdit( parent );
  mSummaryEdit->setWhatsThis( whatsThis );
  summaryLabel->setBuddy( mSummaryEdit );
  hbox->addWidget( mSummaryEdit );
}

void KOEditorGeneralJournal::initDate( QWidget *parent, QBoxLayout *topLayout )
{
  QBoxLayout *dateLayout = new QHBoxLayout();
  topLayout->addItem( dateLayout );

  mDateLabel = new QLabel( i18n("&Date:"), parent );
  dateLayout->addWidget( mDateLabel );

  mDateEdit = new KDateEdit( parent );
  dateLayout->addWidget( mDateEdit );
  mDateLabel->setBuddy( mDateEdit );

  dateLayout->addStretch();

  mTimeCheckBox = new QCheckBox( i18n("&Time: "), parent );
  dateLayout->addWidget( mTimeCheckBox );

  mTimeEdit = new KTimeEdit( parent );
  dateLayout->addWidget( mTimeEdit );
  connect( mTimeCheckBox, SIGNAL(toggled(bool)),
           mTimeEdit, SLOT(setEnabled(bool)) );

  dateLayout->addStretch();
  setTime( QTime( -1, -1, -1 ) );
}

void KOEditorGeneralJournal::setDate( const QDate &date )
{
//  kDebug(5850) <<"KOEditorGeneralJournal::setDate(): Date:" << date.toString();

  mDateEdit->setDate( date );
}

void KOEditorGeneralJournal::setTime( const QTime &time )
{
kDebug()<<"KOEditorGeneralJournal::setTime, time="<<time.toString();
  bool validTime = time.isValid();
  mTimeCheckBox->setChecked( validTime );
  mTimeEdit->setEnabled( validTime );
  if ( validTime ) {
kDebug()<<"KOEditorGeneralJournal::setTime, time is valid";
    mTimeEdit->setTime( time );
  }
}

void KOEditorGeneralJournal::initDescription( QWidget *parent, QBoxLayout *topLayout )
{
  QBoxLayout *htmlLayout = new QHBoxLayout();
  topLayout->addItem( htmlLayout );
  mHtmlLabel = new QLabel( "Use HTML", parent );
  mHtmlCheckBox = new QCheckBox( parent );
  htmlLayout->addWidget( mHtmlLabel );
  htmlLayout->addWidget( mHtmlCheckBox );
  mHtmlLabel->setBuddy( mHtmlCheckBox );
  htmlLayout->addStretch();
  mDescriptionEdit = new KTextEdit( parent );
  mDescriptionEdit->append("");
  mDescriptionEdit->setReadOnly( false );
  mDescriptionEdit->setOverwriteMode( false );
  mDescriptionEdit->setLineWrapMode( KTextEdit::WidgetWidth );
  mDescriptionEdit->setTabChangesFocus( true );
  topLayout->addWidget( mDescriptionEdit );
}

void KOEditorGeneralJournal::initCategories(QWidget *parent, QBoxLayout *topLayout)
{
  QBoxLayout *categoriesLayout = new QHBoxLayout();
  categoriesLayout->setSpacing( topLayout->spacing() );
  topLayout->addItem( categoriesLayout );

  QString whatsThis = i18n("Allows you to select the categories that this "
      "journal belongs to.");

  mCategoriesButton = new QPushButton(parent);
  mCategoriesButton->setText(i18n("Select Cate&gories..."));
  mCategoriesButton->setWhatsThis( whatsThis );
  connect(mCategoriesButton,SIGNAL(clicked()),SLOT(selectCategories()));
  categoriesLayout->addWidget(mCategoriesButton);

  mCategoriesLabel = new KSqueezedTextLabel(parent);
  mCategoriesLabel->setWhatsThis( whatsThis );
  mCategoriesLabel->setFrameStyle(QFrame::Panel|QFrame::Sunken);
  categoriesLayout->addWidget(mCategoriesLabel,1);
}

void KOEditorGeneralJournal::setCategories( const QStringList &categories )
{
  mCategoriesLabel->setText( categories.join(",") );
  mCategories = categories;
}

void KOEditorGeneralJournal::selectCategories()
{
  KPIM::CategorySelectDialog *categoryDialog = new KPIM::CategorySelectDialog( KOPrefs::instance(), mCategoriesButton  );
  KOGlobals::fitDialogToScreen( categoryDialog );
  categoryDialog->setSelected( mCategories );

  connect(categoryDialog, SIGNAL(editCategories()), this, SIGNAL(openCategoryDialog()));

  if ( categoryDialog->exec() ) {
    setCategories( categoryDialog->selectedCategories() );
  }
  delete categoryDialog;
}

void KOEditorGeneralJournal::readJournal( Journal *journal, bool tmpl )
{
  setSummary( journal->summary() );
  if ( !tmpl ) {
    setDate( journal->dtStart().date() );
    if ( !journal->floats() ) {
kDebug()<<"KOEditorGeneralJournal::readJournal, does not float, time="<<(journal->dtStart().time().toString());
      setTime( journal->dtStart().time() );
    } else {
kDebug()<<"KOEditorGeneralJournal::readJournal, does float";
      setTime( QTime( -1, -1, -1 ) );
    }
  }
  setDescription( journal->description(), journal->descriptionIsRich() );
}

void KOEditorGeneralJournal::writeJournal( Journal *journal )
{
//  kDebug(5850) <<"KOEditorGeneralJournal::writeIncidence()";
  journal->setSummary( mSummaryEdit->text() );
  journal->setDescription( mDescriptionEdit->toPlainText(),
                           mHtmlCheckBox->isChecked() );

  KDateTime tmpDT( mDateEdit->date(), QTime(0,0,0), KOPrefs::instance()->timeSpec() );
  bool hasTime = mTimeCheckBox->isChecked();
  journal->setFloats( !hasTime );
  if ( hasTime ) {
    tmpDT.setTime( mTimeEdit->getTime() );
  }
  journal->setDtStart(tmpDT);

//  kDebug(5850) <<"KOEditorGeneralJournal::writeJournal() done";
}

void KOEditorGeneralJournal::setDescription( const QString &text, bool isRich )
{
  //FIXME: Once we have a WYSIWYG editor then make this setHtml
  mDescriptionEdit->setPlainText( text );
  mHtmlCheckBox->setChecked( isRich );
}

void KOEditorGeneralJournal::setSummary( const QString &text )
{
  mSummaryEdit->setText( text );
}

void KOEditorGeneralJournal::finishSetup()
{
  QWidget::setTabOrder( mSummaryEdit, mDateEdit );
  QWidget::setTabOrder( mDateEdit, mTimeCheckBox );
  QWidget::setTabOrder( mTimeCheckBox, mTimeEdit );
  QWidget::setTabOrder( mTimeEdit, mDescriptionEdit );
  mSummaryEdit->setFocus();
}

bool KOEditorGeneralJournal::validateInput()
{
//  kDebug(5850) <<"KOEditorGeneralJournal::validateInput()";

  if (!mDateEdit->date().isValid()) {
    KMessageBox::sorry( 0,
        i18n("Please specify a valid date, for example '%1'.",
          KGlobal::locale()->formatDate( QDate::currentDate() ) ) );
    return false;
  }

  return true;
}

#include "koeditorgeneraljournal.moc"
<commit_msg>Reverse journal editor's HTML checkbox: looks nicer :D<commit_after>/*
  This file is part of KOrganizer.

  Copyright (C) 2004 Reinhold Kainhofer <reinhold@kainhofer.com>
	large parts of code taken from KOEditorGeneralJournal.cpp:
  Copyright (c) 2001 Cornelius Schumacher <schumacher@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.

  This program 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 General Public License for more details.

  You should have received a copy of the GNU General Public License along
  with this program; if not, write to the Free Software Foundation, Inc.,
  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

  As a special exception, permission is given to link this program
  with any edition of Qt, and distribute the resulting executable,
  without including the source code for Qt in the source distribution.
*/

#include "koeditorgeneraljournal.h"
#include "koprefs.h"
#include "koeditorgeneral.h"
#include "koglobals.h"

#include <libkdepim/categoryselectdialog.h>

#include <kcal/journal.h>

#include <ktextedit.h>
#include <kdateedit.h>
#include <ktimeedit.h>
#include <kglobal.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <kdebug.h>
#include <KSqueezedTextLabel>

#include <q3groupbox.h>
#include <QDateTime>
#include <QCheckBox>
#include <QLabel>
#include <QLayout>
#include <QHBoxLayout>
#include <QBoxLayout>
#include <QPushButton>

KOEditorGeneralJournal::KOEditorGeneralJournal( QObject *parent ) : QObject( parent )
{
}

KOEditorGeneralJournal::~KOEditorGeneralJournal()
{
}

void KOEditorGeneralJournal::initTitle( QWidget *parent, QBoxLayout *topLayout )
{
  QHBoxLayout *hbox = new QHBoxLayout();
  topLayout->addItem( hbox );

  QString whatsThis = i18n("Sets the title of this journal.");
  QLabel *summaryLabel = new QLabel( i18n("T&itle:"), parent );
  summaryLabel->setWhatsThis( whatsThis );
  QFont f = summaryLabel->font();
  f.setBold( true );
  summaryLabel->setFont( f );
  hbox->addWidget( summaryLabel );

  mSummaryEdit = new FocusLineEdit( parent );
  mSummaryEdit->setWhatsThis( whatsThis );
  summaryLabel->setBuddy( mSummaryEdit );
  hbox->addWidget( mSummaryEdit );
}

void KOEditorGeneralJournal::initDate( QWidget *parent, QBoxLayout *topLayout )
{
  QBoxLayout *dateLayout = new QHBoxLayout();
  topLayout->addItem( dateLayout );

  mDateLabel = new QLabel( i18n("&Date:"), parent );
  dateLayout->addWidget( mDateLabel );

  mDateEdit = new KDateEdit( parent );
  dateLayout->addWidget( mDateEdit );
  mDateLabel->setBuddy( mDateEdit );

  dateLayout->addStretch();

  mTimeCheckBox = new QCheckBox( i18n("&Time: "), parent );
  dateLayout->addWidget( mTimeCheckBox );

  mTimeEdit = new KTimeEdit( parent );
  dateLayout->addWidget( mTimeEdit );
  connect( mTimeCheckBox, SIGNAL(toggled(bool)),
           mTimeEdit, SLOT(setEnabled(bool)) );

  dateLayout->addStretch();
  setTime( QTime( -1, -1, -1 ) );
}

void KOEditorGeneralJournal::setDate( const QDate &date )
{
//  kDebug(5850) <<"KOEditorGeneralJournal::setDate(): Date:" << date.toString();

  mDateEdit->setDate( date );
}

void KOEditorGeneralJournal::setTime( const QTime &time )
{
kDebug()<<"KOEditorGeneralJournal::setTime, time="<<time.toString();
  bool validTime = time.isValid();
  mTimeCheckBox->setChecked( validTime );
  mTimeEdit->setEnabled( validTime );
  if ( validTime ) {
kDebug()<<"KOEditorGeneralJournal::setTime, time is valid";
    mTimeEdit->setTime( time );
  }
}

void KOEditorGeneralJournal::initDescription( QWidget *parent, QBoxLayout *topLayout )
{
  QBoxLayout *htmlLayout = new QHBoxLayout();
  topLayout->addItem( htmlLayout );
  mHtmlCheckBox = new QCheckBox( parent );
  mHtmlLabel = new QLabel( "Use HTML", parent );
  htmlLayout->addWidget( mHtmlCheckBox );
  htmlLayout->addWidget( mHtmlLabel );
  mHtmlLabel->setBuddy( mHtmlCheckBox );
  htmlLayout->addStretch();
  mDescriptionEdit = new KTextEdit( parent );
  mDescriptionEdit->append("");
  mDescriptionEdit->setReadOnly( false );
  mDescriptionEdit->setOverwriteMode( false );
  mDescriptionEdit->setLineWrapMode( KTextEdit::WidgetWidth );
  mDescriptionEdit->setTabChangesFocus( true );
  topLayout->addWidget( mDescriptionEdit );
}

void KOEditorGeneralJournal::initCategories(QWidget *parent, QBoxLayout *topLayout)
{
  QBoxLayout *categoriesLayout = new QHBoxLayout();
  categoriesLayout->setSpacing( topLayout->spacing() );
  topLayout->addItem( categoriesLayout );

  QString whatsThis = i18n("Allows you to select the categories that this "
      "journal belongs to.");

  mCategoriesButton = new QPushButton(parent);
  mCategoriesButton->setText(i18n("Select Cate&gories..."));
  mCategoriesButton->setWhatsThis( whatsThis );
  connect(mCategoriesButton,SIGNAL(clicked()),SLOT(selectCategories()));
  categoriesLayout->addWidget(mCategoriesButton);

  mCategoriesLabel = new KSqueezedTextLabel(parent);
  mCategoriesLabel->setWhatsThis( whatsThis );
  mCategoriesLabel->setFrameStyle(QFrame::Panel|QFrame::Sunken);
  categoriesLayout->addWidget(mCategoriesLabel,1);
}

void KOEditorGeneralJournal::setCategories( const QStringList &categories )
{
  mCategoriesLabel->setText( categories.join(",") );
  mCategories = categories;
}

void KOEditorGeneralJournal::selectCategories()
{
  KPIM::CategorySelectDialog *categoryDialog = new KPIM::CategorySelectDialog( KOPrefs::instance(), mCategoriesButton  );
  KOGlobals::fitDialogToScreen( categoryDialog );
  categoryDialog->setSelected( mCategories );

  connect(categoryDialog, SIGNAL(editCategories()), this, SIGNAL(openCategoryDialog()));

  if ( categoryDialog->exec() ) {
    setCategories( categoryDialog->selectedCategories() );
  }
  delete categoryDialog;
}

void KOEditorGeneralJournal::readJournal( Journal *journal, bool tmpl )
{
  setSummary( journal->summary() );
  if ( !tmpl ) {
    setDate( journal->dtStart().date() );
    if ( !journal->floats() ) {
kDebug()<<"KOEditorGeneralJournal::readJournal, does not float, time="<<(journal->dtStart().time().toString());
      setTime( journal->dtStart().time() );
    } else {
kDebug()<<"KOEditorGeneralJournal::readJournal, does float";
      setTime( QTime( -1, -1, -1 ) );
    }
  }
  setDescription( journal->description(), journal->descriptionIsRich() );
}

void KOEditorGeneralJournal::writeJournal( Journal *journal )
{
//  kDebug(5850) <<"KOEditorGeneralJournal::writeIncidence()";
  journal->setSummary( mSummaryEdit->text() );
  journal->setDescription( mDescriptionEdit->toPlainText(),
                           mHtmlCheckBox->isChecked() );

  KDateTime tmpDT( mDateEdit->date(), QTime(0,0,0), KOPrefs::instance()->timeSpec() );
  bool hasTime = mTimeCheckBox->isChecked();
  journal->setFloats( !hasTime );
  if ( hasTime ) {
    tmpDT.setTime( mTimeEdit->getTime() );
  }
  journal->setDtStart(tmpDT);

//  kDebug(5850) <<"KOEditorGeneralJournal::writeJournal() done";
}

void KOEditorGeneralJournal::setDescription( const QString &text, bool isRich )
{
  //FIXME: Once we have a WYSIWYG editor then make this setHtml
  mDescriptionEdit->setPlainText( text );
  mHtmlCheckBox->setChecked( isRich );
}

void KOEditorGeneralJournal::setSummary( const QString &text )
{
  mSummaryEdit->setText( text );
}

void KOEditorGeneralJournal::finishSetup()
{
  QWidget::setTabOrder( mSummaryEdit, mDateEdit );
  QWidget::setTabOrder( mDateEdit, mTimeCheckBox );
  QWidget::setTabOrder( mTimeCheckBox, mTimeEdit );
  QWidget::setTabOrder( mTimeEdit, mDescriptionEdit );
  mSummaryEdit->setFocus();
}

bool KOEditorGeneralJournal::validateInput()
{
//  kDebug(5850) <<"KOEditorGeneralJournal::validateInput()";

  if (!mDateEdit->date().isValid()) {
    KMessageBox::sorry( 0,
        i18n("Please specify a valid date, for example '%1'.",
          KGlobal::locale()->formatDate( QDate::currentDate() ) ) );
    return false;
  }

  return true;
}

#include "koeditorgeneraljournal.moc"
<|endoftext|>