<commit_before>/*
 *  Resource loader, functions for loading all supported data types
 *      - Loads JSON scene information from jsoncpp (https://github.com/open-source-parsers/jsoncpp)
 *      - Loads TGA textures via FreeImage
 *      - Loads 3Ds models via Assimp
 */

#include "resourceloader.hpp"

#include <glm/glm.hpp>
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/postprocess.h>
#include <FreeImage.h>

#include <memory>
#include <vector>
#include <fstream>
#include <iostream>

#include <Utilities/exceptions.hpp>
#include <Utilities/log.hpp>
#include <GL/gl3w.h>
#include <Resources/model3d.hpp>
#include <Models/line.hpp>
#include <Models/staticmodel.hpp>

using json = nlohmann::json;

std::shared_ptr<IRenderObject> ResourceLoader::LoadModelJSON(json object) {
    std::string type = "";
    std::string name = "";

    if(object.find("datatype") != object.end()) {
        type = object["datatype"];
    } else {
        type = "normal";
    }

    if(object.find("name") != object.end()) {
        name = object["name"];
    } else {
        name = "null";
    }

    Model3D* model3D;

    if(type == "normal") {
        model3D = ResourceLoader::LoadModel3D(object["filename"]);
    } else if(type == "raw") {
        std::vector<glm::vec3> verts;
        std::vector<std::vector<float>> vertsf = object["vertices"];
        for(std::vector<float> vert : vertsf) {
            if(vert.size() != 3) {
                throw bad_resource("Vertex data size is not 3", name);
            }
            verts.push_back(glm::vec3(vert[0], vert[1], vert[2]));
        }

        std::vector<GLuint> indices;
        std::vector<uint> indicesf = object["indices"];
        for(uint index : indicesf) {
            if(index >= verts.size()) {
                throw bad_resource("Index is out of range", name);
            }
            indices.push_back(index);
        }

        std::vector<glm::vec3> norms;
        if(object.find("noramls") != object.end()) {
            std::vector<std::vector<float>> normsf = object["normals"];
            for(std::vector<float> norm : normsf) {
                if(norm.size() != 3) {
                    throw bad_resource("Normal data size is not 3", name);
                }
                norms.push_back(glm::vec3(norm[0], norm[1], norm[2]));
            }
        } else {
            norms.clear();
            for(uint i = 0; i < verts.size(); i++) {
                norms.push_back(glm::vec3(0.0f));
            }
        }

        std::vector<glm::vec2> uvs;
        if(object.find("uvs") != object.end()) {
            std::vector<std::vector<float>> uvsf = object["uvs"];
            for(std::vector<float> uv : uvsf) {
                if(uv.size() != 2) {
                    throw bad_resource("UV data size is not 2", name);
                }
                uvs.push_back(glm::vec2(uv[0], uv[1]));
            }
        } else {
            uvs.clear();
            for(uint i = 0; i < verts.size(); i++) {
                uvs.push_back(glm::vec2(0.0f));
            }
        }

        std::vector<Model3D::Vertex> vertices;
        for(uint i = 0; i < verts.size(); i++) {
            vertices.push_back(Model3D::Vertex(verts[i], norms[i], uvs[i]));
        }

        std::vector<std::shared_ptr<Model3D::Mesh>> meshes;
        meshes.push_back(std::make_shared<Model3D::Mesh>(vertices, indices));
        meshes[0]->SetMatName("texture");

        std::unordered_map<std::string, std::shared_ptr<Texture>> textures;
        textures["texture"] = ResourceLoader::LoadTexture(object["matname"], true);

        model3D = new Model3D(meshes, textures);
    } else {
        throw bad_resource("Unknown data type", name);
    }

    /*if(object.find("scale") != object.end()) {
        std::vector<float> scale = object["scale"];
        if(scale.size() != 3) {
            throw bad_resource("Scale data size is not 3", name);
        }
        rObject->Scale(glm::vec3(scale[0], scale[1], scale[2]));
    }

    if(object.find("translation") != object.end()) {
        std::vector<float> translation = object["translation"];
        if(translation.size() != 3) {
            throw bad_resource("Translation data size is not 3", name);
        }
        rObject->Translate(glm::vec3(translation[0], translation[1], translation[2]));
    }

    if(object.find("rotation") != object.end()) {
        std::vector<float> rotation = object["rotation"];
        if(rotation.size() != 3) {
            throw bad_resource("Rotation data size is not 3", name);
        }
    }*/

    return std::make_shared<StaticModel>(model3D);
}

std::shared_ptr<IRenderObject> ResourceLoader::LoadLineJSON(json object) {
    glm::vec3 head, tail, color;
    std::string name;

    if(object.find("name") != object.end()) {
        name = object["name"];
    } else {
        name = "null";
    }

    std::vector<float> head3f = object["head"];
    if(head3f.size() == 3) {
        head = glm::vec3(head3f[0], head3f[1], head3f[2]);
    } else {
        throw bad_resource("head data size is not 3", name);
    }

    std::vector<float> tail3f = object["tail"];
    if(tail3f.size() == 3) {
        tail = glm::vec3(tail3f[0], tail3f[1], tail3f[2]);
    } else {
        throw bad_resource("tail data size is not 3", name);
    }

    std::vector<float> color3f = object["color"];
    if(head3f.size() == 3) {
        color = glm::vec3(color3f[0], color3f[1], color3f[2]);
    } else {
        throw bad_resource("color data size is not 3", name);
    }

    return std::make_shared<Line>(head, tail, color);
}

std::shared_ptr<Texture> ResourceLoader::LoadTexture(std::string filename, bool genMipMaps) {
    FIBITMAP *img;
    filename = "Resources/Textures/" + filename + ".tga";
    FREE_IMAGE_FORMAT format = FreeImage_GetFIFFromFilename(filename.c_str());

    if(!FreeImage_FIFSupportsReading(format)) {
        throw bad_resource("FreeImage can't read from file", filename);
    }

    if(format == FIF_UNKNOWN) {
        throw bad_resource("Unknown format", filename);
    }

    img = FreeImage_Load(format, filename.c_str());

    if(!img) {
        throw bad_resource("Couldn't load image data", filename);
    }

    if(FreeImage_GetBPP(img) != 32) {
        FIBITMAP* oldImg = img;
        img = FreeImage_ConvertTo32Bits(oldImg);
        FreeImage_Unload(oldImg);
    }

    int height, width;
    width = FreeImage_GetWidth(img);
    height = FreeImage_GetHeight(img);

    unsigned char* bytes = FreeImage_GetBits(img);

    if(bytes == nullptr) {
        FreeImage_Unload(img);
        throw bad_resource("couldn't load image bytes", filename);
    }

    GLuint glTexture;
    glBindTexture(GL_TEXTURE_2D, 0);
    glGenTextures(1, &glTexture);
    glBindTexture(GL_TEXTURE_2D, glTexture);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, bytes);

    if(genMipMaps) {
        glGenerateMipmap(GL_TEXTURE_2D);
    }

    glBindTexture(GL_TEXTURE_2D, 0);

    if(!glIsTexture(glTexture)) {
        FreeImage_Unload(img);
        throw bad_resource("texture is not valid", filename);
    }

    FreeImage_Unload(img);

    std::shared_ptr<Texture> texture = std::make_shared<Texture>();
    texture->SetFileName(filename);
    texture->SetTexture(glTexture);
    return texture;
}

void CopyaiMat(const aiMatrix4x4* from, glm::mat4& to) {
    to[0][0] = from->a1; to[1][0] = from->a2;
    to[2][0] = from->a3; to[3][0] = from->a4;
    to[0][1] = from->b1; to[1][1] = from->b2;
    to[2][1] = from->b3; to[3][1] = from->b4;
    to[0][2] = from->c1; to[1][2] = from->c2;
    to[2][2] = from->c3; to[3][2] = from->c4;
    to[0][3] = from->d1; to[1][3] = from->d2;
    to[2][3] = from->d3; to[3][3] = from->d4;
}

void LoadNode(const aiScene* scene, const aiNode* node, std::vector<std::shared_ptr<Model3D::Mesh>>& meshes) {
    for(uint i = 0; i < node->mNumChildren; i++) {
        LoadNode(scene, node->mChildren[i], meshes);
    }

    for(uint i = 0; i < node->mNumMeshes; i++) {
        aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
        std::vector<Model3D::Vertex> vertices;

        for(uint j = 0; j < mesh->mNumVertices; j++) {
            Model3D::Vertex vertex;

            vertex.position = glm::vec3(mesh->mVertices[j].x, mesh->mVertices[j].y, mesh->mVertices[j].z);

            vertex.normal = (mesh->HasNormals())
                ? glm::vec3(mesh->mNormals[j].x, mesh->mNormals[j].y, mesh->mNormals[j].z)
                : glm::vec3(0.0f, 0.0f, 0.0f);

            vertex.texCoord = (mesh->HasTextureCoords(0))
                ? glm::vec2(mesh->mTextureCoords[0][j].x, mesh->mTextureCoords[0][j].y)
                : glm::vec2(0.0f, 0.0f);

            vertices.push_back(vertex);
        }

        std::vector<uint> indices;
        if(mesh->HasFaces()) {
            for(uint j = 0; j < mesh->mNumFaces; j++) {
                aiFace face = mesh->mFaces[j];
                for(uint k = 0; k < face.mNumIndices; k++) {
                    indices.push_back(face.mIndices[k]);
                }
            }
        } else {
            throw bad_resource("Node was missing faces, load cancled");
        }

        glm::mat4x4 transformation;
        CopyaiMat(&node->mTransformation, transformation);
        std::shared_ptr<Model3D::Mesh> rmesh = std::make_shared<Model3D::Mesh>(vertices, indices);
        rmesh->SetTransformation(transformation);
        rmesh->SetMatIndex(mesh->mMaterialIndex);

        meshes.push_back(rmesh);
    }
}

Model3D* ResourceLoader::LoadModel3D(std::string modelname) {
    std::string filename = "Resources/Models/" + modelname + ".3ds";
    Assimp::Importer importer;
    const aiScene* scene = importer.ReadFile(filename.c_str(),
        aiProcess_CalcTangentSpace |
        aiProcess_Triangulate |
        aiProcess_JoinIdenticalVertices |
        aiProcess_SortByPType);

    if(!scene || !scene->mRootNode || scene->mFlags == AI_SCENE_FLAGS_INCOMPLETE) {
        throw bad_resource(importer.GetErrorString(), filename);
    }

    auto model = new Model3D();

    aiMaterial** materials = scene->mMaterials;
    std::unordered_map<std::string, std::shared_ptr<Texture>> textures;
    for(uint i = 0; i < scene->mNumMaterials; i++) {
        aiString aName;
        materials[i]->Get(AI_MATKEY_NAME, aName);
        std::string name = std::string(aName.C_Str());

        if(textures.find(name) == textures.end()) {
            try {
                std::shared_ptr<Texture> temp = LoadTexture(modelname + "/" + name, true);
                if(temp != nullptr) {
                    textures[name] = temp;
                }
            } catch (bad_resource& error) {
                error.PrintError();
            }
        }
    }
    model->SetTextures(textures);

    std::vector<std::shared_ptr<Model3D::Mesh>> meshes;
    LoadNode(scene, scene->mRootNode, meshes);

    for(std::shared_ptr<Model3D::Mesh>& mesh : meshes) {
        aiString aName;
        uint index = mesh->GetMatIndex();
        if(index < scene->mNumMaterials) {
            materials[mesh->GetMatIndex()]->Get(AI_MATKEY_NAME, aName);
            mesh->SetMatName(std::string(aName.C_Str()));
        }
    }

    model->SetMeshes(meshes);

    return model;
}
<commit_msg>transformation are applied on load<commit_after>/*
 *  Resource loader, functions for loading all supported data types
 *      - Loads JSON scene information from jsoncpp (https://github.com/open-source-parsers/jsoncpp)
 *      - Loads TGA textures via FreeImage
 *      - Loads 3Ds models via Assimp
 */

#include "resourceloader.hpp"

#include <glm/glm.hpp>
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/postprocess.h>
#include <FreeImage.h>

#include <memory>
#include <vector>
#include <fstream>
#include <iostream>

#include <Utilities/exceptions.hpp>
#include <Utilities/log.hpp>
#include <GL/gl3w.h>
#include <Resources/model3d.hpp>
#include <Models/line.hpp>
#include <Models/staticmodel.hpp>

using json = nlohmann::json;

std::shared_ptr<IRenderObject> ResourceLoader::LoadModelJSON(json object) {
    std::string type = "";
    std::string name = "";

    if(object.find("datatype") != object.end()) {
        type = object["datatype"];
    } else {
        type = "normal";
    }

    if(object.find("name") != object.end()) {
        name = object["name"];
    } else {
        name = "null";
    }

    Model3D* model3D;

    if(type == "normal") {
        model3D = ResourceLoader::LoadModel3D(object["filename"]);
    } else if(type == "raw") {
        std::vector<glm::vec3> verts;
        std::vector<std::vector<float>> vertsf = object["vertices"];
        for(std::vector<float> vert : vertsf) {
            if(vert.size() != 3) {
                throw bad_resource("Vertex data size is not 3", name);
            }
            verts.push_back(glm::vec3(vert[0], vert[1], vert[2]));
        }

        std::vector<GLuint> indices;
        std::vector<uint> indicesf = object["indices"];
        for(uint index : indicesf) {
            if(index >= verts.size()) {
                throw bad_resource("Index is out of range", name);
            }
            indices.push_back(index);
        }

        std::vector<glm::vec3> norms;
        if(object.find("noramls") != object.end()) {
            std::vector<std::vector<float>> normsf = object["normals"];
            for(std::vector<float> norm : normsf) {
                if(norm.size() != 3) {
                    throw bad_resource("Normal data size is not 3", name);
                }
                norms.push_back(glm::vec3(norm[0], norm[1], norm[2]));
            }
        } else {
            norms.clear();
            for(uint i = 0; i < verts.size(); i++) {
                norms.push_back(glm::vec3(0.0f));
            }
        }

        std::vector<glm::vec2> uvs;
        if(object.find("uvs") != object.end()) {
            std::vector<std::vector<float>> uvsf = object["uvs"];
            for(std::vector<float> uv : uvsf) {
                if(uv.size() != 2) {
                    throw bad_resource("UV data size is not 2", name);
                }
                uvs.push_back(glm::vec2(uv[0], uv[1]));
            }
        } else {
            uvs.clear();
            for(uint i = 0; i < verts.size(); i++) {
                uvs.push_back(glm::vec2(0.0f));
            }
        }

        std::vector<Model3D::Vertex> vertices;
        for(uint i = 0; i < verts.size(); i++) {
            vertices.push_back(Model3D::Vertex(verts[i], norms[i], uvs[i]));
        }

        std::vector<std::shared_ptr<Model3D::Mesh>> meshes;
        meshes.push_back(std::make_shared<Model3D::Mesh>(vertices, indices));
        meshes[0]->SetMatName("texture");

        std::unordered_map<std::string, std::shared_ptr<Texture>> textures;
        textures["texture"] = ResourceLoader::LoadTexture(object["matname"], true);

        model3D = new Model3D(meshes, textures);
    } else {
        throw bad_resource("Unknown data type", name);
    }

    /*if(object.find("scale") != object.end()) {
        std::vector<float> scale = object["scale"];
        if(scale.size() != 3) {
            throw bad_resource("Scale data size is not 3", name);
        }
        rObject->Scale(glm::vec3(scale[0], scale[1], scale[2]));
    }

    if(object.find("translation") != object.end()) {
        std::vector<float> translation = object["translation"];
        if(translation.size() != 3) {
            throw bad_resource("Translation data size is not 3", name);
        }
        rObject->Translate(glm::vec3(translation[0], translation[1], translation[2]));
    }

    if(object.find("rotation") != object.end()) {
        std::vector<float> rotation = object["rotation"];
        if(rotation.size() != 3) {
            throw bad_resource("Rotation data size is not 3", name);
        }
    }*/

    return std::make_shared<StaticModel>(model3D);
}

std::shared_ptr<IRenderObject> ResourceLoader::LoadLineJSON(json object) {
    glm::vec3 head, tail, color;
    std::string name;

    if(object.find("name") != object.end()) {
        name = object["name"];
    } else {
        name = "null";
    }

    std::vector<float> head3f = object["head"];
    if(head3f.size() == 3) {
        head = glm::vec3(head3f[0], head3f[1], head3f[2]);
    } else {
        throw bad_resource("head data size is not 3", name);
    }

    std::vector<float> tail3f = object["tail"];
    if(tail3f.size() == 3) {
        tail = glm::vec3(tail3f[0], tail3f[1], tail3f[2]);
    } else {
        throw bad_resource("tail data size is not 3", name);
    }

    std::vector<float> color3f = object["color"];
    if(head3f.size() == 3) {
        color = glm::vec3(color3f[0], color3f[1], color3f[2]);
    } else {
        throw bad_resource("color data size is not 3", name);
    }

    return std::make_shared<Line>(head, tail, color);
}

std::shared_ptr<Texture> ResourceLoader::LoadTexture(std::string filename, bool genMipMaps) {
    FIBITMAP *img;
    filename = "Resources/Textures/" + filename + ".tga";
    FREE_IMAGE_FORMAT format = FreeImage_GetFIFFromFilename(filename.c_str());

    if(!FreeImage_FIFSupportsReading(format)) {
        throw bad_resource("FreeImage can't read from file", filename);
    }

    if(format == FIF_UNKNOWN) {
        throw bad_resource("Unknown format", filename);
    }

    img = FreeImage_Load(format, filename.c_str());

    if(!img) {
        throw bad_resource("Couldn't load image data", filename);
    }

    if(FreeImage_GetBPP(img) != 32) {
        FIBITMAP* oldImg = img;
        img = FreeImage_ConvertTo32Bits(oldImg);
        FreeImage_Unload(oldImg);
    }

    int height, width;
    width = FreeImage_GetWidth(img);
    height = FreeImage_GetHeight(img);

    unsigned char* bytes = FreeImage_GetBits(img);

    if(bytes == nullptr) {
        FreeImage_Unload(img);
        throw bad_resource("couldn't load image bytes", filename);
    }

    GLuint glTexture;
    glBindTexture(GL_TEXTURE_2D, 0);
    glGenTextures(1, &glTexture);
    glBindTexture(GL_TEXTURE_2D, glTexture);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, bytes);

    if(genMipMaps) {
        glGenerateMipmap(GL_TEXTURE_2D);
    }

    glBindTexture(GL_TEXTURE_2D, 0);

    if(!glIsTexture(glTexture)) {
        FreeImage_Unload(img);
        throw bad_resource("texture is not valid", filename);
    }

    FreeImage_Unload(img);

    std::shared_ptr<Texture> texture = std::make_shared<Texture>();
    texture->SetFileName(filename);
    texture->SetTexture(glTexture);
    return texture;
}

void CopyaiMat(const aiMatrix4x4* from, glm::mat4& to) {
    to[0][0] = from->a1; to[1][0] = from->a2;
    to[2][0] = from->a3; to[3][0] = from->a4;
    to[0][1] = from->b1; to[1][1] = from->b2;
    to[2][1] = from->b3; to[3][1] = from->b4;
    to[0][2] = from->c1; to[1][2] = from->c2;
    to[2][2] = from->c3; to[3][2] = from->c4;
    to[0][3] = from->d1; to[1][3] = from->d2;
    to[2][3] = from->d3; to[3][3] = from->d4;
}

void LoadNode(const aiScene* scene, const aiNode* node, glm::mat4 parentTransform, std::vector<std::shared_ptr<Model3D::Mesh>>& meshes) {
    glm::mat4x4 transformation;
    CopyaiMat(&node->mTransformation, transformation);
    transformation = parentTransform * transformation;

    for(uint i = 0; i < node->mNumChildren; i++) {
        LoadNode(scene, node->mChildren[i], transformation, meshes);
    }

    for(uint i = 0; i < node->mNumMeshes; i++) {
        aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
        std::vector<Model3D::Vertex> vertices;

        for(uint j = 0; j < mesh->mNumVertices; j++) {
            Model3D::Vertex vertex;

            glm::vec4 position = glm::vec4(mesh->mVertices[j].x, mesh->mVertices[j].y, mesh->mVertices[j].z, 1.0f);
            position = transformation * position;
            vertex.position = glm::vec3(position.x, position.y, position.z);

            vertex.normal = (mesh->HasNormals())
                ? glm::vec3(mesh->mNormals[j].x, mesh->mNormals[j].y, mesh->mNormals[j].z)
                : glm::vec3(0.0f, 0.0f, 0.0f);

            vertex.texCoord = (mesh->HasTextureCoords(0))
                ? glm::vec2(mesh->mTextureCoords[0][j].x, mesh->mTextureCoords[0][j].y)
                : glm::vec2(0.0f, 0.0f);

            vertices.push_back(vertex);
        }

        std::vector<uint> indices;
        if(mesh->HasFaces()) {
            for(uint j = 0; j < mesh->mNumFaces; j++) {
                aiFace face = mesh->mFaces[j];
                for(uint k = 0; k < face.mNumIndices; k++) {
                    indices.push_back(face.mIndices[k]);
                }
            }
        } else {
            throw bad_resource("Node was missing faces, load cancled");
        }

        std::shared_ptr<Model3D::Mesh> rmesh = std::make_shared<Model3D::Mesh>(vertices, indices);
        rmesh->SetTransformation(transformation);
        rmesh->SetMatIndex(mesh->mMaterialIndex);

        meshes.push_back(rmesh);
    }
}

Model3D* ResourceLoader::LoadModel3D(std::string modelname) {
    std::string filename = "Resources/Models/" + modelname + ".3ds";
    Assimp::Importer importer;
    const aiScene* scene = importer.ReadFile(filename.c_str(),
        aiProcess_CalcTangentSpace |
        aiProcess_Triangulate |
        aiProcess_JoinIdenticalVertices |
        aiProcess_SortByPType);

    if(!scene || !scene->mRootNode || scene->mFlags == AI_SCENE_FLAGS_INCOMPLETE) {
        throw bad_resource(importer.GetErrorString(), filename);
    }

    auto model = new Model3D();

    aiMaterial** materials = scene->mMaterials;
    std::unordered_map<std::string, std::shared_ptr<Texture>> textures;
    for(uint i = 0; i < scene->mNumMaterials; i++) {
        aiString aName;
        materials[i]->Get(AI_MATKEY_NAME, aName);
        std::string name = std::string(aName.C_Str());

        if(textures.find(name) == textures.end()) {
            try {
                std::shared_ptr<Texture> temp = LoadTexture(modelname + "/" + name, true);
                if(temp != nullptr) {
                    textures[name] = temp;
                }
            } catch (bad_resource& error) {
                error.PrintError();
            }
        }
    }
    model->SetTextures(textures);

    std::vector<std::shared_ptr<Model3D::Mesh>> meshes;
    LoadNode(scene, scene->mRootNode, glm::mat4(1.0f), meshes);

    for(std::shared_ptr<Model3D::Mesh>& mesh : meshes) {
        aiString aName;
        uint index = mesh->GetMatIndex();
        if(index < scene->mNumMaterials) {
            materials[mesh->GetMatIndex()]->Get(AI_MATKEY_NAME, aName);
            mesh->SetMatName(std::string(aName.C_Str()));
        }
    }

    model->SetMeshes(meshes);

    return model;
}
<|endoftext|>


<commit_before>/* Copyright 2007-2015 QReal Research Group, Dmitry Mordvinov
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License. */

#include "smartDock.h"

#include <QtCore/QTimer>
#include <QtCore/QPropertyAnimation>
#include <QtGui/QMouseEvent>
#include <QtWidgets/QStyle>
#include <QtWidgets/QApplication>
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QVBoxLayout>
#include <QtWidgets/QPushButton>

#include <qrutils/qRealDialog.h>

using namespace utils;

SmartDock::SmartDock(const QString &objectName, QWidget *innerWidget, QMainWindow *parent)
	: mMainWindow(parent ? parent : findMainWindow())
	, mInnerWidget(innerWidget)
	, mDialog(new QRealDialog(objectName))
	, mCurrentMode(Mode::Docked)
{
	setObjectName(objectName);

	initDock();
	initDialog();
}

SmartDock::~SmartDock()
{
	delete mDialog;
}

void SmartDock::switchToDocked()
{
	if (mCurrentMode == Mode::Docked) {
		return;
	}

	mCurrentMode = Mode::Docked;
	mDialog->close();
	mDialog->layout()->removeWidget(mInnerWidget);
	setWidget(mInnerWidget);
	setFloating(false);
	show();
}

void SmartDock::switchToFloating()
{
	if (mCurrentMode == Mode::Floats) {
		return;
	}

	mCurrentMode = Mode::Floats;
	setWidget(nullptr);
	close();
	static_cast<QVBoxLayout *>(mDialog->layout())->addWidget(mInnerWidget);
	mInnerWidget->show();
	mDialog->show();
	if (QWidget * const button = mDialog->findChild<QWidget *>("dockSmartDockToMainWindowButton")) {
		// This button is not in layout and thus can sunk in other widgets.
		button->raise();
	}
}

void SmartDock::attachToMainWindow(Qt::DockWidgetArea area)
{
	if (!mMainWindow) {
		return;
	}

	mDialog->resumeSerialization();
	setParent(mMainWindow);
	mMainWindow->addDockWidget(area, this);
	if (mCurrentMode == Mode::Docked) {
		mCurrentMode = Mode::Floats;
		switchToDocked();
	} else {
		mCurrentMode = Mode::Docked;
		switchToFloating();
	}
}

void SmartDock::detachFromMainWindow()
{
	mDialog->suspendSerialization();
	close();
	mDialog->close();
	if (mMainWindow) {
		mMainWindow->removeDockWidget(this);
		setParent(nullptr);
	}
}

void SmartDock::checkFloating()
{
	// Mouse button releasing may cause dock animation into some dock area.
	// topLevelChanged() will be emitted only when animation is finished, so
	// we must not change dock state when animation is running.
	if (isFloating() && !mDragged && !isAnimating()) {
		switchToFloating();
	}
}

bool SmartDock::isAnimating()
{
	// A bit hacky way to know dialog animation state. If user repositions dock
	if (!mMainWindow->isAnimated()) {
		return false;
	}

	for (QPropertyAnimation *animation : findChildren<QPropertyAnimation *>()) {
		if (animation->state() == QAbstractAnimation::Running && animation->propertyName() == "geometry") {
			return true;
		}
	}

	return false;
}

QMainWindow *SmartDock::findMainWindow() const
{
	for (QWidget * const topLevelWidget : QApplication::topLevelWidgets()) {
		if (QMainWindow * const window = dynamic_cast<QMainWindow *>(topLevelWidget)) {
			return window;
		}
	}

	return nullptr;
}

bool SmartDock::event(QEvent *event)
{
	switch (event->type()) {
	case QEvent::MouseButtonPress:
	case QEvent::MouseButtonRelease:
		if (static_cast<QMouseEvent *>(event)->button() == Qt::LeftButton) {
			mDragged = event->type() == QEvent::MouseButtonPress;
			if (QEvent::MouseButtonRelease == event->type()) {
				// Mouse button releasing may cause dock animation into some dock area.
				// This animation is not started immediately, so checking for it when all handlers worked out.
				QTimer::singleShot(0, this, SLOT(checkFloating()));
			}
		}
		break;
	case QEvent::MouseButtonDblClick:
		mDragged = false;
		break;
	case QEvent::Show:
		if (!widget()) {
			close();
		}
		break;
	default:
		break;
	}

	return QDockWidget::event(event);
}

void SmartDock::initDock()
{
	if (!mMainWindow) {
		return;
	}

	setWindowTitle(mInnerWidget->windowTitle());
	setWidget(mInnerWidget);
	setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable);
	connect(this, &QDockWidget::topLevelChanged, this, &SmartDock::checkFloating);
}

void SmartDock::initDialog()
{
	mDialog->setWindowTitle(mInnerWidget->windowTitle());
	mDialog->setWindowIcon(mInnerWidget->windowIcon());
	mDialog->setWindowFlags(mDialog->windowFlags() | Qt::WindowMinMaxButtonsHint);
	QVBoxLayout * const layout = new QVBoxLayout;
	layout->setMargin(0);
	layout->setSpacing(0);
	layout->setContentsMargins(0, 0, 0, 0);
	mDialog->setLayout(layout);
	mDialog->setVisible(false);
	connect(mDialog, &QDialog::finished, [=]() {
		if (mMainWindow) {
			switchToDocked();
		} else {
			mInnerWidget->close();
		}
	});
	if (mMainWindow) {
		QPushButton * const button = new QPushButton(mDialog);
		button->setObjectName("dockSmartDockToMainWindowButton");
		button->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
		const int smallButtonSize = 20;
		button->setFixedSize(smallButtonSize, smallButtonSize);
		button->setIcon(style()->standardIcon(QStyle::SP_TitleBarNormalButton));
		button->setToolTip("Dock window into main");
		connect(button, &QAbstractButton::clicked, this, &SmartDock::switchToDocked);
	} else {
		switchToFloating();
	}
}
<commit_msg>Removed horrible dock button from undocked 2D model<commit_after>/* Copyright 2007-2015 QReal Research Group, Dmitry Mordvinov
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License. */

#include "smartDock.h"

#include <QtCore/QTimer>
#include <QtCore/QPropertyAnimation>
#include <QtGui/QMouseEvent>
#include <QtWidgets/QStyle>
#include <QtWidgets/QApplication>
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QVBoxLayout>
#include <QtWidgets/QPushButton>

#include <qrutils/qRealDialog.h>

using namespace utils;

SmartDock::SmartDock(const QString &objectName, QWidget *innerWidget, QMainWindow *parent)
	: mMainWindow(parent ? parent : findMainWindow())
	, mInnerWidget(innerWidget)
	, mDialog(new QRealDialog(objectName))
	, mCurrentMode(Mode::Docked)
{
	setObjectName(objectName);

	initDock();
	initDialog();
}

SmartDock::~SmartDock()
{
	delete mDialog;
}

void SmartDock::switchToDocked()
{
	if (mCurrentMode == Mode::Docked) {
		return;
	}

	mCurrentMode = Mode::Docked;
	mDialog->close();
	mDialog->layout()->removeWidget(mInnerWidget);
	setWidget(mInnerWidget);
	setFloating(false);
	show();
}

void SmartDock::switchToFloating()
{
	if (mCurrentMode == Mode::Floats) {
		return;
	}

	mCurrentMode = Mode::Floats;
	setWidget(nullptr);
	close();
	static_cast<QVBoxLayout *>(mDialog->layout())->addWidget(mInnerWidget);
	mInnerWidget->show();
	mDialog->show();
}

void SmartDock::attachToMainWindow(Qt::DockWidgetArea area)
{
	if (!mMainWindow) {
		return;
	}

	mDialog->resumeSerialization();
	setParent(mMainWindow);
	mMainWindow->addDockWidget(area, this);
	if (mCurrentMode == Mode::Docked) {
		mCurrentMode = Mode::Floats;
		switchToDocked();
	} else {
		mCurrentMode = Mode::Docked;
		switchToFloating();
	}
}

void SmartDock::detachFromMainWindow()
{
	mDialog->suspendSerialization();
	close();
	mDialog->close();
	if (mMainWindow) {
		mMainWindow->removeDockWidget(this);
		setParent(nullptr);
	}
}

void SmartDock::checkFloating()
{
	// Mouse button releasing may cause dock animation into some dock area.
	// topLevelChanged() will be emitted only when animation is finished, so
	// we must not change dock state when animation is running.
	if (isFloating() && !mDragged && !isAnimating()) {
		switchToFloating();
	}
}

bool SmartDock::isAnimating()
{
	// A bit hacky way to know dialog animation state. If user repositions dock
	if (!mMainWindow->isAnimated()) {
		return false;
	}

	for (QPropertyAnimation *animation : findChildren<QPropertyAnimation *>()) {
		if (animation->state() == QAbstractAnimation::Running && animation->propertyName() == "geometry") {
			return true;
		}
	}

	return false;
}

QMainWindow *SmartDock::findMainWindow() const
{
	for (QWidget * const topLevelWidget : QApplication::topLevelWidgets()) {
		if (QMainWindow * const window = dynamic_cast<QMainWindow *>(topLevelWidget)) {
			return window;
		}
	}

	return nullptr;
}

bool SmartDock::event(QEvent *event)
{
	switch (event->type()) {
	case QEvent::MouseButtonPress:
	case QEvent::MouseButtonRelease:
		if (static_cast<QMouseEvent *>(event)->button() == Qt::LeftButton) {
			mDragged = event->type() == QEvent::MouseButtonPress;
			if (QEvent::MouseButtonRelease == event->type()) {
				// Mouse button releasing may cause dock animation into some dock area.
				// This animation is not started immediately, so checking for it when all handlers worked out.
				QTimer::singleShot(0, this, SLOT(checkFloating()));
			}
		}
		break;
	case QEvent::MouseButtonDblClick:
		mDragged = false;
		break;
	case QEvent::Show:
		if (!widget()) {
			close();
		}
		break;
	default:
		break;
	}

	return QDockWidget::event(event);
}

void SmartDock::initDock()
{
	if (!mMainWindow) {
		return;
	}

	setWindowTitle(mInnerWidget->windowTitle());
	setWidget(mInnerWidget);
	setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable);
	connect(this, &QDockWidget::topLevelChanged, this, &SmartDock::checkFloating);
}

void SmartDock::initDialog()
{
	mDialog->setWindowTitle(mInnerWidget->windowTitle());
	mDialog->setWindowIcon(mInnerWidget->windowIcon());
	mDialog->setWindowFlags(mDialog->windowFlags() | Qt::WindowMinMaxButtonsHint);
	QVBoxLayout * const layout = new QVBoxLayout;
	layout->setMargin(0);
	layout->setSpacing(0);
	layout->setContentsMargins(0, 0, 0, 0);
	mDialog->setLayout(layout);
	mDialog->setVisible(false);
	connect(mDialog, &QDialog::finished, [=]() {
		if (mMainWindow) {
			switchToDocked();
		} else {
			mInnerWidget->close();
		}
	});
	if (!mMainWindow) {
		switchToFloating();
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2013, German Neuroinformatics Node (G-Node)
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted under the terms of the BSD License. See
// LICENSE file in the root of the Project.

#include "TestFile.hpp"

#include <nix/util/util.hpp>
#include <nix/valid/validate.hpp>

#include <ctime>

using namespace std;
using namespace nix;
using namespace valid;

void TestFile::setUp() {
    statup_time = time(NULL);
    file_open = File::open("test_file.h5", FileMode::Overwrite);
    file_other = File::open("test_file_other.h5", FileMode::Overwrite);
    file_null = NULL;
}

void TestFile::tearDown() {
    file_open.close();
    file_other.close();
}

void TestFile::testValidate() {
    valid::Result result = validate(file_open);
    CPPUNIT_ASSERT(result.getErrors().size() == 0);
    CPPUNIT_ASSERT(result.getErrors().size() == 0);
}

void TestFile::testFormat() {
    CPPUNIT_ASSERT(file_open.format() == "nix");
}

void TestFile::testLocation() {
    CPPUNIT_ASSERT(file_open.location() == "test_file.h5");
    CPPUNIT_ASSERT(file_other.location() == "test_file_other.h5");
}

void TestFile::testVersion() {
    vector<int> version{1, 0, 0};
    CPPUNIT_ASSERT(file_open.version() == version);
}

void TestFile::testCreatedAt() {
    CPPUNIT_ASSERT(file_open.createdAt() >= statup_time);
    time_t past_time = time(NULL) - 10000000;
    file_open.forceCreatedAt(past_time);
    CPPUNIT_ASSERT(file_open.createdAt() == past_time);
}

void TestFile::testUpdatedAt() {
    CPPUNIT_ASSERT(file_open.updatedAt() >= statup_time);
}

void TestFile::testBlockAccess() {
    vector<string> names = { "block_a", "block_b", "block_c", "block_d", "block_e" };

    CPPUNIT_ASSERT(file_open.blockCount() == 0);
    CPPUNIT_ASSERT(file_open.blocks().size() == 0);
    CPPUNIT_ASSERT(file_open.getBlock("invalid_id") == false);

    vector<string> ids;
    for (auto it = names.begin(); it != names.end(); it++) {
        Block bl = file_open.createBlock(*it, "dataset");
        CPPUNIT_ASSERT(bl.name() == *it);

        ids.push_back(bl.id());
    }
    CPPUNIT_ASSERT_THROW(file_open.createBlock(names[0], "dataset"),
                         DuplicateName);

    CPPUNIT_ASSERT(file_open.blockCount() == names.size());
    CPPUNIT_ASSERT(file_open.blocks().size() == names.size());

    for (const auto &name : names) {
        Block bl_name = file_open.getBlock(name);
        CPPUNIT_ASSERT(bl_name);

        Block bl_id = file_open.getBlock(bl_name.id());
        CPPUNIT_ASSERT(bl_id);
        CPPUNIT_ASSERT_EQUAL(bl_name.name(), bl_id.name());
    }

    for (auto it = ids.begin(); it != ids.end(); it++) {
        Block bl = file_open.getBlock(*it);
        CPPUNIT_ASSERT(file_open.hasBlock(*it) == true);
        CPPUNIT_ASSERT(bl.id() == *it);

        file_open.deleteBlock(*it);
    }

    CPPUNIT_ASSERT(file_open.blockCount() == 0);
    CPPUNIT_ASSERT(file_open.blocks().size() == 0);
    CPPUNIT_ASSERT(file_open.getBlock("invalid_id") == false);
}

void TestFile::testSectionAccess() {
    vector<string> names = {"section_a", "section_b", "section_c", "section_d", "section_e" };

    CPPUNIT_ASSERT(file_open.sectionCount() == 0);
    CPPUNIT_ASSERT(file_open.sections().size() == 0);
    CPPUNIT_ASSERT(file_open.getSection("invalid_id") == false);

    vector<string> ids;
    for (auto it = names.begin(); it != names.end(); it++) {
        Section sec = file_open.createSection(*it, "root section");
        CPPUNIT_ASSERT(sec.name() == *it);

        ids.push_back(sec.id());
    }
    CPPUNIT_ASSERT_THROW(file_open.createSection(names[0], "root section"),
                         DuplicateName);

    CPPUNIT_ASSERT(file_open.sectionCount() == names.size());
    CPPUNIT_ASSERT(file_open.sections().size() == names.size());

    for (auto it = ids.begin(); it != ids.end(); it++) {
        Section sec = file_open.getSection(*it);
        CPPUNIT_ASSERT(file_open.hasSection(*it) == true);
        CPPUNIT_ASSERT(sec.id() == *it);

        file_open.deleteSection(*it);
    }

    CPPUNIT_ASSERT(file_open.sectionCount() == 0);
    CPPUNIT_ASSERT(file_open.sections().size() == 0);
    CPPUNIT_ASSERT(file_open.getSection("invalid_id") == false);
}

void TestFile::testOperators(){
    CPPUNIT_ASSERT(file_null == false);
    CPPUNIT_ASSERT(file_null == none);

    CPPUNIT_ASSERT(file_open != false);
    CPPUNIT_ASSERT(file_open != none);

    CPPUNIT_ASSERT(file_open == file_open);
    CPPUNIT_ASSERT(file_open != file_other);

    file_other = file_open;
    CPPUNIT_ASSERT(file_other == file_open);

    file_other = none;
    CPPUNIT_ASSERT(file_null == false);
    CPPUNIT_ASSERT(file_null == none);
}

void TestFile::testReopen() {
    //file_open is currently open
    Block b = file_open.createBlock("a", "a");
    b = none;
    file_open.close();

    file_open = nix::File::open("test_file_b.h5", FileMode::Overwrite);
    b = file_open.createBlock("b", "b");
}

<commit_msg>[test] File: block access: cleanup + extend<commit_after>// Copyright (c) 2013, German Neuroinformatics Node (G-Node)
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted under the terms of the BSD License. See
// LICENSE file in the root of the Project.

#include "TestFile.hpp"

#include <nix/util/util.hpp>
#include <nix/valid/validate.hpp>

#include <ctime>

using namespace std;
using namespace nix;
using namespace valid;

void TestFile::setUp() {
    statup_time = time(NULL);
    file_open = File::open("test_file.h5", FileMode::Overwrite);
    file_other = File::open("test_file_other.h5", FileMode::Overwrite);
    file_null = NULL;
}

void TestFile::tearDown() {
    file_open.close();
    file_other.close();
}

void TestFile::testValidate() {
    valid::Result result = validate(file_open);
    CPPUNIT_ASSERT(result.getErrors().size() == 0);
    CPPUNIT_ASSERT(result.getErrors().size() == 0);
}

void TestFile::testFormat() {
    CPPUNIT_ASSERT(file_open.format() == "nix");
}

void TestFile::testLocation() {
    CPPUNIT_ASSERT(file_open.location() == "test_file.h5");
    CPPUNIT_ASSERT(file_other.location() == "test_file_other.h5");
}

void TestFile::testVersion() {
    vector<int> version{1, 0, 0};
    CPPUNIT_ASSERT(file_open.version() == version);
}

void TestFile::testCreatedAt() {
    CPPUNIT_ASSERT(file_open.createdAt() >= statup_time);
    time_t past_time = time(NULL) - 10000000;
    file_open.forceCreatedAt(past_time);
    CPPUNIT_ASSERT(file_open.createdAt() == past_time);
}

void TestFile::testUpdatedAt() {
    CPPUNIT_ASSERT(file_open.updatedAt() >= statup_time);
}

void TestFile::testBlockAccess() {
    vector<string> names = { "block_a", "block_b", "block_c", "block_d", "block_e" };

    CPPUNIT_ASSERT(file_open.blockCount() == 0);
    CPPUNIT_ASSERT(file_open.blocks().size() == 0);
    CPPUNIT_ASSERT(file_open.getBlock("invalid_id") == false);
    CPPUNIT_ASSERT_EQUAL(false, file_open.hasBlock("invalid_id"));

    vector<string> ids;
    for (const auto &name : names) {
        Block bl = file_open.createBlock(name, "dataset");
        CPPUNIT_ASSERT(bl.name() == name);
        CPPUNIT_ASSERT(file_open.hasBlock(bl));
        CPPUNIT_ASSERT(file_open.hasBlock(name));

        ids.push_back(bl.id());
    }
    CPPUNIT_ASSERT_THROW(file_open.createBlock(names[0], "dataset"),
                         DuplicateName);

    CPPUNIT_ASSERT(file_open.blockCount() == names.size());
    CPPUNIT_ASSERT(file_open.blocks().size() == names.size());

    for (const auto &name : names) {
        Block bl_name = file_open.getBlock(name);
        CPPUNIT_ASSERT(bl_name);

        Block bl_id = file_open.getBlock(bl_name.id());
        CPPUNIT_ASSERT(bl_id);
        CPPUNIT_ASSERT_EQUAL(bl_name.name(), bl_id.name());
    }

    for (const auto &id: ids) {
        Block bl = file_open.getBlock(id);
        CPPUNIT_ASSERT(file_open.hasBlock(id) == true);
        CPPUNIT_ASSERT(bl.id() == id);

        file_open.deleteBlock(id);
    }

    CPPUNIT_ASSERT(file_open.blockCount() == 0);
    CPPUNIT_ASSERT(file_open.blocks().size() == 0);
    CPPUNIT_ASSERT(file_open.getBlock("invalid_id") == false);
}

void TestFile::testSectionAccess() {
    vector<string> names = {"section_a", "section_b", "section_c", "section_d", "section_e" };

    CPPUNIT_ASSERT(file_open.sectionCount() == 0);
    CPPUNIT_ASSERT(file_open.sections().size() == 0);
    CPPUNIT_ASSERT(file_open.getSection("invalid_id") == false);

    vector<string> ids;
    for (auto it = names.begin(); it != names.end(); it++) {
        Section sec = file_open.createSection(*it, "root section");
        CPPUNIT_ASSERT(sec.name() == *it);

        ids.push_back(sec.id());
    }
    CPPUNIT_ASSERT_THROW(file_open.createSection(names[0], "root section"),
                         DuplicateName);

    CPPUNIT_ASSERT(file_open.sectionCount() == names.size());
    CPPUNIT_ASSERT(file_open.sections().size() == names.size());

    for (auto it = ids.begin(); it != ids.end(); it++) {
        Section sec = file_open.getSection(*it);
        CPPUNIT_ASSERT(file_open.hasSection(*it) == true);
        CPPUNIT_ASSERT(sec.id() == *it);

        file_open.deleteSection(*it);
    }

    CPPUNIT_ASSERT(file_open.sectionCount() == 0);
    CPPUNIT_ASSERT(file_open.sections().size() == 0);
    CPPUNIT_ASSERT(file_open.getSection("invalid_id") == false);
}

void TestFile::testOperators(){
    CPPUNIT_ASSERT(file_null == false);
    CPPUNIT_ASSERT(file_null == none);

    CPPUNIT_ASSERT(file_open != false);
    CPPUNIT_ASSERT(file_open != none);

    CPPUNIT_ASSERT(file_open == file_open);
    CPPUNIT_ASSERT(file_open != file_other);

    file_other = file_open;
    CPPUNIT_ASSERT(file_other == file_open);

    file_other = none;
    CPPUNIT_ASSERT(file_null == false);
    CPPUNIT_ASSERT(file_null == none);
}

void TestFile::testReopen() {
    //file_open is currently open
    Block b = file_open.createBlock("a", "a");
    b = none;
    file_open.close();

    file_open = nix::File::open("test_file_b.h5", FileMode::Overwrite);
    b = file_open.createBlock("b", "b");
}

<|endoftext|>


<commit_before>// Copyright (c) 2013, German Neuroinformatics Node (G-Node)
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted under the terms of the BSD License. See
// LICENSE file in the root of the Project.

#include "TestUtil.hpp"

#include <ctime>
#include <cmath>

using namespace std;
using namespace nix;

void TestUtil::testStrUtils() {
    string a = " a ";
    string b = "\tb\t";
    string c = " c c\tc ";

    const string ac = a;
    const string bc = b;
    const string cc = c;

    string ad = util::deblankString(ac);
    string bd = util::deblankString(bc);
    string cd = util::deblankString(cc);

    util::deblankString(a);
    util::deblankString(b);
    util::deblankString(c);

    CPPUNIT_ASSERT_EQUAL(string("a"), a);
    CPPUNIT_ASSERT_EQUAL(string("b"), b);
    CPPUNIT_ASSERT_EQUAL(string("ccc"), c);

    CPPUNIT_ASSERT_EQUAL(ad, a);
    CPPUNIT_ASSERT_EQUAL(bd, b);
    CPPUNIT_ASSERT_EQUAL(cd, c);
}

void TestUtil::testUnitScaling() {
    CPPUNIT_ASSERT_THROW(util::getSIScaling("mOhm","ms"), nix::InvalidUnit);
    CPPUNIT_ASSERT(util::getSIScaling("mV","kV") == 1e-6);
    CPPUNIT_ASSERT(util::getSIScaling("V","kV") == 1e-03);
    CPPUNIT_ASSERT(util::getSIScaling("kV","V") == 1e+03);
    CPPUNIT_ASSERT_THROW(util::getSIScaling("mV^2","V"), nix::InvalidUnit);
    CPPUNIT_ASSERT(util::getSIScaling("V^2","V^2") == 1.0);
    CPPUNIT_ASSERT(util::getSIScaling("V","mV") == 1e+03);
    CPPUNIT_ASSERT(util::getSIScaling("V^2","mV^2") == 1e+06);
    CPPUNIT_ASSERT(util::getSIScaling("mV^2","kV^2") == 1e-12);
}

void TestUtil::testIsSIUnit() {
    CPPUNIT_ASSERT(util::isSIUnit("V"));
    CPPUNIT_ASSERT(util::isSIUnit("mV"));
    CPPUNIT_ASSERT(util::isSIUnit("mV^-2"));
    CPPUNIT_ASSERT(util::isSIUnit("mV/cm"));
    CPPUNIT_ASSERT(util::isSIUnit("dB"));
    CPPUNIT_ASSERT(util::isSIUnit("rad"));
}

void TestUtil::testSIUnitSplit() {
    string unit_1 = "V";
    string unit_2 = "mV";
    string unit_3 = "mV^2";
    string unit_4 = "mV^-2";
    string unit_5 = "m^2";

    string unit, prefix, power;
    util::splitUnit(unit_1, prefix, unit, power);
    CPPUNIT_ASSERT(prefix == "" && unit == "V" && power == "");
    util::splitUnit(unit_2, prefix, unit, power);
    CPPUNIT_ASSERT(prefix == "m" && unit == "V" && power == "");
    util::splitUnit(unit_3, prefix, unit, power);
    CPPUNIT_ASSERT(prefix == "m" && unit == "V" && power == "2");
    util::splitUnit(unit_4, prefix, unit, power);
    CPPUNIT_ASSERT(prefix == "m" && unit == "V" && power == "-2");
    util::splitUnit(unit_5, prefix, unit, power);
    CPPUNIT_ASSERT(prefix == "" && unit == "m" && power == "2");
}

void TestUtil::testIsAtomicSIUnit() {
    CPPUNIT_ASSERT(util::isAtomicSIUnit("V"));
    CPPUNIT_ASSERT(util::isAtomicSIUnit("mV"));
    CPPUNIT_ASSERT(util::isAtomicSIUnit("mV^-2"));
    CPPUNIT_ASSERT(!util::isAtomicSIUnit("mV/cm"));
    CPPUNIT_ASSERT(util::isAtomicSIUnit("dB"));
    CPPUNIT_ASSERT(util::isAtomicSIUnit("rad"));
}

void TestUtil::testIsCompoundSIUnit() {
    string unit_1 = "mV*cm^-2";
    string unit_2 = "mV/cm^2";
    string unit_3 = "mV/cm^2*kg";
    string unit_4 = "mV";

    CPPUNIT_ASSERT(util::isCompoundSIUnit(unit_1));
    CPPUNIT_ASSERT(util::isCompoundSIUnit(unit_2));
    CPPUNIT_ASSERT(util::isCompoundSIUnit(unit_3));
    CPPUNIT_ASSERT(!util::isCompoundSIUnit(unit_4));
}

void TestUtil::testSplitCompoundUnit() {
    string unit = "mV/cm^2*kg*V";
    vector<string> atomic_units;

    util::splitCompoundUnit(unit, atomic_units);

    CPPUNIT_ASSERT(atomic_units.size() == 4);
    CPPUNIT_ASSERT(atomic_units[0] == "mV" && atomic_units[1] == "cm^2" &&
                   atomic_units[2] == "kg" && atomic_units[3] == "V");
}

void TestUtil::testConvertToSeconds() {
    string unit_min = "min";
    string unit_h = "h";
    string unit_s = "s";
    string unit_ms = "ms";
    string unit_Ms = "Ms";
    double min_value = 25.5;
    double h_value = 12.25;
    double s_value = 100;
    int64_t m_value = 25;
    CPPUNIT_ASSERT(util::convertToSeconds(unit_min, min_value) == 1530.0);
    CPPUNIT_ASSERT(util::convertToSeconds(unit_h, h_value) == 44100.0);
    CPPUNIT_ASSERT(util::convertToSeconds(unit_min, m_value) == 1500);
    CPPUNIT_ASSERT(util::convertToSeconds(unit_s, s_value) == s_value);
    CPPUNIT_ASSERT(util::convertToSeconds(unit_ms, s_value) == s_value/1000.);
    CPPUNIT_ASSERT(util::convertToSeconds(unit_Ms, s_value) == s_value*1000000.);
}

void TestUtil::testConvertToKelvin() {
    string unit_f = "°F";
    string unit_f2 = "F";
    string unit_c = "°C";
    string unit_c2 = "C";
    string unit_k = "K";
    string unit_mk = "mK";
    string unit_Mk = "MK";
    string unit_k2 ="°K" ;
    double temperature = 100.0;
    CPPUNIT_ASSERT(util::convertToKelvin(unit_c, temperature) == 373.15);
    CPPUNIT_ASSERT(util::convertToKelvin(unit_c2, temperature) == 373.15);
    CPPUNIT_ASSERT(round(util::convertToKelvin(unit_f, temperature)) == 311.0);
    CPPUNIT_ASSERT(round(util::convertToKelvin(unit_f2, temperature)) == 311.0);
    CPPUNIT_ASSERT(util::convertToKelvin(unit_k, temperature) == temperature);
    CPPUNIT_ASSERT(util::convertToKelvin(unit_k2, temperature) == temperature);
    CPPUNIT_ASSERT(util::convertToKelvin(unit_mk, temperature) == temperature/1000.);
    CPPUNIT_ASSERT(util::convertToKelvin(unit_Mk, temperature) == temperature*1000000.);
    int temp_fi = 100;
    CPPUNIT_ASSERT(util::convertToKelvin(unit_f, temp_fi) == 311);
}

void TestUtil::testUnitSanitizer() {
    std::string unit = " mul/µs ";
    CPPUNIT_ASSERT(util::unitSanitizer(unit) == "ul/us");
}
<commit_msg>[util] adapt and extend test for util::split_compound<commit_after>// Copyright (c) 2013, German Neuroinformatics Node (G-Node)
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted under the terms of the BSD License. See
// LICENSE file in the root of the Project.

#include "TestUtil.hpp"

#include <ctime>
#include <cmath>

using namespace std;
using namespace nix;

void TestUtil::testStrUtils() {
    string a = " a ";
    string b = "\tb\t";
    string c = " c c\tc ";

    const string ac = a;
    const string bc = b;
    const string cc = c;

    string ad = util::deblankString(ac);
    string bd = util::deblankString(bc);
    string cd = util::deblankString(cc);

    util::deblankString(a);
    util::deblankString(b);
    util::deblankString(c);

    CPPUNIT_ASSERT_EQUAL(string("a"), a);
    CPPUNIT_ASSERT_EQUAL(string("b"), b);
    CPPUNIT_ASSERT_EQUAL(string("ccc"), c);

    CPPUNIT_ASSERT_EQUAL(ad, a);
    CPPUNIT_ASSERT_EQUAL(bd, b);
    CPPUNIT_ASSERT_EQUAL(cd, c);
}

void TestUtil::testUnitScaling() {
    CPPUNIT_ASSERT_THROW(util::getSIScaling("mOhm","ms"), nix::InvalidUnit);
    CPPUNIT_ASSERT(util::getSIScaling("mV","kV") == 1e-6);
    CPPUNIT_ASSERT(util::getSIScaling("V","kV") == 1e-03);
    CPPUNIT_ASSERT(util::getSIScaling("kV","V") == 1e+03);
    CPPUNIT_ASSERT_THROW(util::getSIScaling("mV^2","V"), nix::InvalidUnit);
    CPPUNIT_ASSERT(util::getSIScaling("V^2","V^2") == 1.0);
    CPPUNIT_ASSERT(util::getSIScaling("V","mV") == 1e+03);
    CPPUNIT_ASSERT(util::getSIScaling("V^2","mV^2") == 1e+06);
    CPPUNIT_ASSERT(util::getSIScaling("mV^2","kV^2") == 1e-12);
}

void TestUtil::testIsSIUnit() {
    CPPUNIT_ASSERT(util::isSIUnit("V"));
    CPPUNIT_ASSERT(util::isSIUnit("mV"));
    CPPUNIT_ASSERT(util::isSIUnit("mV^-2"));
    CPPUNIT_ASSERT(util::isSIUnit("mV/cm"));
    CPPUNIT_ASSERT(util::isSIUnit("dB"));
    CPPUNIT_ASSERT(util::isSIUnit("rad"));
}

void TestUtil::testSIUnitSplit() {
    string unit_1 = "V";
    string unit_2 = "mV";
    string unit_3 = "mV^2";
    string unit_4 = "mV^-2";
    string unit_5 = "m^2";

    string unit, prefix, power;
    util::splitUnit(unit_1, prefix, unit, power);
    CPPUNIT_ASSERT(prefix == "" && unit == "V" && power == "");
    util::splitUnit(unit_2, prefix, unit, power);
    CPPUNIT_ASSERT(prefix == "m" && unit == "V" && power == "");
    util::splitUnit(unit_3, prefix, unit, power);
    CPPUNIT_ASSERT(prefix == "m" && unit == "V" && power == "2");
    util::splitUnit(unit_4, prefix, unit, power);
    CPPUNIT_ASSERT(prefix == "m" && unit == "V" && power == "-2");
    util::splitUnit(unit_5, prefix, unit, power);
    CPPUNIT_ASSERT(prefix == "" && unit == "m" && power == "2");
}

void TestUtil::testIsAtomicSIUnit() {
    CPPUNIT_ASSERT(util::isAtomicSIUnit("V"));
    CPPUNIT_ASSERT(util::isAtomicSIUnit("mV"));
    CPPUNIT_ASSERT(util::isAtomicSIUnit("mV^-2"));
    CPPUNIT_ASSERT(!util::isAtomicSIUnit("mV/cm"));
    CPPUNIT_ASSERT(util::isAtomicSIUnit("dB"));
    CPPUNIT_ASSERT(util::isAtomicSIUnit("rad"));
}

void TestUtil::testIsCompoundSIUnit() {
    string unit_1 = "mV*cm^-2";
    string unit_2 = "mV/cm^2";
    string unit_3 = "mV/cm^2*kg";
    string unit_4 = "mV";

    CPPUNIT_ASSERT(util::isCompoundSIUnit(unit_1));
    CPPUNIT_ASSERT(util::isCompoundSIUnit(unit_2));
    CPPUNIT_ASSERT(util::isCompoundSIUnit(unit_3));
    CPPUNIT_ASSERT(!util::isCompoundSIUnit(unit_4));
}

void TestUtil::testSplitCompoundUnit() {
    string unit = "mV/cm^2*kg*V";
    string unit_2 = "mOhm/m";
    string unit_3 = "mV";

    vector<string> atomic_units, atomic_units_2, atomic_units_3;
    util::splitCompoundUnit(unit, atomic_units);
    CPPUNIT_ASSERT(atomic_units.size() == 4);
    CPPUNIT_ASSERT(atomic_units[0] == "mV" && atomic_units[1] == "cm^-2" &&
                   atomic_units[2] == "kg" && atomic_units[3] == "V");

    util::splitCompoundUnit(unit_2, atomic_units_2);
    CPPUNIT_ASSERT(atomic_units_2.size() == 2);
    CPPUNIT_ASSERT(atomic_units_2[0] == "mOhm" && atomic_units_2[1] == "m^-1");

    util::splitCompoundUnit(unit_3, atomic_units_3);
    CPPUNIT_ASSERT(atomic_units_3.size() == 1);
    CPPUNIT_ASSERT(atomic_units_3[0] == unit_3);
}

void TestUtil::testConvertToSeconds() {
    string unit_min = "min";
    string unit_h = "h";
    string unit_s = "s";
    string unit_ms = "ms";
    string unit_Ms = "Ms";
    double min_value = 25.5;
    double h_value = 12.25;
    double s_value = 100;
    int64_t m_value = 25;
    CPPUNIT_ASSERT(util::convertToSeconds(unit_min, min_value) == 1530.0);
    CPPUNIT_ASSERT(util::convertToSeconds(unit_h, h_value) == 44100.0);
    CPPUNIT_ASSERT(util::convertToSeconds(unit_min, m_value) == 1500);
    CPPUNIT_ASSERT(util::convertToSeconds(unit_s, s_value) == s_value);
    CPPUNIT_ASSERT(util::convertToSeconds(unit_ms, s_value) == s_value/1000.);
    CPPUNIT_ASSERT(util::convertToSeconds(unit_Ms, s_value) == s_value*1000000.);
}

void TestUtil::testConvertToKelvin() {
    string unit_f = "°F";
    string unit_f2 = "F";
    string unit_c = "°C";
    string unit_c2 = "C";
    string unit_k = "K";
    string unit_mk = "mK";
    string unit_Mk = "MK";
    string unit_k2 ="°K" ;
    double temperature = 100.0;
    CPPUNIT_ASSERT(util::convertToKelvin(unit_c, temperature) == 373.15);
    CPPUNIT_ASSERT(util::convertToKelvin(unit_c2, temperature) == 373.15);
    CPPUNIT_ASSERT(round(util::convertToKelvin(unit_f, temperature)) == 311.0);
    CPPUNIT_ASSERT(round(util::convertToKelvin(unit_f2, temperature)) == 311.0);
    CPPUNIT_ASSERT(util::convertToKelvin(unit_k, temperature) == temperature);
    CPPUNIT_ASSERT(util::convertToKelvin(unit_k2, temperature) == temperature);
    CPPUNIT_ASSERT(util::convertToKelvin(unit_mk, temperature) == temperature/1000.);
    CPPUNIT_ASSERT(util::convertToKelvin(unit_Mk, temperature) == temperature*1000000.);
    int temp_fi = 100;
    CPPUNIT_ASSERT(util::convertToKelvin(unit_f, temp_fi) == 311);
}

void TestUtil::testUnitSanitizer() {
    std::string unit = " mul/µs ";
    CPPUNIT_ASSERT(util::unitSanitizer(unit) == "ul/us");
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: detdata.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: nn $ $Date: 2002-11-04 15:45:51 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef SC_DETDATA_HXX
#define SC_DETDATA_HXX

#ifndef _SVARRAY_HXX //autogen
#include <svtools/svarray.hxx>
#endif

#ifndef SC_SCGLOB_HXX
#include "global.hxx"
#endif

//------------------------------------------------------------------------

#define SC_DETOP_GROW   4

//------------------------------------------------------------------------
enum ScDetOpType
{
    SCDETOP_ADDSUCC,
    SCDETOP_DELSUCC,
    SCDETOP_ADDPRED,
    SCDETOP_DELPRED,
    SCDETOP_ADDERROR
};

//------------------------------------------------------------------------

class ScDetOpData
{
    ScAddress       aPos;
    ScDetOpType     eOperation;

public:
                        ScDetOpData( const ScAddress& rP, ScDetOpType eOp ) :
                            aPos(rP), eOperation(eOp) {}

                        ScDetOpData( const ScDetOpData& rData ) :
                            aPos(rData.aPos), eOperation(rData.eOperation) {}

    const ScAddress&    GetPos() const          { return aPos; }
    ScDetOpType         GetOperation() const    { return eOperation; }

    // fuer UpdateRef:
    void                SetPos(const ScAddress& rNew)   { aPos=rNew; }

    int operator==      ( const ScDetOpData& r ) const
                            { return eOperation == r.eOperation && aPos == r.aPos; }
};

//------------------------------------------------------------------------

//
//  Liste der Operationen
//

typedef ScDetOpData* ScDetOpDataPtr;

SV_DECL_PTRARR_DEL(ScDetOpArr_Impl, ScDetOpDataPtr, SC_DETOP_GROW, SC_DETOP_GROW);

class ScDetOpList : public ScDetOpArr_Impl
{
    BOOL    bHasAddError;       // updated in Append

public:
        ScDetOpList() : bHasAddError(FALSE) {}
        ScDetOpList(const ScDetOpList& rList);
        ~ScDetOpList() {}

    void    UpdateReference( ScDocument* pDoc, UpdateRefMode eUpdateRefMode,
                                const ScRange& rRange, short nDx, short nDy, short nDz );

    BOOL    operator==( const ScDetOpList& r ) const;       // fuer Ref-Undo

    void    Append( ScDetOpData* pData );

    void    Load( SvStream& rStream );
    void    Store( SvStream& rStream ) const;

    BOOL    HasAddError() const     { return bHasAddError; }
};

#endif
<commit_msg>INTEGRATION: CWS rowlimit (1.2.302); FILE MERGED 2004/01/12 17:14:55 er 1.2.302.2: #i1967# SCCOL,SCROW,SCTAB replace USHORT; SCsCOL,SCsROW,SCsTAB replace short 2003/11/28 19:47:18 er 1.2.302.1: #i1967# move ScAddress, ScRange from global.hxx to address.hxx<commit_after>/*************************************************************************
 *
 *  $RCSfile: detdata.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: obo $ $Date: 2004-06-04 10:06:42 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef SC_DETDATA_HXX
#define SC_DETDATA_HXX

#ifndef _SVARRAY_HXX //autogen
#include <svtools/svarray.hxx>
#endif

#ifndef SC_SCGLOB_HXX
#include "global.hxx"
#endif

#ifndef SC_ADDRESS_HXX
#include "address.hxx"
#endif

//------------------------------------------------------------------------

#define SC_DETOP_GROW   4

//------------------------------------------------------------------------
enum ScDetOpType
{
    SCDETOP_ADDSUCC,
    SCDETOP_DELSUCC,
    SCDETOP_ADDPRED,
    SCDETOP_DELPRED,
    SCDETOP_ADDERROR
};

//------------------------------------------------------------------------

class ScDetOpData
{
    ScAddress       aPos;
    ScDetOpType     eOperation;

public:
                        ScDetOpData( const ScAddress& rP, ScDetOpType eOp ) :
                            aPos(rP), eOperation(eOp) {}

                        ScDetOpData( const ScDetOpData& rData ) :
                            aPos(rData.aPos), eOperation(rData.eOperation) {}

    const ScAddress&    GetPos() const          { return aPos; }
    ScDetOpType         GetOperation() const    { return eOperation; }

    // fuer UpdateRef:
    void                SetPos(const ScAddress& rNew)   { aPos=rNew; }

    int operator==      ( const ScDetOpData& r ) const
                            { return eOperation == r.eOperation && aPos == r.aPos; }
};

//------------------------------------------------------------------------

//
//  Liste der Operationen
//

typedef ScDetOpData* ScDetOpDataPtr;

SV_DECL_PTRARR_DEL(ScDetOpArr_Impl, ScDetOpDataPtr, SC_DETOP_GROW, SC_DETOP_GROW);

class ScDetOpList : public ScDetOpArr_Impl
{
    BOOL    bHasAddError;       // updated in Append

public:
        ScDetOpList() : bHasAddError(FALSE) {}
        ScDetOpList(const ScDetOpList& rList);
        ~ScDetOpList() {}

    void    UpdateReference( ScDocument* pDoc, UpdateRefMode eUpdateRefMode,
                                const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz );

    BOOL    operator==( const ScDetOpList& r ) const;       // fuer Ref-Undo

    void    Append( ScDetOpData* pData );

    void    Load( SvStream& rStream );
    void    Store( SvStream& rStream ) const;

    BOOL    HasAddError() const     { return bHasAddError; }
};

#endif
<|endoftext|>


<commit_before>// Copyright 2018 The Clspv Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <climits>
#include <map>
#include <set>
#include <utility>
#include <vector>

#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/UniqueVector.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/raw_ostream.h"

#include "clspv/Option.h"

#include "ArgKind.h"
#include "Builtins.h"
#include "CallGraphOrderedFunctions.h"
#include "Constants.h"
#include "DirectResourceAccessPass.h"

using namespace llvm;

#define DEBUG_TYPE "directresourceaccess"

namespace {

cl::opt<bool> ShowDRA("show-dra", cl::init(false), cl::Hidden,
                      cl::desc("Show direct resource access details"));

} // namespace

PreservedAnalyses
clspv::DirectResourceAccessPass::run(Module &M, ModuleAnalysisManager &) {
  PreservedAnalyses PA;

  if (clspv::Option::DirectResourceAccess()) {
    auto ordered_functions = clspv::CallGraphOrderedFunctions(M);
    if (ShowDRA) {
      outs() << "DRA: Ordered functions:\n";
      for (Function *fun : ordered_functions) {
        outs() << "DRA:   " << fun->getName() << "\n";
      }
    }

    for (auto *fn : ordered_functions) {
      RewriteResourceAccesses(fn);
    }
  }

  return PA;
}

bool clspv::DirectResourceAccessPass::RewriteResourceAccesses(Function *fn) {
  bool Changed = false;
  int arg_index = 0;
  for (Argument &arg : fn->args()) {
    switch (clspv::GetArgKind(arg)) {
    case clspv::ArgKind::Buffer:
    case clspv::ArgKind::BufferUBO:
    case clspv::ArgKind::SampledImage:
    case clspv::ArgKind::StorageImage:
    case clspv::ArgKind::Sampler:
    case clspv::ArgKind::Local:
      Changed |= RewriteAccessesForArg(fn, arg_index, arg);
      break;
    default:
      // Should not happen
      break;
    }
    arg_index++;
  }
  return Changed;
}

bool clspv::DirectResourceAccessPass::RewriteAccessesForArg(Function *fn,
                                                            int arg_index,
                                                            Argument &arg) {
  bool Changed = false;
  if (fn->use_empty()) {
    return false;
  }

  // We can convert a parameter to a direct resource access if it is
  // either a direct call to a clspv.resource.var.* or if it a GEP of
  // such a thing (where the GEP can only have zero indices).
  struct ParamInfo {
    // The base value. It is either a global variable or a resource-access
    // builtin function. (@clspv.resource.var.* or @clspv.local.var.*)
    Value *base;
    // The descriptor set.
    uint32_t set;
    // The binding.
    uint32_t binding;
    // If the parameter is a GEP, then this is the number of zero-indices
    // the GEP used.
    unsigned num_gep_zeroes;
    // An example call fitting
    CallInst *sample_call;
  };
  // The common valid parameter info across all the callers seen soo far.

  bool seen_one = false;
  ParamInfo common;
  // Tries to merge the given parameter info into |common|.  If it is the first
  // time we've tried, then save it.  Returns true if there is no conflict.
  auto merge_param_info = [&seen_one, &common](const ParamInfo &pi) {
    if (!seen_one) {
      common = pi;
      seen_one = true;
      return true;
    }
    return pi.base == common.base && pi.set == common.set &&
           pi.binding == common.binding &&
           pi.num_gep_zeroes == common.num_gep_zeroes;
  };

  for (auto &use : fn->uses()) {
    if (auto *caller = dyn_cast<CallInst>(use.getUser())) {
      Value *value = caller->getArgOperand(arg_index);
      // We care about two cases:
      //     - a direct call to clspv.resource.var.*
      //     - a GEP with only zero indices, where the base pointer is

      // Unpack GEPs with zeros, if we can.  Rewrite |value| as we go along.
      unsigned num_gep_zeroes = 0;
      bool first_gep = true;
      for (auto *gep = dyn_cast<GetElementPtrInst>(value); gep;
           gep = dyn_cast<GetElementPtrInst>(value)) {
        if (!gep->hasAllZeroIndices()) {
          return false;
        }
        // If not the first GEP, then ignore the "element" index (which I call
        // "slide") since that will be combined with the last index of the
        // previous GEP.
        num_gep_zeroes += gep->getNumIndices() + (first_gep ? 0 : -1);
        value = gep->getPointerOperand();
        first_gep = false;
      }
      if (auto *call = dyn_cast<CallInst>(value)) {
        // If the call is a call to a @clspv.resource.var.* function, then try
        // to merge it, assuming the given number of GEP zero-indices so far.
        auto *callee = call->getCalledFunction();
        auto &func_info = clspv::Builtins::Lookup(callee);
        if (func_info.getType() == clspv::Builtins::kClspvResource) {
          const auto set = uint32_t(
              dyn_cast<ConstantInt>(call->getOperand(0))->getZExtValue());
          const auto binding = uint32_t(
              dyn_cast<ConstantInt>(call->getOperand(1))->getZExtValue());
          if (!merge_param_info({callee, set, binding, num_gep_zeroes, call}))
            return false;
        } else if (func_info.getType() == clspv::Builtins::kClspvLocal) {
          const uint32_t spec_id = uint32_t(
              dyn_cast<ConstantInt>(call->getOperand(0))->getZExtValue());
          if (!merge_param_info({callee, spec_id, 0, num_gep_zeroes, call}))
            return false;
        } else {
          // A call but not to a resource access builtin function.
          return false;
        }
      } else if (isa<GlobalValue>(value)) {
        if (!merge_param_info({value, 0, 0, num_gep_zeroes, nullptr}))
          return false;
      } else {
        // Not a call.
        return false;
      }
    } else {
      // There isn't enough commonality.  Bail out without changing anything.
      return false;
    }
  }
  if (ShowDRA) {
    if (seen_one) {
      outs() << "DRA:  Rewrite " << fn->getName() << " arg " << arg_index << " "
             << arg.getName() << ": " << common.base->getName() << " ("
             << common.set << "," << common.binding
             << ") zeroes: " << common.num_gep_zeroes << " sample-call ";
      if (common.sample_call)
        outs() << *common.sample_call << "\n";
      else
        outs() << "nullptr\n";
    }
  }

  // Now rewrite the argument, using the info in |common|.

  Changed = true;
  IRBuilder<> Builder(fn->getParent()->getContext());
  auto *zero = Builder.getInt32(0);
  Builder.SetInsertPoint(fn->getEntryBlock().getFirstNonPHI());

  Value *replacement = common.base;
  if (Function *function = dyn_cast<Function>(replacement)) {
    // Create the call.
    SmallVector<Value *, 8> args(common.sample_call->arg_begin(),
                                 common.sample_call->arg_end());
    replacement = Builder.CreateCall(function, args);
    if (ShowDRA) {
      outs() << "DRA:    Replace: call " << *replacement << "\n";
    }
  }
  if (common.num_gep_zeroes) {
    SmallVector<Value *, 3> zeroes;
    for (unsigned i = 0; i < common.num_gep_zeroes; i++) {
      zeroes.push_back(zero);
    }
    // Builder.CreateGEP is not used to avoid creating a GEPConstantExpr in the
    // case of global variables.
    replacement = GetElementPtrInst::Create(
        replacement->getType()->getPointerElementType(), replacement, zeroes);
    Builder.Insert(cast<Instruction>(replacement));
    if (ShowDRA) {
      outs() << "DRA:    Replace: gep  " << *replacement << "\n";
    }
  }
  arg.replaceAllUsesWith(replacement);

  return Changed;
}
<commit_msg>DRA: document what happens for other arg kinds (#861)<commit_after>// Copyright 2018 The Clspv Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <climits>
#include <map>
#include <set>
#include <utility>
#include <vector>

#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/UniqueVector.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/raw_ostream.h"

#include "clspv/Option.h"

#include "ArgKind.h"
#include "Builtins.h"
#include "CallGraphOrderedFunctions.h"
#include "Constants.h"
#include "DirectResourceAccessPass.h"

using namespace llvm;

#define DEBUG_TYPE "directresourceaccess"

namespace {

cl::opt<bool> ShowDRA("show-dra", cl::init(false), cl::Hidden,
                      cl::desc("Show direct resource access details"));

} // namespace

PreservedAnalyses
clspv::DirectResourceAccessPass::run(Module &M, ModuleAnalysisManager &) {
  PreservedAnalyses PA;

  if (clspv::Option::DirectResourceAccess()) {
    auto ordered_functions = clspv::CallGraphOrderedFunctions(M);
    if (ShowDRA) {
      outs() << "DRA: Ordered functions:\n";
      for (Function *fun : ordered_functions) {
        outs() << "DRA:   " << fun->getName() << "\n";
      }
    }

    for (auto *fn : ordered_functions) {
      RewriteResourceAccesses(fn);
    }
  }

  return PA;
}

bool clspv::DirectResourceAccessPass::RewriteResourceAccesses(Function *fn) {
  bool Changed = false;
  int arg_index = 0;
  for (Argument &arg : fn->args()) {
    switch (clspv::GetArgKind(arg)) {
    case clspv::ArgKind::Buffer:
    case clspv::ArgKind::BufferUBO:
    case clspv::ArgKind::SampledImage:
    case clspv::ArgKind::StorageImage:
    case clspv::ArgKind::Sampler:
    case clspv::ArgKind::Local:
      Changed |= RewriteAccessesForArg(fn, arg_index, arg);
      break;
    case clspv::ArgKind::Pod:
    case clspv::ArgKind::PodUBO:
    case clspv::ArgKind::PodPushConstant:
      // These are represented by structs. Don't rewrite them.
      break;
    default:
      errs() << "Unhandled ArgKind in "
                "clspv::DirectResourceAccessPass::RewriteResourceAccesses: "
             << int(clspv::GetArgKind(arg)) << "\n";
      llvm_unreachable(
          "Unhandled ArgKind in "
          "clspv::DirectResourceAccessPass::RewriteResourceAccesses");
      break;
    }
    arg_index++;
  }
  return Changed;
}

bool clspv::DirectResourceAccessPass::RewriteAccessesForArg(Function *fn,
                                                            int arg_index,
                                                            Argument &arg) {
  bool Changed = false;
  if (fn->use_empty()) {
    return false;
  }

  // We can convert a parameter to a direct resource access if it is
  // either a direct call to a clspv.resource.var.* or if it a GEP of
  // such a thing (where the GEP can only have zero indices).
  struct ParamInfo {
    // The base value. It is either a global variable or a resource-access
    // builtin function. (@clspv.resource.var.* or @clspv.local.var.*)
    Value *base;
    // The descriptor set.
    uint32_t set;
    // The binding.
    uint32_t binding;
    // If the parameter is a GEP, then this is the number of zero-indices
    // the GEP used.
    unsigned num_gep_zeroes;
    // An example call fitting
    CallInst *sample_call;
  };
  // The common valid parameter info across all the callers seen soo far.

  bool seen_one = false;
  ParamInfo common;
  // Tries to merge the given parameter info into |common|.  If it is the first
  // time we've tried, then save it.  Returns true if there is no conflict.
  auto merge_param_info = [&seen_one, &common](const ParamInfo &pi) {
    if (!seen_one) {
      common = pi;
      seen_one = true;
      return true;
    }
    return pi.base == common.base && pi.set == common.set &&
           pi.binding == common.binding &&
           pi.num_gep_zeroes == common.num_gep_zeroes;
  };

  for (auto &use : fn->uses()) {
    if (auto *caller = dyn_cast<CallInst>(use.getUser())) {
      Value *value = caller->getArgOperand(arg_index);
      // We care about two cases:
      //     - a direct call to clspv.resource.var.*
      //     - a GEP with only zero indices, where the base pointer is

      // Unpack GEPs with zeros, if we can.  Rewrite |value| as we go along.
      unsigned num_gep_zeroes = 0;
      bool first_gep = true;
      for (auto *gep = dyn_cast<GetElementPtrInst>(value); gep;
           gep = dyn_cast<GetElementPtrInst>(value)) {
        if (!gep->hasAllZeroIndices()) {
          return false;
        }
        // If not the first GEP, then ignore the "element" index (which I call
        // "slide") since that will be combined with the last index of the
        // previous GEP.
        num_gep_zeroes += gep->getNumIndices() + (first_gep ? 0 : -1);
        value = gep->getPointerOperand();
        first_gep = false;
      }
      if (auto *call = dyn_cast<CallInst>(value)) {
        // If the call is a call to a @clspv.resource.var.* function, then try
        // to merge it, assuming the given number of GEP zero-indices so far.
        auto *callee = call->getCalledFunction();
        auto &func_info = clspv::Builtins::Lookup(callee);
        if (func_info.getType() == clspv::Builtins::kClspvResource) {
          const auto set = uint32_t(
              dyn_cast<ConstantInt>(call->getOperand(0))->getZExtValue());
          const auto binding = uint32_t(
              dyn_cast<ConstantInt>(call->getOperand(1))->getZExtValue());
          if (!merge_param_info({callee, set, binding, num_gep_zeroes, call}))
            return false;
        } else if (func_info.getType() == clspv::Builtins::kClspvLocal) {
          const uint32_t spec_id = uint32_t(
              dyn_cast<ConstantInt>(call->getOperand(0))->getZExtValue());
          if (!merge_param_info({callee, spec_id, 0, num_gep_zeroes, call}))
            return false;
        } else {
          // A call but not to a resource access builtin function.
          return false;
        }
      } else if (isa<GlobalValue>(value)) {
        if (!merge_param_info({value, 0, 0, num_gep_zeroes, nullptr}))
          return false;
      } else {
        // Not a call.
        return false;
      }
    } else {
      // There isn't enough commonality.  Bail out without changing anything.
      return false;
    }
  }
  if (ShowDRA) {
    if (seen_one) {
      outs() << "DRA:  Rewrite " << fn->getName() << " arg " << arg_index << " "
             << arg.getName() << ": " << common.base->getName() << " ("
             << common.set << "," << common.binding
             << ") zeroes: " << common.num_gep_zeroes << " sample-call ";
      if (common.sample_call)
        outs() << *common.sample_call << "\n";
      else
        outs() << "nullptr\n";
    }
  }

  // Now rewrite the argument, using the info in |common|.

  Changed = true;
  IRBuilder<> Builder(fn->getParent()->getContext());
  auto *zero = Builder.getInt32(0);
  Builder.SetInsertPoint(fn->getEntryBlock().getFirstNonPHI());

  Value *replacement = common.base;
  if (Function *function = dyn_cast<Function>(replacement)) {
    // Create the call.
    SmallVector<Value *, 8> args(common.sample_call->arg_begin(),
                                 common.sample_call->arg_end());
    replacement = Builder.CreateCall(function, args);
    if (ShowDRA) {
      outs() << "DRA:    Replace: call " << *replacement << "\n";
    }
  }
  if (common.num_gep_zeroes) {
    SmallVector<Value *, 3> zeroes;
    for (unsigned i = 0; i < common.num_gep_zeroes; i++) {
      zeroes.push_back(zero);
    }
    // Builder.CreateGEP is not used to avoid creating a GEPConstantExpr in the
    // case of global variables.
    replacement = GetElementPtrInst::Create(
        replacement->getType()->getPointerElementType(), replacement, zeroes);
    Builder.Insert(cast<Instruction>(replacement));
    if (ShowDRA) {
      outs() << "DRA:    Replace: gep  " << *replacement << "\n";
    }
  }
  arg.replaceAllUsesWith(replacement);

  return Changed;
}
<|endoftext|>


<commit_before>#include "scoretabwidget.hpp"

#include <QComboBox>
#include <QString>
#include <QFile>
#include <QTextStream>
#include <QSet>
#include <QDebug>

/**
* Constructeur
* Crée un ScoreTabWidget
* @param parent Widget parent
*/
ScoreTabWidget::ScoreTabWidget(QWidget *parent) : QWidget(parent) {
  playerNameLabel__.setParent(this);
  playerNameLabel__.setText(QString("Filtrer les résultats pour le joueur:"));
  playerName__.setParent(this);
  scoreTree__.setParent(this);
  scoreWatcher__.setParent(this);
  scoreWatcher__.addPath(QString("score.csv"));

  scoreChanged__(QString());

  connect(&playerName__, SIGNAL(currentTextChanged(const QString &)), this,
          SLOT(playerNameChanged__(const QString &)));
  connect(&scoreWatcher__, SIGNAL(fileChanged(const QString &)), this,
          SLOT(scoreChanged__(const QString &)));

  layout__.addWidget(&playerNameLabel__);
  layout__.addWidget(&playerName__);
  layout__.addWidget(&scoreTree__);

  setLayout(&layout__);
}

ScoreTabWidget::~ScoreTabWidget() {
  QTreeWidgetItem *item;
  QVectorIterator<QTreeWidgetItem *> itemIt(items__);
  while (itemIt.hasNext()) {
    item = itemIt.next();
    delete item;
  }
}

void ScoreTabWidget::scoreChanged__(const QString &file) {
  playerName__.setDisabled(true);

  playerName__.clear();
  scores__.clear();

  QSet<QString> players;
  QFile scoreFile(QString("score.csv"));
  if (scoreFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
    QTextStream in(&scoreFile);
    while (!in.atEnd()) {
      QString line = in.readLine();
      QStringList lineSplit = line.split(QChar(';'));
      if (lineSplit.size() >= 5) {
        scores__.append(lineSplit);
        players.insert(lineSplit.at(0));
      }
    }
  }

  playerName__.addItem(QString());
  for (QSet<QString>::const_iterator it = players.constBegin();
       it != players.constEnd(); it++) {
    playerName__.addItem(*it);
  }

  playerName__.setEnabled(true);

  playerNameChanged__(QString());
}

void ScoreTabWidget::playerNameChanged__(const QString &text) {
  qInfo("player name combo box changed");

  scoreTree__.setDisabled(true);

  QTreeWidgetItem *item;
  QVectorIterator<QTreeWidgetItem *> itemIt(items__);
  while (itemIt.hasNext()) {
    item = itemIt.next();
    delete item;
  }
  items__.clear();
  scoreTree__.clear();

  QStringList headerLabels;
  headerLabels.append(QString("Nom"));
  headerLabels.append(QString("Date"));
  headerLabels.append(QString("Partition"));
  headerLabels.append(QString("Score"));
  scoreTree__.setColumnCount(4);
  scoreTree__.setHeaderLabels(headerLabels);

  for (int i = 0; i < scores__.size(); ++i) {
    if (text.isEmpty() || text == scores__.at(i).at(0)) {
      item = new QTreeWidgetItem(&scoreTree__);
      item->setText(0, scores__.at(i).at(0));
      item->setText(1, scores__.at(i).at(1));
      item->setText(2, scores__.at(i).at(2));
      item->setText(3,
                    scores__.at(i).at(3) + QString("/") + scores__.at(i).at(4));
      items__.append(item);
      scoreTree__.addTopLevelItem(item);
    }
  }

  for (int i = 0; i < 4; i++) {
    scoreTree__.resizeColumnToContents(i);
  }

  scoreTree__.setEnabled(true);
}
<commit_msg>c'est pas mal<commit_after>#include "scoretabwidget.hpp"

#include <QComboBox>
#include <QString>
#include <QFile>
#include <QTextStream>
#include <QSet>
#include <QDebug>

/**
* Constructeur
* Crée un ScoreTabWidget
* @param parent Widget parent
*/
ScoreTabWidget::ScoreTabWidget(QWidget *parent) : QWidget(parent) {
  playerNameLabel__.setParent(this);
  playerNameLabel__.setText(QString("Filtrer les résultats pour le joueur:"));
  playerName__.setParent(this);
  scoreTree__.setParent(this);

  QFile scoreFile(QString("score.csv"));
  if (!scoreFile.exists()) {
    scoreFile.open(QIODevice::WriteOnly);
    scoreFile.close();
  }
  scoreWatcher__.setParent(this);
  scoreWatcher__.addPath(QString("score.csv"));

  scoreChanged__(QString());

  connect(&playerName__, SIGNAL(currentTextChanged(const QString &)), this,
          SLOT(playerNameChanged__(const QString &)));
  connect(&scoreWatcher__, SIGNAL(fileChanged(const QString &)), this,
          SLOT(scoreChanged__(const QString &)));

  layout__.addWidget(&playerNameLabel__);
  layout__.addWidget(&playerName__);
  layout__.addWidget(&scoreTree__);

  setLayout(&layout__);
}

ScoreTabWidget::~ScoreTabWidget() {
  QTreeWidgetItem *item;
  QVectorIterator<QTreeWidgetItem *> itemIt(items__);
  while (itemIt.hasNext()) {
    item = itemIt.next();
    delete item;
  }
}

void ScoreTabWidget::scoreChanged__(const QString &file) {
  playerName__.setDisabled(true);

  playerName__.clear();
  scores__.clear();

  QSet<QString> players;
  QFile scoreFile(QString("score.csv"));
  if (scoreFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
    QTextStream in(&scoreFile);
    while (!in.atEnd()) {
      QString line = in.readLine();
      QStringList lineSplit = line.split(QChar(';'));
      if (lineSplit.size() >= 5) {
        scores__.append(lineSplit);
        players.insert(lineSplit.at(0));
      }
    }
  }

  playerName__.addItem(QString());
  for (QSet<QString>::const_iterator it = players.constBegin();
       it != players.constEnd(); it++) {
    playerName__.addItem(*it);
  }

  playerName__.setEnabled(true);

  playerNameChanged__(QString());
}

void ScoreTabWidget::playerNameChanged__(const QString &text) {
  qInfo("player name combo box changed");

  scoreTree__.setDisabled(true);

  QTreeWidgetItem *item;
  QVectorIterator<QTreeWidgetItem *> itemIt(items__);
  while (itemIt.hasNext()) {
    item = itemIt.next();
    delete item;
  }
  items__.clear();
  scoreTree__.clear();

  QStringList headerLabels;
  headerLabels.append(QString("Nom"));
  headerLabels.append(QString("Date"));
  headerLabels.append(QString("Partition"));
  headerLabels.append(QString("Score"));
  scoreTree__.setColumnCount(4);
  scoreTree__.setHeaderLabels(headerLabels);

  for (int i = 0; i < scores__.size(); ++i) {
    if (text.isEmpty() || text == scores__.at(i).at(0)) {
      item = new QTreeWidgetItem(&scoreTree__);
      item->setText(0, scores__.at(i).at(0));
      item->setText(1, scores__.at(i).at(1));
      item->setText(2, scores__.at(i).at(2));
      item->setText(3,
                    scores__.at(i).at(3) + QString("/") + scores__.at(i).at(4));
      items__.append(item);
      scoreTree__.addTopLevelItem(item);
    }
  }

  for (int i = 0; i < 4; i++) {
    scoreTree__.resizeColumnToContents(i);
  }

  scoreTree__.setEnabled(true);
}
<|endoftext|>


<commit_before>/* BEGIN_COMMON_COPYRIGHT_HEADER
 * (c)LGPL2+
 *
 * LXDE-Qt - a lightweight, Qt based, desktop toolset
 *
 * Authors:
 *   Christian Surlykke <christian@surlykke.dk>
 *
 * This program or library is free software; you can redistribute it
 * and/or modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.

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

#include <QComboBox>

#include <LXQt/Power>

#include "helpers.h"

void fillComboBox(QComboBox* comboBox)
{
    comboBox->clear();
    comboBox->addItem(QObject::tr("Nothing"), -1);
    comboBox->addItem(QObject::tr("Lock screen"), -2); // FIXME
    comboBox->addItem(QObject::tr("Suspend"), LXQt::Power::PowerSuspend);
    comboBox->addItem(QObject::tr("Hibernate"), LXQt::Power::PowerHibernate);
    comboBox->addItem(QObject::tr("Shutdown"), LXQt::Power::PowerShutdown);
}

void setComboBoxToValue(QComboBox* comboBox, int value)
{
    for (int index = 0; index < comboBox->count(); index++)
    {
        if (value == comboBox->itemData(index).toInt())
        {
            comboBox->setCurrentIndex(index);
            return;
        }
    }

    comboBox->setCurrentIndex(0);
}

int currentValue(QComboBox *comboBox)
{
    return comboBox->itemData(comboBox->currentIndex()).toInt();
}

<commit_msg>Add support for turning monitor(s) off<commit_after>/* BEGIN_COMMON_COPYRIGHT_HEADER
 * (c)LGPL2+
 *
 * LXDE-Qt - a lightweight, Qt based, desktop toolset
 *
 * Authors:
 *   Christian Surlykke <christian@surlykke.dk>
 *
 * This program or library is free software; you can redistribute it
 * and/or modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.

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

#include <QComboBox>

#include <LXQt/Power>

#include "helpers.h"

void fillComboBox(QComboBox* comboBox)
{
    comboBox->clear();
    comboBox->addItem(QObject::tr("Nothing"), -1);
    comboBox->addItem(QObject::tr("Lock screen"), -2); // FIXME
    comboBox->addItem(QObject::tr("Suspend"), LXQt::Power::PowerSuspend);
    comboBox->addItem(QObject::tr("Hibernate"), LXQt::Power::PowerHibernate);
    comboBox->addItem(QObject::tr("Shutdown"), LXQt::Power::PowerShutdown);
    comboBox->addItem(QObject::tr("Turn Off monitor(s)"), LXQt::Power::PowerMonitorOff);
}

void setComboBoxToValue(QComboBox* comboBox, int value)
{
    for (int index = 0; index < comboBox->count(); index++)
    {
        if (value == comboBox->itemData(index).toInt())
        {
            comboBox->setCurrentIndex(index);
            return;
        }
    }

    comboBox->setCurrentIndex(0);
}

int currentValue(QComboBox *comboBox)
{
    return comboBox->itemData(comboBox->currentIndex()).toInt();
}

<|endoftext|>