<commit_before>#include "sorter.h"
#include <QtQml>

namespace qqsfpm {

/*!
    \qmltype Sorter
    \inqmlmodule SortFilterProxyModel
    \brief Base type for the \l SortFilterProxyModel sorters

    The Sorter type cannot be used directly in a QML file.
    It exists to provide a set of common properties and methods,
    available across all the other sorters types that inherit from it.
    Attempting to use the Sorter type directly will result in an error.
*/

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

Sorter::~Sorter() = default;

/*!
    \qmlproperty bool Sorter::enabled

    This property holds whether the sorter is enabled.
    A disabled sorter will not change the order of the rows.

    By default, sorters are enabled.
*/
bool Sorter::enabled() const
{
    return m_enabled;
}

void Sorter::setEnabled(bool enabled)
{
    if (m_enabled == enabled)
        return;

    m_enabled = enabled;
    Q_EMIT enabledChanged();
    Q_EMIT invalidated();
}

bool Sorter::ascendingOrder() const
{
    return sortOrder() == Qt::AscendingOrder;
}

void Sorter::setAscendingOrder(bool ascendingOrder)
{
    setSortOrder(ascendingOrder ? Qt::AscendingOrder : Qt::DescendingOrder);
}

/*!
    \qmlproperty Qt::SortOrder Sorter::sortOrder

    This property holds the sort order of this sorter.

    \value Qt.AscendingOrder The items are sorted ascending e.g. starts with 'AAA' ends with 'ZZZ' in Latin-1 locales
    \value Qt.DescendingOrder The items are sorted descending e.g. starts with 'ZZZ' ends with 'AAA' in Latin-1 locales

    By default, sorting is in ascending order.
*/
Qt::SortOrder Sorter::sortOrder() const
{
    return m_sortOrder;
}

void Sorter::setSortOrder(Qt::SortOrder sortOrder)
{
    if (m_sortOrder == sortOrder)
        return;

    m_sortOrder = sortOrder;
    Q_EMIT sortOrderChanged();
    invalidate();
}

int Sorter::compareRows(const QModelIndex &source_left, const QModelIndex &source_right, const QQmlSortFilterProxyModel& proxyModel) const
{
    int comparison = compare(source_left, source_right, proxyModel);
    return (m_sortOrder == Qt::AscendingOrder) ? comparison : -comparison;
}

int Sorter::compare(const QModelIndex &sourceLeft, const QModelIndex &sourceRight, const QQmlSortFilterProxyModel& proxyModel) const
{
    if (lessThan(sourceLeft, sourceRight, proxyModel))
        return -1;
    if (lessThan(sourceRight, sourceLeft, proxyModel))
        return 1;
    return 0;
}

void Sorter::proxyModelCompleted(const QQmlSortFilterProxyModel& proxyModel)
{
    Q_UNUSED(proxyModel)
}

bool Sorter::lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight, const QQmlSortFilterProxyModel& proxyModel) const
{
    Q_UNUSED(sourceLeft)
    Q_UNUSED(sourceRight)
    Q_UNUSED(proxyModel)
    return false;
}

void Sorter::invalidate()
{
    if (m_enabled)
        Q_EMIT invalidated();
}

const QString& RoleSorter::roleName() const
{
    return m_roleName;
}

/*!
    \qmltype RoleSorter
    \inherits Sorter
    \inqmlmodule SortFilterProxyModel
    \brief Sorts rows based on a source model role

    A RoleSorter is a simple \l Sorter that sorts rows based on a source model role.

    In the following example, rows with be sorted by their \c lastName role :
    \code
    SortFilterProxyModel {
       sourceModel: contactModel
       sorters: RoleSorter { roleName: "lastName" }
    }
    \endcode
*/

/*!
    \qmlproperty string RoleSorter::roleName

    This property holds the role name that the sorter is using to query the source model's data when sorting items.
*/
void RoleSorter::setRoleName(const QString& roleName)
{
    if (m_roleName == roleName)
        return;

    m_roleName = roleName;
    Q_EMIT roleNameChanged();
    invalidate();
}

QPair<QVariant, QVariant> RoleSorter::sourceData(const QModelIndex &sourceLeft, const QModelIndex& sourceRight, const QQmlSortFilterProxyModel& proxyModel) const
{
    QPair<QVariant, QVariant> pair;
    int role = proxyModel.roleForName(m_roleName);
    pair.first = proxyModel.sourceData(sourceLeft, role);
    pair.second = proxyModel.sourceData(sourceRight, role);
    return pair;
}

int RoleSorter::compare(const QModelIndex &sourceLeft, const QModelIndex& sourceRight, const QQmlSortFilterProxyModel& proxyModel) const
{
    QPair<QVariant, QVariant> pair = sourceData(sourceLeft, sourceRight, proxyModel);
    QVariant leftValue = pair.first;
    QVariant rightValue = pair.second;
    if (leftValue < rightValue)
        return -1;
    if (leftValue > rightValue)
        return 1;
    return 0;
}

/*!
    \qmltype StringSorter
    \inherits RoleSorter
    \inqmlmodule SortFilterProxyModel
    \brief Sorts rows based on a source model string role

    \l StringSorter is a specialized \l RoleSorter that sorts rows based on a source model string role.
    \l StringSorter compares strings according to a localized collation algorithm.

    In the following example, rows with be sorted by their \c lastName role :
    \code
    SortFilterProxyModel {
       sourceModel: contactModel
       sorters: StringSorter { roleName: "lastName" }
    }
    \endcode
*/

/*!
    \qmlproperty Qt.CaseSensitivity StringSorter::caseSensitivity

    This property holds the case sensitivity of the sorter.
*/
Qt::CaseSensitivity StringSorter::caseSensitivity() const
{
    return m_collator.caseSensitivity();
}

void StringSorter::setCaseSensitivity(Qt::CaseSensitivity caseSensitivity)
{
    if (m_collator.caseSensitivity() == caseSensitivity)
        return;

    m_collator.setCaseSensitivity(caseSensitivity);
    Q_EMIT caseSensitivityChanged();
    invalidate();
}

/*!
    \qmlproperty bool StringSorter::ignorePunctation

    This property holds whether the sorter ignores punctation.
    if \c ignorePunctuation is \c true, punctuation characters and symbols are ignored when determining sort order.

    \note This property is not currently supported on Apple platforms or if Qt is configured to not use ICU on Linux.
*/
bool StringSorter::ignorePunctation() const
{
    return m_collator.ignorePunctuation();
}

void StringSorter::setIgnorePunctation(bool ignorePunctation)
{
    if (m_collator.ignorePunctuation() == ignorePunctation)
        return;

    m_collator.setIgnorePunctuation(ignorePunctation);
    Q_EMIT ignorePunctationChanged();
    invalidate();
}

/*!
    \qmlproperty Locale StringSorter::locale

    This property holds the locale of the sorter.
*/
QLocale StringSorter::locale() const
{
    return m_collator.locale();
}

void StringSorter::setLocale(const QLocale &locale)
{
    if (m_collator.locale() == locale)
        return;

    m_collator.setLocale(locale);
    Q_EMIT localeChanged();
    invalidate();
}

/*!
    \qmlproperty bool StringSorter::numericMode

    This property holds whether the numeric mode of the sorter is enabled.
    This will enable proper sorting of numeric digits, so that e.g. 100 sorts after 99.
    By default this mode is off.
*/
bool StringSorter::numericMode() const
{
    return m_collator.numericMode();
}

void StringSorter::setNumericMode(bool numericMode)
{
    if (m_collator.numericMode() == numericMode)
        return;

    m_collator.setNumericMode(numericMode);
    Q_EMIT numericModeChanged();
    invalidate();
}

int StringSorter::compare(const QModelIndex &sourceLeft, const QModelIndex &sourceRight, const QQmlSortFilterProxyModel& proxyModel) const
{
    QPair<QVariant, QVariant> pair = sourceData(sourceLeft, sourceRight, proxyModel);
    QString leftValue = pair.first.toString();
    QString rightValue = pair.second.toString();
    return m_collator.compare(leftValue, rightValue);
}

/*!
    \qmltype ExpressionSorter
    \inherits Sorter
    \inqmlmodule SortFilterProxyModel
    \brief Sorts row with a custom sorting

    An ExpressionSorter is a \l Sorter allowing to implement custom sorting based on a javascript expression.
*/

/*!
    \qmlproperty expression ExpressionSorter::expression

    An expression to implement custom sorting. It must evaluate to a bool.
    It has the same syntax has a \l {http://doc.qt.io/qt-5/qtqml-syntax-propertybinding.html} {Property Binding}, except that it will be evaluated for each of the source model's rows.
    Model data is accessible for both rows with the \c modelLeft, and \c modelRight properties:

    \code
    sorters: ExpressionSorter {
        expression: {
            return modelLeft.someRole < modelRight.someRole;
        }
    }
    \endcode

    The \c index of the row is also available through \c modelLeft and \c modelRight.

    The expression should return \c true if the value of the left item is less than the value of the right item, otherwise returns false.

    This expression is reevaluated for a row every time its model data changes.
    When an external property (not \c index* or in \c model*) the expression depends on changes, the expression is reevaluated for every row of the source model.
    To capture the properties the expression depends on, the expression is first executed with invalid data and each property access is detected by the QML engine.
    This means that if a property is not accessed because of a conditional, it won't be captured and the expression won't be reevaluted when this property changes.

    A workaround to this problem is to access all the properties the expressions depends unconditionally at the beggining of the expression.
*/
const QQmlScriptString& ExpressionSorter::expression() const
{
    return m_scriptString;
}

void ExpressionSorter::setExpression(const QQmlScriptString& scriptString)
{
    if (m_scriptString == scriptString)
        return;

    m_scriptString = scriptString;
    updateExpression();

    Q_EMIT expressionChanged();
    invalidate();
}

void ExpressionSorter::proxyModelCompleted(const QQmlSortFilterProxyModel& proxyModel)
{
    updateContext(proxyModel);
}

bool evaluateBoolExpression(QQmlExpression& expression)
{
    QVariant variantResult = expression.evaluate();
    if (expression.hasError()) {
        qWarning() << expression.error();
        return false;
    }
    if (variantResult.canConvert<bool>()) {
        return variantResult.toBool();
    } else {
        qWarning("%s:%i:%i : Can't convert result to bool",
                 expression.sourceFile().toUtf8().data(),
                 expression.lineNumber(),
                 expression.columnNumber());
        return false;
    }
}

int ExpressionSorter::compare(const QModelIndex& sourceLeft, const QModelIndex& sourceRight, const QQmlSortFilterProxyModel& proxyModel) const
{
    if (!m_scriptString.isEmpty()) {
        QVariantMap modelLeftMap, modelRightMap;
        QHash<int, QByteArray> roles = proxyModel.roleNames();

        QQmlContext context(qmlContext(this));

        for (auto it = roles.cbegin(); it != roles.cend(); ++it) {
            modelLeftMap.insert(it.value(), proxyModel.sourceData(sourceLeft, it.key()));
            modelRightMap.insert(it.value(), proxyModel.sourceData(sourceRight, it.key()));
        }
        modelLeftMap.insert("index", sourceLeft.row());
        modelRightMap.insert("index", sourceRight.row());

        QQmlExpression expression(m_scriptString, &context);

        context.setContextProperty("modelLeft", modelLeftMap);
        context.setContextProperty("modelRight", modelRightMap);
        if (evaluateBoolExpression(expression))
                return -1;

        context.setContextProperty("modelLeft", modelRightMap);
        context.setContextProperty("modelRight", modelLeftMap);
        if (evaluateBoolExpression(expression))
                return 1;
    }
    return 0;
}

void ExpressionSorter::updateContext(const QQmlSortFilterProxyModel& proxyModel)
{
    delete m_context;
    m_context = new QQmlContext(qmlContext(this), this);

    QVariantMap modelLeftMap, modelRightMap;
    // what about roles changes ?

    for (const QByteArray& roleName : proxyModel.roleNames().values()) {
        modelLeftMap.insert(roleName, QVariant());
        modelRightMap.insert(roleName, QVariant());
    }
    modelLeftMap.insert("index", -1);
    modelRightMap.insert("index", -1);

    m_context->setContextProperty("modelLeft", modelLeftMap);
    m_context->setContextProperty("modelRight", modelRightMap);

    updateExpression();
}

void ExpressionSorter::updateExpression()
{
    if (!m_context)
        return;

    delete m_expression;
    m_expression = new QQmlExpression(m_scriptString, m_context, 0, this);
    connect(m_expression, &QQmlExpression::valueChanged, this, &ExpressionSorter::invalidate);
    m_expression->setNotifyOnValueChanged(true);
    m_expression->evaluate();
}

void registerSorterTypes() {
    qmlRegisterUncreatableType<Sorter>("SortFilterProxyModel", 0, 2, "Sorter", "Sorter is an abstract class");
    qmlRegisterType<RoleSorter>("SortFilterProxyModel", 0, 2, "RoleSorter");
    qmlRegisterType<StringSorter>("SortFilterProxyModel", 0, 2, "StringSorter");
    qmlRegisterType<ExpressionSorter>("SortFilterProxyModel", 0, 2, "ExpressionSorter");
}

Q_COREAPP_STARTUP_FUNCTION(registerSorterTypes)

}
<commit_msg>fix: don't call sourceData with an invalid role<commit_after>#include "sorter.h"
#include <QtQml>

namespace qqsfpm {

/*!
    \qmltype Sorter
    \inqmlmodule SortFilterProxyModel
    \brief Base type for the \l SortFilterProxyModel sorters

    The Sorter type cannot be used directly in a QML file.
    It exists to provide a set of common properties and methods,
    available across all the other sorters types that inherit from it.
    Attempting to use the Sorter type directly will result in an error.
*/

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

Sorter::~Sorter() = default;

/*!
    \qmlproperty bool Sorter::enabled

    This property holds whether the sorter is enabled.
    A disabled sorter will not change the order of the rows.

    By default, sorters are enabled.
*/
bool Sorter::enabled() const
{
    return m_enabled;
}

void Sorter::setEnabled(bool enabled)
{
    if (m_enabled == enabled)
        return;

    m_enabled = enabled;
    Q_EMIT enabledChanged();
    Q_EMIT invalidated();
}

bool Sorter::ascendingOrder() const
{
    return sortOrder() == Qt::AscendingOrder;
}

void Sorter::setAscendingOrder(bool ascendingOrder)
{
    setSortOrder(ascendingOrder ? Qt::AscendingOrder : Qt::DescendingOrder);
}

/*!
    \qmlproperty Qt::SortOrder Sorter::sortOrder

    This property holds the sort order of this sorter.

    \value Qt.AscendingOrder The items are sorted ascending e.g. starts with 'AAA' ends with 'ZZZ' in Latin-1 locales
    \value Qt.DescendingOrder The items are sorted descending e.g. starts with 'ZZZ' ends with 'AAA' in Latin-1 locales

    By default, sorting is in ascending order.
*/
Qt::SortOrder Sorter::sortOrder() const
{
    return m_sortOrder;
}

void Sorter::setSortOrder(Qt::SortOrder sortOrder)
{
    if (m_sortOrder == sortOrder)
        return;

    m_sortOrder = sortOrder;
    Q_EMIT sortOrderChanged();
    invalidate();
}

int Sorter::compareRows(const QModelIndex &source_left, const QModelIndex &source_right, const QQmlSortFilterProxyModel& proxyModel) const
{
    int comparison = compare(source_left, source_right, proxyModel);
    return (m_sortOrder == Qt::AscendingOrder) ? comparison : -comparison;
}

int Sorter::compare(const QModelIndex &sourceLeft, const QModelIndex &sourceRight, const QQmlSortFilterProxyModel& proxyModel) const
{
    if (lessThan(sourceLeft, sourceRight, proxyModel))
        return -1;
    if (lessThan(sourceRight, sourceLeft, proxyModel))
        return 1;
    return 0;
}

void Sorter::proxyModelCompleted(const QQmlSortFilterProxyModel& proxyModel)
{
    Q_UNUSED(proxyModel)
}

bool Sorter::lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight, const QQmlSortFilterProxyModel& proxyModel) const
{
    Q_UNUSED(sourceLeft)
    Q_UNUSED(sourceRight)
    Q_UNUSED(proxyModel)
    return false;
}

void Sorter::invalidate()
{
    if (m_enabled)
        Q_EMIT invalidated();
}

const QString& RoleSorter::roleName() const
{
    return m_roleName;
}

/*!
    \qmltype RoleSorter
    \inherits Sorter
    \inqmlmodule SortFilterProxyModel
    \brief Sorts rows based on a source model role

    A RoleSorter is a simple \l Sorter that sorts rows based on a source model role.

    In the following example, rows with be sorted by their \c lastName role :
    \code
    SortFilterProxyModel {
       sourceModel: contactModel
       sorters: RoleSorter { roleName: "lastName" }
    }
    \endcode
*/

/*!
    \qmlproperty string RoleSorter::roleName

    This property holds the role name that the sorter is using to query the source model's data when sorting items.
*/
void RoleSorter::setRoleName(const QString& roleName)
{
    if (m_roleName == roleName)
        return;

    m_roleName = roleName;
    Q_EMIT roleNameChanged();
    invalidate();
}

QPair<QVariant, QVariant> RoleSorter::sourceData(const QModelIndex &sourceLeft, const QModelIndex& sourceRight, const QQmlSortFilterProxyModel& proxyModel) const
{
    QPair<QVariant, QVariant> pair;
    int role = proxyModel.roleForName(m_roleName);

    if (role == -1)
        return pair;

    pair.first = proxyModel.sourceData(sourceLeft, role);
    pair.second = proxyModel.sourceData(sourceRight, role);
    return pair;
}

int RoleSorter::compare(const QModelIndex &sourceLeft, const QModelIndex& sourceRight, const QQmlSortFilterProxyModel& proxyModel) const
{
    QPair<QVariant, QVariant> pair = sourceData(sourceLeft, sourceRight, proxyModel);
    QVariant leftValue = pair.first;
    QVariant rightValue = pair.second;
    if (leftValue < rightValue)
        return -1;
    if (leftValue > rightValue)
        return 1;
    return 0;
}

/*!
    \qmltype StringSorter
    \inherits RoleSorter
    \inqmlmodule SortFilterProxyModel
    \brief Sorts rows based on a source model string role

    \l StringSorter is a specialized \l RoleSorter that sorts rows based on a source model string role.
    \l StringSorter compares strings according to a localized collation algorithm.

    In the following example, rows with be sorted by their \c lastName role :
    \code
    SortFilterProxyModel {
       sourceModel: contactModel
       sorters: StringSorter { roleName: "lastName" }
    }
    \endcode
*/

/*!
    \qmlproperty Qt.CaseSensitivity StringSorter::caseSensitivity

    This property holds the case sensitivity of the sorter.
*/
Qt::CaseSensitivity StringSorter::caseSensitivity() const
{
    return m_collator.caseSensitivity();
}

void StringSorter::setCaseSensitivity(Qt::CaseSensitivity caseSensitivity)
{
    if (m_collator.caseSensitivity() == caseSensitivity)
        return;

    m_collator.setCaseSensitivity(caseSensitivity);
    Q_EMIT caseSensitivityChanged();
    invalidate();
}

/*!
    \qmlproperty bool StringSorter::ignorePunctation

    This property holds whether the sorter ignores punctation.
    if \c ignorePunctuation is \c true, punctuation characters and symbols are ignored when determining sort order.

    \note This property is not currently supported on Apple platforms or if Qt is configured to not use ICU on Linux.
*/
bool StringSorter::ignorePunctation() const
{
    return m_collator.ignorePunctuation();
}

void StringSorter::setIgnorePunctation(bool ignorePunctation)
{
    if (m_collator.ignorePunctuation() == ignorePunctation)
        return;

    m_collator.setIgnorePunctuation(ignorePunctation);
    Q_EMIT ignorePunctationChanged();
    invalidate();
}

/*!
    \qmlproperty Locale StringSorter::locale

    This property holds the locale of the sorter.
*/
QLocale StringSorter::locale() const
{
    return m_collator.locale();
}

void StringSorter::setLocale(const QLocale &locale)
{
    if (m_collator.locale() == locale)
        return;

    m_collator.setLocale(locale);
    Q_EMIT localeChanged();
    invalidate();
}

/*!
    \qmlproperty bool StringSorter::numericMode

    This property holds whether the numeric mode of the sorter is enabled.
    This will enable proper sorting of numeric digits, so that e.g. 100 sorts after 99.
    By default this mode is off.
*/
bool StringSorter::numericMode() const
{
    return m_collator.numericMode();
}

void StringSorter::setNumericMode(bool numericMode)
{
    if (m_collator.numericMode() == numericMode)
        return;

    m_collator.setNumericMode(numericMode);
    Q_EMIT numericModeChanged();
    invalidate();
}

int StringSorter::compare(const QModelIndex &sourceLeft, const QModelIndex &sourceRight, const QQmlSortFilterProxyModel& proxyModel) const
{
    QPair<QVariant, QVariant> pair = sourceData(sourceLeft, sourceRight, proxyModel);
    QString leftValue = pair.first.toString();
    QString rightValue = pair.second.toString();
    return m_collator.compare(leftValue, rightValue);
}

/*!
    \qmltype ExpressionSorter
    \inherits Sorter
    \inqmlmodule SortFilterProxyModel
    \brief Sorts row with a custom sorting

    An ExpressionSorter is a \l Sorter allowing to implement custom sorting based on a javascript expression.
*/

/*!
    \qmlproperty expression ExpressionSorter::expression

    An expression to implement custom sorting. It must evaluate to a bool.
    It has the same syntax has a \l {http://doc.qt.io/qt-5/qtqml-syntax-propertybinding.html} {Property Binding}, except that it will be evaluated for each of the source model's rows.
    Model data is accessible for both rows with the \c modelLeft, and \c modelRight properties:

    \code
    sorters: ExpressionSorter {
        expression: {
            return modelLeft.someRole < modelRight.someRole;
        }
    }
    \endcode

    The \c index of the row is also available through \c modelLeft and \c modelRight.

    The expression should return \c true if the value of the left item is less than the value of the right item, otherwise returns false.

    This expression is reevaluated for a row every time its model data changes.
    When an external property (not \c index* or in \c model*) the expression depends on changes, the expression is reevaluated for every row of the source model.
    To capture the properties the expression depends on, the expression is first executed with invalid data and each property access is detected by the QML engine.
    This means that if a property is not accessed because of a conditional, it won't be captured and the expression won't be reevaluted when this property changes.

    A workaround to this problem is to access all the properties the expressions depends unconditionally at the beggining of the expression.
*/
const QQmlScriptString& ExpressionSorter::expression() const
{
    return m_scriptString;
}

void ExpressionSorter::setExpression(const QQmlScriptString& scriptString)
{
    if (m_scriptString == scriptString)
        return;

    m_scriptString = scriptString;
    updateExpression();

    Q_EMIT expressionChanged();
    invalidate();
}

void ExpressionSorter::proxyModelCompleted(const QQmlSortFilterProxyModel& proxyModel)
{
    updateContext(proxyModel);
}

bool evaluateBoolExpression(QQmlExpression& expression)
{
    QVariant variantResult = expression.evaluate();
    if (expression.hasError()) {
        qWarning() << expression.error();
        return false;
    }
    if (variantResult.canConvert<bool>()) {
        return variantResult.toBool();
    } else {
        qWarning("%s:%i:%i : Can't convert result to bool",
                 expression.sourceFile().toUtf8().data(),
                 expression.lineNumber(),
                 expression.columnNumber());
        return false;
    }
}

int ExpressionSorter::compare(const QModelIndex& sourceLeft, const QModelIndex& sourceRight, const QQmlSortFilterProxyModel& proxyModel) const
{
    if (!m_scriptString.isEmpty()) {
        QVariantMap modelLeftMap, modelRightMap;
        QHash<int, QByteArray> roles = proxyModel.roleNames();

        QQmlContext context(qmlContext(this));

        for (auto it = roles.cbegin(); it != roles.cend(); ++it) {
            modelLeftMap.insert(it.value(), proxyModel.sourceData(sourceLeft, it.key()));
            modelRightMap.insert(it.value(), proxyModel.sourceData(sourceRight, it.key()));
        }
        modelLeftMap.insert("index", sourceLeft.row());
        modelRightMap.insert("index", sourceRight.row());

        QQmlExpression expression(m_scriptString, &context);

        context.setContextProperty("modelLeft", modelLeftMap);
        context.setContextProperty("modelRight", modelRightMap);
        if (evaluateBoolExpression(expression))
                return -1;

        context.setContextProperty("modelLeft", modelRightMap);
        context.setContextProperty("modelRight", modelLeftMap);
        if (evaluateBoolExpression(expression))
                return 1;
    }
    return 0;
}

void ExpressionSorter::updateContext(const QQmlSortFilterProxyModel& proxyModel)
{
    delete m_context;
    m_context = new QQmlContext(qmlContext(this), this);

    QVariantMap modelLeftMap, modelRightMap;
    // what about roles changes ?

    for (const QByteArray& roleName : proxyModel.roleNames().values()) {
        modelLeftMap.insert(roleName, QVariant());
        modelRightMap.insert(roleName, QVariant());
    }
    modelLeftMap.insert("index", -1);
    modelRightMap.insert("index", -1);

    m_context->setContextProperty("modelLeft", modelLeftMap);
    m_context->setContextProperty("modelRight", modelRightMap);

    updateExpression();
}

void ExpressionSorter::updateExpression()
{
    if (!m_context)
        return;

    delete m_expression;
    m_expression = new QQmlExpression(m_scriptString, m_context, 0, this);
    connect(m_expression, &QQmlExpression::valueChanged, this, &ExpressionSorter::invalidate);
    m_expression->setNotifyOnValueChanged(true);
    m_expression->evaluate();
}

void registerSorterTypes() {
    qmlRegisterUncreatableType<Sorter>("SortFilterProxyModel", 0, 2, "Sorter", "Sorter is an abstract class");
    qmlRegisterType<RoleSorter>("SortFilterProxyModel", 0, 2, "RoleSorter");
    qmlRegisterType<StringSorter>("SortFilterProxyModel", 0, 2, "StringSorter");
    qmlRegisterType<ExpressionSorter>("SortFilterProxyModel", 0, 2, "ExpressionSorter");
}

Q_COREAPP_STARTUP_FUNCTION(registerSorterTypes)

}
<|endoftext|>


<commit_before>// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.

#include "okina.hpp"

#include <string.h>
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)

namespace mfem
{

#ifdef MFEM_USE_CUDA
void Device::GpuDeviceSetup(const int device)
{
   cudaGetDeviceCount(&ngpu);
   MFEM_ASSERT(ngpu>0, "No CUDA device found!");
   cuInit(0);
   dev = device;
   cuDeviceGet(&cuDevice,dev);
   cuCtxCreate(&cuContext, CU_CTX_SCHED_AUTO, cuDevice);
   cuStream = new CUstream;
   MFEM_ASSERT(cuStream, "CUDA stream could not be created!");
   cuStreamCreate(cuStream, CU_STREAM_DEFAULT);
}
#endif

void Device::CudaDeviceSetup(const int device)
{
#ifdef MFEM_USE_CUDA
   GpuDeviceSetup(device);
#else
   MFEM_ABORT("CUDA requested but no GPU support has been built!");
#endif
}

void Device::RajaDeviceSetup(const int device)
{
#if defined(MFEM_USE_CUDA) && defined(MFEM_USE_RAJA)
   GpuDeviceSetup(device);
#elif !defined(MFEM_USE_RAJA)
   MFEM_ABORT("RAJA requested but no RAJA support has been built!");
#endif
}

void Device::OccaDeviceSetup(CUdevice cu_dev, CUcontext cu_ctx)
{
#ifdef MFEM_USE_OCCA
   if (cuda)
   {
      occaDevice = OccaWrapDevice(cu_dev, cu_ctx);
   }
   else if (omp)
   {
      occaDevice.setup("mode: 'OpenMP'");
   }
   else
   {
      occaDevice.setup("mode: 'Serial'");
   }
   const std::string mfem_dir = occa::io::dirname("../_config.hpp");
   occa::io::addLibraryPath("fem", mfem_dir + "fem");
   occa::loadKernels();
   occa::loadKernels("fem");
#else
   MFEM_ABORT("OCCA requested but no support has been built!");
#endif
}

void Device::MFEMDeviceSetup(const int dev)
{
   MFEM_ASSERT(ngpu==-1, "Only one MFEMDeviceSetup allowed");
   ngpu = 0;

   // We initialize CUDA first so OccaDeviceSetup() can reuse the same
   // initialized cuDevice and cuContext objects
   if (cuda) { CudaDeviceSetup(dev); }
   if (raja) { RajaDeviceSetup(dev); }
   if (occa) { OccaDeviceSetup(cuDevice, cuContext); }

   if (cuda && ngpu==0)
   {
      MFEM_ABORT("CUDA requested but no GPU has been initialized!");
   }
}

Device::~Device()
{
   if (raja || cuda) { delete cuStream; }
}

} // mfem
<commit_msg>Better error messages in device.cpp<commit_after>// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.

#include "okina.hpp"

#include <string.h>
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)

namespace mfem
{

#ifdef MFEM_USE_CUDA
void Device::GpuDeviceSetup(const int device)
{
   cudaGetDeviceCount(&ngpu);
   MFEM_ASSERT(ngpu>0, "No CUDA device found!");
   cuInit(0);
   dev = device;
   cuDeviceGet(&cuDevice,dev);
   cuCtxCreate(&cuContext, CU_CTX_SCHED_AUTO, cuDevice);
   cuStream = new CUstream;
   MFEM_ASSERT(cuStream, "CUDA stream could not be created!");
   cuStreamCreate(cuStream, CU_STREAM_DEFAULT);
}
#endif

void Device::CudaDeviceSetup(const int device)
{
#ifdef MFEM_USE_CUDA
   GpuDeviceSetup(device);
#else
   MFEM_ABORT("CUDA requested but MFEM was not build with MFEM_USE_CUDA=YES");
#endif
}

void Device::RajaDeviceSetup(const int device)
{
#if defined(MFEM_USE_CUDA) && defined(MFEM_USE_RAJA)
   GpuDeviceSetup(device);
#elif !defined(MFEM_USE_RAJA)
   MFEM_ABORT("RAJA requested but MFEM was not build with MFEM_USE_RAJA=YES");
#endif
}

void Device::OccaDeviceSetup(CUdevice cu_dev, CUcontext cu_ctx)
{
#ifdef MFEM_USE_OCCA
   if (cuda)
   {
      occaDevice = OccaWrapDevice(cu_dev, cu_ctx);
   }
   else if (omp)
   {
      occaDevice.setup("mode: 'OpenMP'");
   }
   else
   {
      occaDevice.setup("mode: 'Serial'");
   }
   const std::string mfem_dir = occa::io::dirname("../_config.hpp");
   occa::io::addLibraryPath("fem", mfem_dir + "fem");
   occa::loadKernels();
   occa::loadKernels("fem");
#else
   MFEM_ABORT("OCCA requested but MFEM was not build with MFEM_USE_OCCA=YES");
#endif
}

void Device::MFEMDeviceSetup(const int dev)
{
   MFEM_ASSERT(ngpu==-1, "Only one MFEMDeviceSetup allowed");
   ngpu = 0;

   // We initialize CUDA first so OccaDeviceSetup() can reuse the same
   // initialized cuDevice and cuContext objects
   if (cuda) { CudaDeviceSetup(dev); }
   if (raja) { RajaDeviceSetup(dev); }
   if (occa) { OccaDeviceSetup(cuDevice, cuContext); }

   if (cuda && ngpu==0)
   {
      MFEM_ABORT("CUDA requested but MFEM was not build with MFEM_USE_CUDA=YES");
   }
}

Device::~Device()
{
   if (raja || cuda) { delete cuStream; }
}

} // mfem
<|endoftext|>


<commit_before>/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
/**
 * Copyright (C) 2013 Regents of the University of California.
 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
 * See COPYING for copyright and distribution information.
 */

#include <stdexcept>
#include <stdlib.h>

#include <ndn-cpp/face.hpp>
#include <ndn-cpp/transport/unix-transport.hpp>

#include <boost/asio.hpp>
#include <boost/bind.hpp>

using namespace std;
typedef boost::asio::local::stream_protocol protocol;

namespace ndn {

const size_t MAX_LENGTH = 9000;

class UnixTransport::Impl
{
public:
  Impl(UnixTransport &transport)
    : transport_(transport),
      socket_(*transport_.ioService_)
  {
  }

  void
  connect()
  {
    socket_.open();
    socket_.connect(protocol::endpoint(transport_.unixSocket_));
    // socket_.async_connect(protocol::endpoint(unixSocket));

    socket_.async_receive(boost::asio::buffer(inputBuffer_, MAX_LENGTH), 0,
                          boost::bind(&Impl::handle_async_receive, this, _1, _2));
  }

  void
  close()
  {
    socket_.close();
  }

  void
  send(const Block &wire)
  {
    socket_.async_send(boost::asio::buffer(wire.wire(), wire.size()),
                       boost::bind(&Impl::handle_async_send, this, _1, wire));
  }

  void
  handle_async_receive(const boost::system::error_code& error, std::size_t bytes_recvd)
  {
    /// @todo The socket is not datagram, so need to have internal buffer to handle partial data reception

    if (!error && bytes_recvd > 0)
      {
        // inputBuffer_ has bytes_recvd received bytes of data
        try {
          Block element(inputBuffer_, bytes_recvd);
          transport_.receive(element);
        }
        catch(Tlv::Error &error)
          {
            // pass
          }
        catch(Block::Error &error)
          {
            // pass
          }
      }

    socket_.async_receive(boost::asio::buffer(inputBuffer_, MAX_LENGTH), 0,
                          boost::bind(&Impl::handle_async_receive, this, _1, _2));
  }

  void
  handle_async_send(const boost::system::error_code& error, const Block &wire)
  {
    // pass
  }

private:
  UnixTransport &transport_;

  protocol::socket socket_;
  uint8_t inputBuffer_[MAX_LENGTH];
};

UnixTransport::UnixTransport(const std::string &unixSocket/* = "/tmp/.ndnd.sock"*/)
  : unixSocket_(unixSocket)
{
}

UnixTransport::~UnixTransport()
{
}

void
UnixTransport::connect(boost::asio::io_service &ioService, const ReceiveCallback &receiveCallback)
{
  Transport::connect(ioService, receiveCallback);

  impl_ = std::auto_ptr<UnixTransport::Impl> (new UnixTransport::Impl(*this));
  impl_->connect();

  isConnected_ = true;
}

void
UnixTransport::send(const Block &wire)
{
  impl_->send(wire);
}

void
UnixTransport::close()
{
  impl_->close();
}

}
<commit_msg>transport/unix: Adding complex logic to handle streamed data<commit_after>/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
/**
 * Copyright (C) 2013 Regents of the University of California.
 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
 * See COPYING for copyright and distribution information.
 */

#include <stdexcept>
#include <stdlib.h>

#include <ndn-cpp/face.hpp>
#include <ndn-cpp/transport/unix-transport.hpp>
#include <ndn-cpp/c/util/ndn_memory.h>

#include <boost/asio.hpp>
#include <boost/bind.hpp>

using namespace std;
typedef boost::asio::local::stream_protocol protocol;

namespace ndn {

const size_t MAX_LENGTH = 9000;

class UnixTransport::Impl
{
public:
  Impl(UnixTransport &transport)
    : transport_(transport)
    , socket_(*transport_.ioService_)
    , partialDataSize_(0)
  {
  }

  void
  connect()
  {
    socket_.open();
    socket_.connect(protocol::endpoint(transport_.unixSocket_));
    // socket_.async_connect(protocol::endpoint(unixSocket));

    partialDataSize_ = 0;
    socket_.async_receive(boost::asio::buffer(inputBuffer_, MAX_LENGTH), 0,
                          boost::bind(&Impl::handle_async_receive, this, _1, _2));
  }

  void
  close()
  {
    socket_.close();
  }

  void
  send(const Block &wire)
  {
    socket_.async_send(boost::asio::buffer(wire.wire(), wire.size()),
                       boost::bind(&Impl::handle_async_send, this, _1, wire));
  }

  inline void
  processAll(uint8_t *buffer, size_t &offset, size_t availableSize)
  {
    while(offset < availableSize)
      {
        Block element(buffer + offset, availableSize - offset);
        transport_.receive(element);

        offset += element.size();
      }
  }

  void
  handle_async_receive(const boost::system::error_code& error, std::size_t bytes_recvd)
  {
    /// @todo The socket is not datagram, so need to have internal buffer to handle partial data reception

    if (!error && bytes_recvd > 0)
      {
        try
          {
            // inputBuffer_ has bytes_recvd received bytes of data
            if (partialDataSize_ > 0)
              {
                size_t newDataSize = std::min(bytes_recvd, MAX_LENGTH-partialDataSize_);
                ndn_memcpy(partialData_ + partialDataSize_, inputBuffer_, newDataSize);
                partialDataSize_ += newDataSize;

                size_t offset = 0;
                try
                  {
                    processAll(partialData_, offset, partialDataSize_);

                    // no exceptions => processed the whole thing
                    if (bytes_recvd - newDataSize > 0)
                      {
                        // there is a little bit more data available

                        offset = 0;
                        partialDataSize_ = bytes_recvd - newDataSize;
                        ndn_memcpy(partialData_, inputBuffer_ + newDataSize, partialDataSize_);

                        processAll(partialData_, offset, partialDataSize_);

                        // no exceptions => processed the whole thing
                        partialDataSize_ = 0;
                      }
                    else
                      {
                        // done processing
                        partialDataSize_ = 0;
                      }
                  }
                catch(Block::Error &)
                  {
                    if (offset > 0)
                      {
                        partialDataSize_ -= offset;
                        ndn_memcpy(partialData_, partialData_ + offset, partialDataSize_);
                      }
                    else if (offset == 0 && partialDataSize_ == MAX_LENGTH)
                      {
                        // very bad... should close connection
                        /// @todo Notify somebody
                        socket_.close();
                      }
                  }
              }
            else
              {
                size_t offset = 0;
                try
                  {
                    processAll(inputBuffer_, offset, bytes_recvd);
                  }
                catch(Block::Error &error)
                  {
                    if (offset > 0)
                      {
                        partialDataSize_ = bytes_recvd - offset;
                        ndn_memcpy(partialData_, inputBuffer_ + offset, partialDataSize_);
                      }
                  }
              }
          }
        catch(Tlv::Error &error)
          {
            std::cerr << "[[handle_async_receive]] Tlv::Error: " << error.what() << std::endl;
            // pass
          }
      }

    socket_.async_receive(boost::asio::buffer(inputBuffer_, MAX_LENGTH), 0,
                          boost::bind(&Impl::handle_async_receive, this, _1, _2));
  }

  void
  handle_async_send(const boost::system::error_code& error, const Block &wire)
  {
    // pass (needed to keep data block alive during the send)
  }

private:
  UnixTransport &transport_;

  protocol::socket socket_;
  uint8_t inputBuffer_[MAX_LENGTH];

  uint8_t partialData_[MAX_LENGTH];
  size_t partialDataSize_;
};

UnixTransport::UnixTransport(const std::string &unixSocket/* = "/tmp/.ndnd.sock"*/)
  : unixSocket_(unixSocket)
{
}

UnixTransport::~UnixTransport()
{
}

void
UnixTransport::connect(boost::asio::io_service &ioService, const ReceiveCallback &receiveCallback)
{
  Transport::connect(ioService, receiveCallback);

  impl_ = std::auto_ptr<UnixTransport::Impl> (new UnixTransport::Impl(*this));
  impl_->connect();

  isConnected_ = true;
}

void
UnixTransport::send(const Block &wire)
{
  impl_->send(wire);
}

void
UnixTransport::close()
{
  impl_->close();
}

}
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/usr/pldm/extended/pldm_fru.C $                            */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2020,2021                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

/* @file pldm_fru.C
 *
 * @brief Implementation of FRU-related utilities.
 */

#include <stdint.h>

#include <targeting/common/target.H>
#include <pldm/extended/pldm_fru.H>

#include <targeting/common/utilFilter.H>

using namespace PLDM;
using namespace TARGETING;

enum encoded_target_class_t
{
    ENCODED_CLASS_CHIP,          // PROC targets
    ENCODED_CLASS_LOGICAL_CARD,  // DIMM
    ENCODED_END                  // sentinel
};

constexpr int target_class_bits = 3;
constexpr int target_type_bits = 7;
constexpr int position_id_bits = 6;

static_assert(ENCODED_END <= (1 << target_class_bits),
              "Not enough bits in encoded rsid to encoded target class");

static_assert(TYPE_LAST_IN_RANGE <= (1 << target_type_bits),
              "Too many possible CLASS attribuet values to encode in 4 bits");

struct target_class_encoding
{
    ATTR_CLASS_type target_class;
    encoded_target_class_t encoded_class;
};

static const target_class_encoding encoded_target_classes[] =
{
    { CLASS_CHIP, ENCODED_CLASS_CHIP },
    { CLASS_LOGICAL_CARD, ENCODED_CLASS_LOGICAL_CARD },
};

static encoded_target_class_t encodeTargetClass(const TARGETING::CLASS i_class)
{
    const auto it = std::find_if(std::begin(encoded_target_classes),
                                 std::end(encoded_target_classes),
                                 [i_class](const target_class_encoding& encoding)
                                 { return encoding.target_class == i_class; });

    assert(it != std::end(encoded_target_classes),
           "Cannot ENCODE target class %d for Hostboot FRU record set ID",
           i_class);

    return it->encoded_class;
}

static ATTR_CLASS_type decodeTargetClass(const encoded_target_class_t i_encoded_class)
{
    const auto it = std::find_if(std::begin(encoded_target_classes),
                                 std::end(encoded_target_classes),
                                 [i_encoded_class](const target_class_encoding& encoding)
                                 { return encoding.encoded_class == i_encoded_class; });

    assert(it != std::end(encoded_target_classes),
           "Cannot DECODE target class %d for Hostboot FRU record set ID",
           i_encoded_class);

    return it->target_class;
}

union encoded_rsid_t
{
    struct
    {
        encoded_target_class_t encoded_class : 3;
        TARGETING::TYPE target_type : 7;
        ATTR_POSITION_type position_id : 6;
    } __attribute__((packed));

    uint16_t packed_rsid;
};

static_assert(sizeof(encoded_rsid_t) == sizeof(PLDM::fru_record_set_id_t),
              "Encoded RSID union not packed");

PLDM::fru_record_set_id_t PLDM::getTargetFruRecordSetID(const Target* const i_target)
{
    const auto target_class = i_target->getAttr<ATTR_CLASS>();
    const auto target_type = i_target->getAttr<ATTR_TYPE>();
    const auto position_id = i_target->getAttr<ATTR_POSITION>();

    assert(target_type <= (1 << target_type_bits),
           "Target type for FRU Record Set ID is out of range (HUID 0x%08x)",
           get_huid(i_target));
    assert(position_id <= (1 << position_id_bits),
           "Position ID for FRU Record Set ID is out of range (HUID 0x%08x)",
           get_huid(i_target));

    encoded_rsid_t rsid = { };

    rsid.encoded_class = encodeTargetClass(target_class);
    rsid.target_type = target_type;
    rsid.position_id = position_id;

    return rsid.packed_rsid;
}

Target* PLDM::getTargetFromHostbootFruRecordSetID(const fru_record_set_id_t i_rsid)
{
    encoded_rsid_t encoded_rsid = { .packed_rsid = i_rsid };

    const ATTR_CLASS_type target_class =  decodeTargetClass(encoded_rsid.encoded_class);

    TARGETING::TargetHandleList target_list;
    getClassResources(target_list,
                      target_class,
                      encoded_rsid.target_type,
                      UTIL_FILTER_PRESENT);

    Target* result_target = nullptr;

    for (Target* const target : target_list)
    {
        if (target->getAttr<ATTR_POSITION>() == encoded_rsid.position_id)
        {
            result_target = target;
            break;
        }
    }

    return result_target;
}
<commit_msg>PLDM rsid needs to allow for cores<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/usr/pldm/extended/pldm_fru.C $                            */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2020,2021                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

/* @file pldm_fru.C
 *
 * @brief Implementation of FRU-related utilities.
 */

#include <stdint.h>

#include <targeting/common/target.H>
#include <pldm/extended/pldm_fru.H>

#include <targeting/common/utilFilter.H>

using namespace PLDM;
using namespace TARGETING;

constexpr int target_type_bits  = 7;
constexpr int ordinal_id_bits   = 9;

static_assert(TYPE_LAST_IN_RANGE <= (1 << target_type_bits),
    "Cannot encode all target types in the given number of bits");

union encoded_rsid_t
{
    struct
    {
        TARGETING::TYPE target_type : 7;
        ATTR_ORDINAL_ID_type ordinal_id : 9;
    } __attribute__((packed));

    uint16_t packed_rsid;
};

static_assert(sizeof(encoded_rsid_t) == sizeof(PLDM::fru_record_set_id_t),
              "Encoded RSID union not packed");

PLDM::fru_record_set_id_t PLDM::getTargetFruRecordSetID(const Target* const i_target)
{
    const auto l_target_type = i_target->getAttr<ATTR_TYPE>();
    const auto l_ordinal_id = i_target->getAttr<ATTR_ORDINAL_ID>();

    assert(l_target_type < (1 << target_type_bits),
           "Target type for FRU Record Set ID is out of range (HUID 0x%08x)",
           get_huid(i_target));

    assert(l_ordinal_id < (1 << ordinal_id_bits),
           "Ordinal ID for FRU Record Set ID is out of range (HUID 0x%08x) - max size: 0x%08x",
           get_huid(i_target), (1 << ordinal_id_bits)-1);

    encoded_rsid_t rsid = { };

    rsid.target_type = l_target_type;
    rsid.ordinal_id = l_ordinal_id;

    return rsid.packed_rsid;
}

Target* PLDM::getTargetFromHostbootFruRecordSetID(const fru_record_set_id_t i_rsid)
{
    encoded_rsid_t encoded_rsid = { .packed_rsid = i_rsid };

    TARGETING::TargetHandleList target_list;
    getClassResources(target_list,
                      CLASS_NA,
                      encoded_rsid.target_type,
                      UTIL_FILTER_PRESENT);

    Target* result_target = nullptr;

    for (Target* const target : target_list)
    {
        if (target->getAttr<ATTR_ORDINAL_ID>() == encoded_rsid.ordinal_id)
        {
            result_target = target;
            break;
        }
    }

    return result_target;
}
<|endoftext|>


<commit_before>/* mbed Microcontroller Library
 * Copyright (c) 2017 ARM Limited
 *
 * 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 "HeapBlockDevice.h"

HeapBlockDevice::HeapBlockDevice(bd_size_t size, bd_size_t block)
    : _read_size(block), _program_size(block), _erase_size(block)
    , _count(size / block), _blocks(0)
{
    MBED_ASSERT(_count * _erase_size == size);
}

HeapBlockDevice::HeapBlockDevice(bd_size_t size, bd_size_t read, bd_size_t program, bd_size_t erase)
    : _read_size(read), _program_size(program), _erase_size(erase)
    , _count(size / erase), _blocks(0)
{
    MBED_ASSERT(_count * _erase_size == size);
}

HeapBlockDevice::~HeapBlockDevice()
{
    if (_blocks) {
        for (size_t i = 0; i < _count; i++) {
            free(_blocks[i]);
        }

        delete[] _blocks;
        _blocks = 0;
    }
}

int HeapBlockDevice::init()
{
    if (!_blocks) {
        _blocks = new uint8_t*[_count];
        for (size_t i = 0; i < _count; i++) {
            _blocks[i] = 0;
        }
    }

    return BD_ERROR_OK;
}

int HeapBlockDevice::deinit()
{
    // Heapory is lazily cleaned up in destructor to allow
    // data to live across de/reinitialization
    return BD_ERROR_OK;
}

bd_size_t HeapBlockDevice::get_read_size() const
{
    return _read_size;
}

bd_size_t HeapBlockDevice::get_program_size() const
{
    return _program_size;
}

bd_size_t HeapBlockDevice::get_erase_size() const
{
    return _erase_size;
}

bd_size_t HeapBlockDevice::size()
{
    return _count * _erase_size;
}

int HeapBlockDevice::read(void *b, bd_addr_t addr, bd_size_t size)
{
    MBED_ASSERT(is_valid_read(addr, size));
    uint8_t *buffer = static_cast<uint8_t*>(b);

    while (size > 0) {
        bd_addr_t hi = addr / _erase_size;
        bd_addr_t lo = addr % _erase_size;

        if (_blocks[hi]) {
            memcpy(buffer, &_blocks[hi][lo], _read_size);
        } else {
            memset(buffer, 0, _read_size);
        }

        buffer += _read_size;
        addr += _read_size;
        size -= _read_size;
    }

    return 0;
}

int HeapBlockDevice::program(const void *b, bd_addr_t addr, bd_size_t size)
{
    MBED_ASSERT(is_valid_program(addr, size));
    const uint8_t *buffer = static_cast<const uint8_t*>(b);

    while (size > 0) {
        bd_addr_t hi = addr / _erase_size;
        bd_addr_t lo = addr % _erase_size;

        if (!_blocks[hi]) {
            _blocks[hi] = (uint8_t*)malloc(_erase_size);
            if (!_blocks[hi]) {
                return BD_ERROR_DEVICE_ERROR;
            }
        }

        memcpy(&_blocks[hi][lo], buffer, _program_size);

        buffer += _program_size;
        addr += _program_size;
        size -= _program_size;
    }

    return 0;
}

int HeapBlockDevice::erase(bd_addr_t addr, bd_size_t size)
{
    MBED_ASSERT(is_valid_erase(addr, size));

    while (size > 0) {
        bd_addr_t hi = addr / _erase_size;

        if (_blocks[hi]) {
            memset(_blocks[hi], 0xcc, _erase_size);
        }

        addr += _erase_size;
        size -= _erase_size;
    }

    return 0;
}

<commit_msg>Filesystem: Remove invalid write to unallocated memory in heap block device<commit_after>/* mbed Microcontroller Library
 * Copyright (c) 2017 ARM Limited
 *
 * 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 "HeapBlockDevice.h"

HeapBlockDevice::HeapBlockDevice(bd_size_t size, bd_size_t block)
    : _read_size(block), _program_size(block), _erase_size(block)
    , _count(size / block), _blocks(0)
{
    MBED_ASSERT(_count * _erase_size == size);
}

HeapBlockDevice::HeapBlockDevice(bd_size_t size, bd_size_t read, bd_size_t program, bd_size_t erase)
    : _read_size(read), _program_size(program), _erase_size(erase)
    , _count(size / erase), _blocks(0)
{
    MBED_ASSERT(_count * _erase_size == size);
}

HeapBlockDevice::~HeapBlockDevice()
{
    if (_blocks) {
        for (size_t i = 0; i < _count; i++) {
            free(_blocks[i]);
        }

        delete[] _blocks;
        _blocks = 0;
    }
}

int HeapBlockDevice::init()
{
    if (!_blocks) {
        _blocks = new uint8_t*[_count];
        for (size_t i = 0; i < _count; i++) {
            _blocks[i] = 0;
        }
    }

    return BD_ERROR_OK;
}

int HeapBlockDevice::deinit()
{
    // Heapory is lazily cleaned up in destructor to allow
    // data to live across de/reinitialization
    return BD_ERROR_OK;
}

bd_size_t HeapBlockDevice::get_read_size() const
{
    return _read_size;
}

bd_size_t HeapBlockDevice::get_program_size() const
{
    return _program_size;
}

bd_size_t HeapBlockDevice::get_erase_size() const
{
    return _erase_size;
}

bd_size_t HeapBlockDevice::size()
{
    return _count * _erase_size;
}

int HeapBlockDevice::read(void *b, bd_addr_t addr, bd_size_t size)
{
    MBED_ASSERT(is_valid_read(addr, size));
    uint8_t *buffer = static_cast<uint8_t*>(b);

    while (size > 0) {
        bd_addr_t hi = addr / _erase_size;
        bd_addr_t lo = addr % _erase_size;

        if (_blocks[hi]) {
            memcpy(buffer, &_blocks[hi][lo], _read_size);
        } else {
            memset(buffer, 0, _read_size);
        }

        buffer += _read_size;
        addr += _read_size;
        size -= _read_size;
    }

    return 0;
}

int HeapBlockDevice::program(const void *b, bd_addr_t addr, bd_size_t size)
{
    MBED_ASSERT(is_valid_program(addr, size));
    const uint8_t *buffer = static_cast<const uint8_t*>(b);

    while (size > 0) {
        bd_addr_t hi = addr / _erase_size;
        bd_addr_t lo = addr % _erase_size;

        if (!_blocks[hi]) {
            _blocks[hi] = (uint8_t*)malloc(_erase_size);
            if (!_blocks[hi]) {
                return BD_ERROR_DEVICE_ERROR;
            }
        }

        memcpy(&_blocks[hi][lo], buffer, _program_size);

        buffer += _program_size;
        addr += _program_size;
        size -= _program_size;
    }

    return 0;
}

int HeapBlockDevice::erase(bd_addr_t addr, bd_size_t size)
{
    MBED_ASSERT(is_valid_erase(addr, size));
    // TODO assert on programming unerased blocks

    return 0;
}

<|endoftext|>


<commit_before>/* -------------------------------------------------------------------------- */
/* Copyright 2002-2012, OpenNebula Project Leads (OpenNebula.org)             */
/*                                                                            */
/* 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 "VirtualMachineTemplate.h"
#include <vector>

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

const string VirtualMachineTemplate::RESTRICTED_ATTRIBUTES[] = {
	"CONTEXT/FILES",
	"DISK/SOURCE",
	"NIC/MAC",
	"NIC/VLAN_ID",
	"RANK"
};

const int VirtualMachineTemplate::RS_ATTRS_LENGTH = 3;

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

bool VirtualMachineTemplate::check(string& rs_attr)
{
	size_t pos;
	string avector, vattr;
    vector<const Attribute *> values;

	for (int i=0; i < RS_ATTRS_LENGTH ;i++)
	{
	    pos = RESTRICTED_ATTRIBUTES[i].find("/");

	    if (pos != string::npos) //Vector Attribute
	    {
		    int num;

	        avector = RESTRICTED_ATTRIBUTES[i].substr(0,pos);
	        vattr   = RESTRICTED_ATTRIBUTES[i].substr(pos+1);

	        if ((num = get(avector,values)) > 0 ) //Template contains the attr
	        {
	        	const VectorAttribute * attr;

	        	for (int j=0; j<num ; j++ )
	        	{
		        	attr = dynamic_cast<const VectorAttribute *>(values[j]);

	        		if (attr == 0)
	        		{
	        			continue;
	        		}

	        		if ( !attr->vector_value(vattr.c_str()).empty() )
	        		{
	        			rs_attr = RESTRICTED_ATTRIBUTES[i];
	        			return true;
	        		}
	        	}

	        }
	    }
	    else //Single Attribute
	    {
			if (get(avector,values) > 0 )
			{
				rs_attr = RESTRICTED_ATTRIBUTES[i];
				return true;
			}
	    }
	}

	return false;
}<commit_msg>bug: Fixed number of restricted attributes constant (cherry picked from commit 38f67ef27b891e34eab91fe38f25ac4eb054d81e)<commit_after>/* -------------------------------------------------------------------------- */
/* Copyright 2002-2012, OpenNebula Project Leads (OpenNebula.org)             */
/*                                                                            */
/* 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 "VirtualMachineTemplate.h"
#include <vector>

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

const string VirtualMachineTemplate::RESTRICTED_ATTRIBUTES[] = {
	"CONTEXT/FILES",
	"DISK/SOURCE",
	"NIC/MAC",
	"NIC/VLAN_ID",
	"RANK"
};

const int VirtualMachineTemplate::RS_ATTRS_LENGTH = 5;

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

bool VirtualMachineTemplate::check(string& rs_attr)
{
	size_t pos;
	string avector, vattr;
    vector<const Attribute *> values;

	for (int i=0; i < RS_ATTRS_LENGTH ;i++)
	{
	    pos = RESTRICTED_ATTRIBUTES[i].find("/");

	    if (pos != string::npos) //Vector Attribute
	    {
		    int num;

	        avector = RESTRICTED_ATTRIBUTES[i].substr(0,pos);
	        vattr   = RESTRICTED_ATTRIBUTES[i].substr(pos+1);

	        if ((num = get(avector,values)) > 0 ) //Template contains the attr
	        {
	        	const VectorAttribute * attr;

	        	for (int j=0; j<num ; j++ )
	        	{
		        	attr = dynamic_cast<const VectorAttribute *>(values[j]);

	        		if (attr == 0)
	        		{
	        			continue;
	        		}

	        		if ( !attr->vector_value(vattr.c_str()).empty() )
	        		{
	        			rs_attr = RESTRICTED_ATTRIBUTES[i];
	        			return true;
	        		}
	        	}

	        }
	    }
	    else //Single Attribute
	    {
			if (get(avector,values) > 0 )
			{
				rs_attr = RESTRICTED_ATTRIBUTES[i];
				return true;
			}
	    }
	}

	return false;
}
<|endoftext|>


<commit_before>

/*
 * Copyright 2012 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "gm.h"
#include "SkCanvas.h"
#include "SkPicture.h"

namespace skiagm {

class DistantClipGM : public GM {
public:
    DistantClipGM() { }

protected:

    SkString onShortName() {
        return SkString("distantclip");
    }

    SkISize onISize() { return make_isize(100, 100); }

    virtual void onDraw(SkCanvas* canvas) {
        int offset = 35000;
        int extents = 1000;

        // We record a picture of huge vertical extents in which we clear the canvas to red, create
        // a 'extents' by 'extents' round rect clip at a vertical offset of 'offset', then draw
        // green into that.
        SkPicture pict;
        SkCanvas* rec = pict.beginRecording(100, offset + extents);
        rec->drawColor(0xffff0000);
        rec->save();
        SkRect r = {-extents, offset - extents, extents, offset + extents};
        SkPath p;
        p.addRoundRect(r, 5, 5);
        rec->clipPath(p, SkRegion::kIntersect_Op, true);
        rec->drawColor(0xff00ff00);
        rec->restore();
        pict.endRecording();

        // Next we play that picture into another picture of the same size.
        SkPicture pict2;
        pict.draw(pict2.beginRecording(100, offset + extents));
        pict2.endRecording();

        // Finally we play the part of that second picture that should be green into the canvas.
        canvas->save();
        canvas->translate(extents / 2, -(offset - extents / 2));
        canvas->drawPicture(pict2);
        canvas->restore();

        // If the image is red, we erroneously decided the clipPath was empty and didn't record
        // the green drawColor, if it's green we're all good.
    }

private:
    typedef GM INHERITED;
};

///////////////////////////////////////////////////////////////////////////////

static GM* MyFactory(void*) { return new DistantClipGM; }
static GMRegistry reg(MyFactory);

}
<commit_msg>Fix picture refcnt bug in distantclip gm. Unreviewed.<commit_after>

/*
 * Copyright 2012 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "gm.h"
#include "SkCanvas.h"
#include "SkPicture.h"

namespace skiagm {

class DistantClipGM : public GM {
public:
    DistantClipGM() { }

protected:

    SkString onShortName() {
        return SkString("distantclip");
    }

    SkISize onISize() { return make_isize(100, 100); }

    virtual void onDraw(SkCanvas* canvas) {
        int offset = 35000;
        int extents = 1000;

        // We record a picture of huge vertical extents in which we clear the canvas to red, create
        // a 'extents' by 'extents' round rect clip at a vertical offset of 'offset', then draw
        // green into that.
        SkPicture pict;
        SkCanvas* rec = pict.beginRecording(100, offset + extents);
        rec->drawColor(0xffff0000);
        rec->save();
        SkRect r = {-extents, offset - extents, extents, offset + extents};
        SkPath p;
        p.addRoundRect(r, 5, 5);
        rec->clipPath(p, SkRegion::kIntersect_Op, true);
        rec->drawColor(0xff00ff00);
        rec->restore();
        pict.endRecording();

        // Next we play that picture into another picture of the same size.
        SkPicture pict2;
        pict.draw(pict2.beginRecording(100, offset + extents));
        pict2.endRecording();

        // Finally we play the part of that second picture that should be green into the canvas.
        canvas->save();
        canvas->translate(extents / 2, -(offset - extents / 2));
        pict2.draw(canvas);
        canvas->restore();

        // If the image is red, we erroneously decided the clipPath was empty and didn't record
        // the green drawColor, if it's green we're all good.
    }

private:
    typedef GM INHERITED;
};

///////////////////////////////////////////////////////////////////////////////

static GM* MyFactory(void*) { return new DistantClipGM; }
static GMRegistry reg(MyFactory);

}
<|endoftext|>


<commit_before>#include "backuplistwidget.h"
#include "backuplistwidgetitem.h"
#include "debug.h"
#include "utils.h"

#include <QDropEvent>
#include <QFileInfo>
#include <QMessageBox>
#include <QMimeData>
#include <QSettings>

BackupListWidget::BackupListWidget(QWidget *parent) : QListWidget(parent)
{
    QSettings   settings;
    QStringList urls = settings.value("app/backup_list").toStringList();
    if(!urls.isEmpty())
    {
        QList<QUrl> urllist;
        foreach(QString url, urls)
            urllist << QUrl::fromUserInput(url);
        if(!urllist.isEmpty())
            QMetaObject::invokeMethod(this, "addItemsWithUrls", QUEUED,
                                      Q_ARG(QList<QUrl>, urllist));
    }
    connect(this, &QListWidget::itemActivated, [&](QListWidgetItem *item) {
        static_cast<BackupListWidgetItem *>(item)->browseUrl();
    });
}

BackupListWidget::~BackupListWidget()
{
    QStringList urls;
    for(int i = 0; i < count(); ++i)
    {
        BackupListWidgetItem *backupItem =
            static_cast<BackupListWidgetItem *>(item(i));
        urls << backupItem->url().toString(QUrl::FullyEncoded);
    }
    QSettings settings;
    settings.setValue("app/backup_list", urls);
    settings.sync();
    clear();
}

void BackupListWidget::addItemWithUrl(QUrl url)
{
    if(url.isEmpty())
        return;

    QString fileUrl = url.toLocalFile();
    if(fileUrl.isEmpty())
        return;
    QFileInfo file(fileUrl);
    if(!file.exists())
        return;

    QList<QUrl> urls    = itemUrls();
    bool        matches = false;
    foreach(QUrl existingUrl, urls)
    {
        if(url == existingUrl)
        {
            matches = true;
            break;
        }
        QFileInfo existingFile(existingUrl.toLocalFile());
        if(existingFile.isDir()
           && fileUrl.startsWith(existingFile.absoluteFilePath()))
        {
            matches = true;
            break;
        }
    }

    if(matches)
    {
        auto confirm =
            QMessageBox::question(this, tr("Confirm action"),
                                  tr("The file or directory:\n    %1\n"
                                     "was already in the backup list;"
                                     " adding it again will have no effect.\n"
                                     "Add anyway?")
                                      .arg(url.toLocalFile()));
        if(confirm == QMessageBox::No)
            return;
    }

    BackupListWidgetItem *item = new BackupListWidgetItem(url);
    connect(item, &BackupListWidgetItem::requestDelete, this,
            &BackupListWidget::removeItems);
    connect(item, &BackupListWidgetItem::requestUpdate, this,
            &BackupListWidget::recomputeListTotals);
    insertItem(count(), item);
    setItemWidget(item, item->widget());
    emit itemWithUrlAdded(url);
}

void BackupListWidget::addItemsWithUrls(QList<QUrl> urls)
{
    setUpdatesEnabled(false);
    foreach(QUrl url, urls)
        addItemWithUrl(url);
    recomputeListTotals();
    setUpdatesEnabled(true);
}

void BackupListWidget::setItemsWithUrls(QList<QUrl> urls)
{
    setUpdatesEnabled(false);
    clear();
    setUpdatesEnabled(true);
    addItemsWithUrls(urls);
}

QList<QUrl> BackupListWidget::itemUrls()
{
    QList<QUrl> urls;
    for(int i = 0; i < count(); ++i)
    {
        BackupListWidgetItem *backupItem =
            static_cast<BackupListWidgetItem *>(item(i));
        urls << backupItem->url().toString(QUrl::FullyEncoded);
    }
    return urls;
}

void BackupListWidget::removeItems()
{
    setUpdatesEnabled(false);
    if(selectedItems().count() == 0)
    {
        // attempt to remove the sender
        BackupListWidgetItem *backupItem =
            qobject_cast<BackupListWidgetItem *>(sender());
        if(backupItem)
            delete backupItem;
    }
    else
    {
        foreach(QListWidgetItem *item, selectedItems())
        {
            if(item && item->isSelected())
                delete item;
        }
    }
    setUpdatesEnabled(true);
    recomputeListTotals();
}

void BackupListWidget::recomputeListTotals()
{
    quint64 items = 0;
    quint64 size  = 0;
    for(int i = 0; i < count(); ++i)
    {
        BackupListWidgetItem *backupItem =
            static_cast<BackupListWidgetItem *>(item(i));
        if(backupItem && (backupItem->count() != 0))
        {
            items += backupItem->count();
            size  += backupItem->size();
        }
    }
    emit itemTotals(items, size);
}

void BackupListWidget::dragMoveEvent(QDragMoveEvent *event)
{
    if(!event->mimeData()->hasUrls())
    {
        event->ignore();
        return;
    }
    event->accept();
}

void BackupListWidget::dragEnterEvent(QDragEnterEvent *event)
{
    if(event->mimeData()->hasUrls())
        event->acceptProposedAction();
}

void BackupListWidget::dropEvent(QDropEvent *event)
{
    QList<QUrl> urls = event->mimeData()->urls();
    if(!urls.isEmpty())
        addItemsWithUrls(urls);

    event->acceptProposedAction();
}

void BackupListWidget::keyPressEvent(QKeyEvent *event)
{
    switch(event->key())
    {
    case Qt::Key_Delete:
    case Qt::Key_Backspace:
        removeItems();
        break;
    case Qt::Key_Escape:
        if(!selectedItems().isEmpty())
            clearSelection();
        else
            QListWidget::keyPressEvent(event);
        break;
    default:
        QListWidget::keyPressEvent(event);
    }
}

void BackupListWidget::changeEvent(QEvent *event)
{
    if(event->type() == QEvent::LanguageChange)
        recomputeListTotals();
    QWidget::changeEvent(event);
}
<commit_msg>clang-format *.cpp: misalign consecutive +=<commit_after>#include "backuplistwidget.h"
#include "backuplistwidgetitem.h"
#include "debug.h"
#include "utils.h"

#include <QDropEvent>
#include <QFileInfo>
#include <QMessageBox>
#include <QMimeData>
#include <QSettings>

BackupListWidget::BackupListWidget(QWidget *parent) : QListWidget(parent)
{
    QSettings   settings;
    QStringList urls = settings.value("app/backup_list").toStringList();
    if(!urls.isEmpty())
    {
        QList<QUrl> urllist;
        foreach(QString url, urls)
            urllist << QUrl::fromUserInput(url);
        if(!urllist.isEmpty())
            QMetaObject::invokeMethod(this, "addItemsWithUrls", QUEUED,
                                      Q_ARG(QList<QUrl>, urllist));
    }
    connect(this, &QListWidget::itemActivated, [&](QListWidgetItem *item) {
        static_cast<BackupListWidgetItem *>(item)->browseUrl();
    });
}

BackupListWidget::~BackupListWidget()
{
    QStringList urls;
    for(int i = 0; i < count(); ++i)
    {
        BackupListWidgetItem *backupItem =
            static_cast<BackupListWidgetItem *>(item(i));
        urls << backupItem->url().toString(QUrl::FullyEncoded);
    }
    QSettings settings;
    settings.setValue("app/backup_list", urls);
    settings.sync();
    clear();
}

void BackupListWidget::addItemWithUrl(QUrl url)
{
    if(url.isEmpty())
        return;

    QString fileUrl = url.toLocalFile();
    if(fileUrl.isEmpty())
        return;
    QFileInfo file(fileUrl);
    if(!file.exists())
        return;

    QList<QUrl> urls    = itemUrls();
    bool        matches = false;
    foreach(QUrl existingUrl, urls)
    {
        if(url == existingUrl)
        {
            matches = true;
            break;
        }
        QFileInfo existingFile(existingUrl.toLocalFile());
        if(existingFile.isDir()
           && fileUrl.startsWith(existingFile.absoluteFilePath()))
        {
            matches = true;
            break;
        }
    }

    if(matches)
    {
        auto confirm =
            QMessageBox::question(this, tr("Confirm action"),
                                  tr("The file or directory:\n    %1\n"
                                     "was already in the backup list;"
                                     " adding it again will have no effect.\n"
                                     "Add anyway?")
                                      .arg(url.toLocalFile()));
        if(confirm == QMessageBox::No)
            return;
    }

    BackupListWidgetItem *item = new BackupListWidgetItem(url);
    connect(item, &BackupListWidgetItem::requestDelete, this,
            &BackupListWidget::removeItems);
    connect(item, &BackupListWidgetItem::requestUpdate, this,
            &BackupListWidget::recomputeListTotals);
    insertItem(count(), item);
    setItemWidget(item, item->widget());
    emit itemWithUrlAdded(url);
}

void BackupListWidget::addItemsWithUrls(QList<QUrl> urls)
{
    setUpdatesEnabled(false);
    foreach(QUrl url, urls)
        addItemWithUrl(url);
    recomputeListTotals();
    setUpdatesEnabled(true);
}

void BackupListWidget::setItemsWithUrls(QList<QUrl> urls)
{
    setUpdatesEnabled(false);
    clear();
    setUpdatesEnabled(true);
    addItemsWithUrls(urls);
}

QList<QUrl> BackupListWidget::itemUrls()
{
    QList<QUrl> urls;
    for(int i = 0; i < count(); ++i)
    {
        BackupListWidgetItem *backupItem =
            static_cast<BackupListWidgetItem *>(item(i));
        urls << backupItem->url().toString(QUrl::FullyEncoded);
    }
    return urls;
}

void BackupListWidget::removeItems()
{
    setUpdatesEnabled(false);
    if(selectedItems().count() == 0)
    {
        // attempt to remove the sender
        BackupListWidgetItem *backupItem =
            qobject_cast<BackupListWidgetItem *>(sender());
        if(backupItem)
            delete backupItem;
    }
    else
    {
        foreach(QListWidgetItem *item, selectedItems())
        {
            if(item && item->isSelected())
                delete item;
        }
    }
    setUpdatesEnabled(true);
    recomputeListTotals();
}

void BackupListWidget::recomputeListTotals()
{
    quint64 items = 0;
    quint64 size  = 0;
    for(int i = 0; i < count(); ++i)
    {
        BackupListWidgetItem *backupItem =
            static_cast<BackupListWidgetItem *>(item(i));
        if(backupItem && (backupItem->count() != 0))
        {
            items += backupItem->count();
            size += backupItem->size();
        }
    }
    emit itemTotals(items, size);
}

void BackupListWidget::dragMoveEvent(QDragMoveEvent *event)
{
    if(!event->mimeData()->hasUrls())
    {
        event->ignore();
        return;
    }
    event->accept();
}

void BackupListWidget::dragEnterEvent(QDragEnterEvent *event)
{
    if(event->mimeData()->hasUrls())
        event->acceptProposedAction();
}

void BackupListWidget::dropEvent(QDropEvent *event)
{
    QList<QUrl> urls = event->mimeData()->urls();
    if(!urls.isEmpty())
        addItemsWithUrls(urls);

    event->acceptProposedAction();
}

void BackupListWidget::keyPressEvent(QKeyEvent *event)
{
    switch(event->key())
    {
    case Qt::Key_Delete:
    case Qt::Key_Backspace:
        removeItems();
        break;
    case Qt::Key_Escape:
        if(!selectedItems().isEmpty())
            clearSelection();
        else
            QListWidget::keyPressEvent(event);
        break;
    default:
        QListWidget::keyPressEvent(event);
    }
}

void BackupListWidget::changeEvent(QEvent *event)
{
    if(event->type() == QEvent::LanguageChange)
        recomputeListTotals();
    QWidget::changeEvent(event);
}
<|endoftext|>


<commit_before>// This is a personal academic project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#include "inputsystem.hpp"

#include "../component/kbmouseinputcomponent.hpp"
#include "../component/physicscomponent.hpp"
#include "../component/rigidbodycomponent.hpp"
#include "../component/guncomponent.hpp"

#include "../../engine.hpp"

InputSystem::~InputSystem() {}

void InputSystem::update(World& world, float delta) {
	rmt_ScopedCPUSample(InputSystem, RMTSF_None);
	std::shared_ptr<HIDInput> hid = Engine::getInstance().getHIDInput();

	for (std::unique_ptr<Entity>& entity : world.getEntities()) {
		if (!entity->getComponent<KBMouseInputComponent>())
			continue;

		auto rigidBodyComponent = entity->getComponent<RigidBodyComponent>();
		if (!rigidBodyComponent)
			continue;

		btRigidBody & rigidBody = *rigidBodyComponent->getRigidBody();

		// TODO: calculate this?
		//glm::vec3 forward = glm::vec3(0, 0, 1);
		//glm::vec3 right = glm::vec3(-1, 0, 0);
		//glm::vec3 up = glm::vec3(0, 1, 0);

		glm::vec3 inputDir;
		if (hid->getKey(SDL_SCANCODE_W))
			inputDir.z++;
		if (hid->getKey(SDL_SCANCODE_S))
			inputDir.z--;

		if (hid->getKey(SDL_SCANCODE_A))
			inputDir.x++;
		if (hid->getKey(SDL_SCANCODE_D))
			inputDir.x--;

		if (hid->getKey(SDL_SCANCODE_SPACE))
			inputDir.y++;
		if (hid->getKey(SDL_SCANCODE_LCTRL))
			inputDir.y--;

		float accelSpeed = 20;
		float maxVelocty = 5;
		float maxVelocty2 = maxVelocty * maxVelocty;

		//physicsComponent->acceleration = -physicsComponent->velocity / 0.05f;
		//physicsComponent->acceleration += inputDir.z * forward * accelSpeed;
		//physicsComponent->acceleration += inputDir.x * right * accelSpeed;
		//physicsComponent->acceleration += inputDir.y * up * accelSpeed;

		rigidBody.applyCentralForce({
			inputDir.x * accelSpeed,
			inputDir.y * accelSpeed * 2,
			inputDir.z * accelSpeed
		});

		if (entity->getName() == "Player") {
			auto gun = entity->getComponent<GunComponent>();
			if (hid->getKey(SDL_SCANCODE_F) && gun->cooldown <= 0) {
				gun->shoot = true;
			}
		}

		btVector3 v = rigidBody.getLinearVelocity();
		if (v.length2() > maxVelocty2)
		{
			v.normalize();
			v *= maxVelocty;
			rigidBody.setLinearVelocity(v);
		}

	}
}

void InputSystem::registerImGui() {}
<commit_msg>player is looking at mouse<commit_after>// This is a personal academic project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#include "inputsystem.hpp"

#include "../component/kbmouseinputcomponent.hpp"
#include "../component/physicscomponent.hpp"
#include "../component/rigidbodycomponent.hpp"
#include "../component/guncomponent.hpp"

#include "../../engine.hpp"

#include <stdio.h>

InputSystem::~InputSystem() {}

void InputSystem::update(World& world, float delta) {
	rmt_ScopedCPUSample(InputSystem, RMTSF_None);
	std::shared_ptr<HIDInput> hid = Engine::getInstance().getHIDInput();

	for (std::unique_ptr<Entity>& entity : world.getEntities()) {
		if (!entity->getComponent<KBMouseInputComponent>())
			continue;

		auto rigidBodyComponent = entity->getComponent<RigidBodyComponent>();
		if (!rigidBodyComponent)
			continue;

		btRigidBody & rigidBody = *rigidBodyComponent->getRigidBody();

		// TODO: calculate this?
		//glm::vec3 forward = glm::vec3(0, 0, 1);
		//glm::vec3 right = glm::vec3(-1, 0, 0);
		//glm::vec3 up = glm::vec3(0, 1, 0);

		glm::vec3 inputDir;
		if (hid->getKey(SDL_SCANCODE_W))
			inputDir.z++;
		if (hid->getKey(SDL_SCANCODE_S))
			inputDir.z--;

		if (hid->getKey(SDL_SCANCODE_A))
			inputDir.x++;
		if (hid->getKey(SDL_SCANCODE_D))
			inputDir.x--;

		if (hid->getKey(SDL_SCANCODE_SPACE))
			inputDir.y++;
		if (hid->getKey(SDL_SCANCODE_LCTRL))
			inputDir.y--;

		float accelSpeed = 60;
		float maxSpeed = 5;

		//physicsComponent->acceleration = -physicsComponent->velocity / 0.05f;
		//physicsComponent->acceleration += inputDir.z * forward * accelSpeed;
		//physicsComponent->acceleration += inputDir.x * right * accelSpeed;
		//physicsComponent->acceleration += inputDir.y * up * accelSpeed;

		rigidBody.applyCentralForce({
			inputDir.x * accelSpeed,
			inputDir.y * accelSpeed * 2,
			inputDir.z * accelSpeed
		});

		auto tc = entity->getComponent<TransformComponent>();
		if (tc)
		{
			static Engine * engine = &Engine::getInstance();
			int width = engine->getWidth();
			int height = engine->getHeight();

			glm::vec2 mpos = hid->getXY();
			glm::vec2 hmpos = { mpos.x / width, 1 - mpos.y / height };
			hmpos *= 2;
			hmpos -= 1;

			glm::vec2 dir = glm::normalize(hmpos);

			tc->setDirection({ dir.x, 0, dir.y });
		}

		auto gun = entity->getComponent<GunComponent>();
		if (gun && hid->getKey(SDL_SCANCODE_F) && gun->cooldown <= 0) {
			gun->shoot = true;
		}
	}
}

void InputSystem::registerImGui() {}
<|endoftext|>


<commit_before>/* BEGIN_COMMON_COPYRIGHT_HEADER
 *
 * Razor - a lightweight, Qt based, desktop toolset
 * http://razor-qt.org
 *
 * Copyright: 2010-2011 Razor team
 * Authors:
 *   Petr Vanek <petr@scribus.info>
 *
 * This program or library is free software; you can redistribute it
 * and/or modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.

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

#include "mainwindow.h"

#include <QtCore/QSettings>
#include <QtGui/QProgressDialog>
#include <qtxdg/xdgdirs.h>
#include <qtxdg/xdgicon.h>
#include <razorqt/razorsettings.h>

MainWindow::MainWindow()
{
    setupUi(this);
    listWidget->setIconSize(QSize(64,64));

    m_settings = new RazorSettings("razor", this);
    m_cache = new RazorSettingsCache(m_settings);

//    qDebug() << "START" << XdgDirs::dataDirs();

    QDir d;
    QStringList dirs = XdgDirs::dataDirs();

    QProgressDialog progress(tr("Searching for icon themes"), "", 0, dirs.count(), this);
    progress.setCancelButton(0);
    progress.setMinimumDuration(0);
    progress.show();
    qDebug() << "AAAAA";
    qApp->processEvents();

    int i = 0;
    foreach(QString basedir, dirs)
    {
        progress.setValue(i);
        qApp->processEvents();
        ++i;

//        // TODO/FIXME: think about this "optimization"
        if (basedir == "/usr/share")
            basedir = "/usr/share/icons";

//        qDebug() << "BASEDIR" << basedir;
        QDirIterator it(basedir, QStringList() << "index.theme", QDir::Files, QDirIterator::Subdirectories);
        while (it.hasNext())
        {
            QFileInfo fi(it.next());
            qDebug() << fi.filePath();
            QSettings check(fi.filePath(), QSettings::IniFormat);
            if (check.childGroups().contains("Icon Theme"))
            {
                if (d.exists(fi.canonicalPath() + "/" + "cursors"))
                {
//                    qDebug() << "    mouse theme. Skipped";
                }
                else
                {
//                    qDebug() << "  ADD" << fi.dir().dirName();
                    XdgIcon::setThemeName(fi.dir().dirName());
                    QString sample = check.value("Icon Theme/Example", "application-exit").toString();
                    new QListWidgetItem(XdgIcon::fromTheme(sample), fi.dir().dirName(), listWidget);
                }
            }
        }
    }
    progress.hide();

    restoreSettings();

    connect(buttons, SIGNAL(clicked(QAbstractButton*)),
            this, SLOT(dialogButtonsAction(QAbstractButton*)));
    connect(listWidget, SIGNAL(currentTextChanged(const QString &)),
            this, SLOT(listWidget_currentTextChanged(const QString &)));
}

MainWindow::~MainWindow()
{
    delete m_cache;
}

void MainWindow::listWidget_currentTextChanged(const QString &text)
{
//    qDebug() << "listWidget_currentTextChanged" << text;
    if (text.isNull())
        return;

    m_settings->setValue("icon_theme", text);
}

void MainWindow::restoreSettings()
{
    QString theme = m_settings->value("icon_theme", "oxygen").toString();
//    qDebug() << "SETTINGS" << theme;
    foreach (QListWidgetItem *item, listWidget->findItems(theme, Qt::MatchFixedString))
    {
//        qDebug() << "FOUND" << item;
        listWidget->setCurrentItem(item);
        break;
    }
}

void MainWindow::dialogButtonsAction(QAbstractButton *btn)
{
    if (buttons->buttonRole(btn) == QDialogButtonBox::ResetRole)
    {
        m_cache->loadToSettings();
        restoreSettings();
    }
    else
    {
        close();
    }
}

<commit_msg>forgotten debugs<commit_after>/* BEGIN_COMMON_COPYRIGHT_HEADER
 *
 * Razor - a lightweight, Qt based, desktop toolset
 * http://razor-qt.org
 *
 * Copyright: 2010-2011 Razor team
 * Authors:
 *   Petr Vanek <petr@scribus.info>
 *
 * This program or library is free software; you can redistribute it
 * and/or modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.

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

#include "mainwindow.h"

#include <QtCore/QSettings>
#include <QtGui/QProgressDialog>
#include <qtxdg/xdgdirs.h>
#include <qtxdg/xdgicon.h>
#include <razorqt/razorsettings.h>

MainWindow::MainWindow()
{
    setupUi(this);
    listWidget->setIconSize(QSize(64,64));

    m_settings = new RazorSettings("razor", this);
    m_cache = new RazorSettingsCache(m_settings);

//    qDebug() << "START" << XdgDirs::dataDirs();

    QDir d;
    QStringList dirs = XdgDirs::dataDirs();

    QProgressDialog progress(tr("Searching for icon themes"), "", 0, dirs.count(), this);
    progress.setCancelButton(0);
    progress.setMinimumDuration(0);
    progress.show();
    qApp->processEvents();

    int i = 0;
    foreach(QString basedir, dirs)
    {
        progress.setValue(i);
        qApp->processEvents();
        ++i;

//        // TODO/FIXME: think about this "optimization"
        if (basedir == "/usr/share")
            basedir = "/usr/share/icons";

//        qDebug() << "BASEDIR" << basedir;
        QDirIterator it(basedir, QStringList() << "index.theme", QDir::Files, QDirIterator::Subdirectories);
        while (it.hasNext())
        {
            QFileInfo fi(it.next());
            qDebug() << fi.filePath();
            QSettings check(fi.filePath(), QSettings::IniFormat);
            if (check.childGroups().contains("Icon Theme"))
            {
                if (d.exists(fi.canonicalPath() + "/" + "cursors"))
                {
//                    qDebug() << "    mouse theme. Skipped";
                }
                else
                {
//                    qDebug() << "  ADD" << fi.dir().dirName();
                    XdgIcon::setThemeName(fi.dir().dirName());
                    QString sample = check.value("Icon Theme/Example", "application-exit").toString();
                    new QListWidgetItem(XdgIcon::fromTheme(sample), fi.dir().dirName(), listWidget);
                }
            }
        }
    }
    progress.hide();

    restoreSettings();

    connect(buttons, SIGNAL(clicked(QAbstractButton*)),
            this, SLOT(dialogButtonsAction(QAbstractButton*)));
    connect(listWidget, SIGNAL(currentTextChanged(const QString &)),
            this, SLOT(listWidget_currentTextChanged(const QString &)));
}

MainWindow::~MainWindow()
{
    delete m_cache;
}

void MainWindow::listWidget_currentTextChanged(const QString &text)
{
//    qDebug() << "listWidget_currentTextChanged" << text;
    if (text.isNull())
        return;

    m_settings->setValue("icon_theme", text);
}

void MainWindow::restoreSettings()
{
    QString theme = m_settings->value("icon_theme", "oxygen").toString();
//    qDebug() << "SETTINGS" << theme;
    foreach (QListWidgetItem *item, listWidget->findItems(theme, Qt::MatchFixedString))
    {
//        qDebug() << "FOUND" << item;
        listWidget->setCurrentItem(item);
        break;
    }
}

void MainWindow::dialogButtonsAction(QAbstractButton *btn)
{
    if (buttons->buttonRole(btn) == QDialogButtonBox::ResetRole)
    {
        m_cache->loadToSettings();
        restoreSettings();
    }
    else
    {
        close();
    }
}

<|endoftext|>