<commit_before>#include "command.hh"
#include "attr-path.hh"
#include "common-eval-args.hh"
#include "derivations.hh"
#include "eval-inline.hh"
#include "eval.hh"
#include "get-drvs.hh"
#include "store-api.hh"
#include "shared.hh"

#include <regex>

namespace nix {

SourceExprCommand::SourceExprCommand()
{
    mkFlag()
        .shortName('f')
        .longName("file")
        .label("file")
        .description("evaluate FILE rather than the default")
        .dest(&file);
}

Value * SourceExprCommand::getSourceExpr(EvalState & state)
{
    if (vSourceExpr) return vSourceExpr;

    auto sToplevel = state.symbols.create("_toplevel");

    vSourceExpr = state.allocValue();

    if (file != "")
        state.evalFile(lookupFileArg(state, file), *vSourceExpr);

    else {

        /* Construct the installation source from $NIX_PATH. */

        auto searchPath = state.getSearchPath();

        state.mkAttrs(*vSourceExpr, searchPath.size() + 1);

        mkBool(*state.allocAttr(*vSourceExpr, sToplevel), true);

        std::unordered_set<std::string> seen;

        for (auto & i : searchPath) {
            if (i.first == "") continue;
            if (seen.count(i.first)) continue;
            seen.insert(i.first);
#if 0
            auto res = state.resolveSearchPathElem(i);
            if (!res.first) continue;
            if (!pathExists(res.second)) continue;
            mkApp(*state.allocAttr(*vSourceExpr, state.symbols.create(i.first)),
                state.getBuiltin("import"),
                mkString(*state.allocValue(), res.second));
#endif
            Value * v1 = state.allocValue();
            mkPrimOpApp(*v1, state.getBuiltin("findFile"), state.getBuiltin("nixPath"));
            Value * v2 = state.allocValue();
            mkApp(*v2, *v1, mkString(*state.allocValue(), i.first));
            mkApp(*state.allocAttr(*vSourceExpr, state.symbols.create(i.first)),
                state.getBuiltin("import"), *v2);
        }

        vSourceExpr->attrs->sort();
    }

    return vSourceExpr;
}

ref<EvalState> SourceExprCommand::getEvalState()
{
    if (!evalState)
        evalState = std::make_shared<EvalState>(searchPath, getStore());
    return ref<EvalState>(evalState);
}

Buildable Installable::toBuildable()
{
    auto buildables = toBuildables();
    if (buildables.size() != 1)
        throw Error("installable '%s' evaluates to %d derivations, where only one is expected", what(), buildables.size());
    return std::move(buildables[0]);
}

struct InstallableStorePath : Installable
{
    Path storePath;

    InstallableStorePath(const Path & storePath) : storePath(storePath) { }

    std::string what() override { return storePath; }

    Buildables toBuildables() override
    {
        return {{isDerivation(storePath) ? storePath : "", {{"out", storePath}}}};
    }
};

struct InstallableValue : Installable
{
    SourceExprCommand & cmd;

    InstallableValue(SourceExprCommand & cmd) : cmd(cmd) { }

    Buildables toBuildables() override
    {
        auto state = cmd.getEvalState();

        auto v = toValue(*state);

        Bindings & autoArgs = *cmd.getAutoArgs(*state);

        DrvInfos drvs;
        getDerivations(*state, *v, "", autoArgs, drvs, false);

        Buildables res;

        PathSet drvPaths;

        for (auto & drv : drvs) {
            Buildable b{drv.queryDrvPath()};
            drvPaths.insert(b.drvPath);

            auto outputName = drv.queryOutputName();
            if (outputName == "")
                throw Error("derivation '%s' lacks an 'outputName' attribute", b.drvPath);

            b.outputs.emplace(outputName, drv.queryOutPath());

            res.push_back(std::move(b));
        }

        // Hack to recognize .all: if all drvs have the same drvPath,
        // merge the buildables.
        if (drvPaths.size() == 1) {
            Buildable b{*drvPaths.begin()};
            for (auto & b2 : res)
                b.outputs.insert(b2.outputs.begin(), b2.outputs.end());
            return {b};
        } else
            return res;
    }
};

struct InstallableExpr : InstallableValue
{
    std::string text;

    InstallableExpr(SourceExprCommand & cmd, const std::string & text)
         : InstallableValue(cmd), text(text) { }

    std::string what() override { return text; }

    Value * toValue(EvalState & state) override
    {
        auto v = state.allocValue();
        state.eval(state.parseExprFromString(text, absPath(".")), *v);
        return v;
    }
};

struct InstallableAttrPath : InstallableValue
{
    std::string attrPath;

    InstallableAttrPath(SourceExprCommand & cmd, const std::string & attrPath)
        : InstallableValue(cmd), attrPath(attrPath)
    { }

    std::string what() override { return attrPath; }

    Value * toValue(EvalState & state) override
    {
        auto source = cmd.getSourceExpr(state);

        Bindings & autoArgs = *cmd.getAutoArgs(state);

        Value * v = findAlongAttrPath(state, attrPath, autoArgs, *source);
        state.forceValue(*v);

        return v;
    }
};

// FIXME: extend
std::string attrRegex = R"([A-Za-z_][A-Za-z0-9-_+]*)";
static std::regex attrPathRegex(fmt(R"(%1%(\.%1%)*)", attrRegex));

static std::vector<std::shared_ptr<Installable>> parseInstallables(
    SourceExprCommand & cmd, ref<Store> store, std::vector<std::string> ss, bool useDefaultInstallables)
{
    std::vector<std::shared_ptr<Installable>> result;

    if (ss.empty() && useDefaultInstallables) {
        if (cmd.file == "")
            cmd.file = ".";
        ss = {""};
    }

    for (auto & s : ss) {

        if (s.compare(0, 1, "(") == 0)
            result.push_back(std::make_shared<InstallableExpr>(cmd, s));

        else if (s.find("/") != std::string::npos) {

            auto path = store->toStorePath(store->followLinksToStore(s));

            if (store->isStorePath(path))
                result.push_back(std::make_shared<InstallableStorePath>(path));
        }

        else if (s == "" || std::regex_match(s, attrPathRegex))
            result.push_back(std::make_shared<InstallableAttrPath>(cmd, s));

        else
            throw UsageError("don't know what to do with argument '%s'", s);
    }

    return result;
}

std::shared_ptr<Installable> parseInstallable(
    SourceExprCommand & cmd, ref<Store> store, const std::string & installable,
    bool useDefaultInstallables)
{
    auto installables = parseInstallables(cmd, store, {installable}, false);
    assert(installables.size() == 1);
    return installables.front();
}

Buildables build(ref<Store> store, RealiseMode mode,
    std::vector<std::shared_ptr<Installable>> installables)
{
    if (mode != Build)
        settings.readOnlyMode = true;

    Buildables buildables;

    PathSet pathsToBuild;

    for (auto & i : installables) {
        for (auto & b : i->toBuildables()) {
            if (b.drvPath != "") {
                StringSet outputNames;
                for (auto & output : b.outputs)
                    outputNames.insert(output.first);
                pathsToBuild.insert(
                    b.drvPath + "!" + concatStringsSep(",", outputNames));
            } else
                for (auto & output : b.outputs)
                    pathsToBuild.insert(output.second);
            buildables.push_back(std::move(b));
        }
    }

    if (mode == DryRun)
        printMissing(store, pathsToBuild, lvlError);
    else if (mode == Build)
        store->buildPaths(pathsToBuild);

    return buildables;
}

PathSet toStorePaths(ref<Store> store, RealiseMode mode,
    std::vector<std::shared_ptr<Installable>> installables)
{
    PathSet outPaths;

    for (auto & b : build(store, mode, installables))
        for (auto & output : b.outputs)
            outPaths.insert(output.second);

    return outPaths;
}

Path toStorePath(ref<Store> store, RealiseMode mode,
    std::shared_ptr<Installable> installable)
{
    auto paths = toStorePaths(store, mode, {installable});

    if (paths.size() != 1)
            throw Error("argument '%s' should evaluate to one store path", installable->what());

    return *paths.begin();
}

PathSet toDerivations(ref<Store> store,
    std::vector<std::shared_ptr<Installable>> installables, bool useDeriver)
{
    PathSet drvPaths;

    for (auto & i : installables)
        for (auto & b : i->toBuildables()) {
            if (b.drvPath.empty()) {
                if (!useDeriver)
                    throw Error("argument '%s' did not evaluate to a derivation", i->what());
                for (auto & output : b.outputs) {
                    auto derivers = store->queryValidDerivers(output.second);
                    if (derivers.empty())
                        throw Error("'%s' does not have a known deriver", i->what());
                    // FIXME: use all derivers?
                    drvPaths.insert(*derivers.begin());
                }
            } else
                drvPaths.insert(b.drvPath);
        }

    return drvPaths;
}

void InstallablesCommand::prepare()
{
    installables = parseInstallables(*this, getStore(), _installables, useDefaultInstallables());
}

void InstallableCommand::prepare()
{
    installable = parseInstallable(*this, getStore(), _installable, false);
}

}
<commit_msg>Revert "Revert "getSourceExpr(): Handle channels" (assert failure)"<commit_after>#include "command.hh"
#include "attr-path.hh"
#include "common-eval-args.hh"
#include "derivations.hh"
#include "eval-inline.hh"
#include "eval.hh"
#include "get-drvs.hh"
#include "store-api.hh"
#include "shared.hh"

#include <regex>

namespace nix {

SourceExprCommand::SourceExprCommand()
{
    mkFlag()
        .shortName('f')
        .longName("file")
        .label("file")
        .description("evaluate FILE rather than the default")
        .dest(&file);
}

Value * SourceExprCommand::getSourceExpr(EvalState & state)
{
    if (vSourceExpr) return vSourceExpr;

    auto sToplevel = state.symbols.create("_toplevel");

    vSourceExpr = state.allocValue();

    if (file != "")
        state.evalFile(lookupFileArg(state, file), *vSourceExpr);

    else {

        /* Construct the installation source from $NIX_PATH. */

        auto searchPath = state.getSearchPath();

        state.mkAttrs(*vSourceExpr, searchPath.size() + 1);

        mkBool(*state.allocAttr(*vSourceExpr, sToplevel), true);

        std::unordered_set<std::string> seen;

        auto addEntry = [&](const std::string & name) {
            if (name == "") return;
            if (!seen.insert(name).second) return;
            Value * v1 = state.allocValue();
            mkPrimOpApp(*v1, state.getBuiltin("findFile"), state.getBuiltin("nixPath"));
            Value * v2 = state.allocValue();
            mkApp(*v2, *v1, mkString(*state.allocValue(), name));
            mkApp(*state.allocAttr(*vSourceExpr, state.symbols.create(name)),
                state.getBuiltin("import"), *v2);
        };

        for (auto & i : searchPath)
            /* Hack to handle channels. */
            if (i.first.empty() && pathExists(i.second + "/manifest.nix")) {
                for (auto & j : readDirectory(i.second))
                    if (j.name != "manifest.nix"
                        && pathExists(fmt("%s/%s/default.nix", i.second, j.name)))
                        addEntry(j.name);
            } else
                addEntry(i.first);

        vSourceExpr->attrs->sort();
    }

    return vSourceExpr;
}

ref<EvalState> SourceExprCommand::getEvalState()
{
    if (!evalState)
        evalState = std::make_shared<EvalState>(searchPath, getStore());
    return ref<EvalState>(evalState);
}

Buildable Installable::toBuildable()
{
    auto buildables = toBuildables();
    if (buildables.size() != 1)
        throw Error("installable '%s' evaluates to %d derivations, where only one is expected", what(), buildables.size());
    return std::move(buildables[0]);
}

struct InstallableStorePath : Installable
{
    Path storePath;

    InstallableStorePath(const Path & storePath) : storePath(storePath) { }

    std::string what() override { return storePath; }

    Buildables toBuildables() override
    {
        return {{isDerivation(storePath) ? storePath : "", {{"out", storePath}}}};
    }
};

struct InstallableValue : Installable
{
    SourceExprCommand & cmd;

    InstallableValue(SourceExprCommand & cmd) : cmd(cmd) { }

    Buildables toBuildables() override
    {
        auto state = cmd.getEvalState();

        auto v = toValue(*state);

        Bindings & autoArgs = *cmd.getAutoArgs(*state);

        DrvInfos drvs;
        getDerivations(*state, *v, "", autoArgs, drvs, false);

        Buildables res;

        PathSet drvPaths;

        for (auto & drv : drvs) {
            Buildable b{drv.queryDrvPath()};
            drvPaths.insert(b.drvPath);

            auto outputName = drv.queryOutputName();
            if (outputName == "")
                throw Error("derivation '%s' lacks an 'outputName' attribute", b.drvPath);

            b.outputs.emplace(outputName, drv.queryOutPath());

            res.push_back(std::move(b));
        }

        // Hack to recognize .all: if all drvs have the same drvPath,
        // merge the buildables.
        if (drvPaths.size() == 1) {
            Buildable b{*drvPaths.begin()};
            for (auto & b2 : res)
                b.outputs.insert(b2.outputs.begin(), b2.outputs.end());
            return {b};
        } else
            return res;
    }
};

struct InstallableExpr : InstallableValue
{
    std::string text;

    InstallableExpr(SourceExprCommand & cmd, const std::string & text)
         : InstallableValue(cmd), text(text) { }

    std::string what() override { return text; }

    Value * toValue(EvalState & state) override
    {
        auto v = state.allocValue();
        state.eval(state.parseExprFromString(text, absPath(".")), *v);
        return v;
    }
};

struct InstallableAttrPath : InstallableValue
{
    std::string attrPath;

    InstallableAttrPath(SourceExprCommand & cmd, const std::string & attrPath)
        : InstallableValue(cmd), attrPath(attrPath)
    { }

    std::string what() override { return attrPath; }

    Value * toValue(EvalState & state) override
    {
        auto source = cmd.getSourceExpr(state);

        Bindings & autoArgs = *cmd.getAutoArgs(state);

        Value * v = findAlongAttrPath(state, attrPath, autoArgs, *source);
        state.forceValue(*v);

        return v;
    }
};

// FIXME: extend
std::string attrRegex = R"([A-Za-z_][A-Za-z0-9-_+]*)";
static std::regex attrPathRegex(fmt(R"(%1%(\.%1%)*)", attrRegex));

static std::vector<std::shared_ptr<Installable>> parseInstallables(
    SourceExprCommand & cmd, ref<Store> store, std::vector<std::string> ss, bool useDefaultInstallables)
{
    std::vector<std::shared_ptr<Installable>> result;

    if (ss.empty() && useDefaultInstallables) {
        if (cmd.file == "")
            cmd.file = ".";
        ss = {""};
    }

    for (auto & s : ss) {

        if (s.compare(0, 1, "(") == 0)
            result.push_back(std::make_shared<InstallableExpr>(cmd, s));

        else if (s.find("/") != std::string::npos) {

            auto path = store->toStorePath(store->followLinksToStore(s));

            if (store->isStorePath(path))
                result.push_back(std::make_shared<InstallableStorePath>(path));
        }

        else if (s == "" || std::regex_match(s, attrPathRegex))
            result.push_back(std::make_shared<InstallableAttrPath>(cmd, s));

        else
            throw UsageError("don't know what to do with argument '%s'", s);
    }

    return result;
}

std::shared_ptr<Installable> parseInstallable(
    SourceExprCommand & cmd, ref<Store> store, const std::string & installable,
    bool useDefaultInstallables)
{
    auto installables = parseInstallables(cmd, store, {installable}, false);
    assert(installables.size() == 1);
    return installables.front();
}

Buildables build(ref<Store> store, RealiseMode mode,
    std::vector<std::shared_ptr<Installable>> installables)
{
    if (mode != Build)
        settings.readOnlyMode = true;

    Buildables buildables;

    PathSet pathsToBuild;

    for (auto & i : installables) {
        for (auto & b : i->toBuildables()) {
            if (b.drvPath != "") {
                StringSet outputNames;
                for (auto & output : b.outputs)
                    outputNames.insert(output.first);
                pathsToBuild.insert(
                    b.drvPath + "!" + concatStringsSep(",", outputNames));
            } else
                for (auto & output : b.outputs)
                    pathsToBuild.insert(output.second);
            buildables.push_back(std::move(b));
        }
    }

    if (mode == DryRun)
        printMissing(store, pathsToBuild, lvlError);
    else if (mode == Build)
        store->buildPaths(pathsToBuild);

    return buildables;
}

PathSet toStorePaths(ref<Store> store, RealiseMode mode,
    std::vector<std::shared_ptr<Installable>> installables)
{
    PathSet outPaths;

    for (auto & b : build(store, mode, installables))
        for (auto & output : b.outputs)
            outPaths.insert(output.second);

    return outPaths;
}

Path toStorePath(ref<Store> store, RealiseMode mode,
    std::shared_ptr<Installable> installable)
{
    auto paths = toStorePaths(store, mode, {installable});

    if (paths.size() != 1)
            throw Error("argument '%s' should evaluate to one store path", installable->what());

    return *paths.begin();
}

PathSet toDerivations(ref<Store> store,
    std::vector<std::shared_ptr<Installable>> installables, bool useDeriver)
{
    PathSet drvPaths;

    for (auto & i : installables)
        for (auto & b : i->toBuildables()) {
            if (b.drvPath.empty()) {
                if (!useDeriver)
                    throw Error("argument '%s' did not evaluate to a derivation", i->what());
                for (auto & output : b.outputs) {
                    auto derivers = store->queryValidDerivers(output.second);
                    if (derivers.empty())
                        throw Error("'%s' does not have a known deriver", i->what());
                    // FIXME: use all derivers?
                    drvPaths.insert(*derivers.begin());
                }
            } else
                drvPaths.insert(b.drvPath);
        }

    return drvPaths;
}

void InstallablesCommand::prepare()
{
    installables = parseInstallables(*this, getStore(), _installables, useDefaultInstallables());
}

void InstallableCommand::prepare()
{
    installable = parseInstallable(*this, getStore(), _installable, false);
}

}
<|endoftext|>


<commit_before>#include <ciso646>
#include <string.h>
#ifdef __unix__
#include <unistd.h>
#include <stdio.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#else
#include <windows.h>
#endif
#include <fcntl.h>
#include <thread>
#include <chrono>
#include "LMS64CProtocol.h"

namespace lime
{

void LMS64CProtocol::InitRemote()
{
    remoteOpen = true;
    socketFd = -1;
    const int port = 5000;
#ifndef __unix__
    WSADATA wsaData;
    if( int err = WSAStartup(0x0202, &wsaData))
        printf("WSAStartup error %i\n", err);
#endif

    socketFd = socket(AF_INET, SOCK_STREAM, 0);
    if(socketFd < 0)
    {
        fprintf(stderr, "socket error %i\n", socketFd);
        return;
    }
#ifdef __unix__
    fcntl(socketFd, F_SETFL, O_NONBLOCK);
#else
    u_long iMode = 0;
    ioctlsocket(socketFd, FIONBIO, &iMode);
#endif

    struct sockaddr_in host;
    memset((void *)&host, 0, sizeof(sockaddr_in));
    host.sin_family = AF_INET;
    host.sin_addr.s_addr = INADDR_ANY;
    host.sin_port = htons(port);
    if(bind(socketFd, (struct sockaddr*)&host, sizeof(host)) < 0)
    {
        fprintf(stderr, "bind error on port %i\n", port);
        CloseRemote();
        return;
    }

    printf("Listening on port: %i\n", port);
    if(int error = listen(socketFd, SOMAXCONN) )
    {
#ifndef __unix__
        error =  WSAGetLastError();
#endif
        fprintf(stderr, "listen error %i\n", error);
        CloseRemote();
        return;
    }

    remoteThread = std::thread(&LMS64CProtocol::ProcessConnections, this);
    if(not remoteThread.joinable())
    {
        fprintf(stderr, "Error creating listening thread\n");
        CloseRemote();
        return;
    }
    return;
}

void LMS64CProtocol::CloseRemote()
{
    if (!remoteOpen)
        return;
    remoteOpen = false;

    if(remoteThread.joinable())
        remoteThread.join();

    if(socketFd > 0)
    {
#ifndef __unix__
    //shutdown(socketFd, SD_BOTH);
    closesocket(socketFd);
#else
    shutdown(socketFd, SHUT_RDWR);
    close(socketFd);
#endif
    }

#ifndef __unix__
    WSACleanup();
#endif
}

void LMS64CProtocol::ProcessConnections()
{
    printf("Started listening thread\n");
    struct sockaddr_in cli_addr;
#ifndef __unix__
    SOCKET clientFd;
    int clilen = sizeof(cli_addr);
#else
    int clientFd;
    unsigned int clilen = sizeof(cli_addr);
#endif // __unix__

    while(remoteOpen && socketFd >= 0)
    {
        memset(&cli_addr, 0, sizeof(cli_addr));
        clientFd = accept(socketFd, (struct sockaddr*)&cli_addr, &clilen);

        //if(clientFd == EAGAIN || clientFd == EWOULDBLOCK)
            //continue;
        if(clientFd < 0)
        {
            continue;
        }
        printf("Accepted\n");
        unsigned long ips = cli_addr.sin_addr.s_addr;

        bool connected = true;

        const int msgSize = 64;
        char data[msgSize] = {0};

        while(connected && remoteOpen)
        {
            unsigned int r = 0;
            do
            {
                int brecv = recv(clientFd, data+r, msgSize-r, 0);
                r += brecv;
                if(brecv == 0)
                {
                    connected = false;
                    break;
                }
                if(brecv < 0 )
                {
#ifndef __unix__
                    brecv = WSAGetLastError();
#endif
                    printf("recv with error: %d\n", brecv);
                    connected = false;
                    break;
                }
            }
            while(r < msgSize);

            if(not connected)
                break;

            mControlPortLock.lock();
            Write((unsigned char*)data, msgSize);
            Read((unsigned char*)data, msgSize);
            mControlPortLock.unlock();

            int bsent = 0;
            while(bsent < msgSize)
            {
                int r = send(clientFd, data+bsent, msgSize-bsent, 0);
                if(r < 0)
                {
                    printf("response error %i\n", r);
                    connected = false;
                    break;
                }
                bsent += r;
            }
        }
        if (clientFd >= 0)
        {
#ifndef __unix__
            //shutdown(socketFd, SD_BOTH);
            closesocket(clientFd);
#else
            shutdown(clientFd, SHUT_RDWR);
            close(clientFd);
#endif
        }
        printf("remote handling done\n");
    }
    return;
}

}
<commit_msg>Remove a couple of printfs from remote connection<commit_after>#include <ciso646>
#include <string.h>
#ifdef __unix__
#include <unistd.h>
#include <stdio.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#else
#include <windows.h>
#endif
#include <fcntl.h>
#include <thread>
#include <chrono>
#include "LMS64CProtocol.h"

namespace lime
{

void LMS64CProtocol::InitRemote()
{
    remoteOpen = true;
    socketFd = -1;
    const int port = 5000;
#ifndef __unix__
    WSADATA wsaData;
    if( int err = WSAStartup(0x0202, &wsaData))
        printf("WSAStartup error %i\n", err);
#endif

    socketFd = socket(AF_INET, SOCK_STREAM, 0);
    if(socketFd < 0)
    {
        fprintf(stderr, "socket error %i\n", socketFd);
        return;
    }
#ifdef __unix__
    fcntl(socketFd, F_SETFL, O_NONBLOCK);
#else
    u_long iMode = 0;
    ioctlsocket(socketFd, FIONBIO, &iMode);
#endif

    struct sockaddr_in host;
    memset((void *)&host, 0, sizeof(sockaddr_in));
    host.sin_family = AF_INET;
    host.sin_addr.s_addr = INADDR_ANY;
    host.sin_port = htons(port);
    if(bind(socketFd, (struct sockaddr*)&host, sizeof(host)) < 0)
    {
        fprintf(stderr, "bind error on port %i\n", port);
        CloseRemote();
        return;
    }

    printf("Listening on port: %i\n", port);
    if(int error = listen(socketFd, SOMAXCONN) )
    {
#ifndef __unix__
        error =  WSAGetLastError();
#endif
        fprintf(stderr, "listen error %i\n", error);
        CloseRemote();
        return;
    }

    remoteThread = std::thread(&LMS64CProtocol::ProcessConnections, this);
    if(not remoteThread.joinable())
    {
        fprintf(stderr, "Error creating listening thread\n");
        CloseRemote();
        return;
    }
    return;
}

void LMS64CProtocol::CloseRemote()
{
    if (!remoteOpen)
        return;
    remoteOpen = false;

    if(remoteThread.joinable())
        remoteThread.join();

    if(socketFd > 0)
    {
#ifndef __unix__
    //shutdown(socketFd, SD_BOTH);
    closesocket(socketFd);
#else
    shutdown(socketFd, SHUT_RDWR);
    close(socketFd);
#endif
    }

#ifndef __unix__
    WSACleanup();
#endif
}

void LMS64CProtocol::ProcessConnections()
{
    printf("Started listening thread\n");
    struct sockaddr_in cli_addr;
#ifndef __unix__
    SOCKET clientFd;
    int clilen = sizeof(cli_addr);
#else
    int clientFd;
    unsigned int clilen = sizeof(cli_addr);
#endif // __unix__

    while(remoteOpen && socketFd >= 0)
    {
        memset(&cli_addr, 0, sizeof(cli_addr));
        clientFd = accept(socketFd, (struct sockaddr*)&cli_addr, &clilen);

        //if(clientFd == EAGAIN || clientFd == EWOULDBLOCK)
            //continue;
        if(clientFd < 0)
        {
            continue;
        }
        unsigned long ips = cli_addr.sin_addr.s_addr;

        bool connected = true;

        const int msgSize = 64;
        char data[msgSize] = {0};

        while(connected && remoteOpen)
        {
            unsigned int r = 0;
            do
            {
                int brecv = recv(clientFd, data+r, msgSize-r, 0);
                r += brecv;
                if(brecv == 0)
                {
                    connected = false;
                    break;
                }
                if(brecv < 0 )
                {
#ifndef __unix__
                    brecv = WSAGetLastError();
#endif
                    printf("recv with error: %d\n", brecv);
                    connected = false;
                    break;
                }
            }
            while(r < msgSize);

            if(not connected)
                break;

            mControlPortLock.lock();
            Write((unsigned char*)data, msgSize);
            Read((unsigned char*)data, msgSize);
            mControlPortLock.unlock();

            int bsent = 0;
            while(bsent < msgSize)
            {
                int r = send(clientFd, data+bsent, msgSize-bsent, 0);
                if(r < 0)
                {
                    printf("response error %i\n", r);
                    connected = false;
                    break;
                }
                bsent += r;
            }
        }
        if (clientFd >= 0)
        {
#ifndef __unix__
            //shutdown(socketFd, SD_BOTH);
            closesocket(clientFd);
#else
            shutdown(clientFd, SHUT_RDWR);
            close(clientFd);
#endif
        }
    }
    return;
}

}
<|endoftext|>


<commit_before>#include "noteeditorlogic.h"
#include "customDocument.h"
#include "markdownhighlighter.h"
#include "dbmanager.h"
#include "taglistview.h"
#include "taglistmodel.h"
#include "tagpool.h"
#include "taglistdelegate.h"
#include <QScrollBar>
#include <QLabel>
#include <QLineEdit>
#include <QListWidget>
#include <QDebug>
#include <QCursor>

#define FIRST_LINE_MAX 80

NoteEditorLogic::NoteEditorLogic(CustomDocument *textEdit,
                                 QLabel* editorDateLabel,
                                 QLineEdit* searchEdit,
                                 TagListView *tagListView, TagPool *tagPool,
                                 DBManager *dbManager,
                                 QObject *parent) : QObject(parent),
    m_textEdit{textEdit},
    m_editorDateLabel{editorDateLabel},
    m_searchEdit{searchEdit},
    m_tagListView{tagListView},
    m_dbManager{dbManager},
    m_isContentModified{false},
    m_spacerColor{26, 26, 26}
{
    m_highlighter = new MarkdownHighlighter(m_textEdit->document());
    connect(m_textEdit, &QTextEdit::textChanged, this, &NoteEditorLogic::onTextEditTextChanged);
    connect(m_textEdit, &CustomDocument::resized, this, &NoteEditorLogic::editorResized);
    connect(this, &NoteEditorLogic::requestCreateUpdateNote,
            m_dbManager, &DBManager::onCreateUpdateRequestedNoteContent, Qt::QueuedConnection);
    // auto save timer
    m_autoSaveTimer.setSingleShot(true);
    m_autoSaveTimer.setInterval(50);
    connect(&m_autoSaveTimer, &QTimer::timeout, this, [this]() {
        saveNoteToDB();
    });
    m_tagListModel = new TagListModel{this};
    m_tagListModel->setTagPool(tagPool);
    m_tagListView->setModel(m_tagListModel);
    m_tagListDelegate = new TagListDelegate{this};
    m_tagListView->setItemDelegate(m_tagListDelegate);
    connect(tagPool, &TagPool::dataUpdated, this, [this] (int) {
        showTagListForCurrentNote();
    });
}

bool NoteEditorLogic::markdownEnabled() const
{
    return m_highlighter == nullptr;
}

void NoteEditorLogic::setMarkdownEnabled(bool newMarkdownEnabled)
{
    if (markdownEnabled()) {
        delete m_highlighter;
        m_highlighter = nullptr;
    }
    if (newMarkdownEnabled) {
        m_highlighter = new MarkdownHighlighter(m_textEdit->document());
    } else {
        delete m_highlighter;
        m_highlighter = nullptr;
    }
}

void NoteEditorLogic::showNotesInEditor(const QVector<NodeData> &notes)
{
    if (notes.size() == 1 && notes[0].id() != SpecialNodeID::InvalidNodeId ) {
        auto currentId = currentEditingNoteId();
        if (currentId != SpecialNodeID::InvalidNodeId && notes[0].id() != currentId) {
            emit noteEditClosed(m_currentNotes[0]);
        }
        m_textEdit->blockSignals(true);
        m_textEdit->setVisible(true);
        m_currentNotes = notes;
        showTagListForCurrentNote();
        //     fixing bug #202
        m_textEdit->setTextBackgroundColor(QColor(247,247,247, 0));

        QString content = notes[0].content();
        QDateTime dateTime = notes[0].lastModificationdateTime();
        int scrollbarPos = notes[0].scrollBarPosition();

        // set text and date
        m_textEdit->setText(content);
        QString noteDate = dateTime.toString(Qt::ISODate);
        QString noteDateEditor = getNoteDateEditor(noteDate);
        m_editorDateLabel->setText(noteDateEditor);
        // set scrollbar position
        m_textEdit->verticalScrollBar()->setValue(scrollbarPos);
        m_textEdit->blockSignals(false);
        m_textEdit->setReadOnly(false);
        m_textEdit->setTextInteractionFlags(Qt::TextEditorInteraction);
        m_textEdit->setFocusPolicy(Qt::StrongFocus);
        highlightSearch();
    } else if (notes.size() > 1) {
        m_currentNotes = notes;
        m_tagListView->setVisible(false);
        m_textEdit->blockSignals(true);
        m_textEdit->clear();
        QPixmap sep(QSize{m_textEdit->width(), 19});
        sep.fill(Qt::transparent);
        QPainter painter(&sep);
        painter.setPen(m_spacerColor);
        painter.drawLine(0, 10, sep.width() - 100, 10);
        m_textEdit->document()->addResource(QTextDocument::ImageResource,
                                            QUrl("mydata://sep.png"),
                                            sep);
        for (int i = 0; i < notes.size(); ++i) {
            auto cursor = m_textEdit->textCursor();
            cursor.movePosition(QTextCursor::End);
            if (!notes[i].content().endsWith("\n")) {
                if (i != 0) {
                    cursor.insertText("\n" + notes[i].content() + "\n");
                } else {
                    cursor.insertText(notes[i].content() + "\n");
                }
            } else {
                cursor.insertText(notes[i].content());
            }
            if (i != notes.size() - 1) {
                cursor.movePosition(QTextCursor::End);
                cursor.insertImage("mydata://sep.png");
            }
        }
        m_textEdit->blockSignals(false);
        m_textEdit->setReadOnly(true);
        m_textEdit->setTextInteractionFlags(Qt::NoTextInteraction);
        m_textEdit->setFocusPolicy(Qt::NoFocus);
        highlightSearch();
    }
}

void NoteEditorLogic::onTextEditTextChanged()
{
    if (currentEditingNoteId() != SpecialNodeID::InvalidNodeId) {
        m_textEdit->blockSignals(true);
        QString content = m_currentNotes[0].content();
        if(m_textEdit->toPlainText() != content){
            // move note to the top of the list
            emit moveNoteToListViewTop(m_currentNotes[0]);

            // Get the new data
            QString firstline = getFirstLine(m_textEdit->toPlainText());
            QDateTime dateTime = QDateTime::currentDateTime();
            QString noteDate = dateTime.toString(Qt::ISODate);
            m_editorDateLabel->setText(NoteEditorLogic::getNoteDateEditor(noteDate));
            // update note data
            m_currentNotes[0].setContent(m_textEdit->toPlainText());
            m_currentNotes[0].setFullTitle(firstline);
            m_currentNotes[0].setLastModificationDateTime(dateTime);
            m_currentNotes[0].setIsTempNote(false);
            m_currentNotes[0].setScrollBarPosition(m_textEdit->verticalScrollBar()->value());
            // update note data in list view
            emit updateNoteDataInList(m_currentNotes[0]);
            m_isContentModified = true;
            m_autoSaveTimer.start();
            emit setVisibilityOfFrameRightNonEditor(false);
        }
        m_textEdit->blockSignals(false);
    } else {
        qDebug() << "NoteEditorLogic::onTextEditTextChanged() : m_currentNote is not valid";
    }
}

QDateTime NoteEditorLogic::getQDateTime(QString date)
{
    QDateTime dateTime = QDateTime::fromString(date, Qt::ISODate);
    return dateTime;
}

void NoteEditorLogic::showTagListForCurrentNote()
{
    if (currentEditingNoteId() != SpecialNodeID::InvalidNodeId) {
        auto tagIds = m_currentNotes[0].tagIds();
        if (tagIds.count() > 0) {
            m_tagListView->setVisible(true);
            m_tagListModel->setModelData(tagIds);
            return;
        }
        m_tagListModel->setModelData(tagIds);
    }
    m_tagListView->setVisible(false);
}

bool NoteEditorLogic::isInEditMode() const
{
    if (m_currentNotes.size() == 1) {
        return true;
    }
    return false;
}

int NoteEditorLogic::currentEditingNoteId() const
{
    if (isInEditMode()) {
        return m_currentNotes[0].id();
    }
    return SpecialNodeID::InvalidNodeId;
}

void NoteEditorLogic::saveNoteToDB()
{
    if(currentEditingNoteId() != SpecialNodeID::InvalidNodeId
            && m_isContentModified && !m_currentNotes[0].isTempNote()) {
        emit requestCreateUpdateNote(m_currentNotes[0]);
        m_isContentModified = false;
    }
}

void NoteEditorLogic::closeEditor()
{
    if (currentEditingNoteId() != SpecialNodeID::InvalidNodeId) {
        saveNoteToDB();
        emit noteEditClosed(m_currentNotes[0]);
    }
    m_currentNotes.clear();

    m_textEdit->blockSignals(true);
    m_textEdit->clear();
    m_textEdit->clearFocus();
    m_textEdit->blockSignals(false);
    m_tagListModel->setModelData({});
}

void NoteEditorLogic::onNoteTagListChanged(int noteId, const QSet<int> tagIds)
{
    if (currentEditingNoteId() == noteId) {
        m_currentNotes[0].setTagIds(tagIds);
        showTagListForCurrentNote();
    }
}

void NoteEditorLogic::editorResized()
{
    if (currentEditingNoteId() != SpecialNodeID::InvalidNodeId) {
        int verticalScrollBarValueToRestore = m_textEdit->verticalScrollBar()->value();
        m_textEdit->setText(m_textEdit->toPlainText());
        m_textEdit->verticalScrollBar()->setValue(verticalScrollBarValueToRestore);
    } else {
        int verticalScrollBarValueToRestore = m_textEdit->verticalScrollBar()->value();
        showNotesInEditor(m_currentNotes);
        m_textEdit->verticalScrollBar()->setValue(verticalScrollBarValueToRestore);
    }
}

void NoteEditorLogic::deleteCurrentNote()
{
    if (currentEditingNoteId() != SpecialNodeID::InvalidNodeId) {
        auto noteNeedDeleted = m_currentNotes[0];
        saveNoteToDB();
        m_currentNotes.clear();
        m_textEdit->blockSignals(true);
        m_textEdit->clear();
        m_textEdit->clearFocus();
        m_textEdit->blockSignals(false);
        emit noteEditClosed(noteNeedDeleted);
        emit deleteNoteRequested(noteNeedDeleted);
    }
}

/*!
 * \brief NoteEditorLogic::getFirstLine
 * Get a string 'str' and return only the first line of it
 * If the string contain no text, return "New Note"
 * TODO: We might make it more efficient by not loading the entire string into the memory
 * \param str
 * \return
 */
QString NoteEditorLogic::getFirstLine(const QString& str)
{
    QString text = str.trimmed();
    if (text.isEmpty()) {
        return "New Note";
    }
    QTextStream ts(&text);
    return ts.readLine(FIRST_LINE_MAX);
}

QString NoteEditorLogic::getSecondLine(const QString &str)
{
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
    auto sl = str.split("\n", QString::SkipEmptyParts);
#else
    auto sl = str.split("\n", Qt::SkipEmptyParts);
#endif
    if (sl.size() < 2) {
        return getFirstLine(str);
    }
    int i = 1;
    QString text;
    do {
        if (i >= sl.size()) {
            return getFirstLine(str);
        }
        text = sl[i].trimmed();
        ++i;
    } while (text.isEmpty());
    QTextStream ts(&text);
    return ts.readLine(FIRST_LINE_MAX);
}

void NoteEditorLogic::setTheme(Theme newTheme)
{
    m_tagListDelegate->setTheme(newTheme);
    switch(newTheme){
    case Theme::Light:
    {
        m_spacerColor = QColor(26, 26, 26);
        break;
    }
    case Theme::Dark:
    {
        m_spacerColor = QColor(204, 204, 204);
        break;
    }
    case Theme::Sepia:
    {
        m_spacerColor = QColor(26, 26, 26);
        break;
    }
    }
    if (currentEditingNoteId() != SpecialNodeID::InvalidNodeId) {
        int verticalScrollBarValueToRestore = m_textEdit->verticalScrollBar()->value();
        m_textEdit->setText(m_textEdit->toPlainText()); // TODO: Update the text color without setting the text
        m_textEdit->verticalScrollBar()->setValue(verticalScrollBarValueToRestore);
    } else {
        int verticalScrollBarValueToRestore = m_textEdit->verticalScrollBar()->value();
        showNotesInEditor(m_currentNotes);
        m_textEdit->verticalScrollBar()->setValue(verticalScrollBarValueToRestore);
    }
}

QString NoteEditorLogic::getNoteDateEditor(QString dateEdited)
{
    QDateTime dateTimeEdited(getQDateTime(dateEdited));
    QLocale usLocale(QLocale(QStringLiteral("en_US")));

    return usLocale.toString(dateTimeEdited, QStringLiteral("MMMM d, yyyy, h:mm A"));
}

void NoteEditorLogic::highlightSearch() const
{
    QString searchString = m_searchEdit->text();

    if (searchString.isEmpty())
        return;

    m_textEdit->moveCursor(QTextCursor::Start);

    QList<QTextEdit::ExtraSelection> extraSelections;
    QTextCharFormat highlightFormat;
    highlightFormat.setBackground(Qt::yellow);

    while (m_textEdit->find(searchString))
        extraSelections.append({ m_textEdit->textCursor(), highlightFormat});

    if (!extraSelections.isEmpty()) {
        m_textEdit->setTextCursor(extraSelections.first().cursor);
        m_textEdit->setExtraSelections(extraSelections);
    }
}

bool NoteEditorLogic::isTempNote() const
{
    if (currentEditingNoteId() != SpecialNodeID::InvalidNodeId && m_currentNotes[0].isTempNote()) {
        return true;
    }
    return false;
}
<commit_msg>fix note edit separator<commit_after>#include "noteeditorlogic.h"
#include "customDocument.h"
#include "markdownhighlighter.h"
#include "dbmanager.h"
#include "taglistview.h"
#include "taglistmodel.h"
#include "tagpool.h"
#include "taglistdelegate.h"
#include <QScrollBar>
#include <QLabel>
#include <QLineEdit>
#include <QListWidget>
#include <QDebug>
#include <QCursor>

#define FIRST_LINE_MAX 80

NoteEditorLogic::NoteEditorLogic(CustomDocument *textEdit,
                                 QLabel* editorDateLabel,
                                 QLineEdit* searchEdit,
                                 TagListView *tagListView, TagPool *tagPool,
                                 DBManager *dbManager,
                                 QObject *parent) : QObject(parent),
    m_textEdit{textEdit},
    m_editorDateLabel{editorDateLabel},
    m_searchEdit{searchEdit},
    m_tagListView{tagListView},
    m_dbManager{dbManager},
    m_isContentModified{false},
    m_spacerColor{26, 26, 26}
{
    m_highlighter = new MarkdownHighlighter(m_textEdit->document());
    connect(m_textEdit, &QTextEdit::textChanged, this, &NoteEditorLogic::onTextEditTextChanged);
    connect(m_textEdit, &CustomDocument::resized, this, &NoteEditorLogic::editorResized);
    connect(this, &NoteEditorLogic::requestCreateUpdateNote,
            m_dbManager, &DBManager::onCreateUpdateRequestedNoteContent, Qt::QueuedConnection);
    // auto save timer
    m_autoSaveTimer.setSingleShot(true);
    m_autoSaveTimer.setInterval(50);
    connect(&m_autoSaveTimer, &QTimer::timeout, this, [this]() {
        saveNoteToDB();
    });
    m_tagListModel = new TagListModel{this};
    m_tagListModel->setTagPool(tagPool);
    m_tagListView->setModel(m_tagListModel);
    m_tagListDelegate = new TagListDelegate{this};
    m_tagListView->setItemDelegate(m_tagListDelegate);
    connect(tagPool, &TagPool::dataUpdated, this, [this] (int) {
        showTagListForCurrentNote();
    });
}

bool NoteEditorLogic::markdownEnabled() const
{
    return m_highlighter == nullptr;
}

void NoteEditorLogic::setMarkdownEnabled(bool newMarkdownEnabled)
{
    if (markdownEnabled()) {
        delete m_highlighter;
        m_highlighter = nullptr;
    }
    if (newMarkdownEnabled) {
        m_highlighter = new MarkdownHighlighter(m_textEdit->document());
    } else {
        delete m_highlighter;
        m_highlighter = nullptr;
    }
}

void NoteEditorLogic::showNotesInEditor(const QVector<NodeData> &notes)
{
    if (notes.size() == 1 && notes[0].id() != SpecialNodeID::InvalidNodeId ) {
        auto currentId = currentEditingNoteId();
        if (currentId != SpecialNodeID::InvalidNodeId && notes[0].id() != currentId) {
            emit noteEditClosed(m_currentNotes[0]);
        }
        m_textEdit->blockSignals(true);
        m_textEdit->setVisible(true);
        m_currentNotes = notes;
        showTagListForCurrentNote();
        //     fixing bug #202
        m_textEdit->setTextBackgroundColor(QColor(247,247,247, 0));

        QString content = notes[0].content();
        QDateTime dateTime = notes[0].lastModificationdateTime();
        int scrollbarPos = notes[0].scrollBarPosition();

        // set text and date
        m_textEdit->setText(content);
        QString noteDate = dateTime.toString(Qt::ISODate);
        QString noteDateEditor = getNoteDateEditor(noteDate);
        m_editorDateLabel->setText(noteDateEditor);
        // set scrollbar position
        m_textEdit->verticalScrollBar()->setValue(scrollbarPos);
        m_textEdit->blockSignals(false);
        m_textEdit->setReadOnly(false);
        m_textEdit->setTextInteractionFlags(Qt::TextEditorInteraction);
        m_textEdit->setFocusPolicy(Qt::StrongFocus);
        highlightSearch();
    } else if (notes.size() > 1) {
        m_currentNotes = notes;
        m_tagListView->setVisible(false);
        m_textEdit->blockSignals(true);
        m_textEdit->clear();
        QPixmap sep(QSize{m_textEdit->width() - 100, 19});
        sep.fill(Qt::transparent);
        QPainter painter(&sep);
        painter.setPen(m_spacerColor);
        painter.drawLine(0, 10, sep.width(), 10);
        m_textEdit->document()->addResource(QTextDocument::ImageResource,
                                            QUrl("mydata://sep.png"),
                                            sep);
        for (int i = 0; i < notes.size(); ++i) {
            auto cursor = m_textEdit->textCursor();
            cursor.movePosition(QTextCursor::End);
            if (!notes[i].content().endsWith("\n")) {
                if (i != 0) {
                    cursor.insertText("\n" + notes[i].content() + "\n");
                } else {
                    cursor.insertText(notes[i].content() + "\n");
                }
            } else {
                cursor.insertText(notes[i].content());
            }
            if (i != notes.size() - 1) {
                cursor.movePosition(QTextCursor::End);
                cursor.insertImage("mydata://sep.png");
            }
        }
        m_textEdit->blockSignals(false);
        m_textEdit->setReadOnly(true);
        m_textEdit->setTextInteractionFlags(Qt::NoTextInteraction);
        m_textEdit->setFocusPolicy(Qt::NoFocus);
        highlightSearch();
    }
}

void NoteEditorLogic::onTextEditTextChanged()
{
    if (currentEditingNoteId() != SpecialNodeID::InvalidNodeId) {
        m_textEdit->blockSignals(true);
        QString content = m_currentNotes[0].content();
        if(m_textEdit->toPlainText() != content){
            // move note to the top of the list
            emit moveNoteToListViewTop(m_currentNotes[0]);

            // Get the new data
            QString firstline = getFirstLine(m_textEdit->toPlainText());
            QDateTime dateTime = QDateTime::currentDateTime();
            QString noteDate = dateTime.toString(Qt::ISODate);
            m_editorDateLabel->setText(NoteEditorLogic::getNoteDateEditor(noteDate));
            // update note data
            m_currentNotes[0].setContent(m_textEdit->toPlainText());
            m_currentNotes[0].setFullTitle(firstline);
            m_currentNotes[0].setLastModificationDateTime(dateTime);
            m_currentNotes[0].setIsTempNote(false);
            m_currentNotes[0].setScrollBarPosition(m_textEdit->verticalScrollBar()->value());
            // update note data in list view
            emit updateNoteDataInList(m_currentNotes[0]);
            m_isContentModified = true;
            m_autoSaveTimer.start();
            emit setVisibilityOfFrameRightNonEditor(false);
        }
        m_textEdit->blockSignals(false);
    } else {
        qDebug() << "NoteEditorLogic::onTextEditTextChanged() : m_currentNote is not valid";
    }
}

QDateTime NoteEditorLogic::getQDateTime(QString date)
{
    QDateTime dateTime = QDateTime::fromString(date, Qt::ISODate);
    return dateTime;
}

void NoteEditorLogic::showTagListForCurrentNote()
{
    if (currentEditingNoteId() != SpecialNodeID::InvalidNodeId) {
        auto tagIds = m_currentNotes[0].tagIds();
        if (tagIds.count() > 0) {
            m_tagListView->setVisible(true);
            m_tagListModel->setModelData(tagIds);
            return;
        }
        m_tagListModel->setModelData(tagIds);
    }
    m_tagListView->setVisible(false);
}

bool NoteEditorLogic::isInEditMode() const
{
    if (m_currentNotes.size() == 1) {
        return true;
    }
    return false;
}

int NoteEditorLogic::currentEditingNoteId() const
{
    if (isInEditMode()) {
        return m_currentNotes[0].id();
    }
    return SpecialNodeID::InvalidNodeId;
}

void NoteEditorLogic::saveNoteToDB()
{
    if(currentEditingNoteId() != SpecialNodeID::InvalidNodeId
            && m_isContentModified && !m_currentNotes[0].isTempNote()) {
        emit requestCreateUpdateNote(m_currentNotes[0]);
        m_isContentModified = false;
    }
}

void NoteEditorLogic::closeEditor()
{
    if (currentEditingNoteId() != SpecialNodeID::InvalidNodeId) {
        saveNoteToDB();
        emit noteEditClosed(m_currentNotes[0]);
    }
    m_currentNotes.clear();

    m_textEdit->blockSignals(true);
    m_textEdit->clear();
    m_textEdit->clearFocus();
    m_textEdit->blockSignals(false);
    m_tagListModel->setModelData({});
}

void NoteEditorLogic::onNoteTagListChanged(int noteId, const QSet<int> tagIds)
{
    if (currentEditingNoteId() == noteId) {
        m_currentNotes[0].setTagIds(tagIds);
        showTagListForCurrentNote();
    }
}

void NoteEditorLogic::editorResized()
{
    if (currentEditingNoteId() != SpecialNodeID::InvalidNodeId) {
        int verticalScrollBarValueToRestore = m_textEdit->verticalScrollBar()->value();
        m_textEdit->setText(m_textEdit->toPlainText());
        m_textEdit->verticalScrollBar()->setValue(verticalScrollBarValueToRestore);
    } else {
        int verticalScrollBarValueToRestore = m_textEdit->verticalScrollBar()->value();
        showNotesInEditor(m_currentNotes);
        m_textEdit->verticalScrollBar()->setValue(verticalScrollBarValueToRestore);
    }
}

void NoteEditorLogic::deleteCurrentNote()
{
    if (currentEditingNoteId() != SpecialNodeID::InvalidNodeId) {
        auto noteNeedDeleted = m_currentNotes[0];
        saveNoteToDB();
        m_currentNotes.clear();
        m_textEdit->blockSignals(true);
        m_textEdit->clear();
        m_textEdit->clearFocus();
        m_textEdit->blockSignals(false);
        emit noteEditClosed(noteNeedDeleted);
        emit deleteNoteRequested(noteNeedDeleted);
    }
}

/*!
 * \brief NoteEditorLogic::getFirstLine
 * Get a string 'str' and return only the first line of it
 * If the string contain no text, return "New Note"
 * TODO: We might make it more efficient by not loading the entire string into the memory
 * \param str
 * \return
 */
QString NoteEditorLogic::getFirstLine(const QString& str)
{
    QString text = str.trimmed();
    if (text.isEmpty()) {
        return "New Note";
    }
    QTextStream ts(&text);
    return ts.readLine(FIRST_LINE_MAX);
}

QString NoteEditorLogic::getSecondLine(const QString &str)
{
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
    auto sl = str.split("\n", QString::SkipEmptyParts);
#else
    auto sl = str.split("\n", Qt::SkipEmptyParts);
#endif
    if (sl.size() < 2) {
        return getFirstLine(str);
    }
    int i = 1;
    QString text;
    do {
        if (i >= sl.size()) {
            return getFirstLine(str);
        }
        text = sl[i].trimmed();
        ++i;
    } while (text.isEmpty());
    QTextStream ts(&text);
    return ts.readLine(FIRST_LINE_MAX);
}

void NoteEditorLogic::setTheme(Theme newTheme)
{
    m_tagListDelegate->setTheme(newTheme);
    switch(newTheme){
    case Theme::Light:
    {
        m_spacerColor = QColor(26, 26, 26);
        break;
    }
    case Theme::Dark:
    {
        m_spacerColor = QColor(204, 204, 204);
        break;
    }
    case Theme::Sepia:
    {
        m_spacerColor = QColor(26, 26, 26);
        break;
    }
    }
    if (currentEditingNoteId() != SpecialNodeID::InvalidNodeId) {
        int verticalScrollBarValueToRestore = m_textEdit->verticalScrollBar()->value();
        m_textEdit->setText(m_textEdit->toPlainText()); // TODO: Update the text color without setting the text
        m_textEdit->verticalScrollBar()->setValue(verticalScrollBarValueToRestore);
    } else {
        int verticalScrollBarValueToRestore = m_textEdit->verticalScrollBar()->value();
        showNotesInEditor(m_currentNotes);
        m_textEdit->verticalScrollBar()->setValue(verticalScrollBarValueToRestore);
    }
}

QString NoteEditorLogic::getNoteDateEditor(QString dateEdited)
{
    QDateTime dateTimeEdited(getQDateTime(dateEdited));
    QLocale usLocale(QLocale(QStringLiteral("en_US")));

    return usLocale.toString(dateTimeEdited, QStringLiteral("MMMM d, yyyy, h:mm A"));
}

void NoteEditorLogic::highlightSearch() const
{
    QString searchString = m_searchEdit->text();

    if (searchString.isEmpty())
        return;

    m_textEdit->moveCursor(QTextCursor::Start);

    QList<QTextEdit::ExtraSelection> extraSelections;
    QTextCharFormat highlightFormat;
    highlightFormat.setBackground(Qt::yellow);

    while (m_textEdit->find(searchString))
        extraSelections.append({ m_textEdit->textCursor(), highlightFormat});

    if (!extraSelections.isEmpty()) {
        m_textEdit->setTextCursor(extraSelections.first().cursor);
        m_textEdit->setExtraSelections(extraSelections);
    }
}

bool NoteEditorLogic::isTempNote() const
{
    if (currentEditingNoteId() != SpecialNodeID::InvalidNodeId && m_currentNotes[0].isTempNote()) {
        return true;
    }
    return false;
}
<|endoftext|>


<commit_before>#include "opencv2/objdetect/objdetect.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"

#include <iostream>
#include <stdio.h>

using namespace std;
using namespace cv;

/** Function Headers */
void detectAndDisplay( Mat frame );

/** Global variables */
String face_cascade_name = "../classifiers/haarcascade_frontalface_alt.xml";
String eyes_cascade_name = "../classifiers/haarcascade_eye_tree_eyeglasses.xml";
CascadeClassifier face_cascade;
CascadeClassifier eyes_cascade;
string window_name = "Capture - Face detection";
RNG rng(12345);

/** @function main */
int main( int argc, const char** argv ) {
 CvCapture* capture;
 Mat frame;

 //-- 1. Load the cascades
 if( !face_cascade.load( face_cascade_name ) ){ printf("--(!)Error loading\n"); return -1; };
 if( !eyes_cascade.load( eyes_cascade_name ) ){ printf("--(!)Error loading\n"); return -1; };

 if (argc > 0) {
     const char *trainer = argv[1];
     printf("Using trainer -> %s", trainer);
 }

 //-- 2. Read the video stream
 capture = cvCaptureFromCAM( -1 );
 if( capture ) {
   while( true )
   {
 frame = cvQueryFrame( capture );

 //-- 3. Apply the classifier to the frame
     if( !frame.empty() ) { detectAndDisplay( frame ); }
     else {
      printf(" --(!) No captured frame -- Break!"); break;
     }

     int c = waitKey(10);
     if( (char)c == 'c' ) { break; }
    }
 }
 return 0;
}

/** @function detectAndDisplay */
void detectAndDisplay( Mat frame ) {
std::vector<Rect> faces;
Mat frame_gray;

cvtColor( frame, frame_gray, CV_BGR2GRAY );
equalizeHist( frame_gray, frame_gray );

//-- Detect faces
face_cascade.detectMultiScale( frame_gray, faces, 1.1, 2, 0|CV_HAAR_SCALE_IMAGE, Size(30, 30) );

for( size_t i = 0; i < faces.size(); i++ ) {
  Point center( faces[i].x + faces[i].width*0.5, faces[i].y + faces[i].height*0.5 );
  ellipse( frame, center, Size( faces[i].width*0.5, faces[i].height*0.5), 0, 0, 360, Scalar( 255, 0, 255 ), 4, 8, 0 );

  Mat faceROI = frame_gray( faces[i] );
  std::vector<Rect> eyes;

  //-- In each face, detect eyes
  eyes_cascade.detectMultiScale( faceROI, eyes, 1.1, 2, 0 |CV_HAAR_SCALE_IMAGE, Size(30, 30) );

  for( size_t j = 0; j < eyes.size(); j++ ) {
     Point center( faces[i].x + eyes[j].x + eyes[j].width*0.5, faces[i].y + eyes[j].y + eyes[j].height*0.5 );
     int radius = cvRound( (eyes[j].width + eyes[j].height)*0.25 );
     circle( frame, center, radius, Scalar( 255, 0, 0 ), 4, 8, 0 );
   }
}
//-- Show what you got
imshow( window_name, frame );
}
<commit_msg>object detect libs pkg-config<commit_after>#include <opencv2/objdetect/objdetect.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

#include <iostream>
#include <stdio.h>

//g++ FaceRec.cpp `pkg-config --cflags --libs opencv`

using namespace std;
using namespace cv;

/** Function Headers */
void detectAndDisplay( Mat frame );

/** Global variables */
String face_cascade_name = "../classifiers/haarcascade_frontalface_alt.xml";
String eyes_cascade_name = "../classifiers/haarcascade_eye_tree_eyeglasses.xml";
CascadeClassifier face_cascade;
CascadeClassifier eyes_cascade;
string window_name = "Capture - Face detection";
RNG rng(12345);

/** @function main */
int main( int argc, const char** argv ) {
 CvCapture* capture;
 Mat frame;

 //-- 1. Load the cascades
 if( !face_cascade.load( face_cascade_name ) ){ printf("--(!)Error loading\n"); return -1; };
 if( !eyes_cascade.load( eyes_cascade_name ) ){ printf("--(!)Error loading\n"); return -1; };

 if (argc > 0) {
     const char *trainer = argv[1];
     printf("Using trainer -> %s", trainer);
 }

 //-- 2. Read the video stream
 capture = cvCaptureFromCAM( -1 );
 if( capture ) {
   while( true )
   {
 frame = cvQueryFrame( capture );

 //-- 3. Apply the classifier to the frame
     if( !frame.empty() ) { detectAndDisplay( frame ); }
     else {
      printf(" --(!) No captured frame -- Break!"); break;
     }

     int c = waitKey(10);
     if( (char)c == 'c' ) { break; }
    }
 }
 return 0;
}

/** @function detectAndDisplay */
void detectAndDisplay( Mat frame ) {
std::vector<Rect> faces;
Mat frame_gray;

cvtColor( frame, frame_gray, CV_BGR2GRAY );
equalizeHist( frame_gray, frame_gray );

//-- Detect faces
face_cascade.detectMultiScale( frame_gray, faces, 1.1, 2, 0|CV_HAAR_SCALE_IMAGE, Size(30, 30) );

for( size_t i = 0; i < faces.size(); i++ ) {
  Point center( faces[i].x + faces[i].width*0.5, faces[i].y + faces[i].height*0.5 );
  ellipse( frame, center, Size( faces[i].width*0.5, faces[i].height*0.5), 0, 0, 360, Scalar( 255, 0, 255 ), 4, 8, 0 );

  Mat faceROI = frame_gray( faces[i] );
  std::vector<Rect> eyes;

  //-- In each face, detect eyes
  eyes_cascade.detectMultiScale( faceROI, eyes, 1.1, 2, 0 |CV_HAAR_SCALE_IMAGE, Size(30, 30) );

  for( size_t j = 0; j < eyes.size(); j++ ) {
     Point center( faces[i].x + eyes[j].x + eyes[j].width*0.5, faces[i].y + eyes[j].y + eyes[j].height*0.5 );
     int radius = cvRound( (eyes[j].width + eyes[j].height)*0.25 );
     circle( frame, center, radius, Scalar( 255, 0, 0 ), 4, 8, 0 );
   }
}
//-- Show what you got
imshow( window_name, frame );
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** 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 Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/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 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.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "puppetcreator.h"

#include <QProcess>
#include <QTemporaryDir>
#include <QCoreApplication>
#include <QCryptographicHash>
#include <QDateTime>

#include <projectexplorer/kit.h>
#include <projectexplorer/toolchain.h>
#include <utils/environment.h>
#include <coreplugin/icore.h>
#include <qtsupport/baseqtversion.h>
#include <qtsupport/qtkitinformation.h>
#include <qtsupport/qtsupportconstants.h>

#include "puppetbuildprogressdialog.h"

#include <QtDebug>

namespace QmlDesigner {

bool PuppetCreator::m_useOnlyFallbackPuppet = !qgetenv("USE_ONLY_FALLBACK_PUPPET").isEmpty();
QHash<Core::Id, PuppetCreator::PuppetType> PuppetCreator::m_qml1PuppetForKitPuppetHash;
QHash<Core::Id, PuppetCreator::PuppetType> PuppetCreator::m_qml2PuppetForKitPuppetHash;

QByteArray PuppetCreator::qtHash() const
{
    if (m_kit) {
        QtSupport::BaseQtVersion *currentQtVersion = QtSupport::QtKitInformation::qtVersion(m_kit);
        if (currentQtVersion)
            return QCryptographicHash::hash(currentQtVersion->qmakeProperty("QT_INSTALL_DATA").toUtf8(), QCryptographicHash::Sha1).toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
    }

    return QByteArray();
}

QDateTime PuppetCreator::qtLastModified() const
{
    if (m_kit) {
        QtSupport::BaseQtVersion *currentQtVersion = QtSupport::QtKitInformation::qtVersion(m_kit);
        if (currentQtVersion)
            return QFileInfo(currentQtVersion->qmakeProperty("QT_INSTALL_LIBS")).lastModified();
    }

    return QDateTime();
}

PuppetCreator::PuppetCreator(ProjectExplorer::Kit *kit, const QString &qtCreatorVersion)
    : m_qtCreatorVersion(qtCreatorVersion),
      m_kit(kit),
      m_availablePuppetType(FallbackPuppet)
{
}

PuppetCreator::~PuppetCreator()
{
}

void PuppetCreator::createPuppetExecutableIfMissing(PuppetCreator::QmlPuppetVersion puppetVersion)
{
    if (puppetVersion == Qml1Puppet)
        createQml1PuppetExecutableIfMissing();
    else
        createQml2PuppetExecutableIfMissing();
}

QProcess *PuppetCreator::createPuppetProcess(PuppetCreator::QmlPuppetVersion puppetVersion, const QString &puppetMode, const QString &socketToken, QObject *handlerObject, const char *outputSlot, const char *finishSlot) const
{
    QString puppetPath;
    if (puppetVersion == Qml1Puppet)
        puppetPath = qmlpuppetPath(m_availablePuppetType);
     else
        puppetPath = qml2puppetPath(m_availablePuppetType);

    return puppetProcess(puppetPath,
                         puppetMode,
                         socketToken,
                         handlerObject,
                         outputSlot,
                         finishSlot);
}

QProcess *PuppetCreator::puppetProcess(const QString &puppetPath,
                                       const QString &puppetMode,
                                       const QString &socketToken,
                                       QObject *handlerObject,
                                       const char *outputSlot,
                                       const char *finishSlot) const
{
    QProcess *puppetProcess = new QProcess;
    puppetProcess->setObjectName(puppetMode);
    puppetProcess->setProcessEnvironment(processEnvironment());
    QObject::connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), puppetProcess, SLOT(kill()));
    QObject::connect(puppetProcess, SIGNAL(finished(int,QProcess::ExitStatus)), handlerObject, finishSlot);
    bool fowardQmlpuppetOutput = !qgetenv("FORWARD_QMLPUPPET_OUTPUT").isEmpty();
    if (fowardQmlpuppetOutput) {
        puppetProcess->setProcessChannelMode(QProcess::MergedChannels);
        QObject::connect(puppetProcess, SIGNAL(readyRead()), handlerObject, outputSlot);
    }
    puppetProcess->start(puppetPath, QStringList() << socketToken << puppetMode << "-graphicssystem raster");

    return puppetProcess;
}

bool PuppetCreator::build(const QString &qmlPuppetProjectFilePath) const
{
    PuppetBuildProgressDialog progressDialog;

    m_compileLog.clear();

    QTemporaryDir buildDirectory;

    bool buildSucceeded = false;

    if (qtIsSupported()) {
        if (buildDirectory.isValid()) {
            QStringList qmakeArguments;
            qmakeArguments.append(QStringLiteral("-r"));
            qmakeArguments.append(QStringLiteral("-after"));
            qmakeArguments.append(QStringLiteral("DESTDIR=") + qmlpuppetDirectory(UserSpacePuppet));
#ifndef QT_DEBUG
            qmakeArguments.append(QStringLiteral("CONFIG+=release"));
#endif
            qmakeArguments.append(qmlPuppetProjectFilePath);
            buildSucceeded = startBuildProcess(buildDirectory.path(), qmakeCommand(), qmakeArguments);
            if (buildSucceeded) {
                progressDialog.show();
                buildSucceeded = startBuildProcess(buildDirectory.path(), buildCommand(), QStringList(), &progressDialog);
                progressDialog.hide();
            }
        } else {
            buildSucceeded = true;
        }
    }

    return buildSucceeded;
}

void PuppetCreator::createQml1PuppetExecutableIfMissing()
{
    if (!m_useOnlyFallbackPuppet && m_kit) {
        if (m_qml1PuppetForKitPuppetHash.contains(m_kit->id())) {
            m_availablePuppetType = m_qml1PuppetForKitPuppetHash.value(m_kit->id());
        } else if (checkQmlpuppetIsReady()) {
            m_availablePuppetType = UserSpacePuppet;
        } else {
            bool buildSucceeded = build(qmlpuppetProjectFile());
            if (buildSucceeded)
                m_availablePuppetType = UserSpacePuppet;
            else
                m_availablePuppetType = FallbackPuppet;
        }

        m_qml1PuppetForKitPuppetHash.insert(m_kit->id(), m_availablePuppetType);

    } else {
        m_availablePuppetType = FallbackPuppet;
    }
}

void PuppetCreator::createQml2PuppetExecutableIfMissing()
{
    if (!m_useOnlyFallbackPuppet && m_kit) {
        if (m_qml2PuppetForKitPuppetHash.contains(m_kit->id())) {
            m_availablePuppetType = m_qml2PuppetForKitPuppetHash.value(m_kit->id());
        } else if (checkQml2puppetIsReady()) {
            m_availablePuppetType = UserSpacePuppet;
        } else {
            bool buildSucceeded = build(qml2puppetProjectFile());
            if (buildSucceeded)
                m_availablePuppetType = UserSpacePuppet;
            else
                m_availablePuppetType = FallbackPuppet;
        }

        m_qml2PuppetForKitPuppetHash.insert(m_kit->id(), m_availablePuppetType);

    } else {
        m_availablePuppetType = FallbackPuppet;
    }
}

QString PuppetCreator::qmlpuppetDirectory(PuppetType puppetType) const
{

    if (puppetType == UserSpacePuppet)
        return Core::ICore::userResourcePath()
                + QStringLiteral("/qmlpuppet/")
                + QCoreApplication::applicationVersion() + QStringLiteral("/")
                + qtHash();

    return qmlpuppetFallbackDirectory();
}

QString PuppetCreator::qmlpuppetFallbackDirectory() const
{
    return QCoreApplication::applicationDirPath();
}

QString PuppetCreator::qml2puppetPath(PuppetType puppetType) const
{
    return qmlpuppetDirectory(puppetType) + QStringLiteral("/qml2puppet") + QStringLiteral(QTC_HOST_EXE_SUFFIX);
}

QString PuppetCreator::qmlpuppetPath(PuppetType puppetType) const
{
    return qmlpuppetDirectory(puppetType) + QStringLiteral("/qmlpuppet") + QStringLiteral(QTC_HOST_EXE_SUFFIX);
}

QProcessEnvironment PuppetCreator::processEnvironment() const
{
    Utils::Environment environment = Utils::Environment::systemEnvironment();
    m_kit->addToEnvironment(environment);
    environment.set("QML_BAD_GUI_RENDER_LOOP", "true");
    environment.set("QML_USE_MOCKUPS", "true");

    return environment.toProcessEnvironment();
}

QString PuppetCreator::buildCommand() const
{
    Utils::Environment environment = Utils::Environment::systemEnvironment();
    m_kit->addToEnvironment(environment);

    ProjectExplorer::ToolChain *toolChain = ProjectExplorer::ToolChainKitInformation::toolChain(m_kit);

    if (toolChain)
        return toolChain->makeCommand(environment);

    return QString();
}

QString PuppetCreator::qmakeCommand() const
{
    QtSupport::BaseQtVersion *currentQtVersion = QtSupport::QtKitInformation::qtVersion(m_kit);
    if (currentQtVersion)
        return currentQtVersion->qmakeCommand().toString();

    return QString();
}

QString PuppetCreator::compileLog() const
{
    return m_compileLog;
}

bool PuppetCreator::startBuildProcess(const QString &buildDirectoryPath,
                                      const QString &command,
                                      const QStringList &processArguments,
                                      PuppetBuildProgressDialog *progressDialog) const
{
    if (command.isEmpty())
        return false;

    QProcess process;
    process.setProcessChannelMode(QProcess::MergedChannels);
    process.setProcessEnvironment(processEnvironment());
    process.setWorkingDirectory(buildDirectoryPath);
    process.start(command, processArguments);
    process.waitForStarted();
    while (true) {
        if (process.waitForReadyRead(100)) {
            QByteArray newOutput = process.readAllStandardOutput();
            if (progressDialog)  {
                progressDialog->newBuildOutput(newOutput);
                m_compileLog.append(newOutput);
            }
        }

        if (process.state() == QProcess::NotRunning)
            break;
    }

    if (process.exitStatus() == QProcess::NormalExit || process.exitCode() == 0)
        return true;
    else
        return false;
}

QString PuppetCreator::puppetSourceDirectoryPath()
{
    return Core::ICore::resourcePath() + QStringLiteral("/qml/qmlpuppet");
}

QString PuppetCreator::qml2puppetProjectFile()
{
    return puppetSourceDirectoryPath() + QStringLiteral("/qml2puppet/qml2puppet.pro");
}

QString PuppetCreator::qmlpuppetProjectFile()
{
    return puppetSourceDirectoryPath() + QStringLiteral("/qmlpuppet/qmlpuppet.pro");
}

bool PuppetCreator::checkPuppetIsReady(const QString &puppetPath) const
{
    QFileInfo puppetFileInfo(puppetPath);

    return puppetFileInfo.exists() && puppetFileInfo.lastModified() > qtLastModified();
}

bool PuppetCreator::checkQml2puppetIsReady() const
{
    return checkPuppetIsReady(qml2puppetPath(UserSpacePuppet));
}

bool PuppetCreator::checkQmlpuppetIsReady() const
{
    return checkPuppetIsReady(qmlpuppetPath(UserSpacePuppet));
}

bool PuppetCreator::qtIsSupported() const
{
    QtSupport::BaseQtVersion *currentQtVersion = QtSupport::QtKitInformation::qtVersion(m_kit);

    if (currentQtVersion
            && currentQtVersion->isValid()
            && currentQtVersion->qtVersion() >= QtSupport::QtVersionNumber(5, 2, 0)
            && (currentQtVersion->type() == QLatin1String(QtSupport::Constants::DESKTOPQT)
                || currentQtVersion->type() == QLatin1String(QtSupport::Constants::SIMULATORQT)))
        return true;

    return false;
}

bool PuppetCreator::checkPuppetVersion(const QString &qmlPuppetPath)
{

    QProcess qmlPuppetVersionProcess;
    qmlPuppetVersionProcess.start(qmlPuppetPath, QStringList() << "--version");
    qmlPuppetVersionProcess.waitForReadyRead(6000);

    QByteArray versionString = qmlPuppetVersionProcess.readAll();

    bool canConvert;
    unsigned int versionNumber = versionString.toUInt(&canConvert);

    return canConvert && versionNumber == 2;

}

} // namespace QmlDesigner
<commit_msg>QmlDesigner: Append qmake output to compile log too<commit_after>/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** 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 Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/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 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.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "puppetcreator.h"

#include <QProcess>
#include <QTemporaryDir>
#include <QCoreApplication>
#include <QCryptographicHash>
#include <QDateTime>

#include <projectexplorer/kit.h>
#include <projectexplorer/toolchain.h>
#include <utils/environment.h>
#include <coreplugin/icore.h>
#include <qtsupport/baseqtversion.h>
#include <qtsupport/qtkitinformation.h>
#include <qtsupport/qtsupportconstants.h>

#include "puppetbuildprogressdialog.h"

#include <QtDebug>

namespace QmlDesigner {

bool PuppetCreator::m_useOnlyFallbackPuppet = !qgetenv("USE_ONLY_FALLBACK_PUPPET").isEmpty();
QHash<Core::Id, PuppetCreator::PuppetType> PuppetCreator::m_qml1PuppetForKitPuppetHash;
QHash<Core::Id, PuppetCreator::PuppetType> PuppetCreator::m_qml2PuppetForKitPuppetHash;

QByteArray PuppetCreator::qtHash() const
{
    if (m_kit) {
        QtSupport::BaseQtVersion *currentQtVersion = QtSupport::QtKitInformation::qtVersion(m_kit);
        if (currentQtVersion)
            return QCryptographicHash::hash(currentQtVersion->qmakeProperty("QT_INSTALL_DATA").toUtf8(), QCryptographicHash::Sha1).toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
    }

    return QByteArray();
}

QDateTime PuppetCreator::qtLastModified() const
{
    if (m_kit) {
        QtSupport::BaseQtVersion *currentQtVersion = QtSupport::QtKitInformation::qtVersion(m_kit);
        if (currentQtVersion)
            return QFileInfo(currentQtVersion->qmakeProperty("QT_INSTALL_LIBS")).lastModified();
    }

    return QDateTime();
}

PuppetCreator::PuppetCreator(ProjectExplorer::Kit *kit, const QString &qtCreatorVersion)
    : m_qtCreatorVersion(qtCreatorVersion),
      m_kit(kit),
      m_availablePuppetType(FallbackPuppet)
{
}

PuppetCreator::~PuppetCreator()
{
}

void PuppetCreator::createPuppetExecutableIfMissing(PuppetCreator::QmlPuppetVersion puppetVersion)
{
    if (puppetVersion == Qml1Puppet)
        createQml1PuppetExecutableIfMissing();
    else
        createQml2PuppetExecutableIfMissing();
}

QProcess *PuppetCreator::createPuppetProcess(PuppetCreator::QmlPuppetVersion puppetVersion, const QString &puppetMode, const QString &socketToken, QObject *handlerObject, const char *outputSlot, const char *finishSlot) const
{
    QString puppetPath;
    if (puppetVersion == Qml1Puppet)
        puppetPath = qmlpuppetPath(m_availablePuppetType);
     else
        puppetPath = qml2puppetPath(m_availablePuppetType);

    return puppetProcess(puppetPath,
                         puppetMode,
                         socketToken,
                         handlerObject,
                         outputSlot,
                         finishSlot);
}

QProcess *PuppetCreator::puppetProcess(const QString &puppetPath,
                                       const QString &puppetMode,
                                       const QString &socketToken,
                                       QObject *handlerObject,
                                       const char *outputSlot,
                                       const char *finishSlot) const
{
    QProcess *puppetProcess = new QProcess;
    puppetProcess->setObjectName(puppetMode);
    puppetProcess->setProcessEnvironment(processEnvironment());
    QObject::connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), puppetProcess, SLOT(kill()));
    QObject::connect(puppetProcess, SIGNAL(finished(int,QProcess::ExitStatus)), handlerObject, finishSlot);
    bool fowardQmlpuppetOutput = !qgetenv("FORWARD_QMLPUPPET_OUTPUT").isEmpty();
    if (fowardQmlpuppetOutput) {
        puppetProcess->setProcessChannelMode(QProcess::MergedChannels);
        QObject::connect(puppetProcess, SIGNAL(readyRead()), handlerObject, outputSlot);
    }
    puppetProcess->start(puppetPath, QStringList() << socketToken << puppetMode << "-graphicssystem raster");

    return puppetProcess;
}

bool PuppetCreator::build(const QString &qmlPuppetProjectFilePath) const
{
    PuppetBuildProgressDialog progressDialog;

    m_compileLog.clear();

    QTemporaryDir buildDirectory;

    bool buildSucceeded = false;

    if (qtIsSupported()) {
        if (buildDirectory.isValid()) {
            QStringList qmakeArguments;
            qmakeArguments.append(QStringLiteral("-r"));
            qmakeArguments.append(QStringLiteral("-after"));
            qmakeArguments.append(QStringLiteral("DESTDIR=") + qmlpuppetDirectory(UserSpacePuppet));
#ifndef QT_DEBUG
            qmakeArguments.append(QStringLiteral("CONFIG+=release"));
#endif
            qmakeArguments.append(qmlPuppetProjectFilePath);
            buildSucceeded = startBuildProcess(buildDirectory.path(), qmakeCommand(), qmakeArguments);
            if (buildSucceeded) {
                progressDialog.show();
                buildSucceeded = startBuildProcess(buildDirectory.path(), buildCommand(), QStringList(), &progressDialog);
                progressDialog.hide();
            }
        } else {
            buildSucceeded = true;
        }
    }

    return buildSucceeded;
}

void PuppetCreator::createQml1PuppetExecutableIfMissing()
{
    if (!m_useOnlyFallbackPuppet && m_kit) {
        if (m_qml1PuppetForKitPuppetHash.contains(m_kit->id())) {
            m_availablePuppetType = m_qml1PuppetForKitPuppetHash.value(m_kit->id());
        } else if (checkQmlpuppetIsReady()) {
            m_availablePuppetType = UserSpacePuppet;
        } else {
            bool buildSucceeded = build(qmlpuppetProjectFile());
            if (buildSucceeded)
                m_availablePuppetType = UserSpacePuppet;
            else
                m_availablePuppetType = FallbackPuppet;
        }

        m_qml1PuppetForKitPuppetHash.insert(m_kit->id(), m_availablePuppetType);

    } else {
        m_availablePuppetType = FallbackPuppet;
    }
}

void PuppetCreator::createQml2PuppetExecutableIfMissing()
{
    if (!m_useOnlyFallbackPuppet && m_kit) {
        if (m_qml2PuppetForKitPuppetHash.contains(m_kit->id())) {
            m_availablePuppetType = m_qml2PuppetForKitPuppetHash.value(m_kit->id());
        } else if (checkQml2puppetIsReady()) {
            m_availablePuppetType = UserSpacePuppet;
        } else {
            bool buildSucceeded = build(qml2puppetProjectFile());
            if (buildSucceeded)
                m_availablePuppetType = UserSpacePuppet;
            else
                m_availablePuppetType = FallbackPuppet;
        }

        m_qml2PuppetForKitPuppetHash.insert(m_kit->id(), m_availablePuppetType);

    } else {
        m_availablePuppetType = FallbackPuppet;
    }
}

QString PuppetCreator::qmlpuppetDirectory(PuppetType puppetType) const
{

    if (puppetType == UserSpacePuppet)
        return Core::ICore::userResourcePath()
                + QStringLiteral("/qmlpuppet/")
                + QCoreApplication::applicationVersion() + QStringLiteral("/")
                + qtHash();

    return qmlpuppetFallbackDirectory();
}

QString PuppetCreator::qmlpuppetFallbackDirectory() const
{
    return QCoreApplication::applicationDirPath();
}

QString PuppetCreator::qml2puppetPath(PuppetType puppetType) const
{
    return qmlpuppetDirectory(puppetType) + QStringLiteral("/qml2puppet") + QStringLiteral(QTC_HOST_EXE_SUFFIX);
}

QString PuppetCreator::qmlpuppetPath(PuppetType puppetType) const
{
    return qmlpuppetDirectory(puppetType) + QStringLiteral("/qmlpuppet") + QStringLiteral(QTC_HOST_EXE_SUFFIX);
}

QProcessEnvironment PuppetCreator::processEnvironment() const
{
    Utils::Environment environment = Utils::Environment::systemEnvironment();
    m_kit->addToEnvironment(environment);
    environment.set("QML_BAD_GUI_RENDER_LOOP", "true");
    environment.set("QML_USE_MOCKUPS", "true");

    return environment.toProcessEnvironment();
}

QString PuppetCreator::buildCommand() const
{
    Utils::Environment environment = Utils::Environment::systemEnvironment();
    m_kit->addToEnvironment(environment);

    ProjectExplorer::ToolChain *toolChain = ProjectExplorer::ToolChainKitInformation::toolChain(m_kit);

    if (toolChain)
        return toolChain->makeCommand(environment);

    return QString();
}

QString PuppetCreator::qmakeCommand() const
{
    QtSupport::BaseQtVersion *currentQtVersion = QtSupport::QtKitInformation::qtVersion(m_kit);
    if (currentQtVersion)
        return currentQtVersion->qmakeCommand().toString();

    return QString();
}

QString PuppetCreator::compileLog() const
{
    return m_compileLog;
}

bool PuppetCreator::startBuildProcess(const QString &buildDirectoryPath,
                                      const QString &command,
                                      const QStringList &processArguments,
                                      PuppetBuildProgressDialog *progressDialog) const
{
    if (command.isEmpty())
        return false;

    QProcess process;
    process.setProcessChannelMode(QProcess::MergedChannels);
    process.setProcessEnvironment(processEnvironment());
    process.setWorkingDirectory(buildDirectoryPath);
    process.start(command, processArguments);
    process.waitForStarted();
    while (true) {
        if (process.waitForReadyRead(100)) {
            QByteArray newOutput = process.readAllStandardOutput();
            if (progressDialog)
                progressDialog->newBuildOutput(newOutput);

            m_compileLog.append(newOutput);
        }

        if (process.state() == QProcess::NotRunning)
            break;
    }

    if (process.exitStatus() == QProcess::NormalExit || process.exitCode() == 0)
        return true;
    else
        return false;
}

QString PuppetCreator::puppetSourceDirectoryPath()
{
    return Core::ICore::resourcePath() + QStringLiteral("/qml/qmlpuppet");
}

QString PuppetCreator::qml2puppetProjectFile()
{
    return puppetSourceDirectoryPath() + QStringLiteral("/qml2puppet/qml2puppet.pro");
}

QString PuppetCreator::qmlpuppetProjectFile()
{
    return puppetSourceDirectoryPath() + QStringLiteral("/qmlpuppet/qmlpuppet.pro");
}

bool PuppetCreator::checkPuppetIsReady(const QString &puppetPath) const
{
    QFileInfo puppetFileInfo(puppetPath);

    return puppetFileInfo.exists() && puppetFileInfo.lastModified() > qtLastModified();
}

bool PuppetCreator::checkQml2puppetIsReady() const
{
    return checkPuppetIsReady(qml2puppetPath(UserSpacePuppet));
}

bool PuppetCreator::checkQmlpuppetIsReady() const
{
    return checkPuppetIsReady(qmlpuppetPath(UserSpacePuppet));
}

bool PuppetCreator::qtIsSupported() const
{
    QtSupport::BaseQtVersion *currentQtVersion = QtSupport::QtKitInformation::qtVersion(m_kit);

    if (currentQtVersion
            && currentQtVersion->isValid()
            && currentQtVersion->qtVersion() >= QtSupport::QtVersionNumber(5, 2, 0)
            && (currentQtVersion->type() == QLatin1String(QtSupport::Constants::DESKTOPQT)
                || currentQtVersion->type() == QLatin1String(QtSupport::Constants::SIMULATORQT)))
        return true;

    return false;
}

bool PuppetCreator::checkPuppetVersion(const QString &qmlPuppetPath)
{

    QProcess qmlPuppetVersionProcess;
    qmlPuppetVersionProcess.start(qmlPuppetPath, QStringList() << "--version");
    qmlPuppetVersionProcess.waitForReadyRead(6000);

    QByteArray versionString = qmlPuppetVersionProcess.readAll();

    bool canConvert;
    unsigned int versionNumber = versionString.toUInt(&canConvert);

    return canConvert && versionNumber == 2;

}

} // namespace QmlDesigner
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2009, Willow Garage, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the Willow Garage, Inc. nor the names of its
 *       contributors may be used to endorse or promote products derived from
 *       this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <OgreViewport.h>
#include <OgreQuaternion.h>
#include <OgreVector3.h>
#include <OgreSceneNode.h>
#include <OgreSceneManager.h>
#include <OgreCamera.h>

#include "rviz/uniform_string_stream.h"
#include "rviz/display_context.h"
#include "rviz/viewport_mouse_event.h"
#include "rviz/geometry.h"
#include "rviz/ogre_helpers/shape.h"
#include "rviz/properties/bool_property.h"
#include "rviz/properties/float_property.h"
#include "rviz/properties/vector_property.h"

#include "fps_view_controller.h"

namespace rviz
{

static const Ogre::Quaternion ROBOT_TO_CAMERA_ROTATION =
  Ogre::Quaternion( Ogre::Radian( -Ogre::Math::HALF_PI ), Ogre::Vector3::UNIT_Y ) *
  Ogre::Quaternion( Ogre::Radian( -Ogre::Math::HALF_PI ), Ogre::Vector3::UNIT_Z );

static const float PITCH_LIMIT_LOW = -Ogre::Math::HALF_PI + 0.001;
static const float PITCH_LIMIT_HIGH = Ogre::Math::HALF_PI - 0.001;

FPSViewController::FPSViewController()
{
  yaw_property_ = new FloatProperty( "Yaw", 0, "Rotation of the camera around the Z (up) axis.", this );

  pitch_property_ = new FloatProperty( "Pitch", 0, "How much the camera is tipped downward.", this );
  pitch_property_->setMax( Ogre::Math::HALF_PI - 0.001 );
  pitch_property_->setMin( -pitch_property_->getMax() );

  position_property_ = new VectorProperty( "Position", Ogre::Vector3( 5, 5, 10 ), "Position of the camera.", this );

  invert_z_->hide();
}

FPSViewController::~FPSViewController()
{
}

void FPSViewController::onInitialize()
{
  FramePositionTrackingViewController::onInitialize();
  camera_->setProjectionType( Ogre::PT_PERSPECTIVE );
}

void FPSViewController::reset()
{
  camera_->setPosition( Ogre::Vector3( 5, 5, 10 ));
  camera_->lookAt( 0, 0, 0 );
  setPropertiesFromCamera( camera_ );

  // Hersh says: why is the following junk necessary?  I don't know.
  // However, without this you need to call reset() twice after
  // switching from TopDownOrtho to FPS.  After the first call the
  // camera is in the right position but pointing the wrong way.
  updateCamera();
  camera_->lookAt( 0, 0, 0 );
  setPropertiesFromCamera( camera_ );
}

void FPSViewController::handleMouseEvent(ViewportMouseEvent& event)
{
  if ( event.shift() )
  {
    setStatus( "Left-Click: Move X/Y.  Right-Click:: Move Z." );
  }
  else
  {
    setStatus( "Left-Click: Rotate.  Middle-Click: Move X/Y.  Right-Click:: Zoom.  Shift: More options." );
  }

  int32_t diff_x = 0;
  int32_t diff_y = 0;

  if( event.type == QEvent::MouseMove )
  {
    diff_x = event.x - event.last_x;
    diff_y = event.y - event.last_y;
  }
  bool moved = diff_x != 0 || diff_y != 0;

  if( event.left() && !event.shift() )
  {
    setCursor( Rotate3D );
    yaw( -diff_x*0.005 );
    pitch( diff_y*0.005 );
  }
  else if( event.middle() || ( event.shift() && event.left() ))
  {
    setCursor( MoveXY );
    move( diff_x*0.01, -diff_y*0.01, 0.0f );
  }
  else if( event.right() )
  {
    setCursor( MoveZ );
    move( 0.0f, 0.0f, diff_y*0.1 );
  }
  else
  {
    setCursor( event.shift() ? MoveXY : Rotate3D );
    moved = false;
  }

  if ( event.wheel_delta != 0 )
  {
    int diff = event.wheel_delta;
    move( 0.0f, 0.0f, -diff * 0.01 );
    moved = diff != 0;
  }

  if (moved)
  {
    context_->queueRender();
  }
}

void FPSViewController::setPropertiesFromCamera( Ogre::Camera* source_camera )
{
  Ogre::Quaternion quat = source_camera->getOrientation() * ROBOT_TO_CAMERA_ROTATION.Inverse();
  float yaw = quat.getRoll( false ).valueRadians(); // OGRE camera frame looks along -Z, so they call rotation around Z "roll".
  float pitch = quat.getYaw( false ).valueRadians(); // OGRE camera frame has +Y as "up", so they call rotation around Y "yaw".

  Ogre::Vector3 direction = quat * Ogre::Vector3::NEGATIVE_UNIT_Z;

  if ( direction.dotProduct( Ogre::Vector3::NEGATIVE_UNIT_Z ) < 0 )
  {
    if ( pitch > Ogre::Math::HALF_PI )
    {
      pitch -= Ogre::Math::PI;
    }
    else if ( pitch < -Ogre::Math::HALF_PI )
    {
      pitch += Ogre::Math::PI;
    }

    yaw = -yaw;

    if ( direction.dotProduct( Ogre::Vector3::UNIT_X ) < 0 )
    {
      yaw -= Ogre::Math::PI;
    }
    else
    {
      yaw += Ogre::Math::PI;
    }
  }

  pitch_property_->setFloat( pitch );
  yaw_property_->setFloat( mapAngleTo0_2Pi( yaw ));
  position_property_->setVector( source_camera->getPosition() );
}

void FPSViewController::mimic( ViewController* source_view )
{
  FramePositionTrackingViewController::mimic( source_view );
  setPropertiesFromCamera( source_view->getCamera() );
}

void FPSViewController::update(float dt, float ros_dt)
{
  FramePositionTrackingViewController::update( dt, ros_dt );
  updateCamera();
}

void FPSViewController::lookAt( const Ogre::Vector3& point )
{
  camera_->lookAt( point );
  setPropertiesFromCamera( camera_ );
}

void FPSViewController::onTargetFrameChanged(const Ogre::Vector3& old_reference_position, const Ogre::Quaternion& old_reference_orientation)
{
  position_property_->add( old_reference_position - reference_position_ );
}

void FPSViewController::updateCamera()
{
  camera_->setOrientation( getOrientation() );
  camera_->setPosition( position_property_->getVector() );
}

void FPSViewController::yaw( float angle )
{
  yaw_property_->setFloat( mapAngleTo0_2Pi( yaw_property_->getFloat() + angle ));
}

void FPSViewController::pitch( float angle )
{
  pitch_property_->add( angle );
}

Ogre::Quaternion FPSViewController::getOrientation()
{
  Ogre::Quaternion pitch, yaw;

  yaw.FromAngleAxis( Ogre::Radian( yaw_property_->getFloat() ), Ogre::Vector3::UNIT_Z );
  pitch.FromAngleAxis( Ogre::Radian( pitch_property_->getFloat() ), Ogre::Vector3::UNIT_Y );

  return yaw * pitch * ROBOT_TO_CAMERA_ROTATION;
}

void FPSViewController::move( float x, float y, float z )
{
  Ogre::Vector3 translate( x, y, z );
  position_property_->add( getOrientation() * translate );
}

} // end namespace rviz

#include <pluginlib/class_list_macros.hpp>
PLUGINLIB_EXPORT_CLASS( rviz::FPSViewController, rviz::ViewController )
<commit_msg>FPS view: fix reset(), lookat()<commit_after>/*
 * Copyright (c) 2009, Willow Garage, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the Willow Garage, Inc. nor the names of its
 *       contributors may be used to endorse or promote products derived from
 *       this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <OgreViewport.h>
#include <OgreQuaternion.h>
#include <OgreVector3.h>
#include <OgreSceneNode.h>
#include <OgreSceneManager.h>
#include <OgreCamera.h>

#include "rviz/uniform_string_stream.h"
#include "rviz/display_context.h"
#include "rviz/viewport_mouse_event.h"
#include "rviz/geometry.h"
#include "rviz/ogre_helpers/shape.h"
#include "rviz/properties/bool_property.h"
#include "rviz/properties/float_property.h"
#include "rviz/properties/vector_property.h"

#include "fps_view_controller.h"

namespace rviz
{

static const Ogre::Quaternion ROBOT_TO_CAMERA_ROTATION =
  Ogre::Quaternion( Ogre::Radian( -Ogre::Math::HALF_PI ), Ogre::Vector3::UNIT_Y ) *
  Ogre::Quaternion( Ogre::Radian( -Ogre::Math::HALF_PI ), Ogre::Vector3::UNIT_Z );

FPSViewController::FPSViewController()
{
  yaw_property_ = new FloatProperty( "Yaw", 0, "Rotation of the camera around the Z (up) axis.", this );

  pitch_property_ = new FloatProperty( "Pitch", 0, "How much the camera is tipped downward.", this );
  pitch_property_->setMax( Ogre::Math::HALF_PI);
  pitch_property_->setMin(-Ogre::Math::HALF_PI);

  position_property_ = new VectorProperty( "Position", Ogre::Vector3( 5, 5, 10 ), "Position of the camera.", this );

  invert_z_->hide();
}

FPSViewController::~FPSViewController()
{
}

void FPSViewController::onInitialize()
{
  FramePositionTrackingViewController::onInitialize();
  camera_->setProjectionType( Ogre::PT_PERSPECTIVE );
}

void FPSViewController::reset()
{
  camera_->setPosition( Ogre::Vector3( 5, 5, 10 ));
  camera_->lookAt( 0, 0, 0 );
  setPropertiesFromCamera( camera_ );
  context_->queueRender();
}

void FPSViewController::handleMouseEvent(ViewportMouseEvent& event)
{
  if ( event.shift() )
  {
    setStatus( "Left-Click: Move X/Y.  Right-Click:: Move Z." );
  }
  else
  {
    setStatus( "Left-Click: Rotate.  Middle-Click: Move X/Y.  Right-Click:: Move Z.  Shift: More options." );
  }

  int32_t diff_x = 0;
  int32_t diff_y = 0;

  if( event.type == QEvent::MouseMove )
  {
    diff_x = event.x - event.last_x;
    diff_y = event.y - event.last_y;
  }
  bool moved = diff_x != 0 || diff_y != 0;

  if( event.left() && !event.shift() )
  {
    setCursor( Rotate3D );
    yaw( -diff_x*0.005 );
    pitch( diff_y*0.005 );
  }
  else if( event.middle() || ( event.shift() && event.left() ))
  {
    setCursor( MoveXY );
    move( diff_x*0.01, -diff_y*0.01, 0.0f );
  }
  else if( event.right() )
  {
    setCursor( MoveZ );
    move( 0.0f, 0.0f, diff_y*0.1 );
  }
  else
  {
    setCursor( event.shift() ? MoveXY : Rotate3D );
    moved = false;
  }

  if ( event.wheel_delta != 0 )
  {
    int diff = event.wheel_delta;
    move( 0.0f, 0.0f, -diff * 0.01 );
    moved = diff != 0;
  }

  if (moved)
  {
    context_->queueRender();
  }
}

void FPSViewController::setPropertiesFromCamera( Ogre::Camera* source_camera )
{
  Ogre::Quaternion quat = source_camera->getOrientation() * ROBOT_TO_CAMERA_ROTATION.Inverse();
  // need to reset roll to zero to correctly interpret retrieved yaw and pitch angles
  quat = camera_->getOrientation() * Ogre::Quaternion(-quat.getRoll(false), Ogre::Vector3::UNIT_Z) * ROBOT_TO_CAMERA_ROTATION.Inverse();

  float yaw = quat.getRoll( false ).valueRadians(); // OGRE camera frame looks along -Z, so they call rotation around Z "roll".
  float pitch = quat.getYaw( false ).valueRadians(); // OGRE camera frame has +Y as "up", so they call rotation around Y "yaw".

  Ogre::Vector3 direction = quat * Ogre::Vector3::NEGATIVE_UNIT_Z;

  if ( direction.dotProduct( Ogre::Vector3::NEGATIVE_UNIT_Z ) < 0 )
  {
    if ( pitch > Ogre::Math::HALF_PI )
    {
      pitch -= Ogre::Math::PI;
    }
    else if ( pitch < -Ogre::Math::HALF_PI )
    {
      pitch += Ogre::Math::PI;
    }

    yaw = -yaw;

    if ( direction.dotProduct( Ogre::Vector3::UNIT_X ) < 0 )
    {
      yaw -= Ogre::Math::PI;
    }
    else
    {
      yaw += Ogre::Math::PI;
    }
  }

  pitch_property_->setFloat( pitch );
  yaw_property_->setFloat( mapAngleTo0_2Pi( yaw ));
  position_property_->setVector( source_camera->getPosition() );
}

void FPSViewController::mimic( ViewController* source_view )
{
  FramePositionTrackingViewController::mimic( source_view );
  setPropertiesFromCamera( source_view->getCamera() );
}

void FPSViewController::update(float dt, float ros_dt)
{
  FramePositionTrackingViewController::update( dt, ros_dt );
  updateCamera();
}

void FPSViewController::lookAt( const Ogre::Vector3& point )
{
  camera_->lookAt(target_scene_node_->convertWorldToLocalPosition(point));
  setPropertiesFromCamera( camera_ );
}

void FPSViewController::onTargetFrameChanged(const Ogre::Vector3& old_reference_position, const Ogre::Quaternion& old_reference_orientation)
{
  position_property_->add( old_reference_position - reference_position_ );
}

void FPSViewController::updateCamera()
{
  camera_->setOrientation( getOrientation() );
  camera_->setPosition( position_property_->getVector() );
}

void FPSViewController::yaw( float angle )
{
  yaw_property_->setFloat( mapAngleTo0_2Pi( yaw_property_->getFloat() + angle ));
}

void FPSViewController::pitch( float angle )
{
  pitch_property_->add( angle );
}

Ogre::Quaternion FPSViewController::getOrientation()
{
  Ogre::Quaternion pitch, yaw;

  yaw.FromAngleAxis( Ogre::Radian( yaw_property_->getFloat() ), Ogre::Vector3::UNIT_Z );
  pitch.FromAngleAxis( Ogre::Radian( pitch_property_->getFloat() ), Ogre::Vector3::UNIT_Y );

  return yaw * pitch * ROBOT_TO_CAMERA_ROTATION;
}

void FPSViewController::move( float x, float y, float z )
{
  Ogre::Vector3 translate( x, y, z );
  position_property_->add( getOrientation() * translate );
}

} // end namespace rviz

#include <pluginlib/class_list_macros.hpp>
PLUGINLIB_EXPORT_CLASS( rviz::FPSViewController, rviz::ViewController )
<|endoftext|>