<commit_before>/*
Copyright libCellML Contributors

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 "utilities.h"

#include "libcellml/units.h"
#include "libcellml/variable.h"

#include <algorithm>
#include <cassert>
#include <map>
#include <sstream>
#include <vector>

namespace libcellml {

/**
 * @brief Map to convert an interface type into its string form.
 *
 * An internal map used to convert a Variable InterfaceType enum class member into its string form.
 */
static const std::map<Variable::InterfaceType, const std::string> interfaceTypeToString = {
    {Variable::InterfaceType::NONE, "none"},
    {Variable::InterfaceType::PRIVATE, "private"},
    {Variable::InterfaceType::PUBLIC, "public"},
    {Variable::InterfaceType::PUBLIC_AND_PRIVATE, "public_and_private"}};

using VariableWeakPtr = std::weak_ptr<Variable>; /**< Type definition for weak variable pointer. */

/**
 * @brief The Variable::VariableImpl struct.
 *
 * The private implementation for the Variable class.
 */
struct Variable::VariableImpl
{
    /**
     * @brief Private function to add an equivalent variable to the set for this variable.
     *
     * Add the argument equivalent variable to the set of equivalent variables for this
     * variable if it is not already present. If the equivalent variable is present,
     * do nothing.
     *
     * @sa addEquivalence, unsetEquivalentTo
     *
     * @param equivalentVariable The variable to add to this variable's equivalent
     * variable set if not already present.
     */
    void setEquivalentTo(const VariablePtr &equivalentVariable);

    /**
     * @brief Private function to remove an equivalent variable from the set for this variable.
     *
     * Remove the @p equivalentVariable from the set of equivalent variables for this
     * variable if it is present.
     *
     * @sa removeEquivalence, setEquivalentTo
     *
     * @param equivalentVariable The variable to remove from this variable's equivalent
     * variable set if it is present.
     *
     * @return True if the @p equivalentVariable is removed from set of equivalent variables, false otherwise.
     */
    bool unsetEquivalentTo(const VariablePtr &equivalentVariable);

    /**
     * @brief Test if the given variable is equivalent to this one.
     *
     * The two variables are considered equivalent if this variable holds a valid reference to the
     * given variable.  Returns @c true if this variable holds a reference to the given variable
     * and that that reference is a valid reference to the given variable.
     *
     * @param equivalentVariable The varialbe to test for equivalence to this one.
     * @return @c true if the variables are equivalent @c false otherwise.
     */
    bool hasEquivalentVariable(const VariablePtr &equivalentVariable) const;

    bool areEquivalentVariables(const Variable *variable1,
                                const Variable *variable2,
                                std::vector<const Variable *> &testedVariables) const;

    /**
     * @brief Set the equivalent mapping id for this equivalence.
     *
     * Record the given id as the mapping id for the equivalence defined with this variable
     * and the given one.  This id appears in the 'map_variables' element of the model when
     * serialised.
     *
     * To clear an equivalence mapping id set it to the empty string. If the two variables are
     * not equivalent the mapping id is not set.
     *
     * @param equivalentVariable The equivalent variable the id refers to.
     * @param id @c std::string id to set.
     */
    void setEquivalentMappingId(const VariablePtr &equivalentVariable, const std::string &id);

    /**
     * @brief Set the equivalent connection id for this equivalence.
     *
     * Record the given id as the connection id for the equivalence defined with this variable
     * and the given one.  This id appears in the 'connection' element of the model when serialised.
     *
     * Where the same component pair has multiple equivalent variables only the last connection id
     * found in the set will be serialised.
     *
     * To clear an equivalence connection id set it to the empty string.  If the two variables are not
     * equivalent the connection id is not set.
     *
     * @param equivalentVariable The equivalent variable the id refers to.
     * @param id @c std::string id to set.
     */
    void setEquivalentConnectionId(const VariablePtr &equivalentVariable, const std::string &id);

    /**
     * @brief Get the equivalent mapping id for this equivalence.
     *
     * Get the mapping id set for the equivalence defined by the this variable and the given one.
     * If no mapping id is set the empty string is returned.
     *
     * If the two variables are not equivalent the empty string is returned.
     *
     * @param equivalentVariable The variable this variable is equivalent to.
     * @return The @c std::string id of the equivalence if found otherwise returns the empty string.
     */
    std::string getEquivalentMappingId(const VariablePtr &equivalentVariable) const;

    /**
     * @brief Get the equivalent connection id for this equivalence.
     *
     * Get the connection id set for the equivalence defined by the this variable and the given one.
     * If no connection id is set the empty string is returned.
     *
     * If the two variables are not equivalent the empty string is returned.
     *
     * @param equivalentVariable The variable this variable is equivalent to.
     * @return The @c std::string id of the equivalence if found otherwise returns the empty string.
     */
    std::string getEquivalentConnectionId(const VariablePtr &equivalentVariable) const;

    std::vector<VariableWeakPtr>::iterator findEquivalentVariable(const VariablePtr &equivalentVariable);
    std::vector<VariableWeakPtr>::const_iterator findEquivalentVariable(const VariablePtr &equivalentVariable) const;
    std::vector<VariableWeakPtr> mEquivalentVariables; /**< Equivalent variables for this Variable.*/
    std::map<VariableWeakPtr, std::string, std::owner_less<VariableWeakPtr>> mMappingIdMap; /**< Mapping id map for equivalent variable.*/
    std::map<VariableWeakPtr, std::string, std::owner_less<VariableWeakPtr>> mConnectionIdMap; /**< Connection id map for equivalent variable.*/
    std::string mInitialValue; /**< Initial value for this Variable.*/
    std::string mInterfaceType; /**< Interface type for this Variable.*/
    std::string mUnits; /**< The name of the units defined for this Variable.*/
};

std::vector<VariableWeakPtr>::const_iterator Variable::VariableImpl::findEquivalentVariable(const VariablePtr &equivalentVariable) const
{
    return std::find_if(mEquivalentVariables.begin(), mEquivalentVariables.end(),
                        [=](const VariableWeakPtr &variableWeak) -> bool { return equivalentVariable == variableWeak.lock(); });
}

std::vector<VariableWeakPtr>::iterator Variable::VariableImpl::findEquivalentVariable(const VariablePtr &equivalentVariable)
{
    return std::find_if(mEquivalentVariables.begin(), mEquivalentVariables.end(),
                        [=](const VariableWeakPtr &variableWeak) -> bool { return equivalentVariable == variableWeak.lock(); });
}

Variable::Variable()
    : mPimpl(new VariableImpl())
{
}

Variable::~Variable()
{
    delete mPimpl;
}

Variable::Variable(const Variable &rhs)
    : NamedEntity(rhs)
    , mPimpl(new VariableImpl())
{
    mPimpl->mEquivalentVariables = rhs.mPimpl->mEquivalentVariables;
    mPimpl->mConnectionIdMap = rhs.mPimpl->mConnectionIdMap;
    mPimpl->mMappingIdMap = rhs.mPimpl->mMappingIdMap;
    mPimpl->mInitialValue = rhs.mPimpl->mInitialValue;
    mPimpl->mInterfaceType = rhs.mPimpl->mInterfaceType;
    mPimpl->mUnits = rhs.mPimpl->mUnits;
}

Variable::Variable(Variable &&rhs) noexcept
    : NamedEntity(std::move(rhs))
    , mPimpl(rhs.mPimpl)
{
    rhs.mPimpl = nullptr;
}

Variable &Variable::operator=(Variable rhs)
{
    NamedEntity::operator=(rhs);
    rhs.swap(*this);
    return *this;
}

void Variable::swap(Variable &rhs)
{
    std::swap(this->mPimpl, rhs.mPimpl);
}

void Variable::addEquivalence(const VariablePtr &variable1, const VariablePtr &variable2)
{
    variable1->mPimpl->setEquivalentTo(variable2);
    variable2->mPimpl->setEquivalentTo(variable1);
}

void Variable::addEquivalence(const VariablePtr &variable1, const VariablePtr &variable2, const std::string &mappingId, const std::string &connectionId)
{
    Variable::addEquivalence(variable1, variable2);
    variable1->mPimpl->setEquivalentMappingId(variable2, mappingId);
    variable1->mPimpl->setEquivalentConnectionId(variable2, connectionId);
    variable2->mPimpl->setEquivalentMappingId(variable1, mappingId);
    variable2->mPimpl->setEquivalentConnectionId(variable1, connectionId);
}

bool Variable::removeEquivalence(const VariablePtr &variable1, const VariablePtr &variable2)
{
    bool equivalence_1 = variable1->mPimpl->unsetEquivalentTo(variable2);
    bool equivalence_2 = variable2->mPimpl->unsetEquivalentTo(variable1);

    return equivalence_1 && equivalence_2;
}

void Variable::removeAllEquivalences()
{
    mPimpl->mEquivalentVariables.clear();
}

VariablePtr Variable::getEquivalentVariable(size_t index) const
{
    VariablePtr equivalentVariable = nullptr;
    if (index < mPimpl->mEquivalentVariables.size()) {
        VariableWeakPtr weakEquivalentVariable = mPimpl->mEquivalentVariables.at(index);
        equivalentVariable = weakEquivalentVariable.lock();
    }

    return equivalentVariable;
}

size_t Variable::equivalentVariableCount() const
{
    return mPimpl->mEquivalentVariables.size();
}

bool Variable::hasEquivalentVariable(const VariablePtr &equivalentVariable) const
{
    return mPimpl->hasEquivalentVariable(equivalentVariable);
}

bool Variable::isEquivalentVariable(const VariablePtr &equivalentVariable) const
{
    std::vector<const Variable *> testedVariables;

    return mPimpl->areEquivalentVariables(this, equivalentVariable.get(), testedVariables);
}

bool Variable::VariableImpl::hasEquivalentVariable(const VariablePtr &equivalentVariable) const
{
    auto it = findEquivalentVariable(equivalentVariable);
    if (it == mEquivalentVariables.end()) {
        return false;
    }
    return !it->expired();
}

bool Variable::VariableImpl::areEquivalentVariables(const Variable *variable1,
                                                    const Variable *variable2,
                                                    std::vector<const Variable *> &testedVariables) const
{
    if (variable1 == variable2) {
        return true;
    }

    testedVariables.push_back(variable2);

    for (size_t i = 0; i < variable2->equivalentVariableCount(); ++i) {
        Variable *equivalentVariable2 = variable2->getEquivalentVariable(i).get();

        if (   (std::find(testedVariables.begin(), testedVariables.end(), equivalentVariable2) == testedVariables.end())
            && areEquivalentVariables(variable1, equivalentVariable2, testedVariables)) {
            return true;
        }
    }

    return false;
}

void Variable::VariableImpl::setEquivalentTo(const VariablePtr &equivalentVariable)
{
    if (!hasEquivalentVariable(equivalentVariable)) {
        VariableWeakPtr weakEquivalentVariable = equivalentVariable;
        mEquivalentVariables.push_back(weakEquivalentVariable);
    }
}

bool Variable::VariableImpl::unsetEquivalentTo(const VariablePtr &equivalentVariable)
{
    bool status = false;
    auto result = findEquivalentVariable(equivalentVariable);
    if (result != mEquivalentVariables.end()) {
        mEquivalentVariables.erase(result);
        auto mappingIdResult = mMappingIdMap.find(equivalentVariable);
        if (mappingIdResult != mMappingIdMap.end()) {
            mMappingIdMap.erase(mappingIdResult);
        }
        auto connectionIdResult = mConnectionIdMap.find(equivalentVariable);
        if (connectionIdResult != mConnectionIdMap.end()) {
            mConnectionIdMap.erase(connectionIdResult);
        }
        status = true;
    }

    return status;
}

void Variable::VariableImpl::setEquivalentMappingId(const VariablePtr &equivalentVariable, const std::string &id)
{
    VariableWeakPtr weakEquivalentVariable = equivalentVariable;
    mMappingIdMap[weakEquivalentVariable] = id;
}

std::string Variable::VariableImpl::getEquivalentMappingId(const VariablePtr &equivalentVariable) const
{
    if (mMappingIdMap.find(equivalentVariable) != mMappingIdMap.end()) {
        return mMappingIdMap.at(equivalentVariable);
    }
    return "";
}

void Variable::VariableImpl::setEquivalentConnectionId(const VariablePtr &equivalentVariable, const std::string &id)
{
    VariableWeakPtr weakEquivalentVariable = equivalentVariable;
    mConnectionIdMap[weakEquivalentVariable] = id;
}

std::string Variable::VariableImpl::getEquivalentConnectionId(const VariablePtr &equivalentVariable) const
{
    if (mConnectionIdMap.find(equivalentVariable) != mConnectionIdMap.end()) {
        return mConnectionIdMap.at(equivalentVariable);
    }
    return "";
}

void Variable::setUnits(const std::string &name)
{
    mPimpl->mUnits = name;
}

void Variable::setUnits(const UnitsPtr &units)
{
    mPimpl->mUnits = units->getName();
}

std::string Variable::getUnits() const
{
    return mPimpl->mUnits;
}

void Variable::setInitialValue(const std::string &initialValue)
{
    mPimpl->mInitialValue = initialValue;
}

void Variable::setInitialValue(double initialValue)
{
    mPimpl->mInitialValue = convertDoubleToString(initialValue);
}

void Variable::setInitialValue(const VariablePtr &variable)
{
    mPimpl->mInitialValue = variable->getName();
}

std::string Variable::getInitialValue() const
{
    return mPimpl->mInitialValue;
}

void Variable::setInterfaceType(const std::string &interfaceType)
{
    mPimpl->mInterfaceType = interfaceType;
}

void Variable::setInterfaceType(Variable::InterfaceType interfaceType)
{
    auto search = interfaceTypeToString.find(interfaceType);
    const std::string interfaceTypeString = search->second;
    setInterfaceType(interfaceTypeString);
}

std::string Variable::getInterfaceType() const
{
    return mPimpl->mInterfaceType;
}

void Variable::setEquivalenceMappingId(const VariablePtr &variable1, const VariablePtr &variable2, const std::string &mappingId)
{
    if (variable1->hasEquivalentVariable(variable2) && variable2->hasEquivalentVariable(variable1)) {
        variable1->mPimpl->setEquivalentMappingId(variable2, mappingId);
        variable2->mPimpl->setEquivalentMappingId(variable1, mappingId);
    }
}

void Variable::setEquivalenceConnectionId(const VariablePtr &variable1, const VariablePtr &variable2, const std::string &connectionId)
{
    if (variable1->hasEquivalentVariable(variable2) && variable2->hasEquivalentVariable(variable1)) {
        variable1->mPimpl->setEquivalentConnectionId(variable2, connectionId);
        variable2->mPimpl->setEquivalentConnectionId(variable1, connectionId);
    }
}

std::string Variable::getEquivalenceMappingId(const VariablePtr &variable1, const VariablePtr &variable2)
{
    std::string id;
    if (variable1->hasEquivalentVariable(variable2) && variable2->hasEquivalentVariable(variable1)) {
        std::string id_1 = variable1->mPimpl->getEquivalentMappingId(variable2);
        std::string id_2 = variable2->mPimpl->getEquivalentMappingId(variable1);
        if (id_1 == id_2) {
            id = id_1;
        }
    }
    return id;
}

std::string Variable::getEquivalenceConnectionId(const VariablePtr &variable1, const VariablePtr &variable2)
{
    std::string id;
    if (variable1->hasEquivalentVariable(variable2) && variable2->hasEquivalentVariable(variable1)) {
        std::string id_1 = variable1->mPimpl->getEquivalentConnectionId(variable2);
        std::string id_2 = variable2->mPimpl->getEquivalentConnectionId(variable1);
        if (id_1 == id_2) {
            id = id_1;
        }
    }
    return id;
}

} // namespace libcellml
<commit_msg>Make ClangFormat happy.<commit_after>/*
Copyright libCellML Contributors

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 "utilities.h"

#include "libcellml/units.h"
#include "libcellml/variable.h"

#include <algorithm>
#include <cassert>
#include <map>
#include <sstream>
#include <vector>

namespace libcellml {

/**
 * @brief Map to convert an interface type into its string form.
 *
 * An internal map used to convert a Variable InterfaceType enum class member into its string form.
 */
static const std::map<Variable::InterfaceType, const std::string> interfaceTypeToString = {
    {Variable::InterfaceType::NONE, "none"},
    {Variable::InterfaceType::PRIVATE, "private"},
    {Variable::InterfaceType::PUBLIC, "public"},
    {Variable::InterfaceType::PUBLIC_AND_PRIVATE, "public_and_private"}};

using VariableWeakPtr = std::weak_ptr<Variable>; /**< Type definition for weak variable pointer. */

/**
 * @brief The Variable::VariableImpl struct.
 *
 * The private implementation for the Variable class.
 */
struct Variable::VariableImpl
{
    /**
     * @brief Private function to add an equivalent variable to the set for this variable.
     *
     * Add the argument equivalent variable to the set of equivalent variables for this
     * variable if it is not already present. If the equivalent variable is present,
     * do nothing.
     *
     * @sa addEquivalence, unsetEquivalentTo
     *
     * @param equivalentVariable The variable to add to this variable's equivalent
     * variable set if not already present.
     */
    void setEquivalentTo(const VariablePtr &equivalentVariable);

    /**
     * @brief Private function to remove an equivalent variable from the set for this variable.
     *
     * Remove the @p equivalentVariable from the set of equivalent variables for this
     * variable if it is present.
     *
     * @sa removeEquivalence, setEquivalentTo
     *
     * @param equivalentVariable The variable to remove from this variable's equivalent
     * variable set if it is present.
     *
     * @return True if the @p equivalentVariable is removed from set of equivalent variables, false otherwise.
     */
    bool unsetEquivalentTo(const VariablePtr &equivalentVariable);

    /**
     * @brief Test if the given variable is equivalent to this one.
     *
     * The two variables are considered equivalent if this variable holds a valid reference to the
     * given variable.  Returns @c true if this variable holds a reference to the given variable
     * and that that reference is a valid reference to the given variable.
     *
     * @param equivalentVariable The varialbe to test for equivalence to this one.
     * @return @c true if the variables are equivalent @c false otherwise.
     */
    bool hasEquivalentVariable(const VariablePtr &equivalentVariable) const;

    bool areEquivalentVariables(const Variable *variable1,
                                const Variable *variable2,
                                std::vector<const Variable *> &testedVariables) const;

    /**
     * @brief Set the equivalent mapping id for this equivalence.
     *
     * Record the given id as the mapping id for the equivalence defined with this variable
     * and the given one.  This id appears in the 'map_variables' element of the model when
     * serialised.
     *
     * To clear an equivalence mapping id set it to the empty string. If the two variables are
     * not equivalent the mapping id is not set.
     *
     * @param equivalentVariable The equivalent variable the id refers to.
     * @param id @c std::string id to set.
     */
    void setEquivalentMappingId(const VariablePtr &equivalentVariable, const std::string &id);

    /**
     * @brief Set the equivalent connection id for this equivalence.
     *
     * Record the given id as the connection id for the equivalence defined with this variable
     * and the given one.  This id appears in the 'connection' element of the model when serialised.
     *
     * Where the same component pair has multiple equivalent variables only the last connection id
     * found in the set will be serialised.
     *
     * To clear an equivalence connection id set it to the empty string.  If the two variables are not
     * equivalent the connection id is not set.
     *
     * @param equivalentVariable The equivalent variable the id refers to.
     * @param id @c std::string id to set.
     */
    void setEquivalentConnectionId(const VariablePtr &equivalentVariable, const std::string &id);

    /**
     * @brief Get the equivalent mapping id for this equivalence.
     *
     * Get the mapping id set for the equivalence defined by the this variable and the given one.
     * If no mapping id is set the empty string is returned.
     *
     * If the two variables are not equivalent the empty string is returned.
     *
     * @param equivalentVariable The variable this variable is equivalent to.
     * @return The @c std::string id of the equivalence if found otherwise returns the empty string.
     */
    std::string getEquivalentMappingId(const VariablePtr &equivalentVariable) const;

    /**
     * @brief Get the equivalent connection id for this equivalence.
     *
     * Get the connection id set for the equivalence defined by the this variable and the given one.
     * If no connection id is set the empty string is returned.
     *
     * If the two variables are not equivalent the empty string is returned.
     *
     * @param equivalentVariable The variable this variable is equivalent to.
     * @return The @c std::string id of the equivalence if found otherwise returns the empty string.
     */
    std::string getEquivalentConnectionId(const VariablePtr &equivalentVariable) const;

    std::vector<VariableWeakPtr>::iterator findEquivalentVariable(const VariablePtr &equivalentVariable);
    std::vector<VariableWeakPtr>::const_iterator findEquivalentVariable(const VariablePtr &equivalentVariable) const;
    std::vector<VariableWeakPtr> mEquivalentVariables; /**< Equivalent variables for this Variable.*/
    std::map<VariableWeakPtr, std::string, std::owner_less<VariableWeakPtr>> mMappingIdMap; /**< Mapping id map for equivalent variable.*/
    std::map<VariableWeakPtr, std::string, std::owner_less<VariableWeakPtr>> mConnectionIdMap; /**< Connection id map for equivalent variable.*/
    std::string mInitialValue; /**< Initial value for this Variable.*/
    std::string mInterfaceType; /**< Interface type for this Variable.*/
    std::string mUnits; /**< The name of the units defined for this Variable.*/
};

std::vector<VariableWeakPtr>::const_iterator Variable::VariableImpl::findEquivalentVariable(const VariablePtr &equivalentVariable) const
{
    return std::find_if(mEquivalentVariables.begin(), mEquivalentVariables.end(),
                        [=](const VariableWeakPtr &variableWeak) -> bool { return equivalentVariable == variableWeak.lock(); });
}

std::vector<VariableWeakPtr>::iterator Variable::VariableImpl::findEquivalentVariable(const VariablePtr &equivalentVariable)
{
    return std::find_if(mEquivalentVariables.begin(), mEquivalentVariables.end(),
                        [=](const VariableWeakPtr &variableWeak) -> bool { return equivalentVariable == variableWeak.lock(); });
}

Variable::Variable()
    : mPimpl(new VariableImpl())
{
}

Variable::~Variable()
{
    delete mPimpl;
}

Variable::Variable(const Variable &rhs)
    : NamedEntity(rhs)
    , mPimpl(new VariableImpl())
{
    mPimpl->mEquivalentVariables = rhs.mPimpl->mEquivalentVariables;
    mPimpl->mConnectionIdMap = rhs.mPimpl->mConnectionIdMap;
    mPimpl->mMappingIdMap = rhs.mPimpl->mMappingIdMap;
    mPimpl->mInitialValue = rhs.mPimpl->mInitialValue;
    mPimpl->mInterfaceType = rhs.mPimpl->mInterfaceType;
    mPimpl->mUnits = rhs.mPimpl->mUnits;
}

Variable::Variable(Variable &&rhs) noexcept
    : NamedEntity(std::move(rhs))
    , mPimpl(rhs.mPimpl)
{
    rhs.mPimpl = nullptr;
}

Variable &Variable::operator=(Variable rhs)
{
    NamedEntity::operator=(rhs);
    rhs.swap(*this);
    return *this;
}

void Variable::swap(Variable &rhs)
{
    std::swap(this->mPimpl, rhs.mPimpl);
}

void Variable::addEquivalence(const VariablePtr &variable1, const VariablePtr &variable2)
{
    variable1->mPimpl->setEquivalentTo(variable2);
    variable2->mPimpl->setEquivalentTo(variable1);
}

void Variable::addEquivalence(const VariablePtr &variable1, const VariablePtr &variable2, const std::string &mappingId, const std::string &connectionId)
{
    Variable::addEquivalence(variable1, variable2);
    variable1->mPimpl->setEquivalentMappingId(variable2, mappingId);
    variable1->mPimpl->setEquivalentConnectionId(variable2, connectionId);
    variable2->mPimpl->setEquivalentMappingId(variable1, mappingId);
    variable2->mPimpl->setEquivalentConnectionId(variable1, connectionId);
}

bool Variable::removeEquivalence(const VariablePtr &variable1, const VariablePtr &variable2)
{
    bool equivalence_1 = variable1->mPimpl->unsetEquivalentTo(variable2);
    bool equivalence_2 = variable2->mPimpl->unsetEquivalentTo(variable1);

    return equivalence_1 && equivalence_2;
}

void Variable::removeAllEquivalences()
{
    mPimpl->mEquivalentVariables.clear();
}

VariablePtr Variable::getEquivalentVariable(size_t index) const
{
    VariablePtr equivalentVariable = nullptr;
    if (index < mPimpl->mEquivalentVariables.size()) {
        VariableWeakPtr weakEquivalentVariable = mPimpl->mEquivalentVariables.at(index);
        equivalentVariable = weakEquivalentVariable.lock();
    }

    return equivalentVariable;
}

size_t Variable::equivalentVariableCount() const
{
    return mPimpl->mEquivalentVariables.size();
}

bool Variable::hasEquivalentVariable(const VariablePtr &equivalentVariable) const
{
    return mPimpl->hasEquivalentVariable(equivalentVariable);
}

bool Variable::isEquivalentVariable(const VariablePtr &equivalentVariable) const
{
    std::vector<const Variable *> testedVariables;

    return mPimpl->areEquivalentVariables(this, equivalentVariable.get(), testedVariables);
}

bool Variable::VariableImpl::hasEquivalentVariable(const VariablePtr &equivalentVariable) const
{
    auto it = findEquivalentVariable(equivalentVariable);
    if (it == mEquivalentVariables.end()) {
        return false;
    }
    return !it->expired();
}

bool Variable::VariableImpl::areEquivalentVariables(const Variable *variable1,
                                                    const Variable *variable2,
                                                    std::vector<const Variable *> &testedVariables) const
{
    if (variable1 == variable2) {
        return true;
    }

    testedVariables.push_back(variable2);

    for (size_t i = 0; i < variable2->equivalentVariableCount(); ++i) {
        Variable *equivalentVariable2 = variable2->getEquivalentVariable(i).get();

        if ((std::find(testedVariables.begin(), testedVariables.end(), equivalentVariable2) == testedVariables.end())
            && areEquivalentVariables(variable1, equivalentVariable2, testedVariables)) {
            return true;
        }
    }

    return false;
}

void Variable::VariableImpl::setEquivalentTo(const VariablePtr &equivalentVariable)
{
    if (!hasEquivalentVariable(equivalentVariable)) {
        VariableWeakPtr weakEquivalentVariable = equivalentVariable;
        mEquivalentVariables.push_back(weakEquivalentVariable);
    }
}

bool Variable::VariableImpl::unsetEquivalentTo(const VariablePtr &equivalentVariable)
{
    bool status = false;
    auto result = findEquivalentVariable(equivalentVariable);
    if (result != mEquivalentVariables.end()) {
        mEquivalentVariables.erase(result);
        auto mappingIdResult = mMappingIdMap.find(equivalentVariable);
        if (mappingIdResult != mMappingIdMap.end()) {
            mMappingIdMap.erase(mappingIdResult);
        }
        auto connectionIdResult = mConnectionIdMap.find(equivalentVariable);
        if (connectionIdResult != mConnectionIdMap.end()) {
            mConnectionIdMap.erase(connectionIdResult);
        }
        status = true;
    }

    return status;
}

void Variable::VariableImpl::setEquivalentMappingId(const VariablePtr &equivalentVariable, const std::string &id)
{
    VariableWeakPtr weakEquivalentVariable = equivalentVariable;
    mMappingIdMap[weakEquivalentVariable] = id;
}

std::string Variable::VariableImpl::getEquivalentMappingId(const VariablePtr &equivalentVariable) const
{
    if (mMappingIdMap.find(equivalentVariable) != mMappingIdMap.end()) {
        return mMappingIdMap.at(equivalentVariable);
    }
    return "";
}

void Variable::VariableImpl::setEquivalentConnectionId(const VariablePtr &equivalentVariable, const std::string &id)
{
    VariableWeakPtr weakEquivalentVariable = equivalentVariable;
    mConnectionIdMap[weakEquivalentVariable] = id;
}

std::string Variable::VariableImpl::getEquivalentConnectionId(const VariablePtr &equivalentVariable) const
{
    if (mConnectionIdMap.find(equivalentVariable) != mConnectionIdMap.end()) {
        return mConnectionIdMap.at(equivalentVariable);
    }
    return "";
}

void Variable::setUnits(const std::string &name)
{
    mPimpl->mUnits = name;
}

void Variable::setUnits(const UnitsPtr &units)
{
    mPimpl->mUnits = units->getName();
}

std::string Variable::getUnits() const
{
    return mPimpl->mUnits;
}

void Variable::setInitialValue(const std::string &initialValue)
{
    mPimpl->mInitialValue = initialValue;
}

void Variable::setInitialValue(double initialValue)
{
    mPimpl->mInitialValue = convertDoubleToString(initialValue);
}

void Variable::setInitialValue(const VariablePtr &variable)
{
    mPimpl->mInitialValue = variable->getName();
}

std::string Variable::getInitialValue() const
{
    return mPimpl->mInitialValue;
}

void Variable::setInterfaceType(const std::string &interfaceType)
{
    mPimpl->mInterfaceType = interfaceType;
}

void Variable::setInterfaceType(Variable::InterfaceType interfaceType)
{
    auto search = interfaceTypeToString.find(interfaceType);
    const std::string interfaceTypeString = search->second;
    setInterfaceType(interfaceTypeString);
}

std::string Variable::getInterfaceType() const
{
    return mPimpl->mInterfaceType;
}

void Variable::setEquivalenceMappingId(const VariablePtr &variable1, const VariablePtr &variable2, const std::string &mappingId)
{
    if (variable1->hasEquivalentVariable(variable2) && variable2->hasEquivalentVariable(variable1)) {
        variable1->mPimpl->setEquivalentMappingId(variable2, mappingId);
        variable2->mPimpl->setEquivalentMappingId(variable1, mappingId);
    }
}

void Variable::setEquivalenceConnectionId(const VariablePtr &variable1, const VariablePtr &variable2, const std::string &connectionId)
{
    if (variable1->hasEquivalentVariable(variable2) && variable2->hasEquivalentVariable(variable1)) {
        variable1->mPimpl->setEquivalentConnectionId(variable2, connectionId);
        variable2->mPimpl->setEquivalentConnectionId(variable1, connectionId);
    }
}

std::string Variable::getEquivalenceMappingId(const VariablePtr &variable1, const VariablePtr &variable2)
{
    std::string id;
    if (variable1->hasEquivalentVariable(variable2) && variable2->hasEquivalentVariable(variable1)) {
        std::string id_1 = variable1->mPimpl->getEquivalentMappingId(variable2);
        std::string id_2 = variable2->mPimpl->getEquivalentMappingId(variable1);
        if (id_1 == id_2) {
            id = id_1;
        }
    }
    return id;
}

std::string Variable::getEquivalenceConnectionId(const VariablePtr &variable1, const VariablePtr &variable2)
{
    std::string id;
    if (variable1->hasEquivalentVariable(variable2) && variable2->hasEquivalentVariable(variable1)) {
        std::string id_1 = variable1->mPimpl->getEquivalentConnectionId(variable2);
        std::string id_2 = variable2->mPimpl->getEquivalentConnectionId(variable1);
        if (id_1 == id_2) {
            id = id_1;
        }
    }
    return id;
}

} // namespace libcellml
<|endoftext|>


<commit_before>/*
    This file is part of libkholidays.
    Copyright (c) 2004,2006 Allen Winter <winter@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 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
    Library General Public License for more details.

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

#include "kde-holidays.h"
#include "kde-holidays_parser.h"

#include <kapplication.h>
#include <kcmdlineargs.h>
#include <kaboutdata.h>
#include <kdebug.h>

#include <QFile>
#include <QTextStream>

#include <iostream>
using namespace std;

static const KCmdLineOptions options[] =
{
  { "+file", "Name of holiday XML file", 0 },
  KCmdLineLastOption
};

//void displaySpec( Datespec *d )
//{
//}

void displayHolidays( const QList<Holiday> holidays )
{
  foreach( Holiday h, holidays ) {
    cout << "NAME: " << h.name().toLocal8Bit().data() << endl;
    cout << "  TYPE: " << h.type().toLocal8Bit().data() << endl;
    if ( !h.description().isEmpty() )
      cout << "  DESC: " << h.description().toLocal8Bit().data() << endl;
    else
      cout << "  DESC: " << "(none)" << endl;
//    displaySpec( h.datespec() );
    cout << endl;
  }
}

int main( int argc, char **argv )
{
  // KApplication::disableAutoDcopRegistration();
  KAboutData aboutData( "dumpholidaylist", "Dump XML holiday list to stdout",
                        "0.1" );
  KCmdLineArgs::init( argc, argv, &aboutData, KCmdLineArgs::CmdLineArgNone );
  KCmdLineArgs::addCmdLineOptions( options );

  KApplication app( false );

  KCmdLineArgs *args = KCmdLineArgs::parsedArgs();

  if ( args->count() != 1 ) {
    args->usage( "Wrong number of arguments." );
  }

  QString filename = QFile::decodeName( args->arg( 0 ) );

  HolidayCalendarParser parser;

  bool ok;
  HolidayCalendar holcalendar = parser.parseFile( filename, &ok );

  if ( ok ) {
    displayHolidays( holcalendar.holidayList() );
  } else {
    kError() << "Parse error" << endl;
  }

  QString out = filename + ".out";
  if ( !holcalendar.writeFile( out ) ) {
    kError() << "Write error" << endl;
  }
}
<commit_msg>Untested port from kapp, since this code is in a lib instead of being in a separate program as it was meant to be. CCMAIL: Allen Winter <winter@kde.org><commit_after>/*
    This file is part of libkholidays.
    Copyright (c) 2004,2006 Allen Winter <winter@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 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
    Library General Public License for more details.

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

#include "kde-holidays.h"
#include "kde-holidays_parser.h"

#include <kcmdlineargs.h>
#include <kaboutdata.h>
#include <kdebug.h>

#include <QFile>
#include <QTextStream>
#include <QCoreApplication>

#include <iostream>
using namespace std;

static const KCmdLineOptions options[] =
{
  { "+file", "Name of holiday XML file", 0 },
  KCmdLineLastOption
};

//void displaySpec( Datespec *d )
//{
//}

void displayHolidays( const QList<Holiday> holidays )
{
  foreach( Holiday h, holidays ) {
    cout << "NAME: " << h.name().toLocal8Bit().data() << endl;
    cout << "  TYPE: " << h.type().toLocal8Bit().data() << endl;
    if ( !h.description().isEmpty() )
      cout << "  DESC: " << h.description().toLocal8Bit().data() << endl;
    else
      cout << "  DESC: " << "(none)" << endl;
//    displaySpec( h.datespec() );
    cout << endl;
  }
}

int main( int argc, char **argv )
{
  KAboutData aboutData( "dumpholidaylist", "Dump XML holiday list to stdout",
                        "0.1" );
  KCmdLineArgs::init( argc, argv, &aboutData, KCmdLineArgs::CmdLineArgNone );
  KCmdLineArgs::addCmdLineOptions( options );

  // is a KInstance needed?
  QCoreApplication app( *KCmdLineArgs::qt_argc(), *KCmdLineArgs::qt_argv() );

  KCmdLineArgs *args = KCmdLineArgs::parsedArgs();

  if ( args->count() != 1 ) {
    args->usage( "Wrong number of arguments." );
  }

  QString filename = QFile::decodeName( args->arg( 0 ) );

  HolidayCalendarParser parser;

  bool ok;
  HolidayCalendar holcalendar = parser.parseFile( filename, &ok );

  if ( ok ) {
    displayHolidays( holcalendar.holidayList() );
  } else {
    kError() << "Parse error" << endl;
  }

  QString out = filename + ".out";
  if ( !holcalendar.writeFile( out ) ) {
    kError() << "Write error" << endl;
  }
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: parser.hxx,v $
 *
 *  $Revision: 1.1.1.1 $
 *
 *  last change: $Author: np $ $Date: 2002-03-08 14:45:17 $
 *
 *  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 ADC_PARSER_HXX
#define ADC_PARSER_HXX

// USED SERVICES
    // BASE CLASSES
    // COMPONENTS
    // PARAMETERS

namespace autodoc
{
    class FileCollector_Ifc;
}

class CodeParser
{
  public:
    virtual             ~CodeParser() {}

    virtual void        Run(
                            const autodoc::FileCollector_Ifc &
                                                i_rFiles ) = 0;
};

#endif

<commit_msg>INTEGRATION: CWS ooo19126 (1.1.1.1.146); FILE MERGED 2005/09/05 13:09:44 rt 1.1.1.1.146.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: parser.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-07 16:28:56 $
 *
 *  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
 *
 ************************************************************************/

#ifndef ADC_PARSER_HXX
#define ADC_PARSER_HXX

// USED SERVICES
    // BASE CLASSES
    // COMPONENTS
    // PARAMETERS

namespace autodoc
{
    class FileCollector_Ifc;
}

class CodeParser
{
  public:
    virtual             ~CodeParser() {}

    virtual void        Run(
                            const autodoc::FileCollector_Ifc &
                                                i_rFiles ) = 0;
};

#endif

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015, Nils Moehrle
 * TU Darmstadt - Graphics, Capture and Massively Parallel Computing
 * All rights reserved.
 *
 * This software may be modified and distributed under the terms
 * of the BSD 3-Clause license. See the LICENSE.txt file for details.
 */

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

#include <util/timer.h>
#include <util/system.h>
#include <util/file_system.h>
#include <mve/mesh_io_ply.h>

#include "tex/util.h"
#include "tex/timer.h"
#include "tex/debug.h"
#include "tex/texturing.h"
#include "tex/progress_counter.h"

#include "arguments.h"

int main(int argc, char **argv) {
    util::system::print_build_timestamp(argv[0]);
    util::system::register_segfault_handler();

#ifdef RESEARCH
    std::cout << "******************************************************************************" << std::endl
              << " Due to use of the -DRESEARCH=ON compile option, this program is licensed "     << std::endl
              << " for research purposes only. Please pay special attention to the gco license."  << std::endl
              << "******************************************************************************" << std::endl;
#endif

    Timer timer;
    util::WallTimer wtimer;

    Arguments conf;
    try {
        conf = parse_args(argc, argv);
    } catch (std::invalid_argument & ia) {
        std::cerr << ia.what() << std::endl;
        std::exit(EXIT_FAILURE);
    }

    if (!util::fs::dir_exists(util::fs::dirname(conf.out_prefix).c_str())) {
        std::cerr << "Destination directory does not exist!" << std::endl;
        std::exit(EXIT_FAILURE);
    }

    std::cout << "Load and prepare mesh: " << std::endl;
    mve::TriangleMesh::Ptr mesh;
    try {
        mesh = mve::geom::load_ply_mesh(conf.in_mesh);
    } catch (std::exception& e) {
        std::cerr << "\tCould not load mesh: "<< e.what() << std::endl;
        std::exit(EXIT_FAILURE);
    }
    mve::MeshInfo mesh_info(mesh);
    tex::prepare_mesh(&mesh_info, mesh);

    std::cout << "Generating texture views: " << std::endl;
    tex::TextureViews texture_views;
    tex::generate_texture_views(conf.in_scene, &texture_views);

    write_string_to_file(conf.out_prefix + ".conf", conf.to_string());
    timer.measure("Loading");

    std::size_t const num_faces = mesh->get_faces().size() / 3;

    std::cout << "Building adjacency graph: " << std::endl;
    tex::Graph graph(num_faces);
    tex::build_adjacency_graph(mesh, mesh_info, &graph);

    if (conf.labeling_file.empty()) {
        std::cout << "View selection:" << std::endl;

        tex::DataCosts data_costs(num_faces, texture_views.size());
        if (conf.data_cost_file.empty()) {
            tex::calculate_data_costs(mesh, &texture_views, conf.settings, &data_costs);

            if (conf.write_intermediate_results) {
                std::cout << "\tWriting data cost file... " << std::flush;
                    ST::save_to_file(data_costs, conf.out_prefix + "_data_costs.spt");
                std::cout << "done." << std::endl;
            }
        } else {
            std::cout << "\tLoading data cost file... " << std::flush;
            try {
                ST::load_from_file(conf.data_cost_file, &data_costs);
            } catch (util::FileException e) {
                std::cout << "failed!" << std::endl;
                std::cerr << e.what() << std::endl;
                std::exit(EXIT_FAILURE);
            }
            std::cout << "done." << std::endl;
        }
        timer.measure("Calculating data costs");

        tex::view_selection(data_costs, &graph, conf.settings);
        timer.measure("Running MRF optimization");

        /* Write labeling to file. */
        if (conf.write_intermediate_results) {
            std::vector<std::size_t> labeling(graph.num_nodes());
            for (std::size_t i = 0; i < graph.num_nodes(); ++i) {
                labeling[i] = graph.get_label(i);
            }
            vector_to_file(conf.out_prefix + "_labeling.vec", labeling);
        }
    } else {
        std::cout << "Loading labeling from file... " << std::flush;

        /* Load labeling from file. */
        std::vector<std::size_t> labeling = vector_from_file<std::size_t>(conf.labeling_file);
        if (labeling.size() != graph.num_nodes()) {
            std::cerr << "Wrong labeling file for this mesh/scene combination... aborting!" << std::endl;
            std::exit(EXIT_FAILURE);
        }

        /* Transfer labeling to graph. */
        for (std::size_t i = 0; i < labeling.size(); ++i) {
            const std::size_t label = labeling[i];
            if (label > texture_views.size()){
                std::cerr << "Wrong labeling file for this mesh/scene combination... aborting!" << std::endl;
                std::exit(EXIT_FAILURE);
            }
            graph.set_label(i, label);
        }

        std::cout << "done." << std::endl;
    }
    std::cout << "\tTook: " << wtimer.get_elapsed_sec() << "s" << std::endl;

    tex::TextureAtlases texture_atlases;
    {
        /* Create texture patches and adjust them. */
        tex::TexturePatches texture_patches;
        tex::VertexProjectionInfos vertex_projection_infos;
        std::cout << "Generating texture patches:" << std::endl;
        tex::generate_texture_patches(graph, mesh, mesh_info, &texture_views, &vertex_projection_infos, &texture_patches);

        if (conf.settings.global_seam_leveling) {
            std::cout << "Running global seam leveling:" << std::endl;
            tex::global_seam_leveling(graph, mesh, mesh_info, vertex_projection_infos, &texture_patches);
            timer.measure("Running global seam leveling");
        } else {
            ProgressCounter texture_patch_counter("Calculating validity masks for texture patches", texture_patches.size());
            #pragma omp parallel for schedule(dynamic)
            for (std::size_t i = 0; i < texture_patches.size(); ++i) {
                texture_patch_counter.progress<SIMPLE>();
                TexturePatch::Ptr texture_patch = texture_patches[i];
                std::vector<math::Vec3f> patch_adjust_values(texture_patch->get_faces().size() * 3, math::Vec3f(0.0f));
                texture_patch->adjust_colors(patch_adjust_values);
                texture_patch_counter.inc();
            }
            timer.measure("Calculating texture patch validity masks");
        }

        if (conf.settings.local_seam_leveling) {
            std::cout << "Running local seam leveling:" << std::endl;
            tex::local_seam_leveling(graph, mesh, vertex_projection_infos, &texture_patches);
        }
        timer.measure("Running local seam leveling");

        /* Generate texture atlases. */
        std::cout << "Generating texture atlases:" << std::endl;
        tex::generate_texture_atlases(&texture_patches, &texture_atlases);
    }

    /* Create and write out obj model. */
    {
        std::cout << "Building objmodel:" << std::endl;
        tex::Model model;
        tex::build_model(mesh, texture_atlases, &model);
        timer.measure("Building OBJ model");

        std::cout << "\tSaving model... " << std::flush;
        tex::Model::save(model, conf.out_prefix);
        std::cout << "done." << std::endl;
        timer.measure("Saving");
    }

    std::cout << "Whole texturing procedure took: " << wtimer.get_elapsed_sec() << "s" << std::endl;
    timer.measure("Total");
    if (conf.write_timings) {
        timer.write_to_file(conf.out_prefix + "_timings.csv");
    }

    if (conf.write_view_selection_model) {
        texture_atlases.clear();
        std::cout << "Generating debug texture patches:" << std::endl;
        {
            tex::TexturePatches texture_patches;
            generate_debug_embeddings(&texture_views);
            tex::VertexProjectionInfos vertex_projection_infos; // Will only be written
            tex::generate_texture_patches(graph, mesh, mesh_info, &texture_views, &vertex_projection_infos, &texture_patches);
            tex::generate_texture_atlases(&texture_patches, &texture_atlases);
        }

        std::cout << "Building debug objmodel:" << std::endl;
        {
            tex::Model model;
            tex::build_model(mesh, texture_atlases, &model);
            std::cout << "\tSaving model... " << std::flush;
            tex::Model::save(model, conf.out_prefix + "_view_selection");
            std::cout << "done." << std::endl;
        }
    }
}
<commit_msg>Fix main() not returning anything when successful<commit_after>/*
 * Copyright (C) 2015, Nils Moehrle
 * TU Darmstadt - Graphics, Capture and Massively Parallel Computing
 * All rights reserved.
 *
 * This software may be modified and distributed under the terms
 * of the BSD 3-Clause license. See the LICENSE.txt file for details.
 */

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

#include <util/timer.h>
#include <util/system.h>
#include <util/file_system.h>
#include <mve/mesh_io_ply.h>

#include "tex/util.h"
#include "tex/timer.h"
#include "tex/debug.h"
#include "tex/texturing.h"
#include "tex/progress_counter.h"

#include "arguments.h"

int main(int argc, char **argv) {
    util::system::print_build_timestamp(argv[0]);
    util::system::register_segfault_handler();

#ifdef RESEARCH
    std::cout << "******************************************************************************" << std::endl
              << " Due to use of the -DRESEARCH=ON compile option, this program is licensed "     << std::endl
              << " for research purposes only. Please pay special attention to the gco license."  << std::endl
              << "******************************************************************************" << std::endl;
#endif

    Timer timer;
    util::WallTimer wtimer;

    Arguments conf;
    try {
        conf = parse_args(argc, argv);
    } catch (std::invalid_argument & ia) {
        std::cerr << ia.what() << std::endl;
        std::exit(EXIT_FAILURE);
    }

    if (!util::fs::dir_exists(util::fs::dirname(conf.out_prefix).c_str())) {
        std::cerr << "Destination directory does not exist!" << std::endl;
        std::exit(EXIT_FAILURE);
    }

    std::cout << "Load and prepare mesh: " << std::endl;
    mve::TriangleMesh::Ptr mesh;
    try {
        mesh = mve::geom::load_ply_mesh(conf.in_mesh);
    } catch (std::exception& e) {
        std::cerr << "\tCould not load mesh: "<< e.what() << std::endl;
        std::exit(EXIT_FAILURE);
    }
    mve::MeshInfo mesh_info(mesh);
    tex::prepare_mesh(&mesh_info, mesh);

    std::cout << "Generating texture views: " << std::endl;
    tex::TextureViews texture_views;
    tex::generate_texture_views(conf.in_scene, &texture_views);

    write_string_to_file(conf.out_prefix + ".conf", conf.to_string());
    timer.measure("Loading");

    std::size_t const num_faces = mesh->get_faces().size() / 3;

    std::cout << "Building adjacency graph: " << std::endl;
    tex::Graph graph(num_faces);
    tex::build_adjacency_graph(mesh, mesh_info, &graph);

    if (conf.labeling_file.empty()) {
        std::cout << "View selection:" << std::endl;

        tex::DataCosts data_costs(num_faces, texture_views.size());
        if (conf.data_cost_file.empty()) {
            tex::calculate_data_costs(mesh, &texture_views, conf.settings, &data_costs);

            if (conf.write_intermediate_results) {
                std::cout << "\tWriting data cost file... " << std::flush;
                    ST::save_to_file(data_costs, conf.out_prefix + "_data_costs.spt");
                std::cout << "done." << std::endl;
            }
        } else {
            std::cout << "\tLoading data cost file... " << std::flush;
            try {
                ST::load_from_file(conf.data_cost_file, &data_costs);
            } catch (util::FileException e) {
                std::cout << "failed!" << std::endl;
                std::cerr << e.what() << std::endl;
                std::exit(EXIT_FAILURE);
            }
            std::cout << "done." << std::endl;
        }
        timer.measure("Calculating data costs");

        tex::view_selection(data_costs, &graph, conf.settings);
        timer.measure("Running MRF optimization");

        /* Write labeling to file. */
        if (conf.write_intermediate_results) {
            std::vector<std::size_t> labeling(graph.num_nodes());
            for (std::size_t i = 0; i < graph.num_nodes(); ++i) {
                labeling[i] = graph.get_label(i);
            }
            vector_to_file(conf.out_prefix + "_labeling.vec", labeling);
        }
    } else {
        std::cout << "Loading labeling from file... " << std::flush;

        /* Load labeling from file. */
        std::vector<std::size_t> labeling = vector_from_file<std::size_t>(conf.labeling_file);
        if (labeling.size() != graph.num_nodes()) {
            std::cerr << "Wrong labeling file for this mesh/scene combination... aborting!" << std::endl;
            std::exit(EXIT_FAILURE);
        }

        /* Transfer labeling to graph. */
        for (std::size_t i = 0; i < labeling.size(); ++i) {
            const std::size_t label = labeling[i];
            if (label > texture_views.size()){
                std::cerr << "Wrong labeling file for this mesh/scene combination... aborting!" << std::endl;
                std::exit(EXIT_FAILURE);
            }
            graph.set_label(i, label);
        }

        std::cout << "done." << std::endl;
    }
    std::cout << "\tTook: " << wtimer.get_elapsed_sec() << "s" << std::endl;

    tex::TextureAtlases texture_atlases;
    {
        /* Create texture patches and adjust them. */
        tex::TexturePatches texture_patches;
        tex::VertexProjectionInfos vertex_projection_infos;
        std::cout << "Generating texture patches:" << std::endl;
        tex::generate_texture_patches(graph, mesh, mesh_info, &texture_views, &vertex_projection_infos, &texture_patches);

        if (conf.settings.global_seam_leveling) {
            std::cout << "Running global seam leveling:" << std::endl;
            tex::global_seam_leveling(graph, mesh, mesh_info, vertex_projection_infos, &texture_patches);
            timer.measure("Running global seam leveling");
        } else {
            ProgressCounter texture_patch_counter("Calculating validity masks for texture patches", texture_patches.size());
            #pragma omp parallel for schedule(dynamic)
            for (std::size_t i = 0; i < texture_patches.size(); ++i) {
                texture_patch_counter.progress<SIMPLE>();
                TexturePatch::Ptr texture_patch = texture_patches[i];
                std::vector<math::Vec3f> patch_adjust_values(texture_patch->get_faces().size() * 3, math::Vec3f(0.0f));
                texture_patch->adjust_colors(patch_adjust_values);
                texture_patch_counter.inc();
            }
            timer.measure("Calculating texture patch validity masks");
        }

        if (conf.settings.local_seam_leveling) {
            std::cout << "Running local seam leveling:" << std::endl;
            tex::local_seam_leveling(graph, mesh, vertex_projection_infos, &texture_patches);
        }
        timer.measure("Running local seam leveling");

        /* Generate texture atlases. */
        std::cout << "Generating texture atlases:" << std::endl;
        tex::generate_texture_atlases(&texture_patches, &texture_atlases);
    }

    /* Create and write out obj model. */
    {
        std::cout << "Building objmodel:" << std::endl;
        tex::Model model;
        tex::build_model(mesh, texture_atlases, &model);
        timer.measure("Building OBJ model");

        std::cout << "\tSaving model... " << std::flush;
        tex::Model::save(model, conf.out_prefix);
        std::cout << "done." << std::endl;
        timer.measure("Saving");
    }

    std::cout << "Whole texturing procedure took: " << wtimer.get_elapsed_sec() << "s" << std::endl;
    timer.measure("Total");
    if (conf.write_timings) {
        timer.write_to_file(conf.out_prefix + "_timings.csv");
    }

    if (conf.write_view_selection_model) {
        texture_atlases.clear();
        std::cout << "Generating debug texture patches:" << std::endl;
        {
            tex::TexturePatches texture_patches;
            generate_debug_embeddings(&texture_views);
            tex::VertexProjectionInfos vertex_projection_infos; // Will only be written
            tex::generate_texture_patches(graph, mesh, mesh_info, &texture_views, &vertex_projection_infos, &texture_patches);
            tex::generate_texture_atlases(&texture_patches, &texture_atlases);
        }

        std::cout << "Building debug objmodel:" << std::endl;
        {
            tex::Model model;
            tex::build_model(mesh, texture_atlases, &model);
            std::cout << "\tSaving model... " << std::flush;
            tex::Model::save(model, conf.out_prefix + "_view_selection");
            std::cout << "done." << std::endl;
        }
    }

    return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>#include <cstring>
#include <sstream>

#include "ksync/logging.h"
#include "ksync/comm_system_object.h"

namespace KSync {
	namespace Comm {
		CommObject::PackException::PackException(Type_t type) {
			std::stringstream ss;
			ss << "There was a problem packing an object of type (" << GetTypeName(type) << ")";
			SetMessage(ss.str());
		}
		CommObject::UnPackException::UnPackException(Type_t type) {
			std::stringstream ss;
			ss << "There was a problem un packing an object of type (" << GetTypeName(type) << ")";
			SetMessage(ss.str());
		}
		CommObject::CRCException::CRCException() {
			SetMessage("There was a CRC miss-match");
		}
		CommObject::CommObjectConstructorException::CommObjectConstructorException() {
			SetMessage("There was a problem constructing the comm object!");
		}

		CommObject::CommObject(const char* data, const size_t size, const bool pre_packed, const Type_t type) {
			if(data == 0) {
				if (size != 0) {
					Error("Can't use size != 0 with a null data pointer!!\n");
					throw CommObjectConstructorException();
				}
				if (pre_packed) {
					Error("Can't say an object is pre-packed if using a null data input\n");
					throw CommObjectConstructorException();
				}
				this->type = type;
				this->data = 0;
				this->size = 0;
				if(Pack() < 0) {
					throw PackException(this->type);
				}
			} else {
				this->data = new char[size];
				memcpy(this->data, data, size);
				this->size = size;
				if (pre_packed) {
					this->type = ((Type_t*)this->data)[0];
					this->crc = ((char*)this->data)[sizeof(this->type)];
					this->packed = true;
				} else {
					this->type = type;
					if(Pack() < 0) {
						throw PackException(this->type);
					}
				}
			}

		}

		CommObject::~CommObject() {
			if (data != 0) {
				delete[] data;
			}
			size = 0;
		}

		int CommObject::Pack() {
			size_t num_extra_bytes = sizeof(this->type)+sizeof(this->crc);
			char* new_data = new char[num_extra_bytes+this->size];
			if (this->data == 0) {
				this->crc = 0;
				new_data[0] = this->type;
				new_data[sizeof(this->type)] = this->crc;
				this->data = new_data;
				this->size += num_extra_bytes;
				this->packed = true;
			} else {
				this->crc = GenCRC8(this->data, this->size);
				new_data[0] = this->type;
				new_data[sizeof(this->type)] = this->crc;
				memcpy(new_data+num_extra_bytes, this->data, this->size);
				delete this->data;
				this->data = new_data;
				this->size += num_extra_bytes;
				this->packed = true;
			}
			return 0;
		}

		int CommObject::UnPack() {
			if (!this->packed) {
				return 0;
			}
			size_t num_extra_bytes = sizeof(this->type)+sizeof(this->crc);
			if (this->size == num_extra_bytes) {
				if (this->crc != 0) {
					return -1;
				}
				delete this->data;
				this->data = 0;
			} else {
				char new_crc = GenCRC8(this->data+num_extra_bytes, this->size-num_extra_bytes);
				if (new_crc != this->crc) {
					return -1;
				}
				size_t new_size = this->size-num_extra_bytes;
				char* new_data = new char[this->size-num_extra_bytes];
				memcpy(new_data, this->data+num_extra_bytes, new_size);
				delete this->data;
				this->data = new_data;
			}
			this->size -= num_extra_bytes;
			this->packed = false;
			return 0;
		}

		char CommObject::GenCRC8(const char* data, const size_t size) {
			char out = 0;
			int bits_read = 0;
			int bit_flag;

			if (data == 0) {
				return 0;
			}

			size_t temp_size = size;

			while(temp_size > 0) {
				bit_flag = out >> 15;

				/* Get next bit: */
				out <<= 1;
				out |= (*data >> bits_read) & 1; // item a) work from the least significant bits

				/* Increment bit counter: */
				bits_read++;
				if(bits_read > 7) {
					bits_read = 0;
					data++;
					temp_size--;
				}

				/* Cycle check: */
				if (bit_flag)
					out ^= CRC8;
			}

			// item b) "push out" the last 8 bits
			for (int i = 0; i < 8; ++i) {
				bit_flag = out >> 7;
				out <<= 1;
				if (bit_flag) {
					out ^= CRC8;
				}
			}

			// item c) reverse the bits
			char crc = 0;
			int i = 0x80;
			int j = 0x01;
			for (; i != 0; i >>= 1, j <<= 1) {
				if (i & out) {
					crc |= j;
				}
			}

			return crc;
		}
	}
}
<commit_msg>Fix memory errors found with valgrind<commit_after>#include <cstring>
#include <sstream>

#include "ksync/logging.h"
#include "ksync/comm_system_object.h"

namespace KSync {
	namespace Comm {
		CommObject::PackException::PackException(Type_t type) {
			std::stringstream ss;
			ss << "There was a problem packing an object of type (" << GetTypeName(type) << ")";
			SetMessage(ss.str());
		}
		CommObject::UnPackException::UnPackException(Type_t type) {
			std::stringstream ss;
			ss << "There was a problem un packing an object of type (" << GetTypeName(type) << ")";
			SetMessage(ss.str());
		}
		CommObject::CRCException::CRCException() {
			SetMessage("There was a CRC miss-match");
		}
		CommObject::CommObjectConstructorException::CommObjectConstructorException() {
			SetMessage("There was a problem constructing the comm object!");
		}

		CommObject::CommObject(const char* data, const size_t size, const bool pre_packed, const Type_t type) {
			if(data == 0) {
				if (size != 0) {
					Error("Can't use size != 0 with a null data pointer!!\n");
					throw CommObjectConstructorException();
				}
				if (pre_packed) {
					Error("Can't say an object is pre-packed if using a null data input\n");
					throw CommObjectConstructorException();
				}
				this->type = type;
				this->data = 0;
				this->size = 0;
				if(Pack() < 0) {
					throw PackException(this->type);
				}
			} else {
				this->data = new char[size];
				memcpy(this->data, data, size);
				this->size = size;
				if (pre_packed) {
					this->type = ((Type_t*)this->data)[0];
					this->crc = ((char*)this->data)[sizeof(this->type)];
					this->packed = true;
				} else {
					this->type = type;
					if(Pack() < 0) {
						throw PackException(this->type);
					}
				}
			}

		}

		CommObject::~CommObject() {
			if (data != 0) {
				delete[] data;
			}
			size = 0;
		}

		int CommObject::Pack() {
			size_t num_extra_bytes = sizeof(this->type)+sizeof(this->crc);
			char* new_data = new char[num_extra_bytes+this->size];
			if (this->data == 0) {
				this->crc = 0;
				new_data[0] = this->type;
				new_data[sizeof(this->type)] = this->crc;
				this->data = new_data;
				this->size += num_extra_bytes;
				this->packed = true;
			} else {
				this->crc = GenCRC8(this->data, this->size);
				new_data[0] = this->type;
				new_data[sizeof(this->type)] = this->crc;
				memcpy(new_data+num_extra_bytes, this->data, this->size);
				delete[] this->data;
				this->data = new_data;
				this->size += num_extra_bytes;
				this->packed = true;
			}
			return 0;
		}

		int CommObject::UnPack() {
			if (!this->packed) {
				return 0;
			}
			size_t num_extra_bytes = sizeof(this->type)+sizeof(this->crc);
			if (this->size == num_extra_bytes) {
				if (this->crc != 0) {
					return -1;
				}
				delete[] this->data;
				this->data = 0;
			} else {
				char new_crc = GenCRC8(this->data+num_extra_bytes, this->size-num_extra_bytes);
				if (new_crc != this->crc) {
					return -1;
				}
				size_t new_size = this->size-num_extra_bytes;
				char* new_data = new char[this->size-num_extra_bytes];
				memcpy(new_data, this->data+num_extra_bytes, new_size);
				delete[] this->data;
				this->data = new_data;
			}
			this->size -= num_extra_bytes;
			this->packed = false;
			return 0;
		}

		char CommObject::GenCRC8(const char* data, const size_t size) {
			char out = 0;
			int bits_read = 0;
			int bit_flag;

			if (data == 0) {
				return 0;
			}

			size_t temp_size = size;

			while(temp_size > 0) {
				bit_flag = out >> 15;

				/* Get next bit: */
				out <<= 1;
				out |= (*data >> bits_read) & 1; // item a) work from the least significant bits

				/* Increment bit counter: */
				bits_read++;
				if(bits_read > 7) {
					bits_read = 0;
					data++;
					temp_size--;
				}

				/* Cycle check: */
				if (bit_flag)
					out ^= CRC8;
			}

			// item b) "push out" the last 8 bits
			for (int i = 0; i < 8; ++i) {
				bit_flag = out >> 7;
				out <<= 1;
				if (bit_flag) {
					out ^= CRC8;
				}
			}

			// item c) reverse the bits
			char crc = 0;
			int i = 0x80;
			int j = 0x01;
			for (; i != 0; i >>= 1, j <<= 1) {
				if (i & out) {
					crc |= j;
				}
			}

			return crc;
		}
	}
}
<|endoftext|>


<commit_before>#include "vtoolbox.h"

#include <QPushButton>
#include <QStackedLayout>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QVariant>
#include <QLabel>

#include "vnote.h"
#include "utils/vutils.h"
#include "utils/viconutils.h"

extern VNote *g_vnote;

VToolBox::VToolBox(QWidget *p_parent)
    : QWidget(p_parent),
      m_currentIndex(-1)
{
    setupUI();
}

void VToolBox::setupUI()
{
    m_btnLayout = new QHBoxLayout();
    m_btnLayout->addStretch();
    m_btnLayout->setContentsMargins(0, 0, 0, 2);
    m_btnLayout->setSpacing(0);
    QWidget *wid = new QWidget();
    wid->setProperty("ToolBoxTitle", true);
    wid->setLayout(m_btnLayout);

    m_widgetLayout = new QStackedLayout();

    QVBoxLayout *mainLayout = new QVBoxLayout();
    mainLayout->addWidget(wid);
    mainLayout->addLayout(m_widgetLayout);
    int margin = 2 * VUtils::calculateScaleFactor();
    mainLayout->setContentsMargins(margin, 0, margin, 0);

    setLayout(mainLayout);
}

int VToolBox::addItem(QWidget *p_widget,
                      const QString &p_iconFile,
                      const QString &p_text,
                      QWidget *p_focusWidget)
{
    int idx = m_items.size();

    // New a button.
    QIcon icon = VIconUtils::toolBoxIcon(p_iconFile);
    QPushButton *btn = new QPushButton(icon, "");
    btn->setToolTip(p_text);
    btn->setProperty("FlatBtn", true);
    btn->setProperty("ToolBoxTitleBtn", true);
    connect(btn, &QPushButton::clicked,
            this, [this]() {
                QObject *btn = sender();
                for (int i = 0; i < m_items.size(); ++i) {
                    if (m_items[i].m_btn == btn) {
                        setCurrentIndex(i);
                        break;
                    }
                }
            });

    m_btnLayout->insertWidget(idx, btn);

    // Insert widget to layout.
    m_widgetLayout->insertWidget(idx, p_widget);

    m_items.push_back(ItemInfo(p_widget,
                               p_focusWidget,
                               p_text,
                               btn,
                               icon,
                               VIconUtils::toolBoxActiveIcon(p_iconFile)));

    if (m_items.size() == 1) {
        setCurrentIndex(0);
    }

    return idx;
}

void VToolBox::setCurrentIndex(int p_idx, bool p_focus)
{
    if (p_idx < 0 || p_idx >= m_items.size()) {
        if (m_items.isEmpty()) {
            m_currentIndex = -1;
        } else {
            m_currentIndex = 0;
        }
    } else {
        m_currentIndex = p_idx;
    }

    setCurrentButtonIndex(m_currentIndex);

    m_widgetLayout->setCurrentIndex(m_currentIndex);

    QWidget *widget = m_widgetLayout->widget(m_currentIndex);
    if (widget && p_focus) {
        if (m_items[m_currentIndex].m_focusWidget) {
            m_items[m_currentIndex].m_focusWidget->setFocus();
        } else {
            widget->setFocus();
        }
    }
}

void VToolBox::setCurrentWidget(QWidget *p_widget, bool p_focus)
{
    int idx = -1;
    for (int i = 0; i < m_items.size(); ++i) {
        if (m_items[i].m_widget == p_widget) {
            idx = i;
            break;
        }
    }

    setCurrentIndex(idx, p_focus);
}

void VToolBox::setCurrentButtonIndex(int p_idx)
{
    // Remove the text of all button.
    for (int i = 0; i < m_items.size(); ++i) {
        QPushButton *btn = m_items[i].m_btn;
        btn->setText("");
        btn->setIcon(m_items[i].m_icon);
        btn->clearFocus();
        VUtils::setDynamicProperty(btn, "ToolBoxActiveBtn", false);
    }

    if (p_idx < 0 || p_idx >= m_items.size()) {
        return;
    }

    QPushButton *curBtn = m_items[p_idx].m_btn;
    curBtn->setText(m_items[p_idx].m_text);
    curBtn->setIcon(m_items[p_idx].m_activeIcon);
    VUtils::setDynamicProperty(curBtn, "ToolBoxActiveBtn", true);
}

void VToolBox::showNavigation()
{
    clearNavigation();

    if (!isVisible()) {
        return;
    }

    for (int i = 0; i < 26 && i < m_items.size(); ++i) {
        const ItemInfo &item = m_items[i];

        QChar key('a' + i);
        m_keyMap[key] = item.m_widget;

        QString str = QString(m_majorKey) + key;
        QLabel *label = new QLabel(str, this);
        label->setStyleSheet(g_vnote->getNavigationLabelStyle(str));
        label->show();
        QRect rect = item.m_btn->geometry();
        // Display the label at the end to show the file name.
        label->move(rect.x(), rect.y() + rect.height() / 2);
        m_naviLabels.append(label);
    }
}

bool VToolBox::handleKeyNavigation(int p_key, bool &p_succeed)
{
    bool ret = false;
    p_succeed = false;
    QChar keyChar = VUtils::keyToChar(p_key);
    if (m_isSecondKey && !keyChar.isNull()) {
        m_isSecondKey = false;
        p_succeed = true;
        auto it = m_keyMap.find(keyChar);
        if (it != m_keyMap.end()) {
            ret = true;
            QWidget *widget = static_cast<QWidget *>(it.value());
            setCurrentWidget(widget);
        }
    } else if (keyChar == m_majorKey) {
        // Major key pressed.
        // Need second key if m_keyMap is not empty.
        if (m_keyMap.isEmpty()) {
            p_succeed = true;
        } else {
            m_isSecondKey = true;
        }

        ret = true;
    }

    return ret;
}
<commit_msg>update VToolBox's margin<commit_after>#include "vtoolbox.h"

#include <QPushButton>
#include <QStackedLayout>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QVariant>
#include <QLabel>

#include "vnote.h"
#include "utils/vutils.h"
#include "utils/viconutils.h"

extern VNote *g_vnote;

VToolBox::VToolBox(QWidget *p_parent)
    : QWidget(p_parent),
      m_currentIndex(-1)
{
    setupUI();
}

void VToolBox::setupUI()
{
    m_btnLayout = new QHBoxLayout();
    m_btnLayout->addStretch();
    m_btnLayout->setContentsMargins(0, 0, 0, 2);
    m_btnLayout->setSpacing(0);
    QWidget *wid = new QWidget();
    wid->setProperty("ToolBoxTitle", true);
    wid->setLayout(m_btnLayout);

    m_widgetLayout = new QStackedLayout();

    QVBoxLayout *mainLayout = new QVBoxLayout();
    mainLayout->addWidget(wid);
    mainLayout->addLayout(m_widgetLayout);
    mainLayout->setContentsMargins(3, 0, 3, 0);

    setLayout(mainLayout);
}

int VToolBox::addItem(QWidget *p_widget,
                      const QString &p_iconFile,
                      const QString &p_text,
                      QWidget *p_focusWidget)
{
    int idx = m_items.size();

    // New a button.
    QIcon icon = VIconUtils::toolBoxIcon(p_iconFile);
    QPushButton *btn = new QPushButton(icon, "");
    btn->setToolTip(p_text);
    btn->setProperty("FlatBtn", true);
    btn->setProperty("ToolBoxTitleBtn", true);
    connect(btn, &QPushButton::clicked,
            this, [this]() {
                QObject *btn = sender();
                for (int i = 0; i < m_items.size(); ++i) {
                    if (m_items[i].m_btn == btn) {
                        setCurrentIndex(i);
                        break;
                    }
                }
            });

    m_btnLayout->insertWidget(idx, btn);

    // Insert widget to layout.
    m_widgetLayout->insertWidget(idx, p_widget);

    m_items.push_back(ItemInfo(p_widget,
                               p_focusWidget,
                               p_text,
                               btn,
                               icon,
                               VIconUtils::toolBoxActiveIcon(p_iconFile)));

    if (m_items.size() == 1) {
        setCurrentIndex(0);
    }

    return idx;
}

void VToolBox::setCurrentIndex(int p_idx, bool p_focus)
{
    if (p_idx < 0 || p_idx >= m_items.size()) {
        if (m_items.isEmpty()) {
            m_currentIndex = -1;
        } else {
            m_currentIndex = 0;
        }
    } else {
        m_currentIndex = p_idx;
    }

    setCurrentButtonIndex(m_currentIndex);

    m_widgetLayout->setCurrentIndex(m_currentIndex);

    QWidget *widget = m_widgetLayout->widget(m_currentIndex);
    if (widget && p_focus) {
        if (m_items[m_currentIndex].m_focusWidget) {
            m_items[m_currentIndex].m_focusWidget->setFocus();
        } else {
            widget->setFocus();
        }
    }
}

void VToolBox::setCurrentWidget(QWidget *p_widget, bool p_focus)
{
    int idx = -1;
    for (int i = 0; i < m_items.size(); ++i) {
        if (m_items[i].m_widget == p_widget) {
            idx = i;
            break;
        }
    }

    setCurrentIndex(idx, p_focus);
}

void VToolBox::setCurrentButtonIndex(int p_idx)
{
    // Remove the text of all button.
    for (int i = 0; i < m_items.size(); ++i) {
        QPushButton *btn = m_items[i].m_btn;
        btn->setText("");
        btn->setIcon(m_items[i].m_icon);
        btn->clearFocus();
        VUtils::setDynamicProperty(btn, "ToolBoxActiveBtn", false);
    }

    if (p_idx < 0 || p_idx >= m_items.size()) {
        return;
    }

    QPushButton *curBtn = m_items[p_idx].m_btn;
    curBtn->setText(m_items[p_idx].m_text);
    curBtn->setIcon(m_items[p_idx].m_activeIcon);
    VUtils::setDynamicProperty(curBtn, "ToolBoxActiveBtn", true);
}

void VToolBox::showNavigation()
{
    clearNavigation();

    if (!isVisible()) {
        return;
    }

    for (int i = 0; i < 26 && i < m_items.size(); ++i) {
        const ItemInfo &item = m_items[i];

        QChar key('a' + i);
        m_keyMap[key] = item.m_widget;

        QString str = QString(m_majorKey) + key;
        QLabel *label = new QLabel(str, this);
        label->setStyleSheet(g_vnote->getNavigationLabelStyle(str));
        label->show();
        QRect rect = item.m_btn->geometry();
        // Display the label at the end to show the file name.
        label->move(rect.x(), rect.y() + rect.height() / 2);
        m_naviLabels.append(label);
    }
}

bool VToolBox::handleKeyNavigation(int p_key, bool &p_succeed)
{
    bool ret = false;
    p_succeed = false;
    QChar keyChar = VUtils::keyToChar(p_key);
    if (m_isSecondKey && !keyChar.isNull()) {
        m_isSecondKey = false;
        p_succeed = true;
        auto it = m_keyMap.find(keyChar);
        if (it != m_keyMap.end()) {
            ret = true;
            QWidget *widget = static_cast<QWidget *>(it.value());
            setCurrentWidget(widget);
        }
    } else if (keyChar == m_majorKey) {
        // Major key pressed.
        // Need second key if m_keyMap is not empty.
        if (m_keyMap.isEmpty()) {
            p_succeed = true;
        } else {
            m_isSecondKey = true;
        }

        ret = true;
    }

    return ret;
}
<|endoftext|>