<commit_before>/*
 * This file is part of qasmtools.
 *
 * Copyright (c) 2019 - 2021 softwareQ Inc. All rights reserved.
 *
 * MIT License
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/**
 * \file qasmtools/ast/semantic.hpp
 * \brief Semantic analysis for syntax trees
 */

#pragma once

#include "ast.hpp"
#include "visitor.hpp"

#include <algorithm>
#include <cstddef>
#include <set>
#include <unordered_map>

namespace qasmtools {
namespace ast {

/**
 * \class qasmtools::ast::SemanticError
 * \brief Exception class for semantic errors
 */
class SemanticError : public std::exception {
  public:
    SemanticError() noexcept = default;
    ~SemanticError() = default;
    const char* what() const noexcept { return "Error(s) occurred"; }
};

/**
 * \class qasmtools::ast::BitType
 * \brief Enum for types of bits
 */
enum class BitType { Cbit, Qubit };

/**
 * \struct qasmtools::ast::GateType
 * \brief Data struct for gate types
 */
struct GateType {
    int num_c_params;
    int num_q_params;
};

/**
 * \struct qasmtools::ast::RegisterType
 * \brief Data struct for register types
 */
struct RegisterType {
    BitType type;
    int length;
};

/**
 * \struct qasmtools::ast::RealType
 * \brief Empty structure denoting a real type
 */
struct RealType {};

/**
 * \brief OpenQASM types as a std::variant
 *
 * Functional-style syntax trees in C++17 as a simpler alternative
 * to inheritance hierarchy. Support is still lacking for large-scale.
 */
using Type = std::variant<BitType, GateType, RegisterType, RealType>;

/**
 * \class qasmtools::ast::SemanticChecker
 * \brief Implementation of the semantic analysis compiler phase
 * \see qasmtools::ast::Visitor
 *
 * Checks for anything that could cause a run-time error -- notably,
 * type errors, invalid uniform gates, etc. Use the functional
 * interface qasmtools::ast::check_source instead.
 */
class SemanticChecker final : public Visitor {
  public:
    bool run(Program& prog) {
        prog.accept(*this);
        return error_;
    }

    void visit(VarAccess&) {}

    void visit(BExpr& expr) {
        expr.lexp().accept(*this);
        expr.rexp().accept(*this);
    }
    void visit(UExpr& expr) { expr.subexp().accept(*this); }
    void visit(PiExpr&) {}
    void visit(IntExpr&) {}
    void visit(RealExpr&) {}
    void visit(VarExpr& expr) {
        auto entry = lookup(expr.var());

        if (!entry) {
            std::cerr << expr.pos() << ": Identifier \"" << expr.var()
                      << "\" undeclared\n";
            error_ = true;
        } else if (!std::holds_alternative<RealType>(*entry)) {
            std::cerr << expr.pos() << ": Identifier \"" << expr.var();
            std::cerr << "\" does not have numeric type\n";
            error_ = true;
        }
    }

    void visit(MeasureStmt& stmt) {
        check_uniform({stmt.q_arg(), stmt.c_arg()},
                      {BitType::Qubit, BitType::Cbit});
    }
    void visit(ResetStmt& stmt) {
        check_uniform({stmt.arg()}, {BitType::Qubit});
    }
    void visit(IfStmt& stmt) {
        auto entry = lookup(stmt.var());

        if (!entry) {
            std::cerr << stmt.pos() << ": Identifier \"" << stmt.var()
                      << "\" undeclared\n";
            error_ = true;
        } else if (!std::holds_alternative<RegisterType>(*entry) ||
                   !(std::get<RegisterType>(*entry).type == BitType::Cbit)) {
            std::cerr << stmt.pos() << ": Identifier \"" << stmt.var();
            std::cerr << "\" does not have classical register type\n";
            error_ = true;
        } else {
            stmt.then().accept(*this);
        }
    }

    void visit(UGate& gate) {
        gate.theta().accept(*this);
        gate.phi().accept(*this);
        gate.lambda().accept(*this);

        check_uniform({gate.arg()}, {BitType::Qubit});
    }
    void visit(CNOTGate& gate) {
        check_uniform({gate.ctrl(), gate.tgt()},
                      {BitType::Qubit, BitType::Qubit});
    }
    void visit(BarrierGate& gate) {
        std::vector<std::optional<BitType>> types(gate.args().size(),
                                                  std::nullopt);
        check_uniform(gate.args(), types);
    }
    void visit(DeclaredGate& gate) {
        auto entry = lookup_gate(gate.name());

        if (!entry) {
            std::cerr << gate.pos() << ": Gate \"" << gate.name()
                      << "\" undeclared\n";
            error_ = true;
        } else {
            auto ty = *entry;
            if (ty.num_c_params != gate.num_cargs()) {
                std::cerr << gate.pos() << ": Gate \"" << gate.name()
                          << "\" expects " << ty.num_c_params;
                std::cerr << " classical arguments, got " << gate.num_cargs()
                          << "\n";
                error_ = true;
            } else if (ty.num_q_params != gate.num_qargs()) {
                std::cerr << gate.pos() << ": Gate \"" << gate.name()
                          << "\" expects " << ty.num_q_params;
                std::cerr << " quantum arguments, got " << gate.num_qargs()
                          << "\n";
                error_ = true;
            } else {
                gate.foreach_carg([this](Expr& expr) { expr.accept(*this); });

                std::vector<std::optional<BitType>> types(ty.num_q_params,
                                                          BitType::Qubit);
                check_uniform(gate.qargs(), types);
            }
        }
    }

    void visit(GateDecl& decl) {
        if (lookup_gate(decl.id())) {
            std::cerr << decl.pos() << ": Gate \"" << decl.id()
                      << "\" previously declared\n";
            error_ = true;
        } else {
            // Check the body
            push_scope();
            for (const ast::symbol& param : decl.c_params()) {
                set(param, RealType{});
            }
            for (const ast::symbol& param : decl.q_params()) {
                set(param, BitType::Qubit);
            }

            decl.foreach_stmt([this](Gate& gate) { gate.accept(*this); });

            pop_scope();

            // Add declaration
            set_gate(decl.id(), GateType{(int) decl.c_params().size(),
                                         (int) decl.q_params().size()});
        }
    }
    void visit(OracleDecl& decl) {
        if (lookup(decl.id())) {
            std::cerr << decl.pos() << ": Identifier \"" << decl.id()
                      << "\" previously declared\n";
            error_ = true;
        } else {
            set_gate(decl.id(), GateType{0, (int) decl.params().size()});
        }
    }
    void visit(RegisterDecl& decl) {
        if (lookup(decl.id())) {
            std::cerr << decl.pos() << ": Identifier \"" << decl.id()
                      << "\" previously declared\n";
            error_ = true;
        } else if (decl.size() < 0) {
            std::cerr << decl.pos()
                      << ": Registers must have non-negative size\n";
            error_ = true;
        } else {
            set(decl.id(),
                RegisterType{decl.is_quantum() ? BitType::Qubit : BitType::Cbit,
                             decl.size()});
        }
    }
    void visit(AncillaDecl& decl) {
        if (lookup(decl.id())) {
            std::cerr << decl.pos() << ": Identifier \"" << decl.id()
                      << "\" previously declared\n";
            error_ = true;
        } else if (decl.size() < 0) {
            std::cerr << decl.pos()
                      << ": Registers must have non-negative size\n";
            error_ = true;
        } else {
            set(decl.id(), RegisterType{BitType::Qubit, decl.size()});
        }
    }

    void visit(Program& prog) {
        push_scope();

        prog.foreach_stmt([this](Stmt& stmt) { stmt.accept(*this); });

        pop_scope();
    }

  private:
    bool error_ = false; ///< whether errors have occurred
    std::unordered_map<ast::symbol, GateType>
        gate_decls_{}; ///< global gate declarations
    std::list<std::unordered_map<ast::symbol, Type>> symbol_table_{
        {}}; ///< a stack of symbol tables

    /**
     * \brief Enters a new scope
     */
    void push_scope() { symbol_table_.push_front({}); }

    /**
     * \brief Exits the current scope
     */
    void pop_scope() { symbol_table_.pop_front(); }

    /**
     * \brief Looks up a symbol in the symbol table
     *
     * Lookup checks in each symbol table going backwards up the enclosing
     * scopes. Does not look in the global gate scope.
     *
     * \param id Const reference to a symbol
     * \return The type of the symbol, if found
     */
    std::optional<Type> lookup(const ast::symbol& id) {
        for (auto& table : symbol_table_) {
            if (auto it = table.find(id); it != table.end()) {
                return it->second;
            }
        }
        return std::nullopt;
    }

    /**
     * \brief Assigns a symbol in the current scope
     *
     * \param id Const reference to a symbol
     * \param typ The type of the symbol
     */
    void set(const ast::symbol& id, Type typ) {
        if (symbol_table_.empty())
            throw std::logic_error("No current symbol table!");

        symbol_table_.front()[id] = typ;
    }

    /**
     * \brief Looks up a symbol in the gate table
     *
     * \param id Const reference to a symbol
     * \return The gate type of the symbol, if found
     */
    std::optional<GateType> lookup_gate(const ast::symbol& id) {
        if (auto it = gate_decls_.find(id); it != gate_decls_.end()) {
            return it->second;
        }
        return std::nullopt;
    }

    /**
     * \brief Assigns a symbol in the global gate scope
     *
     * \param id Const reference to a symbol
     * \param typ The gate type
     */
    void set_gate(const ast::symbol& id, GateType typ) {
        gate_decls_[id] = typ;
    }

    /**
     * \brief Checks a vector of bit accesses
     *
     * Given a vector of variable access and a vector of optional bit types,
     * checks that each variable access is well-formed, is of the correct type
     * if its type is specific, that all **register** accesses are of the
     * same length, and that no bit is used multiple times.
     *
     * For instance,
     *     qreg q[2];
     *     qreg r[2];
     *     CX q,r;
     * will pass the check, while
     *     qreg q[2];
     *     qreg r[1];
     *     CX q,r;
     * will not.
     *
     * \param args Const reference to a vector of arguments
     * \param types Const reference to a vector of optional bit types
     * \note Sets the error flag if an error is found
     */
    void check_uniform(const std::vector<VarAccess>& args,
                       const std::vector<std::optional<BitType>>& types) {
        int mapping_size = -1;
        std::set<VarAccess> seen;

        for (std::size_t i = 0; i < args.size(); i++) {
            auto entry = lookup(args[i].var());

            if (!entry) {
                std::cerr << args[i].pos() << ": Identifier \"" << args[i].var()
                          << "\" undeclared\n";
                error_ = true;
            } else if (std::holds_alternative<BitType>(*entry)) {
                auto ty = std::get<BitType>(*entry);

                // Check that the bit is not a dereference
                if (args[i].offset()) {
                    std::cerr << args[i].pos()
                              << ": Illegal dereference of non-register type\n";
                    error_ = true;
                }

                // Check that it's compatible with the type list
                if (types[i] && ty != *(types[i])) {
                    std::cerr << args[i].pos() << ": Argument " << args[i]
                              << " has incorrect type\n";
                    error_ = true;
                }

                // Check that the bit hasn't been used previously
                if (seen.find(args[i]) != seen.end()) {
                    std::cerr << args[i].pos() << ": Repeated argument "
                              << args[i] << "\n";
                    error_ = true;
                }
            } else if (std::holds_alternative<RegisterType>(*entry) &&
                       args[i].offset()) {
                auto ty = std::get<RegisterType>(*entry);

                // Check that it's within bounds
                if (0 > *(args[i].offset()) ||
                    *(args[i].offset()) >= ty.length) {
                    std::cerr << args[i].pos() << ": Register access "
                              << args[i] << " out of bounds\n";
                    error_ = true;
                }

                // Check if it's compatible with the type list
                if (types[i] && ty.type != *(types[i])) {
                    std::cerr << args[i].pos() << ": Argument " << args[i]
                              << " has incorrect type\n";
                    error_ = true;
                }

                // Check that it hasn't been used previously
                if (seen.find(args[i]) != seen.end() ||
                    seen.find(args[i].root()) != seen.end()) {
                    std::cerr << args[i].pos() << ": Repeated argument "
                              << args[i] << "\n";
                    error_ = true;
                }

            } else if (std::holds_alternative<RegisterType>(*entry)) {
                auto ty = std::get<RegisterType>(*entry);

                // Check that the register length is consistent
                if (mapping_size == -1) {
                    mapping_size = ty.length;
                } else if (mapping_size != ty.length) {
                    std::cerr << args[i].pos() << ": Register " << args[i]
                              << " has incompatible length\n";
                    error_ = true;
                }

                // Check if it's compatible with the type list
                if (types[i] && ty.type != *(types[i])) {
                    std::cerr << args[i].pos() << ": Argument " << args[i]
                              << " has incorrect type\n";
                    error_ = true;
                }

                // Check that it hasn't been used previously
                if (std::any_of(seen.begin(), seen.end(), [&args, &i](auto& v) {
                        return args[i].contains(v);
                    })) {
                    std::cerr << args[i].pos() << ": Repeated argument "
                              << args[i] << "\n";
                    error_ = true;
                }

            } else {
                std::cerr << args[i].pos() << ": Identifier " << args[i]
                          << " is not a bit or register\n";
                error_ = true;
            }

            seen.insert(args[i]);
        }
    }
};

/**
 * \brief Checks a program for semantic errors
 */
inline void check_source(Program& prog) {
    SemanticChecker analysis;
    if (analysis.run(prog))
        throw SemanticError();
}

} // namespace ast
} // namespace qasmtools
<commit_msg>Updated qasmtools<commit_after>/*
 * This file is part of qasmtools.
 *
 * Copyright (c) 2019 - 2021 softwareQ Inc. All rights reserved.
 *
 * MIT License
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/**
 * \file qasmtools/ast/semantic.hpp
 * \brief Semantic analysis for syntax trees
 */

#pragma once

#include "ast.hpp"
#include "visitor.hpp"

#include <algorithm>
#include <cstddef>
#include <set>
#include <unordered_map>

namespace qasmtools {
namespace ast {

/**
 * \class qasmtools::ast::SemanticError
 * \brief Exception class for semantic errors
 */
class SemanticError : public std::exception {
  public:
    SemanticError() noexcept = default;
    ~SemanticError() = default;
    const char* what() const noexcept { return "Error(s) occurred"; }
};

/**
 * \class qasmtools::ast::BitType
 * \brief Enum for types of bits
 */
enum class BitType { Cbit, Qubit };

/**
 * \struct qasmtools::ast::GateType
 * \brief Data struct for gate types
 */
struct GateType {
    int num_c_params;
    int num_q_params;
};

/**
 * \struct qasmtools::ast::RegisterType
 * \brief Data struct for register types
 */
struct RegisterType {
    BitType type;
    int length;
};

/**
 * \struct qasmtools::ast::RealType
 * \brief Empty structure denoting a real type
 */
struct RealType {};

/**
 * \brief OpenQASM types as a std::variant
 *
 * Functional-style syntax trees in C++17 as a simpler alternative
 * to inheritance hierarchy. Support is still lacking for large-scale.
 */
using Type = std::variant<BitType, GateType, RegisterType, RealType>;

/**
 * \class qasmtools::ast::SemanticChecker
 * \brief Implementation of the semantic analysis compiler phase
 * \see qasmtools::ast::Visitor
 *
 * Checks for anything that could cause a run-time error -- notably,
 * type errors, invalid uniform gates, etc. Use the functional
 * interface qasmtools::ast::check_source instead.
 */
class SemanticChecker final : public Visitor {
  public:
    bool run(Program& prog) {
        prog.accept(*this);
        return error_;
    }

    void visit(VarAccess&) {}

    void visit(BExpr& expr) {
        expr.lexp().accept(*this);
        expr.rexp().accept(*this);
    }
    void visit(UExpr& expr) { expr.subexp().accept(*this); }
    void visit(PiExpr&) {}
    void visit(IntExpr&) {}
    void visit(RealExpr&) {}
    void visit(VarExpr& expr) {
        auto entry = lookup(expr.var());

        if (!entry) {
            std::cerr << expr.pos() << ": Identifier \"" << expr.var()
                      << "\" undeclared\n";
            error_ = true;
        } else if (!std::holds_alternative<RealType>(*entry)) {
            std::cerr << expr.pos() << ": Identifier \"" << expr.var();
            std::cerr << "\" does not have numeric type\n";
            error_ = true;
        }
    }

    void visit(MeasureStmt& stmt) {
        check_uniform({stmt.q_arg(), stmt.c_arg()},
                      {BitType::Qubit, BitType::Cbit});
    }
    void visit(ResetStmt& stmt) {
        check_uniform({stmt.arg()}, {BitType::Qubit});
    }
    void visit(IfStmt& stmt) {
        auto entry = lookup(stmt.var());

        if (!entry) {
            std::cerr << stmt.pos() << ": Identifier \"" << stmt.var()
                      << "\" undeclared\n";
            error_ = true;
        } else if (!std::holds_alternative<RegisterType>(*entry) ||
                   !(std::get<RegisterType>(*entry).type == BitType::Cbit)) {
            std::cerr << stmt.pos() << ": Identifier \"" << stmt.var();
            std::cerr << "\" does not have classical register type\n";
            error_ = true;
        } else {
            stmt.then().accept(*this);
        }
    }

    void visit(UGate& gate) {
        gate.theta().accept(*this);
        gate.phi().accept(*this);
        gate.lambda().accept(*this);

        check_uniform({gate.arg()}, {BitType::Qubit});
    }
    void visit(CNOTGate& gate) {
        check_uniform({gate.ctrl(), gate.tgt()},
                      {BitType::Qubit, BitType::Qubit});
    }
    void visit(BarrierGate& gate) {
        std::vector<std::optional<BitType>> types(gate.args().size(),
                                                  std::nullopt);
        check_uniform(gate.args(), types);
    }
    void visit(DeclaredGate& gate) {
        auto entry = lookup(gate.name());

        if (!entry) {
            std::cerr << gate.pos() << ": Gate \"" << gate.name()
                      << "\" undeclared\n";
            error_ = true;
        } else if (std::holds_alternative<GateType>(*entry)) {
            auto ty = std::get<GateType>(*entry);
            if (ty.num_c_params != gate.num_cargs()) {
                std::cerr << gate.pos() << ": Gate \"" << gate.name()
                          << "\" expects " << ty.num_c_params;
                std::cerr << " classical arguments, got " << gate.num_cargs()
                          << "\n";
                error_ = true;
            } else if (ty.num_q_params != gate.num_qargs()) {
                std::cerr << gate.pos() << ": Gate \"" << gate.name()
                          << "\" expects " << ty.num_q_params;
                std::cerr << " quantum arguments, got " << gate.num_qargs()
                          << "\n";
                error_ = true;
            } else {
                gate.foreach_carg([this](Expr& expr) { expr.accept(*this); });

                std::vector<std::optional<BitType>> types(ty.num_q_params,
                                                          BitType::Qubit);
                check_uniform(gate.qargs(), types);
            }
        } else {
            std::cerr << gate.pos() << ": Identifier \"" << gate.name()
                      << "\" is not a gate\n";
            error_ = true;
        }
    }

    void visit(GateDecl& decl) {
        if (lookup_local(decl.id())) {
            std::cerr << decl.pos() << ": Identifier \"" << decl.id()
                      << "\" previously declared\n";
            error_ = true;
        } else {
            // Check the body
            push_scope();
            for (const ast::symbol& param : decl.c_params()) {
                set(param, RealType{});
            }
            for (const ast::symbol& param : decl.q_params()) {
                set(param, BitType::Qubit);
            }

            decl.foreach_stmt([this](Gate& gate) { gate.accept(*this); });

            pop_scope();

            // Add declaration
            set(decl.id(), GateType{(int) decl.c_params().size(),
                                    (int) decl.q_params().size()});
        }
    }
    void visit(OracleDecl& decl) {
        if (lookup_local(decl.id())) {
            std::cerr << decl.pos() << ": Identifier \"" << decl.id()
                      << "\" previously declared\n";
            error_ = true;
        } else {
            set(decl.id(), GateType{0, (int) decl.params().size()});
        }
    }
    void visit(RegisterDecl& decl) {
        if (lookup_local(decl.id())) {
            std::cerr << decl.pos() << ": Identifier \"" << decl.id()
                      << "\" previously declared\n";
            error_ = true;
        } else if (decl.size() < 0) {
            std::cerr << decl.pos()
                      << ": Registers must have non-negative size\n";
            error_ = true;
        } else {
            set(decl.id(),
                RegisterType{decl.is_quantum() ? BitType::Qubit : BitType::Cbit,
                             decl.size()});
        }
    }
    void visit(AncillaDecl& decl) {
        if (lookup_local(decl.id())) {
            std::cerr << decl.pos() << ": Identifier \"" << decl.id()
                      << "\" previously declared\n";
            error_ = true;
        } else if (decl.size() < 0) {
            std::cerr << decl.pos()
                      << ": Registers must have non-negative size\n";
            error_ = true;
        } else {
            set(decl.id(), RegisterType{BitType::Qubit, decl.size()});
        }
    }

    void visit(Program& prog) {
        push_scope();

        prog.foreach_stmt([this](Stmt& stmt) { stmt.accept(*this); });

        pop_scope();
    }

  private:
    bool error_ = false; ///< whether errors have occurred
    std::list<std::unordered_map<ast::symbol, Type>> symbol_table_{
        {}}; ///< a stack of symbol tables

    /**
     * \brief Enters a new scope
     */
    void push_scope() { symbol_table_.push_front({}); }

    /**
     * \brief Exits the current scope
     */
    void pop_scope() { symbol_table_.pop_front(); }

    /**
     * \brief Looks up a symbol in the symbol table
     *
     * Lookup checks in each symbol table going backwards up the enclosing
     * scopes.
     *
     * \param id Const reference to a symbol
     * \return The type of the symbol, if found
     */
    std::optional<Type> lookup(const ast::symbol& id) {
        for (auto& table : symbol_table_) {
            if (auto it = table.find(id); it != table.end()) {
                return it->second;
            }
        }
        return std::nullopt;
    }

    /**
     * \brief Looks up a symbol in the local scope.
     *
     * \param id Const reference to a symbol
     * \return The type of the symbol, if found
     */
    std::optional<Type> lookup_local(const ast::symbol& id) {
        if (!(symbol_table_.empty())) {
            const auto& local = symbol_table_.front();
            if (auto it = local.find(id); it != local.end()) {
                return it->second;
            }
        }
        return std::nullopt;
    }

    /**
     * \brief Assigns a symbol in the current scope
     *
     * \param id Const reference to a symbol
     * \param typ The type of the symbol
     */
    void set(const ast::symbol& id, Type typ) {
        if (symbol_table_.empty())
            throw std::logic_error("No current symbol table!");

        symbol_table_.front()[id] = typ;
    }

    /**
     * \brief Checks a vector of bit accesses
     *
     * Given a vector of variable access and a vector of optional bit types,
     * checks that each variable access is well-formed, is of the correct type
     * if its type is specific, that all **register** accesses are of the
     * same length, and that no bit is used multiple times.
     *
     * For instance,
     *     qreg q[2];
     *     qreg r[2];
     *     CX q,r;
     * will pass the check, while
     *     qreg q[2];
     *     qreg r[1];
     *     CX q,r;
     * will not.
     *
     * \param args Const reference to a vector of arguments
     * \param types Const reference to a vector of optional bit types
     * \note Sets the error flag if an error is found
     */
    void check_uniform(const std::vector<VarAccess>& args,
                       const std::vector<std::optional<BitType>>& types) {
        int mapping_size = -1;
        std::set<VarAccess> seen;

        for (std::size_t i = 0; i < args.size(); i++) {
            auto entry = lookup(args[i].var());

            if (!entry) {
                std::cerr << args[i].pos() << ": Identifier \"" << args[i].var()
                          << "\" undeclared\n";
                error_ = true;
            } else if (std::holds_alternative<BitType>(*entry)) {
                auto ty = std::get<BitType>(*entry);

                // Check that the bit is not a dereference
                if (args[i].offset()) {
                    std::cerr << args[i].pos()
                              << ": Illegal dereference of non-register type\n";
                    error_ = true;
                }

                // Check that it's compatible with the type list
                if (types[i] && ty != *(types[i])) {
                    std::cerr << args[i].pos() << ": Argument " << args[i]
                              << " has incorrect type\n";
                    error_ = true;
                }

                // Check that the bit hasn't been used previously
                if (seen.find(args[i]) != seen.end()) {
                    std::cerr << args[i].pos() << ": Repeated argument "
                              << args[i] << "\n";
                    error_ = true;
                }
            } else if (std::holds_alternative<RegisterType>(*entry) &&
                       args[i].offset()) {
                auto ty = std::get<RegisterType>(*entry);

                // Check that it's within bounds
                if (0 > *(args[i].offset()) ||
                    *(args[i].offset()) >= ty.length) {
                    std::cerr << args[i].pos() << ": Register access "
                              << args[i] << " out of bounds\n";
                    error_ = true;
                }

                // Check if it's compatible with the type list
                if (types[i] && ty.type != *(types[i])) {
                    std::cerr << args[i].pos() << ": Argument " << args[i]
                              << " has incorrect type\n";
                    error_ = true;
                }

                // Check that it hasn't been used previously
                if (seen.find(args[i]) != seen.end() ||
                    seen.find(args[i].root()) != seen.end()) {
                    std::cerr << args[i].pos() << ": Repeated argument "
                              << args[i] << "\n";
                    error_ = true;
                }

            } else if (std::holds_alternative<RegisterType>(*entry)) {
                auto ty = std::get<RegisterType>(*entry);

                // Check that the register length is consistent
                if (mapping_size == -1) {
                    mapping_size = ty.length;
                } else if (mapping_size != ty.length) {
                    std::cerr << args[i].pos() << ": Register " << args[i]
                              << " has incompatible length\n";
                    error_ = true;
                }

                // Check if it's compatible with the type list
                if (types[i] && ty.type != *(types[i])) {
                    std::cerr << args[i].pos() << ": Argument " << args[i]
                              << " has incorrect type\n";
                    error_ = true;
                }

                // Check that it hasn't been used previously
                if (std::any_of(seen.begin(), seen.end(), [&args, &i](auto& v) {
                        return args[i].contains(v);
                    })) {
                    std::cerr << args[i].pos() << ": Repeated argument "
                              << args[i] << "\n";
                    error_ = true;
                }

            } else {
                std::cerr << args[i].pos() << ": Identifier " << args[i]
                          << " is not a bit or register\n";
                error_ = true;
            }

            seen.insert(args[i]);
        }
    }
};

/**
 * \brief Checks a program for semantic errors
 */
inline void check_source(Program& prog) {
    SemanticChecker analysis;
    if (analysis.run(prog))
        throw SemanticError();
}

} // namespace ast
} // namespace qasmtools
<|endoftext|>


<commit_before><commit_msg>Support HiDPI in auto filter (and pivot table) pop-up menu window<commit_after><|endoftext|>


<commit_before>// ======================================================================== //
// Copyright 2009-2016 Intel Corporation                                    //
//                                                                          //
// 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 "Managed.h"
#include "Data.h"
#include "OSPCommon_ispc.h"

namespace ospray {

  /*! \brief destructor */
  ManagedObject::~ManagedObject()
  {
    // it is OK to potentially delete nullptr, nothing bad happens ==> no need to check
    ispc::delete_uniform(ispcEquivalent);
    ispcEquivalent = nullptr;
  }

  /*! \brief commit the object's outstanding changes (i.e. changed parameters etc) */
  void ManagedObject::commit()
  {}

  //! \brief common function to help printf-debugging
  /*! \detailed Every derived class should overrride this! */
  std::string ManagedObject::toString() const
  {
    return "ospray::ManagedObject";
  }

  //! \brief register a new listener for given object
  /*! \detailed this object will now get update notifications from us */
  void ManagedObject::registerListener(ManagedObject *newListener)
  {
    objectsListeningForChanges.insert(newListener);
  }

  //! \brief un-register a listener
  /*! \detailed this object will no longer get update notifications from us  */
  void ManagedObject::unregisterListener(ManagedObject *noLongerListening)
  {
    objectsListeningForChanges.erase(noLongerListening);
  }

  /*! \brief gets called whenever any of this node's dependencies got changed */
  void ManagedObject::dependencyGotChanged(ManagedObject *object)
  {
    UNUSED(object);
  }

  void ManagedObject::Param::set(ManagedObject *object)
  {
    Assert2(this,"trying to set null parameter");
    clear();
    if (object) object->refInc();
    ptr  = object;
    type = OSP_OBJECT;
  }

  void ManagedObject::Param::set(const char *str)
  {
    Assert2(this,"trying to set null parameter");
    clear();
    new(&s) std::string;
    s = strdup(str);
    type = OSP_STRING;
  }

  void ManagedObject::Param::set(void *ptr)
  {
    Assert2(this,"trying to set null parameter");
    clear();
    (void*&)this->ptr = ptr;
    type = OSP_VOID_PTR;
  }

  void ManagedObject::Param::clear()
  {
    Assert2(this,"trying to clear null parameter");
    if (type == OSP_OBJECT && ptr)
      ptr->refDec();
    if (type == OSP_STRING)
      s.clear();
    type = OSP_OBJECT;
    ptr  = nullptr;
  }

  ManagedObject::Param::Param(const char *_name)
    : ptr(nullptr), type(OSP_FLOAT), name(strdup(_name))
  {
    Assert(_name);
  }

  void *ManagedObject::getVoidPtr(const char *name, void *valIfNotFound)
  {
    Param *param = findParam(name);
    if (!param) return valIfNotFound;
    if (param->type != OSP_VOID_PTR) return valIfNotFound;
    return (void*)param->ptr;
  }

  ManagedObject::Param *ManagedObject::findParam(const char *name,
                                                 bool addIfNotExist)
  {
    auto foundParam =
        std::find_if(paramList.begin(), paramList.end(),
          [&](const std::shared_ptr<Param> &p) {
            return p->name == name;
          });

    if (foundParam != paramList.end())
      return foundParam->get();
    else if (addIfNotExist) {
      paramList.push_back(std::make_shared<Param>(name));
      return paramList[paramList.size()-1].get();
    }
    else
      return nullptr;
  }

#define define_getparam(T,ABB,TARGETTYPE,FIELD)                     \
  T ManagedObject::getParam##ABB(const char *name, T valIfNotFound) \
  {                                                                 \
    Param *param = findParam(name);                                 \
    if (!param) return valIfNotFound;                               \
    if (param->type != TARGETTYPE) return valIfNotFound;            \
    return (T&)param->FIELD;                                        \
  }

  define_getparam(ManagedObject *, Object, OSP_OBJECT, ptr)
  define_getparam(int32,  1i, OSP_INT,    _int)
  define_getparam(vec3i,  3i, OSP_INT3,   _vec3i)
  define_getparam(vec3f,  3f, OSP_FLOAT3, _vec3f)
  define_getparam(vec3fa, 3f, OSP_FLOAT3, _vec3fa)
  define_getparam(vec4f,  4f, OSP_FLOAT4, _vec4f)
  define_getparam(vec2f,  2f, OSP_FLOAT2, _vec2f)
  define_getparam(float,  1f, OSP_FLOAT,  _float)
  define_getparam(float,  f,  OSP_FLOAT,  _float)

#undef define_getparam

  const char *ManagedObject::getParamString(const char *name,
                                            const char *valIfNotFound)
  {
    Param *param = findParam(name);
    if (!param) return valIfNotFound;
    if (param->type != OSP_STRING) return valIfNotFound;
    return param->s.c_str();
  }

  void ManagedObject::removeParam(const char *name)
  {
    auto foundParam =
        std::find_if(paramList.begin(), paramList.end(),
          [&](const std::shared_ptr<Param> &p) {
            return p->name == name;
          });

    if (foundParam != paramList.end()) {
      paramList.erase(foundParam);
    }
  }

  void ManagedObject::notifyListenersThatObjectGotChanged()
  {
    for (auto *object : objectsListeningForChanges)
      object->dependencyGotChanged(this);
  }

  void ManagedObject::emitMessage(const std::string &kind,
                                  const std::string &message) const
  {
    std::cerr << "  " + toString()
              << "  " + kind + ": " + message + "." << std::endl;
  }

  void ManagedObject::exitOnCondition(bool condition,
                                      const std::string &message) const
  {
    if (!condition)
      return;
    emitMessage("ERROR", message);
    exit(1);
  }

  void ManagedObject::warnOnCondition(bool condition,
                                      const std::string &message) const
  {
    if (!condition)
      return;

    emitMessage("WARNING", message);
  }

} // ::ospray
<commit_msg>fix typo OSP_FLOAT3-->OSP_FLOAT3A<commit_after>// ======================================================================== //
// Copyright 2009-2016 Intel Corporation                                    //
//                                                                          //
// 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 "Managed.h"
#include "Data.h"
#include "OSPCommon_ispc.h"

namespace ospray {

  /*! \brief destructor */
  ManagedObject::~ManagedObject()
  {
    // it is OK to potentially delete nullptr, nothing bad happens ==> no need to check
    ispc::delete_uniform(ispcEquivalent);
    ispcEquivalent = nullptr;
  }

  /*! \brief commit the object's outstanding changes (i.e. changed parameters etc) */
  void ManagedObject::commit()
  {}

  //! \brief common function to help printf-debugging
  /*! \detailed Every derived class should overrride this! */
  std::string ManagedObject::toString() const
  {
    return "ospray::ManagedObject";
  }

  //! \brief register a new listener for given object
  /*! \detailed this object will now get update notifications from us */
  void ManagedObject::registerListener(ManagedObject *newListener)
  {
    objectsListeningForChanges.insert(newListener);
  }

  //! \brief un-register a listener
  /*! \detailed this object will no longer get update notifications from us  */
  void ManagedObject::unregisterListener(ManagedObject *noLongerListening)
  {
    objectsListeningForChanges.erase(noLongerListening);
  }

  /*! \brief gets called whenever any of this node's dependencies got changed */
  void ManagedObject::dependencyGotChanged(ManagedObject *object)
  {
    UNUSED(object);
  }

  void ManagedObject::Param::set(ManagedObject *object)
  {
    Assert2(this,"trying to set null parameter");
    clear();
    if (object) object->refInc();
    ptr  = object;
    type = OSP_OBJECT;
  }

  void ManagedObject::Param::set(const char *str)
  {
    Assert2(this,"trying to set null parameter");
    clear();
    new(&s) std::string;
    s = strdup(str);
    type = OSP_STRING;
  }

  void ManagedObject::Param::set(void *ptr)
  {
    Assert2(this,"trying to set null parameter");
    clear();
    (void*&)this->ptr = ptr;
    type = OSP_VOID_PTR;
  }

  void ManagedObject::Param::clear()
  {
    Assert2(this,"trying to clear null parameter");
    if (type == OSP_OBJECT && ptr)
      ptr->refDec();
    if (type == OSP_STRING)
      s.clear();
    type = OSP_OBJECT;
    ptr  = nullptr;
  }

  ManagedObject::Param::Param(const char *_name)
    : ptr(nullptr), type(OSP_FLOAT), name(strdup(_name))
  {
    Assert(_name);
  }

  void *ManagedObject::getVoidPtr(const char *name, void *valIfNotFound)
  {
    Param *param = findParam(name);
    if (!param) return valIfNotFound;
    if (param->type != OSP_VOID_PTR) return valIfNotFound;
    return (void*)param->ptr;
  }

  ManagedObject::Param *ManagedObject::findParam(const char *name,
                                                 bool addIfNotExist)
  {
    auto foundParam =
        std::find_if(paramList.begin(), paramList.end(),
          [&](const std::shared_ptr<Param> &p) {
            return p->name == name;
          });

    if (foundParam != paramList.end())
      return foundParam->get();
    else if (addIfNotExist) {
      paramList.push_back(std::make_shared<Param>(name));
      return paramList[paramList.size()-1].get();
    }
    else
      return nullptr;
  }

#define define_getparam(T,ABB,TARGETTYPE,FIELD)                     \
  T ManagedObject::getParam##ABB(const char *name, T valIfNotFound) \
  {                                                                 \
    Param *param = findParam(name);                                 \
    if (!param) return valIfNotFound;                               \
    if (param->type != TARGETTYPE) return valIfNotFound;            \
    return (T&)param->FIELD;                                        \
  }

  define_getparam(ManagedObject *, Object, OSP_OBJECT, ptr)
  define_getparam(int32,  1i, OSP_INT,     _int)
  define_getparam(vec3i,  3i, OSP_INT3,    _vec3i)
  define_getparam(vec3f,  3f, OSP_FLOAT3,  _vec3f)
  define_getparam(vec3fa, 3f, OSP_FLOAT3A, _vec3fa)
  define_getparam(vec4f,  4f, OSP_FLOAT4,  _vec4f)
  define_getparam(vec2f,  2f, OSP_FLOAT2,  _vec2f)
  define_getparam(float,  1f, OSP_FLOAT,   _float)
  define_getparam(float,  f,  OSP_FLOAT,   _float)

#undef define_getparam

  const char *ManagedObject::getParamString(const char *name,
                                            const char *valIfNotFound)
  {
    Param *param = findParam(name);
    if (!param) return valIfNotFound;
    if (param->type != OSP_STRING) return valIfNotFound;
    return param->s.c_str();
  }

  void ManagedObject::removeParam(const char *name)
  {
    auto foundParam =
        std::find_if(paramList.begin(), paramList.end(),
          [&](const std::shared_ptr<Param> &p) {
            return p->name == name;
          });

    if (foundParam != paramList.end()) {
      paramList.erase(foundParam);
    }
  }

  void ManagedObject::notifyListenersThatObjectGotChanged()
  {
    for (auto *object : objectsListeningForChanges)
      object->dependencyGotChanged(this);
  }

  void ManagedObject::emitMessage(const std::string &kind,
                                  const std::string &message) const
  {
    std::cerr << "  " + toString()
              << "  " + kind + ": " + message + "." << std::endl;
  }

  void ManagedObject::exitOnCondition(bool condition,
                                      const std::string &message) const
  {
    if (!condition)
      return;
    emitMessage("ERROR", message);
    exit(1);
  }

  void ManagedObject::warnOnCondition(bool condition,
                                      const std::string &message) const
  {
    if (!condition)
      return;

    emitMessage("WARNING", message);
  }

} // ::ospray
<|endoftext|>


<commit_before>// Copyright (c) 2013 Intel Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/path_service.h"
#include "base/process/launch.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "xwalk/runtime/browser/image_util.h"
#include "xwalk/runtime/browser/runtime.h"
#include "xwalk/runtime/browser/runtime_ui_delegate.h"
#include "xwalk/runtime/common/xwalk_notification_types.h"
#include "xwalk/test/base/in_process_browser_test.h"
#include "xwalk/test/base/xwalk_test_utils.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_utils.h"
#include "net/base/net_util.h"
#include "testing/gmock/include/gmock/gmock.h"

#if defined(USE_AURA)
#include "ui/aura/window.h"
#endif

using xwalk::NativeAppWindow;
using xwalk::Runtime;
using content::NotificationService;
using content::WebContents;
using content::WindowedNotificationObserver;
using testing::_;

class XWalkRuntimeTest : public InProcessBrowserTest {
};

IN_PROC_BROWSER_TEST_F(XWalkRuntimeTest, CreateAndCloseRuntime) {
  size_t len = runtimes().size();
  // Create a new Runtime instance.
  GURL url(test_server()->GetURL("test.html"));
  Runtime* runtime = CreateRuntime(url);
  EXPECT_TRUE(url == runtime->web_contents()->GetURL());
  EXPECT_EQ(len + 1, runtimes().size());

  // Close the newly created Runtime instance.
  runtime->Close();
  content::RunAllPendingInMessageLoop();
  EXPECT_EQ(len, runtimes().size());
}

IN_PROC_BROWSER_TEST_F(XWalkRuntimeTest, LoadURLAndClose) {
  GURL url(test_server()->GetURL("test.html"));
  Runtime* runtime = CreateRuntime(url);
  size_t len = runtimes().size();
  runtime->Close();
  content::RunAllPendingInMessageLoop();
  EXPECT_EQ(len - 1, runtimes().size());
}

IN_PROC_BROWSER_TEST_F(XWalkRuntimeTest, CloseNativeWindow) {
  GURL url(test_server()->GetURL("test.html"));
  Runtime* new_runtime = CreateRuntime(url);
  size_t len = runtimes().size();
  new_runtime->window()->Close();
  content::RunAllPendingInMessageLoop();
  // Closing native window will lead to close Runtime instance.
  EXPECT_EQ(len - 1, runtimes().size());
}

IN_PROC_BROWSER_TEST_F(XWalkRuntimeTest, LaunchWithFullscreenWindow) {
  GURL url(test_server()->GetURL("test.html"));
  NativeAppWindow::CreateParams params;
  params.state = ui::SHOW_STATE_FULLSCREEN;
  Runtime* new_runtime = CreateRuntime(url, params);

  EXPECT_TRUE(new_runtime->window()->IsFullscreen());
}

IN_PROC_BROWSER_TEST_F(XWalkRuntimeTest, HTML5FullscreenAPI) {
  GURL url = xwalk_test_utils::GetTestURL(
      base::FilePath(), base::FilePath().AppendASCII("fullscreen.html"));
  Runtime* runtime = CreateRuntime(url);
  EXPECT_TRUE(false == runtime->window()->IsFullscreen());

  WindowedNotificationObserver enter_observer(
     xwalk::NOTIFICATION_FULLSCREEN_CHANGED,
     NotificationService::AllSources());

  bool ret = content::ExecuteScript(
      runtime->web_contents(), "doFullscreenClick();");
  EXPECT_TRUE(ret);
  content::RunAllPendingInMessageLoop();
  enter_observer.Wait();
  // Calling doFullscreenClick defined in fullscreen.html leads to enter into
  // fullscreen window state, so it's expected to be fullscreen.
  EXPECT_TRUE(true == runtime->window()->IsFullscreen());

  WindowedNotificationObserver exit_observer(
     xwalk::NOTIFICATION_FULLSCREEN_CHANGED,
     NotificationService::AllSources());

  ret = content::ExecuteScript(
      runtime->web_contents(), "doExitFullscreenClick();");
  EXPECT_TRUE(ret);
  content::RunAllPendingInMessageLoop();
  exit_observer.Wait();
  // Calling doExitFullscreenClick defined in fullscreen.html leads to exit
  // fullscreen window state, so it's expected to be not fullscreen.
  EXPECT_TRUE(false == runtime->window()->IsFullscreen());
}

#if !defined(OS_MACOSX)
IN_PROC_BROWSER_TEST_F(XWalkRuntimeTest, GetWindowTitle) {
  GURL url = xwalk_test_utils::GetTestURL(
      base::FilePath(), base::FilePath().AppendASCII("title.html"));
  base::string16 title = base::ASCIIToUTF16("Dummy Title");
  Runtime* runtime = CreateRuntime();
  content::TitleWatcher title_watcher(runtime->web_contents(), title);
  xwalk_test_utils::NavigateToURL(runtime, url);
  EXPECT_EQ(title, title_watcher.WaitAndGetTitle());

  NativeAppWindow* window = runtime->window();
  base::string16 window_title = window->GetNativeWindow()->title();
  EXPECT_EQ(title, window_title);
}
#endif

IN_PROC_BROWSER_TEST_F(XWalkRuntimeTest, OpenLinkInNewRuntime) {
  GURL url = xwalk_test_utils::GetTestURL(
      base::FilePath(), base::FilePath().AppendASCII("new_target.html"));
  Runtime* runtime = CreateRuntime(url);
  size_t len = runtimes().size();
  bool ret = content::ExecuteScript(runtime->web_contents(), "doClick();");
  EXPECT_TRUE(ret);
  content::RunAllPendingInMessageLoop();
  // Calling doClick defined in new_target.html leads to open a href in a new
  // target window, and so it is expected to create a new Runtime instance.
  EXPECT_EQ(len + 1, runtimes().size());
  Runtime* second = runtimes().back();
  EXPECT_TRUE(NULL != second);
  EXPECT_NE(runtime, second);
}

<commit_msg>xwalk_browsertest: Port to embedded_test_server.<commit_after>// Copyright (c) 2013 Intel Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/path_service.h"
#include "base/process/launch.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "xwalk/runtime/browser/image_util.h"
#include "xwalk/runtime/browser/runtime.h"
#include "xwalk/runtime/browser/runtime_ui_delegate.h"
#include "xwalk/runtime/common/xwalk_notification_types.h"
#include "xwalk/test/base/in_process_browser_test.h"
#include "xwalk/test/base/xwalk_test_utils.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_utils.h"
#include "net/base/net_util.h"
#include "testing/gmock/include/gmock/gmock.h"

#if defined(USE_AURA)
#include "ui/aura/window.h"
#endif

using xwalk::NativeAppWindow;
using xwalk::Runtime;
using content::NotificationService;
using content::WebContents;
using content::WindowedNotificationObserver;
using testing::_;

class XWalkRuntimeTest : public InProcessBrowserTest {
 protected:
  void SetUp() override {
    ASSERT_TRUE(embedded_test_server()->Start());
    InProcessBrowserTest::SetUp();
  }
};

IN_PROC_BROWSER_TEST_F(XWalkRuntimeTest, CreateAndCloseRuntime) {
  size_t len = runtimes().size();
  // Create a new Runtime instance.
  GURL url(embedded_test_server()->GetURL("/test.html"));
  Runtime* runtime = CreateRuntime(url);
  EXPECT_TRUE(url == runtime->web_contents()->GetURL());
  EXPECT_EQ(len + 1, runtimes().size());

  // Close the newly created Runtime instance.
  runtime->Close();
  content::RunAllPendingInMessageLoop();
  EXPECT_EQ(len, runtimes().size());
}

IN_PROC_BROWSER_TEST_F(XWalkRuntimeTest, LoadURLAndClose) {
  GURL url(embedded_test_server()->GetURL("/test.html"));
  Runtime* runtime = CreateRuntime(url);
  size_t len = runtimes().size();
  runtime->Close();
  content::RunAllPendingInMessageLoop();
  EXPECT_EQ(len - 1, runtimes().size());
}

IN_PROC_BROWSER_TEST_F(XWalkRuntimeTest, CloseNativeWindow) {
  GURL url(embedded_test_server()->GetURL("/test.html"));
  Runtime* new_runtime = CreateRuntime(url);
  size_t len = runtimes().size();
  new_runtime->window()->Close();
  content::RunAllPendingInMessageLoop();
  // Closing native window will lead to close Runtime instance.
  EXPECT_EQ(len - 1, runtimes().size());
}

IN_PROC_BROWSER_TEST_F(XWalkRuntimeTest, LaunchWithFullscreenWindow) {
  GURL url(embedded_test_server()->GetURL("/test.html"));
  NativeAppWindow::CreateParams params;
  params.state = ui::SHOW_STATE_FULLSCREEN;
  Runtime* new_runtime = CreateRuntime(url, params);

  EXPECT_TRUE(new_runtime->window()->IsFullscreen());
}

IN_PROC_BROWSER_TEST_F(XWalkRuntimeTest, HTML5FullscreenAPI) {
  GURL url = xwalk_test_utils::GetTestURL(
      base::FilePath(), base::FilePath().AppendASCII("fullscreen.html"));
  Runtime* runtime = CreateRuntime(url);
  EXPECT_TRUE(false == runtime->window()->IsFullscreen());

  WindowedNotificationObserver enter_observer(
     xwalk::NOTIFICATION_FULLSCREEN_CHANGED,
     NotificationService::AllSources());

  bool ret = content::ExecuteScript(
      runtime->web_contents(), "doFullscreenClick();");
  EXPECT_TRUE(ret);
  content::RunAllPendingInMessageLoop();
  enter_observer.Wait();
  // Calling doFullscreenClick defined in fullscreen.html leads to enter into
  // fullscreen window state, so it's expected to be fullscreen.
  EXPECT_TRUE(true == runtime->window()->IsFullscreen());

  WindowedNotificationObserver exit_observer(
     xwalk::NOTIFICATION_FULLSCREEN_CHANGED,
     NotificationService::AllSources());

  ret = content::ExecuteScript(
      runtime->web_contents(), "doExitFullscreenClick();");
  EXPECT_TRUE(ret);
  content::RunAllPendingInMessageLoop();
  exit_observer.Wait();
  // Calling doExitFullscreenClick defined in fullscreen.html leads to exit
  // fullscreen window state, so it's expected to be not fullscreen.
  EXPECT_TRUE(false == runtime->window()->IsFullscreen());
}

#if !defined(OS_MACOSX)
IN_PROC_BROWSER_TEST_F(XWalkRuntimeTest, GetWindowTitle) {
  GURL url = xwalk_test_utils::GetTestURL(
      base::FilePath(), base::FilePath().AppendASCII("title.html"));
  base::string16 title = base::ASCIIToUTF16("Dummy Title");
  Runtime* runtime = CreateRuntime();
  content::TitleWatcher title_watcher(runtime->web_contents(), title);
  xwalk_test_utils::NavigateToURL(runtime, url);
  EXPECT_EQ(title, title_watcher.WaitAndGetTitle());

  NativeAppWindow* window = runtime->window();
  base::string16 window_title = window->GetNativeWindow()->title();
  EXPECT_EQ(title, window_title);
}
#endif

IN_PROC_BROWSER_TEST_F(XWalkRuntimeTest, OpenLinkInNewRuntime) {
  GURL url = xwalk_test_utils::GetTestURL(
      base::FilePath(), base::FilePath().AppendASCII("new_target.html"));
  Runtime* runtime = CreateRuntime(url);
  size_t len = runtimes().size();
  bool ret = content::ExecuteScript(runtime->web_contents(), "doClick();");
  EXPECT_TRUE(ret);
  content::RunAllPendingInMessageLoop();
  // Calling doClick defined in new_target.html leads to open a href in a new
  // target window, and so it is expected to create a new Runtime instance.
  EXPECT_EQ(len + 1, runtimes().size());
  Runtime* second = runtimes().back();
  EXPECT_TRUE(NULL != second);
  EXPECT_NE(runtime, second);
}

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: test_oustring_compare.cxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 15:50:37 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 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
 *
 ************************************************************************/

#include "cppunit/simpleheader.hxx"
#include "rtl/string.h"
#include "rtl/ustring.hxx"

namespace test { namespace oustring {

class Compare: public CppUnit::TestFixture
{
private:
    void equalsIgnoreAsciiCaseAscii();

    CPPUNIT_TEST_SUITE(Compare);
    CPPUNIT_TEST(equalsIgnoreAsciiCaseAscii);
    CPPUNIT_TEST_SUITE_END();
};

} }

CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(test::oustring::Compare, "alltest");

void test::oustring::Compare::equalsIgnoreAsciiCaseAscii()
{
    CPPUNIT_ASSERT(!rtl::OUString().equalsIgnoreAsciiCaseAscii("abc"));
    CPPUNIT_ASSERT(!rtl::OUString().equalsIgnoreAsciiCaseAsciiL(
                       RTL_CONSTASCII_STRINGPARAM("abc")));
    CPPUNIT_ASSERT(!rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("abc")).
                   equalsIgnoreAsciiCaseAscii(""));
    CPPUNIT_ASSERT(!rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("abc")).
                   equalsIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM("")));

    CPPUNIT_ASSERT(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("abc")).
                   equalsIgnoreAsciiCaseAscii("abc"));
    CPPUNIT_ASSERT(!rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("abcd")).
                   equalsIgnoreAsciiCaseAscii("abc"));
    CPPUNIT_ASSERT(!rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("abc")).
                   equalsIgnoreAsciiCaseAscii("abcd"));
}
<commit_msg>INTEGRATION: CWS pchfix02 (1.3.140); FILE MERGED 2006/09/01 17:34:13 kaib 1.3.140.1: #i68856# Added header markers and pch files<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: test_oustring_compare.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-17 08:59:46 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 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
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sal.hxx"

#include "cppunit/simpleheader.hxx"
#include "rtl/string.h"
#include "rtl/ustring.hxx"

namespace test { namespace oustring {

class Compare: public CppUnit::TestFixture
{
private:
    void equalsIgnoreAsciiCaseAscii();

    CPPUNIT_TEST_SUITE(Compare);
    CPPUNIT_TEST(equalsIgnoreAsciiCaseAscii);
    CPPUNIT_TEST_SUITE_END();
};

} }

CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(test::oustring::Compare, "alltest");

void test::oustring::Compare::equalsIgnoreAsciiCaseAscii()
{
    CPPUNIT_ASSERT(!rtl::OUString().equalsIgnoreAsciiCaseAscii("abc"));
    CPPUNIT_ASSERT(!rtl::OUString().equalsIgnoreAsciiCaseAsciiL(
                       RTL_CONSTASCII_STRINGPARAM("abc")));
    CPPUNIT_ASSERT(!rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("abc")).
                   equalsIgnoreAsciiCaseAscii(""));
    CPPUNIT_ASSERT(!rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("abc")).
                   equalsIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM("")));

    CPPUNIT_ASSERT(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("abc")).
                   equalsIgnoreAsciiCaseAscii("abc"));
    CPPUNIT_ASSERT(!rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("abcd")).
                   equalsIgnoreAsciiCaseAscii("abc"));
    CPPUNIT_ASSERT(!rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("abc")).
                   equalsIgnoreAsciiCaseAscii("abcd"));
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: DllGetVersion.cpp,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: hr $ $Date: 2006-06-20 04:32:24 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 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
 *
 ************************************************************************/

#define WIN32_LEAN_AND_MEAN
#pragma warning(push,1)
#include <windows.h>
#include <shlwapi.h>
#pragma warning(pop)
#include <malloc.h>

extern HMODULE      UWINAPI_BaseAddress;

// This function should be exported by every DLL that wants to provide it's version number.
// This code automaticly generates the information from the version resource

extern "C" HRESULT CALLBACK DllGetVersion( DLLVERSIONINFO *pdvi )
{
    TCHAR   szModulePath[MAX_PATH];
    BOOL    fSuccess = FALSE;

    if ( UWINAPI_BaseAddress && GetModuleFileName( UWINAPI_BaseAddress, szModulePath, MAX_PATH ) )
    {
        DWORD   dwHandle = 0;
        DWORD   dwSize = GetFileVersionInfoSize( szModulePath, &dwHandle );
        LPVOID  lpData = _alloca( dwSize );

        if ( GetFileVersionInfo( szModulePath, dwHandle, dwSize, lpData ) )
        {
            VS_FIXEDFILEINFO    *lpBuffer = NULL;
            UINT    uLen = 0;

            if ( VerQueryValue( lpData, TEXT("\\"), (LPVOID *)&lpBuffer, &uLen ) )
            {
                pdvi->dwMajorVersion = HIWORD( lpBuffer->dwFileVersionMS );
                pdvi->dwMinorVersion = LOWORD( lpBuffer->dwFileVersionMS );
                pdvi->dwBuildNumber = HIWORD( lpBuffer->dwFileVersionLS );
                pdvi->dwPlatformID = (lpBuffer->dwFileOS & VOS_NT) ? DLLVER_PLATFORM_NT : DLLVER_PLATFORM_WINDOWS;

                fSuccess = TRUE;
            }
        }
    }

    return fSuccess ? HRESULT_FROM_WIN32( GetLastError() ) : HRESULT_FROM_WIN32( NO_ERROR );
}

<commit_msg>INTEGRATION: CWS obo05 (1.4.2); FILE MERGED 2006/06/28 10:29:31 obo 1.4.2.1: #i53711# .net 2005 signed/unsigned warnings<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: DllGetVersion.cpp,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: vg $ $Date: 2006-09-25 13:15:48 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 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
 *
 ************************************************************************/

#define WIN32_LEAN_AND_MEAN
#pragma warning(push,1)
#include <windows.h>
#include <shlwapi.h>
#pragma warning(pop)
#include <malloc.h>

extern HMODULE      UWINAPI_BaseAddress;

// This function should be exported by every DLL that wants to provide it's version number.
// This code automaticly generates the information from the version resource

extern "C" HRESULT CALLBACK DllGetVersion( DLLVERSIONINFO *pdvi )
{
    TCHAR   szModulePath[MAX_PATH];
    BOOL    fSuccess = FALSE;

    if ( UWINAPI_BaseAddress && GetModuleFileName( UWINAPI_BaseAddress, szModulePath, MAX_PATH ) )
    {
        DWORD   dwHandle = 0;
        DWORD   dwSize = GetFileVersionInfoSize( szModulePath, &dwHandle );
        LPVOID  lpData = _alloca( dwSize );

        if ( GetFileVersionInfo( szModulePath, dwHandle, dwSize, lpData ) )
        {
            VS_FIXEDFILEINFO    *lpBuffer = NULL;
            UINT    uLen = 0;

            if ( VerQueryValue( lpData, TEXT("\\"), (LPVOID *)&lpBuffer, &uLen ) )
            {
                pdvi->dwMajorVersion = HIWORD( lpBuffer->dwFileVersionMS );
                pdvi->dwMinorVersion = LOWORD( lpBuffer->dwFileVersionMS );
                pdvi->dwBuildNumber = HIWORD( lpBuffer->dwFileVersionLS );
                pdvi->dwPlatformID = (DWORD) ((lpBuffer->dwFileOS & VOS_NT) ? DLLVER_PLATFORM_NT : DLLVER_PLATFORM_WINDOWS);

                fSuccess = TRUE;
            }
        }
    }

    return fSuccess ? HRESULT_FROM_WIN32( GetLastError() ) : HRESULT_FROM_WIN32( NO_ERROR );
}
<|endoftext|>


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

#include "propertyeditorvalue.h"
#include <abstractview.h>
#include <nodeabstractproperty.h>
#include <nodeproperty.h>
#include <model.h>
#include <nodemetainfo.h>
#include <metainfo.h>
#include <propertymetainfo.h>
#include <nodeproperty.h>
#include <qmlobjectnode.h>

//using namespace QmlDesigner;

PropertyEditorValue::PropertyEditorValue(QObject *parent)
   : QObject(parent),
   m_isInSubState(false),
   m_isInModel(false),
   m_isBound(false),
   m_isValid(false),
   m_complexNode(new PropertyEditorNodeWrapper(this))
{
}

QVariant PropertyEditorValue::value() const
{
    QVariant returnValue = m_value;
    if (modelNode().isValid() && modelNode().metaInfo().isValid() && modelNode().metaInfo().property(name()).isValid())
        if (modelNode().metaInfo().property(name()).type() == QLatin1String("QUrl")) {
        returnValue = returnValue.toUrl().toString();
    }
    return returnValue;
}

static bool cleverDoubleCompare(QVariant value1, QVariant value2)
{ //we ignore slight changes on doubles
    if ((value1.type() == QVariant::Double) && (value2.type() == QVariant::Double)) {
        int a = value1.toDouble() * 100;
        int b = value2.toDouble() * 100;

        if (qFuzzyCompare((qreal(a) / 100), (qreal(b) / 100))) {
            return true;
        }
    }
    return false;
}

void PropertyEditorValue::setValueWithEmit(const QVariant &value)
{
    if ( m_value != value) {
        QVariant newValue = value;
        if (modelNode().isValid() && modelNode().metaInfo().isValid() && modelNode().metaInfo().property(name()).isValid())
            if (modelNode().metaInfo().property(name()).type() == QLatin1String("QUrl")) {
            newValue = QUrl(newValue.toString());
        }

        if (cleverDoubleCompare(newValue, m_value))
            return;
        setValue(newValue);
        m_isBound = false;
        emit valueChanged(name(), value);
        emit isBoundChanged();
    }
}

void PropertyEditorValue::setValue(const QVariant &value)
{
    if ( m_value != value) {
        m_value = value;
    }
    emit valueChanged(QString(), value);
    emit isBoundChanged();
}

QString PropertyEditorValue::expression() const
{

    return m_expression;
}

void PropertyEditorValue::setExpressionWithEmit(const QString &expression)
{
    if ( m_expression != expression) {
        setExpression(expression);
        emit expressionChanged(name());
    }
}

void PropertyEditorValue::setExpression(const QString &expression)
{
    if ( m_expression != expression) {
        m_expression = expression;
        emit expressionChanged(QString());
    }
}

bool PropertyEditorValue::isInSubState() const
{
    const QmlDesigner::QmlObjectNode objectNode(modelNode());
    return objectNode.isValid() && objectNode.propertyAffectedByCurrentState(name());
}

bool PropertyEditorValue::isBound() const
{
    return modelNode().isValid() && modelNode().property(name()).isValid() && modelNode().property(name()).isBindingProperty();
}

bool PropertyEditorValue::isInModel() const
{
    qDebug() << name();
    qDebug() << (modelNode().isValid() && modelNode().hasProperty(name()));
    return modelNode().isValid() && modelNode().hasProperty(name());
}

QString PropertyEditorValue::name() const
{
    return m_name;
}

void PropertyEditorValue::setName(const QString &name)
{
    m_name = name;
}

bool PropertyEditorValue::isValid() const
{
    return m_isValid;
}

void PropertyEditorValue::setIsValid(bool valid)
{
    m_isValid = valid;
}

ModelNode PropertyEditorValue::modelNode() const
{
    return m_modelNode;
}

void PropertyEditorValue::setModelNode(const ModelNode &modelNode)
{
    if (modelNode != m_modelNode) {
        m_modelNode = modelNode;
        m_complexNode->update();
        emit modelNodeChanged();
    }
}

PropertyEditorNodeWrapper* PropertyEditorValue::complexNode()
{
    return m_complexNode;
}

void PropertyEditorValue::resetValue()
{
    if (m_value.isValid()) {
        setValue(QVariant());
        m_isBound = false;
        emit valueChanged(name(), QVariant());
    }
}

void PropertyEditorValue::registerDeclarativeTypes()
{
    qmlRegisterType<PropertyEditorValue>("Bauhaus",1,0,"PropertyEditorValue");
    qmlRegisterType<PropertyEditorNodeWrapper>("Bauhaus",1,0,"PropertyEditorNodeWrapper");
    qmlRegisterType<QDeclarativePropertyMap>("Bauhaus",1,0,"QDeclarativePropertyMap");
}

PropertyEditorNodeWrapper::PropertyEditorNodeWrapper(PropertyEditorValue* parent) : m_valuesPropertyMap(this)
{
    m_editorValue = parent;
    connect(m_editorValue, SIGNAL(modelNodeChanged()), this, SLOT(update()));
}

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

bool PropertyEditorNodeWrapper::exists()
{
    if (!(m_editorValue && m_editorValue->modelNode().isValid()))
        return false;

    return m_modelNode.isValid();
}

QString PropertyEditorNodeWrapper::type()
{
    if (!(m_modelNode.isValid()))
        return QString("");

    return m_modelNode.simplifiedTypeName();

}

ModelNode PropertyEditorNodeWrapper::parentModelNode() const
{
    return  m_editorValue->modelNode();
}

QString PropertyEditorNodeWrapper::propertyName() const
{
    return m_editorValue->name();
}

QDeclarativePropertyMap* PropertyEditorNodeWrapper::properties()
{
    return &m_valuesPropertyMap;
}

void PropertyEditorNodeWrapper::add(const QString &type)
{

    QString propertyType = type;

    if ((m_editorValue && m_editorValue->modelNode().isValid())) {
        if (propertyType.isEmpty())
            propertyType = m_editorValue->modelNode().metaInfo().property(m_editorValue->name()).type();
        while (propertyType.contains('*')) //strip star
            propertyType.chop(1);
        m_modelNode = m_editorValue->modelNode().view()->createModelNode(propertyType, 4, 6);
        m_editorValue->modelNode().nodeAbstractProperty(m_editorValue->name()).reparentHere(m_modelNode);
        if (!m_modelNode.isValid()) {
            qWarning("PropertyEditorNodeWrapper::add failed");
        }
    } else {
        qWarning("PropertyEditorNodeWrapper::add failed - node invalid");
    }
    setup();
}

void PropertyEditorNodeWrapper::remove()
{
    if ((m_editorValue && m_editorValue->modelNode().isValid())) {
        if (QmlDesigner::QmlObjectNode(m_modelNode).isValid())
            QmlDesigner::QmlObjectNode(m_modelNode).destroy();
        m_editorValue->modelNode().removeProperty(m_editorValue->name());
    } else {
        qWarning("PropertyEditorNodeWrapper::remove failed - node invalid");
    }
    m_modelNode = QmlDesigner::ModelNode();

    foreach (const QString &propertyName, m_valuesPropertyMap.keys())
        m_valuesPropertyMap.clear(propertyName);
    foreach (QObject *object, m_valuesPropertyMap.children())
        delete object;
    emit propertiesChanged();
    emit existsChanged();
}

void PropertyEditorNodeWrapper::changeValue(const QString &name)
{
    if (name.isNull())
        return;
    if (m_modelNode.isValid()) {
        QmlDesigner::QmlObjectNode fxObjectNode(m_modelNode);

        PropertyEditorValue *valueObject = qvariant_cast<PropertyEditorValue *>(m_valuesPropertyMap.value(name));

        if (valueObject->value().isValid())
            fxObjectNode.setVariantProperty(name, valueObject->value());
        else
            fxObjectNode.removeVariantProperty(name);
    }
}

void PropertyEditorNodeWrapper::setup()
{
    Q_ASSERT(m_editorValue);
    Q_ASSERT(m_editorValue->modelNode().isValid());
    if ((m_editorValue->modelNode().isValid() && m_modelNode.isValid())) {
        QmlDesigner::QmlObjectNode fxObjectNode(m_modelNode);
        foreach ( const QString &propertyName, m_valuesPropertyMap.keys())
            m_valuesPropertyMap.clear(propertyName);
        foreach (QObject *object, m_valuesPropertyMap.children())
            delete object;

        foreach (const QString &propertyName, m_modelNode.metaInfo().properties().keys()) {
            PropertyEditorValue *valueObject = new PropertyEditorValue(&m_valuesPropertyMap);
            valueObject->setName(propertyName);
            valueObject->setValue(fxObjectNode.instanceValue(propertyName));

            connect(valueObject, SIGNAL(valueChanged(QString, const QVariant&)), &m_valuesPropertyMap, SIGNAL(valueChanged(QString, const QVariant&)));
            m_valuesPropertyMap.insert(propertyName, QVariant::fromValue(valueObject));
        }
    }
    connect(&m_valuesPropertyMap, SIGNAL(valueChanged(const QString &, const QVariant&)), this, SLOT(changeValue(const QString&)));

    emit propertiesChanged();
    emit existsChanged();
}

void PropertyEditorNodeWrapper::update()
{
    if (m_editorValue && m_editorValue->modelNode().isValid()) {
        if (m_editorValue->modelNode().hasProperty(m_editorValue->name()) && m_editorValue->modelNode().property(m_editorValue->name()).isNodeProperty()) {
            m_modelNode = m_editorValue->modelNode().nodeProperty(m_editorValue->name()).modelNode();
        }
        setup();
        emit existsChanged();
        emit typeChanged();
    }
}

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

#include "propertyeditorvalue.h"
#include <abstractview.h>
#include <nodeabstractproperty.h>
#include <nodeproperty.h>
#include <model.h>
#include <nodemetainfo.h>
#include <metainfo.h>
#include <propertymetainfo.h>
#include <nodeproperty.h>
#include <qmlobjectnode.h>

//using namespace QmlDesigner;

PropertyEditorValue::PropertyEditorValue(QObject *parent)
   : QObject(parent),
   m_isInSubState(false),
   m_isInModel(false),
   m_isBound(false),
   m_isValid(false),
   m_complexNode(new PropertyEditorNodeWrapper(this))
{
}

QVariant PropertyEditorValue::value() const
{
    QVariant returnValue = m_value;
    if (modelNode().isValid() && modelNode().metaInfo().isValid() && modelNode().metaInfo().property(name()).isValid())
        if (modelNode().metaInfo().property(name()).type() == QLatin1String("QUrl")) {
        returnValue = returnValue.toUrl().toString();
    }
    return returnValue;
}

static bool cleverDoubleCompare(QVariant value1, QVariant value2)
{ //we ignore slight changes on doubles
    if ((value1.type() == QVariant::Double) && (value2.type() == QVariant::Double)) {
        int a = value1.toDouble() * 100;
        int b = value2.toDouble() * 100;

        if (qFuzzyCompare((qreal(a) / 100), (qreal(b) / 100))) {
            return true;
        }
    }
    return false;
}

void PropertyEditorValue::setValueWithEmit(const QVariant &value)
{
    if ( m_value != value) {
        QVariant newValue = value;
        if (modelNode().isValid() && modelNode().metaInfo().isValid() && modelNode().metaInfo().property(name()).isValid())
            if (modelNode().metaInfo().property(name()).type() == QLatin1String("QUrl")) {
            newValue = QUrl(newValue.toString());
        }

        if (cleverDoubleCompare(newValue, m_value))
            return;
        setValue(newValue);
        m_isBound = false;
        emit valueChanged(name(), value);
        emit isBoundChanged();
    }
}

void PropertyEditorValue::setValue(const QVariant &value)
{
    if ( m_value != value) {
        m_value = value;
    }
    emit valueChanged(QString(), value);
    emit isBoundChanged();
}

QString PropertyEditorValue::expression() const
{

    return m_expression;
}

void PropertyEditorValue::setExpressionWithEmit(const QString &expression)
{
    if ( m_expression != expression) {
        setExpression(expression);
        emit expressionChanged(name());
    }
}

void PropertyEditorValue::setExpression(const QString &expression)
{
    if ( m_expression != expression) {
        m_expression = expression;
        emit expressionChanged(QString());
    }
}

bool PropertyEditorValue::isInSubState() const
{
    const QmlDesigner::QmlObjectNode objectNode(modelNode());
    return objectNode.isValid() && objectNode.propertyAffectedByCurrentState(name());
}

bool PropertyEditorValue::isBound() const
{
    return modelNode().isValid() && modelNode().property(name()).isValid() && modelNode().property(name()).isBindingProperty();
}

bool PropertyEditorValue::isInModel() const
{
    return modelNode().isValid() && modelNode().hasProperty(name());
}

QString PropertyEditorValue::name() const
{
    return m_name;
}

void PropertyEditorValue::setName(const QString &name)
{
    m_name = name;
}

bool PropertyEditorValue::isValid() const
{
    return m_isValid;
}

void PropertyEditorValue::setIsValid(bool valid)
{
    m_isValid = valid;
}

ModelNode PropertyEditorValue::modelNode() const
{
    return m_modelNode;
}

void PropertyEditorValue::setModelNode(const ModelNode &modelNode)
{
    if (modelNode != m_modelNode) {
        m_modelNode = modelNode;
        m_complexNode->update();
        emit modelNodeChanged();
    }
}

PropertyEditorNodeWrapper* PropertyEditorValue::complexNode()
{
    return m_complexNode;
}

void PropertyEditorValue::resetValue()
{
    if (m_value.isValid()) {
        setValue(QVariant());
        m_isBound = false;
        emit valueChanged(name(), QVariant());
    }
}

void PropertyEditorValue::registerDeclarativeTypes()
{
    qmlRegisterType<PropertyEditorValue>("Bauhaus",1,0,"PropertyEditorValue");
    qmlRegisterType<PropertyEditorNodeWrapper>("Bauhaus",1,0,"PropertyEditorNodeWrapper");
    qmlRegisterType<QDeclarativePropertyMap>("Bauhaus",1,0,"QDeclarativePropertyMap");
}

PropertyEditorNodeWrapper::PropertyEditorNodeWrapper(PropertyEditorValue* parent) : m_valuesPropertyMap(this)
{
    m_editorValue = parent;
    connect(m_editorValue, SIGNAL(modelNodeChanged()), this, SLOT(update()));
}

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

bool PropertyEditorNodeWrapper::exists()
{
    if (!(m_editorValue && m_editorValue->modelNode().isValid()))
        return false;

    return m_modelNode.isValid();
}

QString PropertyEditorNodeWrapper::type()
{
    if (!(m_modelNode.isValid()))
        return QString("");

    return m_modelNode.simplifiedTypeName();

}

ModelNode PropertyEditorNodeWrapper::parentModelNode() const
{
    return  m_editorValue->modelNode();
}

QString PropertyEditorNodeWrapper::propertyName() const
{
    return m_editorValue->name();
}

QDeclarativePropertyMap* PropertyEditorNodeWrapper::properties()
{
    return &m_valuesPropertyMap;
}

void PropertyEditorNodeWrapper::add(const QString &type)
{

    QString propertyType = type;

    if ((m_editorValue && m_editorValue->modelNode().isValid())) {
        if (propertyType.isEmpty())
            propertyType = m_editorValue->modelNode().metaInfo().property(m_editorValue->name()).type();
        while (propertyType.contains('*')) //strip star
            propertyType.chop(1);
        m_modelNode = m_editorValue->modelNode().view()->createModelNode(propertyType, 4, 6);
        m_editorValue->modelNode().nodeAbstractProperty(m_editorValue->name()).reparentHere(m_modelNode);
        if (!m_modelNode.isValid()) {
            qWarning("PropertyEditorNodeWrapper::add failed");
        }
    } else {
        qWarning("PropertyEditorNodeWrapper::add failed - node invalid");
    }
    setup();
}

void PropertyEditorNodeWrapper::remove()
{
    if ((m_editorValue && m_editorValue->modelNode().isValid())) {
        if (QmlDesigner::QmlObjectNode(m_modelNode).isValid())
            QmlDesigner::QmlObjectNode(m_modelNode).destroy();
        m_editorValue->modelNode().removeProperty(m_editorValue->name());
    } else {
        qWarning("PropertyEditorNodeWrapper::remove failed - node invalid");
    }
    m_modelNode = QmlDesigner::ModelNode();

    foreach (const QString &propertyName, m_valuesPropertyMap.keys())
        m_valuesPropertyMap.clear(propertyName);
    foreach (QObject *object, m_valuesPropertyMap.children())
        delete object;
    emit propertiesChanged();
    emit existsChanged();
}

void PropertyEditorNodeWrapper::changeValue(const QString &name)
{
    if (name.isNull())
        return;
    if (m_modelNode.isValid()) {
        QmlDesigner::QmlObjectNode fxObjectNode(m_modelNode);

        PropertyEditorValue *valueObject = qvariant_cast<PropertyEditorValue *>(m_valuesPropertyMap.value(name));

        if (valueObject->value().isValid())
            fxObjectNode.setVariantProperty(name, valueObject->value());
        else
            fxObjectNode.removeVariantProperty(name);
    }
}

void PropertyEditorNodeWrapper::setup()
{
    Q_ASSERT(m_editorValue);
    Q_ASSERT(m_editorValue->modelNode().isValid());
    if ((m_editorValue->modelNode().isValid() && m_modelNode.isValid())) {
        QmlDesigner::QmlObjectNode fxObjectNode(m_modelNode);
        foreach ( const QString &propertyName, m_valuesPropertyMap.keys())
            m_valuesPropertyMap.clear(propertyName);
        foreach (QObject *object, m_valuesPropertyMap.children())
            delete object;

        foreach (const QString &propertyName, m_modelNode.metaInfo().properties().keys()) {
            PropertyEditorValue *valueObject = new PropertyEditorValue(&m_valuesPropertyMap);
            valueObject->setName(propertyName);
            valueObject->setValue(fxObjectNode.instanceValue(propertyName));

            connect(valueObject, SIGNAL(valueChanged(QString, const QVariant&)), &m_valuesPropertyMap, SIGNAL(valueChanged(QString, const QVariant&)));
            m_valuesPropertyMap.insert(propertyName, QVariant::fromValue(valueObject));
        }
    }
    connect(&m_valuesPropertyMap, SIGNAL(valueChanged(const QString &, const QVariant&)), this, SLOT(changeValue(const QString&)));

    emit propertiesChanged();
    emit existsChanged();
}

void PropertyEditorNodeWrapper::update()
{
    if (m_editorValue && m_editorValue->modelNode().isValid()) {
        if (m_editorValue->modelNode().hasProperty(m_editorValue->name()) && m_editorValue->modelNode().property(m_editorValue->name()).isNodeProperty()) {
            m_modelNode = m_editorValue->modelNode().nodeProperty(m_editorValue->name()).modelNode();
        }
        setup();
        emit existsChanged();
        emit typeChanged();
    }
}

<|endoftext|>