<commit_before>/*
 * Copyright (c) 2011, Georgia Tech Research Corporation
 * All rights reserved.
 *
 * Author(s): Sehoon Ha <sehoon.ha@gmail.com>
 * Date: 06/12/2011
 *
 * Geoorgia Tech Graphics Lab and Humanoid Robotics Lab
 *
 * Directed by Prof. C. Karen Liu and Prof. Mike Stilman
 * <karenliu@cc.gatech.edu> <mstilman@cc.gatech.edu>
 *
 * This file is provided under the following "BSD-style" License:
 *   Redistribution and use in source and binary forms, with or
 *   without modification, are permitted provided that the following
 *   conditions are met:
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 *   CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 *   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 *   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 *   DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 *   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 *   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 *   AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *   POSSIBILITY OF SUCH DAMAGE.
 */

#include "Skeleton.h"

#include <cassert>
using namespace std;
using namespace Eigen;

#include "Dof.h"
#include "Joint.h"
#include "BodyNode.h"
#include "Marker.h"
#include "Transformation.h"
#include "math/UtilsMath.h"

#include "renderer/RenderInterface.h"

namespace kinematics {

    Skeleton::Skeleton()
        : mMass(0.0),
          mSelfCollidable(false) {
        mMass = 0;
    }

    Skeleton::~Skeleton(){
        for(unsigned int i = 0; i < mJoints.size(); i++) delete mJoints[i];
        mJoints.clear();
        mDofs.clear();
        mTransforms.clear();
        for(unsigned int i=0; i<mNodes.size(); i++) delete mNodes[i];
        mNodes.clear();
        mMarkers.clear();
    }

    BodyNode* Skeleton::createBodyNode(const char* const _name) {
        return new BodyNode(_name);
    }

    void Skeleton::addMarker(Marker *_h) {
        mMarkers.push_back(_h);
        _h->setSkelIndex(mMarkers.size()-1);
        BodyNode *body = _h->getNode();
        body->addMarker(_h);
    }

    void Skeleton::addNode(BodyNode *_b, bool _addParentJoint) {
        mNodes.push_back(_b);
        _b->setSkelIndex(mNodes.size()-1);
        // The parent joint possibly be null
        if (_addParentJoint)
            addJoint(_b->getParentJoint());
    }

    void Skeleton::addJoint(Joint *_j) {
        mJoints.push_back(_j);
        _j->setSkelIndex(mJoints.size()-1);
    }

    void Skeleton::addDof(Dof *_q) {
        mDofs.push_back(_q);
        _q->setSkelIndex(mDofs.size()-1);
        _q->setVariable();
    }

    void Skeleton::addTransform(Transformation *_t) {
        mTransforms.push_back(_t);
        _t->setVariable(true);
        _t->setSkelIndex(mTransforms.size()-1);
        for(int i=0; i<_t->getNumDofs(); i++) {
            addDof(_t->getDof(i));
        }
    }

    void Skeleton::initSkel() {
        mRoot = mNodes[0];

        // calculate mass
        // init the dependsOnDof stucture for each bodylink
        for(int i=0; i<getNumNodes(); i++) {
            mNodes[i]->setSkel(this);
            // mNodes[i]->setDependDofMap(getNumDofs());
            mNodes[i]->setDependDofList();
            mNodes.at(i)->init();
            mMass += mNodes[i]->getMass();
        }

        mCurrPose = VectorXd::Zero(getNumDofs());

        for(int i=0; i<getNumDofs(); i++)
            mCurrPose[i] = mDofs.at(i)->getValue();
        for(int i=0; i<getNumNodes(); i++) {
            mNodes.at(i)->updateTransform();
        }
    }

    BodyNode* Skeleton::getNode(const char* const _name) const {
        const int nNodes = getNumNodes();
        for(int i = 0; i < nNodes; i++){
            BodyNode* node = getNode(i);
            if (strcmp(_name, node->getName()) == 0) {
                return node;
            }
        }
        return NULL;
    }

    int Skeleton::getNodeIndex(const char* const _name) const {
        const int nNodes = getNumNodes();
        for(int i = 0; i < nNodes; i++){
            BodyNode* node = getNode(i);
            if (strcmp(_name, node->getName()) == 0) {
                return i;
            }
        }
        return -1;
    }

    Joint* Skeleton::getJoint(const char* const _name) const {
        const int nJoints = getNumJoints();
        for (int i = 0; i < nJoints; ++i) {
            Joint* joint = getJoint(i);
            if (strcmp(_name, joint->getName()) == 0) {
                return joint;
            }
        }
        return NULL;
    }

    int Skeleton::getJointIndex(const char* const _name) const {
        const int nJoints = getNumJoints();
        for (int i = 0; i < nJoints; ++i) {
            Joint* joint = getJoint(i);
            if (strcmp(_name, joint->getName()) == 0) {
                return i;
            }
        }
        return -1;
    }

    Vector3d Skeleton::getWorldCOM() {
        assert(mMass != 0);
        Vector3d com(0, 0, 0);
        const int nNodes = getNumNodes();
        for(int i = 0; i < nNodes; i++) {
            BodyNode* node = getNode(i);
            com += (node->getMass() * node->getWorldCOM());
        }
        return com / mMass;
    }

    void Skeleton::setPose(const VectorXd& state, bool bCalcTrans, bool bCalcDeriv) {
        mCurrPose = state;
        for (int i = 0; i < getNumDofs(); i++) {
            mDofs.at(i)->setValue(state[i]);
        }

        if (bCalcTrans) {
            for (int i = 0; i < getNumNodes(); i++) {
                mNodes.at(i)->updateTransform();
            }
        }

        if (bCalcDeriv) {
            for (int i = 0; i < getNumNodes(); i++) {
                mNodes.at(i)->updateFirstDerivatives();
            }
        }
    }

    Eigen::VectorXd Skeleton::getPose() {
        Eigen::VectorXd pose(getNumDofs());
        for (int i = 0; i < getNumDofs(); i++) {
            pose(i) = mDofs[i]->getValue();
        }
        return pose;
    }

    Eigen::VectorXd Skeleton::getConfig(std::vector<int> _id)
    {
        Eigen::VectorXd dofs(_id.size());
        for(unsigned int i = 0; i < _id.size(); i++) {
            dofs[i] = mDofs[_id[i]]->getValue();
        }
        return dofs;
    }

    void Skeleton::setConfig(std::vector<int> _id, Eigen::VectorXd _vals, bool _calcTrans, bool _calcDeriv) {
        for( unsigned int i = 0; i < _id.size(); i++ ) {
            mCurrPose[_id[i]] = _vals(i);
            mDofs[_id[i]]->setValue(_vals(i));
        }

        // TODO: Only do the necessary updates
        if (_calcTrans) {
            for (int i = 0; i < getNumNodes(); i++) {
                mNodes.at(i)->updateTransform();
            }
        }

        if (_calcDeriv) {
            for (int i = 0; i < getNumNodes(); i++) {
                mNodes.at(i)->updateFirstDerivatives();
            }
        }
  }

    MatrixXd Skeleton::getJacobian(BodyNode* _bd, Vector3d& _localOffset) {
        MatrixXd J(3, mDofs.size());
        J.setZero();
        for(int i = 0; i < _bd->getNumDependentDofs(); i++) {
            int dofindex = _bd->getDependentDof(i);
            VectorXd deriv = math::xformHom(_bd->getDerivWorldTransform(i), _localOffset);
            J.col(dofindex) = deriv;
        }
        return J;
    }

    void Skeleton::draw(renderer::RenderInterface* _ri, const Vector4d& _color, bool _useDefaultColor) const {
        mRoot->draw(_ri, _color, _useDefaultColor);
    }
    void Skeleton::drawMarkers(renderer::RenderInterface* _ri, const Vector4d& _color, bool _useDefaultColor) const {
        mRoot->drawMarkers(_ri, _color, _useDefaultColor);
    }

} // namespace kinematics
<commit_msg>Fix bug in calculation of skeleton mass if Skeleton::initSkel() is called multiple times<commit_after>/*
 * Copyright (c) 2011, Georgia Tech Research Corporation
 * All rights reserved.
 *
 * Author(s): Sehoon Ha <sehoon.ha@gmail.com>
 * Date: 06/12/2011
 *
 * Geoorgia Tech Graphics Lab and Humanoid Robotics Lab
 *
 * Directed by Prof. C. Karen Liu and Prof. Mike Stilman
 * <karenliu@cc.gatech.edu> <mstilman@cc.gatech.edu>
 *
 * This file is provided under the following "BSD-style" License:
 *   Redistribution and use in source and binary forms, with or
 *   without modification, are permitted provided that the following
 *   conditions are met:
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 *   CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 *   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 *   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 *   DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 *   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 *   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 *   AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *   POSSIBILITY OF SUCH DAMAGE.
 */

#include "Skeleton.h"

#include <cassert>
using namespace std;
using namespace Eigen;

#include "Dof.h"
#include "Joint.h"
#include "BodyNode.h"
#include "Marker.h"
#include "Transformation.h"
#include "math/UtilsMath.h"

#include "renderer/RenderInterface.h"

namespace kinematics {

    Skeleton::Skeleton()
        : mMass(0.0),
          mSelfCollidable(false) {
        mMass = 0;
    }

    Skeleton::~Skeleton(){
        for(unsigned int i = 0; i < mJoints.size(); i++) delete mJoints[i];
        mJoints.clear();
        mDofs.clear();
        mTransforms.clear();
        for(unsigned int i=0; i<mNodes.size(); i++) delete mNodes[i];
        mNodes.clear();
        mMarkers.clear();
    }

    BodyNode* Skeleton::createBodyNode(const char* const _name) {
        return new BodyNode(_name);
    }

    void Skeleton::addMarker(Marker *_h) {
        mMarkers.push_back(_h);
        _h->setSkelIndex(mMarkers.size()-1);
        BodyNode *body = _h->getNode();
        body->addMarker(_h);
    }

    void Skeleton::addNode(BodyNode *_b, bool _addParentJoint) {
        mNodes.push_back(_b);
        _b->setSkelIndex(mNodes.size()-1);
        // The parent joint possibly be null
        if (_addParentJoint)
            addJoint(_b->getParentJoint());
    }

    void Skeleton::addJoint(Joint *_j) {
        mJoints.push_back(_j);
        _j->setSkelIndex(mJoints.size()-1);
    }

    void Skeleton::addDof(Dof *_q) {
        mDofs.push_back(_q);
        _q->setSkelIndex(mDofs.size()-1);
        _q->setVariable();
    }

    void Skeleton::addTransform(Transformation *_t) {
        mTransforms.push_back(_t);
        _t->setVariable(true);
        _t->setSkelIndex(mTransforms.size()-1);
        for(int i=0; i<_t->getNumDofs(); i++) {
            addDof(_t->getDof(i));
        }
    }

    void Skeleton::initSkel() {
        mRoot = mNodes[0];

        // calculate mass
        // init the dependsOnDof stucture for each bodylink
        mMass = 0.0;
        for(int i=0; i<getNumNodes(); i++) {
            mNodes[i]->setSkel(this);
            // mNodes[i]->setDependDofMap(getNumDofs());
            mNodes[i]->setDependDofList();
            mNodes.at(i)->init();
            mMass += mNodes[i]->getMass();
        }

        mCurrPose = VectorXd::Zero(getNumDofs());

        for(int i=0; i<getNumDofs(); i++)
            mCurrPose[i] = mDofs.at(i)->getValue();
        for(int i=0; i<getNumNodes(); i++) {
            mNodes.at(i)->updateTransform();
        }
    }

    BodyNode* Skeleton::getNode(const char* const _name) const {
        const int nNodes = getNumNodes();
        for(int i = 0; i < nNodes; i++){
            BodyNode* node = getNode(i);
            if (strcmp(_name, node->getName()) == 0) {
                return node;
            }
        }
        return NULL;
    }

    int Skeleton::getNodeIndex(const char* const _name) const {
        const int nNodes = getNumNodes();
        for(int i = 0; i < nNodes; i++){
            BodyNode* node = getNode(i);
            if (strcmp(_name, node->getName()) == 0) {
                return i;
            }
        }
        return -1;
    }

    Joint* Skeleton::getJoint(const char* const _name) const {
        const int nJoints = getNumJoints();
        for (int i = 0; i < nJoints; ++i) {
            Joint* joint = getJoint(i);
            if (strcmp(_name, joint->getName()) == 0) {
                return joint;
            }
        }
        return NULL;
    }

    int Skeleton::getJointIndex(const char* const _name) const {
        const int nJoints = getNumJoints();
        for (int i = 0; i < nJoints; ++i) {
            Joint* joint = getJoint(i);
            if (strcmp(_name, joint->getName()) == 0) {
                return i;
            }
        }
        return -1;
    }

    Vector3d Skeleton::getWorldCOM() {
        assert(mMass != 0);
        Vector3d com(0, 0, 0);
        const int nNodes = getNumNodes();
        for(int i = 0; i < nNodes; i++) {
            BodyNode* node = getNode(i);
            com += (node->getMass() * node->getWorldCOM());
        }
        return com / mMass;
    }

    void Skeleton::setPose(const VectorXd& state, bool bCalcTrans, bool bCalcDeriv) {
        mCurrPose = state;
        for (int i = 0; i < getNumDofs(); i++) {
            mDofs.at(i)->setValue(state[i]);
        }

        if (bCalcTrans) {
            for (int i = 0; i < getNumNodes(); i++) {
                mNodes.at(i)->updateTransform();
            }
        }

        if (bCalcDeriv) {
            for (int i = 0; i < getNumNodes(); i++) {
                mNodes.at(i)->updateFirstDerivatives();
            }
        }
    }

    Eigen::VectorXd Skeleton::getPose() {
        Eigen::VectorXd pose(getNumDofs());
        for (int i = 0; i < getNumDofs(); i++) {
            pose(i) = mDofs[i]->getValue();
        }
        return pose;
    }

    Eigen::VectorXd Skeleton::getConfig(std::vector<int> _id)
    {
        Eigen::VectorXd dofs(_id.size());
        for(unsigned int i = 0; i < _id.size(); i++) {
            dofs[i] = mDofs[_id[i]]->getValue();
        }
        return dofs;
    }

    void Skeleton::setConfig(std::vector<int> _id, Eigen::VectorXd _vals, bool _calcTrans, bool _calcDeriv) {
        for( unsigned int i = 0; i < _id.size(); i++ ) {
            mCurrPose[_id[i]] = _vals(i);
            mDofs[_id[i]]->setValue(_vals(i));
        }

        // TODO: Only do the necessary updates
        if (_calcTrans) {
            for (int i = 0; i < getNumNodes(); i++) {
                mNodes.at(i)->updateTransform();
            }
        }

        if (_calcDeriv) {
            for (int i = 0; i < getNumNodes(); i++) {
                mNodes.at(i)->updateFirstDerivatives();
            }
        }
  }

    MatrixXd Skeleton::getJacobian(BodyNode* _bd, Vector3d& _localOffset) {
        MatrixXd J(3, mDofs.size());
        J.setZero();
        for(int i = 0; i < _bd->getNumDependentDofs(); i++) {
            int dofindex = _bd->getDependentDof(i);
            VectorXd deriv = math::xformHom(_bd->getDerivWorldTransform(i), _localOffset);
            J.col(dofindex) = deriv;
        }
        return J;
    }

    void Skeleton::draw(renderer::RenderInterface* _ri, const Vector4d& _color, bool _useDefaultColor) const {
        mRoot->draw(_ri, _color, _useDefaultColor);
    }
    void Skeleton::drawMarkers(renderer::RenderInterface* _ri, const Vector4d& _color, bool _useDefaultColor) const {
        mRoot->drawMarkers(_ri, _color, _useDefaultColor);
    }

} // namespace kinematics
<|endoftext|>


<commit_before>#include "overviewpage.h"
#include "ui_overviewpage.h"

#include "walletmodel.h"
#include "bitcoinunits.h"
#include "optionsmodel.h"
#include "transactiontablemodel.h"
#include "transactionfilterproxy.h"
#include "guiutil.h"
#include "guiconstants.h"
#include <iostream>
#include <QAbstractItemDelegate>
#include <QPainter>
#include <QGraphicsDropShadowEffect>
#include "svgiconengine.h"

#define DECORATION_SIZE 64
#define NUM_ITEMS 3

class TxViewDelegate : public QAbstractItemDelegate
{
    Q_OBJECT
public:
    TxViewDelegate(): QAbstractItemDelegate(), unit(IocoinUnits::BTC)
    {

    }

    inline void paint(QPainter *painter, const QStyleOptionViewItem &option,
                      const QModelIndex &index ) const
    {
        painter->save();

        QIcon icon = qvariant_cast<QIcon>(index.data(Qt::DecorationRole));
        QRect mainRect = option.rect;
        QRect decorationRect(mainRect.topLeft(), QSize(DECORATION_SIZE, DECORATION_SIZE));
        int xspace = DECORATION_SIZE + 8;
        int ypad = 6;
        int halfheight = (mainRect.height() - 2*ypad)/2;
        QRect amountRect(mainRect.left() + xspace, mainRect.top()+ypad, mainRect.width() - xspace, halfheight);
        QRect addressRect(mainRect.left() + xspace, mainRect.top()+ypad+halfheight, mainRect.width() - xspace, halfheight);
        icon.paint(painter, decorationRect);

        QDateTime date = index.data(TransactionTableModel::DateRole).toDateTime();
        QString address = index.data(Qt::DisplayRole).toString();
        qint64 amount = index.data(TransactionTableModel::AmountRole).toLongLong();
        bool confirmed = index.data(TransactionTableModel::ConfirmedRole).toBool();
        QVariant value = index.data(Qt::ForegroundRole);
        QColor foreground = option.palette.color(QPalette::Text);
        if(qVariantCanConvert<QColor>(value))
        {
            foreground = qvariant_cast<QColor>(value);
        }

        painter->setPen(foreground);
        painter->drawText(addressRect, Qt::AlignLeft|Qt::AlignVCenter, address);

        if(amount < 0)
        {
            foreground = COLOR_NEGATIVE;
        }
        else if(!confirmed)
        {
            foreground = COLOR_UNCONFIRMED;
        }
        else
        {
            foreground = option.palette.color(QPalette::Text);
        }
        painter->setPen(foreground);
        QString amountText = IocoinUnits::formatWithUnit(unit, amount, true);
        if(!confirmed)
        {
            amountText = QString("[") + amountText + QString("]");
        }
        painter->drawText(amountRect, Qt::AlignRight|Qt::AlignVCenter, amountText);

        painter->setPen(option.palette.color(QPalette::Text));
        painter->drawText(amountRect, Qt::AlignLeft|Qt::AlignVCenter, GUIUtil::dateTimeStr(date));

        painter->restore();
    }

    inline QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
    {
        return QSize(DECORATION_SIZE, DECORATION_SIZE);
    }

    int unit;

};
#include "overviewpage.moc"

OverviewPage::OverviewPage(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::OverviewPage),
    currentBalance(-1),
    currentStake(0),
    currentUnconfirmedBalance(-1),
    currentImmatureBalance(-1),
    txdelegate(new TxViewDelegate()),
    filter(0)
{
    ui->setupUi(this);

    txv_ = new TransactionView(this);
    txv_->setObjectName("txv");

    QGraphicsDropShadowEffect* ef = new QGraphicsDropShadowEffect();
    ef->setBlurRadius(10);
    ef->setXOffset(2);
    ef->setYOffset(2);
    QColor col = QColor("#d3d3d3");
    ef->setColor(col);
    ui->available->setGraphicsEffect(ef);
    QGraphicsDropShadowEffect* ef2 = new QGraphicsDropShadowEffect();
    ef2->setBlurRadius(10);
    ef2->setXOffset(2);
    ef2->setYOffset(2);
    ef2->setColor(col);
    ui->pending->setGraphicsEffect(ef2);
    QGraphicsDropShadowEffect* ef3 = new QGraphicsDropShadowEffect();
    ef3->setBlurRadius(10);
    ef3->setXOffset(2);
    ef3->setYOffset(2);
    ef3->setColor(col);
    ui->staked->setGraphicsEffect(ef3);

    // init "out of sync" warning labels
    //ui->labelWalletStatus->setText("(" + tr("out of sync") + ")");
    //ui->labelTransactionsStatus->setText("(" + tr("out of sync") + ")");

    ui->vl->setContentsMargins(0 , 0, 0, 0);
    ui->statusGL->setSpacing(0);
    ui->statusGL->setContentsMargins(10 , 0, 10, 0);
    ui->statusHB->setContentsMargins(0 , 0, 0, 0);
    ui->statusGL->setColumnStretch(0,0);

    ui->labelIntBalance->setMargin(0);
    ui->labelIntBalance->sizePolicy().setHorizontalStretch(1);
    ui->labelIntBalance->setContentsMargins(0,0,0,0);
    ui->labelFracBalance->setMargin(0);

    ui->unconfirmedGL->setSpacing(0);
    ui->unconfirmedGL->setContentsMargins(10 , 0, 10, 0);
    ui->unconfirmedGL->setColumnStretch(0,0);
    ui->labelIntUnconfirmed->setMargin(0);
    ui->labelIntUnconfirmed->sizePolicy().setHorizontalStretch(1);
    ui->labelIntUnconfirmed->setContentsMargins(0,0,0,0);
    ui->labelFracUnconfirmed->setMargin(0);

    ui->stakedGL->setSpacing(0);
    ui->stakedGL->setContentsMargins(10 , 0, 10, 0);
    ui->stakedGL->setColumnStretch(0,0);
    ui->labelIntStaked->setMargin(0);
    ui->labelIntStaked->sizePolicy().setHorizontalStretch(1);
    ui->labelIntStaked->setContentsMargins(0,0,0,0);
    ui->labelFracStaked->setMargin(0);

    //ui->availableAmountLayout->setMargin(0);
    //ui->availableAmountLayout->setSpacing(0);
    //QVBoxLayout *vbox = new QVBoxLayout();
    //QLabel* tmp = new QLabel();
    //tmp->setText("hello");
    //vbox->addWidget(txv_);
    //vbox->addWidget(tmp);
    //ui->txv->setLayout(vbox);

    // start with displaying the "out of sync" warnings
    showOutOfSyncWarning(true);
}

void OverviewPage::handleTransactionClicked(const QModelIndex &index)
{
    if(filter)
        emit transactionClicked(filter->mapToSource(index));
}

OverviewPage::~OverviewPage()
{
    delete ui;
}

void OverviewPage::setBalance(qint64 balance, qint64 stake, qint64 unconfirmedBalance, qint64 immatureBalance)
{
    int unit = model->getOptionsModel()->getDisplayUnit();
    currentBalance = balance;
    currentStake = stake;
    currentUnconfirmedBalance = unconfirmedBalance;
    currentImmatureBalance = immatureBalance;
    ui->labelIntBalance->setText(IocoinUnits::intFormatWithUnit(unit, balance));
    ui->labelFracBalance->setText(IocoinUnits::fracFormatWithUnit(unit, balance));
    ui->labelIntStaked->setText(IocoinUnits::intFormatWithUnit(unit, stake));
    ui->labelFracStaked->setText(IocoinUnits::fracFormatWithUnit(unit, stake));
    ui->labelIntUnconfirmed->setText(IocoinUnits::intFormatWithUnit(unit, unconfirmedBalance));
    ui->labelFracUnconfirmed->setText(IocoinUnits::fracFormatWithUnit(unit, unconfirmedBalance));

    std::string check = "<svg   xmlns=\"http://www.w3.org/2000/svg\""
"   xmlns:xlink=\"http://www.w3.org/1999/xlink\""
"        x=\"0px\" y=\"0px\" viewBox=\"0 0 24 24\">"
"            <g transform=\"translate(0, 0)\">"
"                <circle fill=\"#45e283\" stroke-width=\"2\" stroke-linecap=\"square\" stroke-miterlimit=\"10\" cx=\"12\" cy=\"12\" r=\"11\" stroke-linejoin=\"miter\"></circle>"
"                <circle fill=\"white\" stroke-width=\"2\" stroke-linecap=\"square\" stroke-miterlimit=\"10\" cx=\"12\" cy=\"12\" r=\"9\" stroke-linejoin=\"miter\"></circle>"
"                <polyline data-color=\"color-2\" fill=\"#45e283\" stroke-width=\"2\" stroke-linecap=\"square\" stroke-miterlimit=\"10\" points=\" 6,12 10,16 18,8 \" stroke-linejoin=\"miter\"></polyline>"
"                <polyline data-color=\"color-2\" fill=\"white\" stroke-width=\"2\" stroke-linecap=\"square\" stroke-miterlimit=\"10\" points=\" 6,9 10,13 18,5 \" stroke-linejoin=\"miter\"></polyline>"
"            </g>"
"        </svg>";
    std::string pending = "<?xml version=\"1.0\" standalone=\"no\"?>"
"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\""
"  \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">"
" <svg   xmlns=\"http://www.w3.org/2000/svg\""
"   xmlns:xlink=\"http://www.w3.org/1999/xlink\""
"        x=\"0px\" y=\"0px\" viewBox=\"0 0 24 24\">"
"            <g transform=\"translate(0, 0)\">"
"                <circle fill=\"#ffcd9d\" stroke-width=\"2\" stroke-linecap=\"square\" stroke-miterlimit=\"10\" cx=\"12\" cy=\"12\" r=\"11\" stroke-linejoin=\"miter\"></circle>"
"                <circle fill=\"white\" stroke-width=\"2\" stroke-linecap=\"square\" stroke-miterlimit=\"10\" cx=\"12\" cy=\"12\" r=\"9\" stroke-linejoin=\"miter\"></circle>"
"                <polyline data-color=\"color-2\" fill=\"#ffcd9d\" stroke-width=\"2\" stroke-linecap=\"square\" stroke-miterlimit=\"10\" points=\"12,6 12,12 18,12\" stroke-linejoin=\"miter\"></polyline>"
"                <polyline data-color=\"color-2\" fill=\"white\" stroke-width=\"2\" stroke-linecap=\"square\" stroke-miterlimit=\"10\" points=\"14,4 14,10 20,10\" stroke-linejoin=\"miter\"></polyline>"
"            </g>"
"        </svg>";

    QIcon i = QIcon(new SVGIconEngine(check));
    QPixmap p = i.pixmap(i.actualSize(QSize(48,48)));
    //p.setPixmap(new SVGIconEngine(check));
    ui->balanceIcon->setPixmap(p);
    QIcon pend = QIcon(new SVGIconEngine(pending));
    QPixmap p1 = pend.pixmap(pend.actualSize(QSize(48,48)));
    ui->pendingIcon->setPixmap(p1);
    QIcon stakedIcon = QIcon(new SVGIconEngine(pending));
    QPixmap p2 = stakedIcon.pixmap(stakedIcon.actualSize(QSize(48,48)));
    ui->stakedIcon->setPixmap(p2);
    // only show immature (newly mined) balance if it's non-zero, so as not to complicate things
    // for the non-mining users
    bool showImmature = immatureBalance != 0;
}

void OverviewPage::setModel(WalletModel *model)
{
    this->model = model;

    if(model && model->getOptionsModel())
    {
        // Set up transaction list
        filter = new TransactionFilterProxy();
        filter->setSourceModel(model->getTransactionTableModel());
        filter->setLimit(NUM_ITEMS);
        filter->setDynamicSortFilter(true);
        filter->setSortRole(Qt::EditRole);
        filter->setShowInactive(false);
        filter->sort(TransactionTableModel::Status, Qt::DescendingOrder);

        //TRANS ui->listTransactions->setModel(filter);
        //TRANS ui->listTransactions->setModelColumn(TransactionTableModel::ToAddress);

        // Keep up to date with wallet
        setBalance(model->getBalance(), model->getStake(), model->getUnconfirmedBalance(), model->getImmatureBalance());
        connect(model, SIGNAL(balanceChanged(qint64, qint64, qint64, qint64)), this, SLOT(setBalance(qint64, qint64, qint64, qint64)));

        connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
    }
    txv_->setModel(model);
    QVBoxLayout *vbox = new QVBoxLayout();
    vbox->addWidget(txv_);
    ui->txv->setLayout(vbox);
    // update the display unit, to not use the default ("BTC")
    updateDisplayUnit();
}

void OverviewPage::updateDisplayUnit()
{
    if(model && model->getOptionsModel())
    {
        if(currentBalance != -1)
            setBalance(currentBalance, model->getStake(), currentUnconfirmedBalance, currentImmatureBalance);

        // Update txdelegate->unit with the current unit
        txdelegate->unit = model->getOptionsModel()->getDisplayUnit();

        //TRANS ui->listTransactions->update();
    }
}

void OverviewPage::showOutOfSyncWarning(bool fShow)
{
    //ui->labelWalletStatus->setVisible(fShow);
    //ui->labelTransactionsStatus->setVisible(fShow);
}
<commit_msg>handle signal from locked status icon - prod test harness - review<commit_after>#include "overviewpage.h"
#include "ui_overviewpage.h"

#include "walletmodel.h"
#include "bitcoinunits.h"
#include "optionsmodel.h"
#include "transactiontablemodel.h"
#include "transactionfilterproxy.h"
#include "guiutil.h"
#include "guiconstants.h"
#include <iostream>
#include <QAbstractItemDelegate>
#include <QPainter>
#include <QGraphicsDropShadowEffect>
#include "svgiconengine.h"

#define DECORATION_SIZE 64
#define NUM_ITEMS 3

class TxViewDelegate : public QAbstractItemDelegate
{
    Q_OBJECT
public:
    TxViewDelegate(): QAbstractItemDelegate(), unit(IocoinUnits::BTC)
    {

    }

    inline void paint(QPainter *painter, const QStyleOptionViewItem &option,
                      const QModelIndex &index ) const
    {
        painter->save();

        QIcon icon = qvariant_cast<QIcon>(index.data(Qt::DecorationRole));
        QRect mainRect = option.rect;
        QRect decorationRect(mainRect.topLeft(), QSize(DECORATION_SIZE, DECORATION_SIZE));
        int xspace = DECORATION_SIZE + 8;
        int ypad = 6;
        int halfheight = (mainRect.height() - 2*ypad)/2;
        QRect amountRect(mainRect.left() + xspace, mainRect.top()+ypad, mainRect.width() - xspace, halfheight);
        QRect addressRect(mainRect.left() + xspace, mainRect.top()+ypad+halfheight, mainRect.width() - xspace, halfheight);
        icon.paint(painter, decorationRect);

        QDateTime date = index.data(TransactionTableModel::DateRole).toDateTime();
        QString address = index.data(Qt::DisplayRole).toString();
        qint64 amount = index.data(TransactionTableModel::AmountRole).toLongLong();
        bool confirmed = index.data(TransactionTableModel::ConfirmedRole).toBool();
        QVariant value = index.data(Qt::ForegroundRole);
        QColor foreground = option.palette.color(QPalette::Text);
        if(qVariantCanConvert<QColor>(value))
        {
            foreground = qvariant_cast<QColor>(value);
        }

        painter->setPen(foreground);
        painter->drawText(addressRect, Qt::AlignLeft|Qt::AlignVCenter, address);

        if(amount < 0)
        {
            foreground = COLOR_NEGATIVE;
        }
        else if(!confirmed)
        {
            foreground = COLOR_UNCONFIRMED;
        }
        else
        {
            foreground = option.palette.color(QPalette::Text);
        }
        painter->setPen(foreground);
        QString amountText = IocoinUnits::formatWithUnit(unit, amount, true);
        if(!confirmed)
        {
            amountText = QString("[") + amountText + QString("]");
        }
        painter->drawText(amountRect, Qt::AlignRight|Qt::AlignVCenter, amountText);

        painter->setPen(option.palette.color(QPalette::Text));
        painter->drawText(amountRect, Qt::AlignLeft|Qt::AlignVCenter, GUIUtil::dateTimeStr(date));

        painter->restore();
    }

    inline QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
    {
        return QSize(DECORATION_SIZE, DECORATION_SIZE);
    }

    int unit;

};
#include "overviewpage.moc"

OverviewPage::OverviewPage(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::OverviewPage),
    currentBalance(-1),
    currentStake(0),
    currentUnconfirmedBalance(-1),
    currentImmatureBalance(-1),
    txdelegate(new TxViewDelegate()),
    filter(0)
{
    ui->setupUi(this);

    txv_ = new TransactionView(this);
    txv_->setObjectName("txv");

    QGraphicsDropShadowEffect* ef = new QGraphicsDropShadowEffect();
    ef->setBlurRadius(10);
    ef->setXOffset(2);
    ef->setYOffset(2);
    QColor col = QColor("#d3d3d3");
    ef->setColor(col);
    ui->available->setGraphicsEffect(ef);
    QGraphicsDropShadowEffect* ef2 = new QGraphicsDropShadowEffect();
    ef2->setBlurRadius(10);
    ef2->setXOffset(2);
    ef2->setYOffset(2);
    ef2->setColor(col);
    ui->pending->setGraphicsEffect(ef2);
    QGraphicsDropShadowEffect* ef3 = new QGraphicsDropShadowEffect();
    ef3->setBlurRadius(10);
    ef3->setXOffset(2);
    ef3->setYOffset(2);
    ef3->setColor(col);
    ui->staked->setGraphicsEffect(ef3);

    ui->vl->setContentsMargins(0 , 0, 0, 0);
    ui->statusGL->setSpacing(0);
    ui->statusGL->setContentsMargins(10 , 0, 10, 0);
    ui->statusHB->setContentsMargins(0 , 0, 0, 0);
    ui->statusGL->setColumnStretch(0,0);

    ui->labelIntBalance->setMargin(0);
    ui->labelIntBalance->sizePolicy().setHorizontalStretch(1);
    ui->labelIntBalance->setContentsMargins(0,0,0,0);
    ui->labelFracBalance->setMargin(0);

    ui->unconfirmedGL->setSpacing(0);
    ui->unconfirmedGL->setContentsMargins(10 , 0, 10, 0);
    ui->unconfirmedGL->setColumnStretch(0,0);
    ui->labelIntUnconfirmed->setMargin(0);
    ui->labelIntUnconfirmed->sizePolicy().setHorizontalStretch(1);
    ui->labelIntUnconfirmed->setContentsMargins(0,0,0,0);
    ui->labelFracUnconfirmed->setMargin(0);

    ui->stakedGL->setSpacing(0);
    ui->stakedGL->setContentsMargins(10 , 0, 10, 0);
    ui->stakedGL->setColumnStretch(0,0);
    ui->labelIntStaked->setMargin(0);
    ui->labelIntStaked->sizePolicy().setHorizontalStretch(1);
    ui->labelIntStaked->setContentsMargins(0,0,0,0);
    ui->labelFracStaked->setMargin(0);

    //ui->availableAmountLayout->setMargin(0);
    //ui->availableAmountLayout->setSpacing(0);
    //QVBoxLayout *vbox = new QVBoxLayout();
    //QLabel* tmp = new QLabel();
    //tmp->setText("hello");
    //vbox->addWidget(txv_);
    //vbox->addWidget(tmp);
    //ui->txv->setLayout(vbox);

    // start with displaying the "out of sync" warnings
    showOutOfSyncWarning(true);
}

void OverviewPage::handleTransactionClicked(const QModelIndex &index)
{
    if(filter)
        emit transactionClicked(filter->mapToSource(index));
}

OverviewPage::~OverviewPage()
{
    delete ui;
}

void OverviewPage::setBalance(qint64 balance, qint64 stake, qint64 unconfirmedBalance, qint64 immatureBalance)
{
    int unit = model->getOptionsModel()->getDisplayUnit();
    currentBalance = balance;
    currentStake = stake;
    currentUnconfirmedBalance = unconfirmedBalance;
    currentImmatureBalance = immatureBalance;
    ui->labelIntBalance->setText(IocoinUnits::intFormatWithUnit(unit, balance));
    ui->labelFracBalance->setText(IocoinUnits::fracFormatWithUnit(unit, balance));
    ui->labelIntStaked->setText(IocoinUnits::intFormatWithUnit(unit, stake));
    ui->labelFracStaked->setText(IocoinUnits::fracFormatWithUnit(unit, stake));
    ui->labelIntUnconfirmed->setText(IocoinUnits::intFormatWithUnit(unit, unconfirmedBalance));
    ui->labelFracUnconfirmed->setText(IocoinUnits::fracFormatWithUnit(unit, unconfirmedBalance));

    std::string check = "<svg   xmlns=\"http://www.w3.org/2000/svg\""
"   xmlns:xlink=\"http://www.w3.org/1999/xlink\""
"        x=\"0px\" y=\"0px\" viewBox=\"0 0 24 24\">"
"            <g transform=\"translate(0, 0)\">"
"                <circle fill=\"#45e283\" stroke-width=\"2\" stroke-linecap=\"square\" stroke-miterlimit=\"10\" cx=\"12\" cy=\"12\" r=\"11\" stroke-linejoin=\"miter\"></circle>"
"                <circle fill=\"white\" stroke-width=\"2\" stroke-linecap=\"square\" stroke-miterlimit=\"10\" cx=\"12\" cy=\"12\" r=\"9\" stroke-linejoin=\"miter\"></circle>"
"                <polyline data-color=\"color-2\" fill=\"#45e283\" stroke-width=\"2\" stroke-linecap=\"square\" stroke-miterlimit=\"10\" points=\" 6,12 10,16 18,8 \" stroke-linejoin=\"miter\"></polyline>"
"                <polyline data-color=\"color-2\" fill=\"white\" stroke-width=\"2\" stroke-linecap=\"square\" stroke-miterlimit=\"10\" points=\" 6,9 10,13 18,5 \" stroke-linejoin=\"miter\"></polyline>"
"            </g>"
"        </svg>";
    std::string pending = "<?xml version=\"1.0\" standalone=\"no\"?>"
"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\""
"  \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">"
" <svg   xmlns=\"http://www.w3.org/2000/svg\""
"   xmlns:xlink=\"http://www.w3.org/1999/xlink\""
"        x=\"0px\" y=\"0px\" viewBox=\"0 0 24 24\">"
"            <g transform=\"translate(0, 0)\">"
"                <circle fill=\"#ffcd9d\" stroke-width=\"2\" stroke-linecap=\"square\" stroke-miterlimit=\"10\" cx=\"12\" cy=\"12\" r=\"11\" stroke-linejoin=\"miter\"></circle>"
"                <circle fill=\"white\" stroke-width=\"2\" stroke-linecap=\"square\" stroke-miterlimit=\"10\" cx=\"12\" cy=\"12\" r=\"9\" stroke-linejoin=\"miter\"></circle>"
"                <polyline data-color=\"color-2\" fill=\"#ffcd9d\" stroke-width=\"2\" stroke-linecap=\"square\" stroke-miterlimit=\"10\" points=\"12,6 12,12 18,12\" stroke-linejoin=\"miter\"></polyline>"
"                <polyline data-color=\"color-2\" fill=\"white\" stroke-width=\"2\" stroke-linecap=\"square\" stroke-miterlimit=\"10\" points=\"14,4 14,10 20,10\" stroke-linejoin=\"miter\"></polyline>"
"            </g>"
"        </svg>";

    QIcon i = QIcon(new SVGIconEngine(check));
    QPixmap p = i.pixmap(i.actualSize(QSize(48,48)));
    //p.setPixmap(new SVGIconEngine(check));
    ui->balanceIcon->setPixmap(p);
    QIcon pend = QIcon(new SVGIconEngine(pending));
    QPixmap p1 = pend.pixmap(pend.actualSize(QSize(48,48)));
    ui->pendingIcon->setPixmap(p1);
    QIcon stakedIcon = QIcon(new SVGIconEngine(pending));
    QPixmap p2 = stakedIcon.pixmap(stakedIcon.actualSize(QSize(48,48)));
    ui->stakedIcon->setPixmap(p2);
    // only show immature (newly mined) balance if it's non-zero, so as not to complicate things
    // for the non-mining users
    bool showImmature = immatureBalance != 0;
}

void OverviewPage::setModel(WalletModel *model)
{
    this->model = model;

    if(model && model->getOptionsModel())
    {
        // Set up transaction list
        filter = new TransactionFilterProxy();
        filter->setSourceModel(model->getTransactionTableModel());
        filter->setLimit(NUM_ITEMS);
        filter->setDynamicSortFilter(true);
        filter->setSortRole(Qt::EditRole);
        filter->setShowInactive(false);
        filter->sort(TransactionTableModel::Status, Qt::DescendingOrder);

        //TRANS ui->listTransactions->setModel(filter);
        //TRANS ui->listTransactions->setModelColumn(TransactionTableModel::ToAddress);

        // Keep up to date with wallet
        setBalance(model->getBalance(), model->getStake(), model->getUnconfirmedBalance(), model->getImmatureBalance());
        connect(model, SIGNAL(balanceChanged(qint64, qint64, qint64, qint64)), this, SLOT(setBalance(qint64, qint64, qint64, qint64)));

        connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
    }
    txv_->setModel(model);
    QVBoxLayout *vbox = new QVBoxLayout();
    vbox->addWidget(txv_);
    ui->txv->setLayout(vbox);
    // update the display unit, to not use the default ("BTC")
    updateDisplayUnit();
}

void OverviewPage::updateDisplayUnit()
{
    if(model && model->getOptionsModel())
    {
        if(currentBalance != -1)
            setBalance(currentBalance, model->getStake(), currentUnconfirmedBalance, currentImmatureBalance);

        // Update txdelegate->unit with the current unit
        txdelegate->unit = model->getOptionsModel()->getDisplayUnit();

        //TRANS ui->listTransactions->update();
    }
}

void OverviewPage::showOutOfSyncWarning(bool fShow)
{
    //ui->labelWalletStatus->setVisible(fShow);
    //ui->labelTransactionsStatus->setVisible(fShow);
}
<|endoftext|>


<commit_before>#include "overviewpage.h"
#include "ui_overviewpage.h"

#include "walletmodel.h"
#include "bitcoinunits.h"
#include "optionsmodel.h"
#include "transactiontablemodel.h"
#include "transactionfilterproxy.h"
#include "guiutil.h"
#include "guiconstants.h"

#include <QAbstractItemDelegate>
#include <QPainter>

#define DECORATION_SIZE 64
#define NUM_ITEMS 3

class TxViewDelegate : public QAbstractItemDelegate
{
    Q_OBJECT
public:
    TxViewDelegate(): QAbstractItemDelegate(), unit(BitcoinUnits::BTC)
    {

    }

    inline void paint(QPainter *painter, const QStyleOptionViewItem &option,
                      const QModelIndex &index ) const
    {
        painter->save();

        QIcon icon = qvariant_cast<QIcon>(index.data(Qt::DecorationRole));
        QRect mainRect = option.rect;
        QRect decorationRect(mainRect.topLeft(), QSize(DECORATION_SIZE, DECORATION_SIZE));
        int xspace = DECORATION_SIZE + 8;
        int ypad = 6;
        int halfheight = (mainRect.height() - 2*ypad)/2;
        QRect amountRect(mainRect.left() + xspace, mainRect.top()+ypad, mainRect.width() - xspace, halfheight);
        QRect addressRect(mainRect.left() + xspace, mainRect.top()+ypad+halfheight, mainRect.width() - xspace, halfheight);
        icon.paint(painter, decorationRect);

        QDateTime date = index.data(TransactionTableModel::DateRole).toDateTime();
        QString address = index.data(Qt::DisplayRole).toString();
        qint64 amount = index.data(TransactionTableModel::AmountRole).toLongLong();
        bool confirmed = index.data(TransactionTableModel::ConfirmedRole).toBool();
        QVariant value = index.data(Qt::ForegroundRole);
        QColor foreground = option.palette.color(QPalette::Text);
        if(value.canConvert(QMetaType::QColor))
        {
            foreground = qvariant_cast<QColor>(value);
        }

        painter->setPen(foreground);
        painter->drawText(addressRect, Qt::AlignLeft|Qt::AlignVCenter, address);

        if(amount < 0)
        {
            foreground = COLOR_NEGATIVE;
        }
        else if(!confirmed)
        {
            foreground = COLOR_UNCONFIRMED;
        }
        else
        {
            foreground = option.palette.color(QPalette::Text);
        }
        painter->setPen(foreground);
        QString amountText = BitcoinUnits::formatWithUnit(unit, amount, true);
        if(!confirmed)
        {
            amountText = QString("[") + amountText + QString("]");
        }
        painter->drawText(amountRect, Qt::AlignRight|Qt::AlignVCenter, amountText);

        painter->setPen(option.palette.color(QPalette::Text));
        painter->drawText(amountRect, Qt::AlignLeft|Qt::AlignVCenter, GUIUtil::dateTimeStr(date));

        painter->restore();
    }

    inline QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
    {
        return QSize(DECORATION_SIZE, DECORATION_SIZE);
    }

    int unit;

};
#include "overviewpage.moc"

OverviewPage::OverviewPage(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::OverviewPage),
    currentBalance(-1),
    currentUnconfirmedBalance(-1),
    currentImmatureBalance(-1),
    txdelegate(new TxViewDelegate()),
    filter(0)
{
    ui->setupUi(this);

    // Recent transactions
    ui->listTransactions->setItemDelegate(txdelegate);
    ui->listTransactions->setIconSize(QSize(DECORATION_SIZE, DECORATION_SIZE));
    ui->listTransactions->setMinimumHeight(NUM_ITEMS * (DECORATION_SIZE + 2));
    ui->listTransactions->setAttribute(Qt::WA_MacShowFocusRect, false);

    connect(ui->listTransactions, SIGNAL(clicked(QModelIndex)), this, SLOT(handleTransactionClicked(QModelIndex)));

    // init "out of sync" warning labels
    ui->labelWalletStatus->setText("(" + tr("Out of sync") + ")");
    ui->labelTransactionsStatus->setText("(" + tr("Out of sync") + ")");

    // start with displaying the "out of sync" warnings
    showOutOfSyncWarning(true);
}

void OverviewPage::handleTransactionClicked(const QModelIndex &index)
{
    if(filter)
        emit transactionClicked(filter->mapToSource(index));
}

OverviewPage::~OverviewPage()
{
    delete ui;
}

void OverviewPage::setBalance(qint64 balance, qint64 unconfirmedBalance, qint64 immatureBalance)
{
    int unit = model->getOptionsModel()->getDisplayUnit();
    currentBalance = balance;
    currentUnconfirmedBalance = unconfirmedBalance;
    currentImmatureBalance = immatureBalance;
    ui->labelBalance->setText(BitcoinUnits::formatWithUnit(unit, balance));
    ui->labelUnconfirmed->setText(BitcoinUnits::formatWithUnit(unit, unconfirmedBalance));
    ui->labelImmature->setText(BitcoinUnits::formatWithUnit(unit, immatureBalance));

    // only show immature (newly mined) balance if it's non-zero, so as not to complicate things
    // for the non-mining users
    bool showImmature = immatureBalance != 0;
    ui->labelImmature->setVisible(showImmature);
    ui->labelImmatureText->setVisible(showImmature);
}

void OverviewPage::setNumTransactions(int count)
{
    ui->labelNumTransactions->setText(QLocale::system().toString(count));
}

void OverviewPage::setModel(WalletModel *model)
{
    this->model = model;
    if(model && model->getOptionsModel())
    {
        // Set up transaction list
        filter = new TransactionFilterProxy();
        filter->setSourceModel(model->getTransactionTableModel());
        filter->setLimit(NUM_ITEMS);
        filter->setDynamicSortFilter(true);
        filter->setSortRole(Qt::EditRole);
        filter->sort(TransactionTableModel::Status, Qt::DescendingOrder);

        ui->listTransactions->setModel(filter);
        ui->listTransactions->setModelColumn(TransactionTableModel::ToAddress);

        // Keep up to date with wallet
        setBalance(model->getBalance(), model->getUnconfirmedBalance(), model->getImmatureBalance());
        connect(model, SIGNAL(balanceChanged(qint64, qint64, qint64)), this, SLOT(setBalance(qint64, qint64, qint64)));

        setNumTransactions(model->getNumTransactions());
        connect(model, SIGNAL(numTransactionsChanged(int)), this, SLOT(setNumTransactions(int)));

        connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
    }

    // update the display unit, to not use the default ("ZLB")
    updateDisplayUnit();
}

void OverviewPage::updateDisplayUnit()
{
    if(model && model->getOptionsModel())
    {
        if(currentBalance != -1)
            setBalance(currentBalance, currentUnconfirmedBalance, currentImmatureBalance);

        // Update txdelegate->unit with the current unit
        txdelegate->unit = model->getOptionsModel()->getDisplayUnit();

        ui->listTransactions->update();
    }
}

void OverviewPage::showOutOfSyncWarning(bool fShow)
{
    ui->labelWalletStatus->setVisible(fShow);
    ui->labelTransactionsStatus->setVisible(fShow);
}

<commit_msg>Update overviewpage.cpp<commit_after>#include "overviewpage.h"
#include "ui_overviewpage.h"
#include "walletmodel.h"
#include "bitcoinunits.h"
#include "optionsmodel.h"
#include "transactiontablemodel.h"
#include "transactionfilterproxy.h"
#include "guiutil.h"
#include "guiconstants.h"
#include <QAbstractItemDelegate>
#include <QPainter>
#define DECORATION_SIZE 64
#define NUM_ITEMS 3
class TxViewDelegate : public QAbstractItemDelegate
{
Q_OBJECT
public:
TxViewDelegate(): QAbstractItemDelegate(), unit(BitcoinUnits::BTC)
{
}
inline void paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index ) const
{
painter->save();
QIcon icon = qvariant_cast<QIcon>(index.data(Qt::DecorationRole));
QRect mainRect = option.rect;
QRect decorationRect(mainRect.topLeft(), QSize(DECORATION_SIZE, DECORATION_SIZE));
int xspace = DECORATION_SIZE + 8;
int ypad = 6;
int halfheight = (mainRect.height() - 2*ypad)/2;
QRect amountRect(mainRect.left() + xspace, mainRect.top()+ypad, mainRect.width() - xspace, halfheight);
QRect addressRect(mainRect.left() + xspace, mainRect.top()+ypad+halfheight, mainRect.width() - xspace, halfheight);
icon.paint(painter, decorationRect);
QDateTime date = index.data(TransactionTableModel::DateRole).toDateTime();
QString address = index.data(Qt::DisplayRole).toString();
qint64 amount = index.data(TransactionTableModel::AmountRole).toLongLong();
bool confirmed = index.data(TransactionTableModel::ConfirmedRole).toBool();
QVariant value = index.data(Qt::ForegroundRole);
QColor foreground = option.palette.color(QPalette::Text);
if(qVariantCanConvert<QColor>(value))
{
foreground = qvariant_cast<QColor>(value);
}
painter->setPen(foreground);
painter->drawText(addressRect, Qt::AlignLeft|Qt::AlignVCenter, address);
if(amount < 0)
{
foreground = COLOR_NEGATIVE;
}
else if(!confirmed)
{
foreground = COLOR_UNCONFIRMED;
}
else
{
foreground = option.palette.color(QPalette::Text);
}
painter->setPen(foreground);
QString amountText = BitcoinUnits::formatWithUnit(unit, amount, true);
if(!confirmed)
{
amountText = QString("[") + amountText + QString("]");
}
painter->drawText(amountRect, Qt::AlignRight|Qt::AlignVCenter, amountText);
painter->setPen(option.palette.color(QPalette::Text));
painter->drawText(amountRect, Qt::AlignLeft|Qt::AlignVCenter, GUIUtil::dateTimeStr(date));
painter->restore();
}
inline QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
return QSize(DECORATION_SIZE, DECORATION_SIZE);
}
int unit;
};
#include "overviewpage.moc"
OverviewPage::OverviewPage(QWidget *parent) :
QWidget(parent),
ui(new Ui::OverviewPage),
currentBalance(-1),
currentUnconfirmedBalance(-1),
currentImmatureBalance(-1),
txdelegate(new TxViewDelegate()),
filter(0)
{
ui->setupUi(this);
// Recent transactions
ui->listTransactions->setItemDelegate(txdelegate);
ui->listTransactions->setIconSize(QSize(DECORATION_SIZE, DECORATION_SIZE));
ui->listTransactions->setMinimumHeight(NUM_ITEMS * (DECORATION_SIZE + 2));
ui->listTransactions->setAttribute(Qt::WA_MacShowFocusRect, false);
connect(ui->listTransactions, SIGNAL(clicked(QModelIndex)), this, SLOT(handleTransactionClicked(QModelIndex)));
// init "out of sync" warning labels
ui->labelWalletStatus->setText("(" + tr("Out of sync") + ")");
ui->labelTransactionsStatus->setText("(" + tr("Out of sync") + ")");
// start with displaying the "out of sync" warnings
showOutOfSyncWarning(true);
}
void OverviewPage::handleTransactionClicked(const QModelIndex &index)
{
if(filter)
emit transactionClicked(filter->mapToSource(index));
}
OverviewPage::~OverviewPage()
{
delete ui;
}
void OverviewPage::setBalance(qint64 balance, qint64 unconfirmedBalance, qint64 immatureBalance)
{
int unit = model->getOptionsModel()->getDisplayUnit();
currentBalance = balance;
currentUnconfirmedBalance = unconfirmedBalance;
currentImmatureBalance = immatureBalance;
ui->labelBalance->setText(BitcoinUnits::formatWithUnit(unit, balance));
ui->labelUnconfirmed->setText(BitcoinUnits::formatWithUnit(unit, unconfirmedBalance));
ui->labelImmature->setText(BitcoinUnits::formatWithUnit(unit, immatureBalance));
// only show immature (newly mined) balance if it's non-zero, so as not to complicate things
// for the non-mining users
bool showImmature = immatureBalance != 0;
ui->labelImmature->setVisible(showImmature);
ui->labelImmatureText->setVisible(showImmature);
}
void OverviewPage::setNumTransactions(int count)
{
ui->labelNumTransactions->setText(QLocale::system().toString(count));
}
void OverviewPage::setModel(WalletModel *model)
{
this->model = model;
if(model && model->getOptionsModel())
{
// Set up transaction list
filter = new TransactionFilterProxy();
filter->setSourceModel(model->getTransactionTableModel());
filter->setLimit(NUM_ITEMS);
filter->setDynamicSortFilter(true);
filter->setSortRole(Qt::EditRole);
filter->sort(TransactionTableModel::Status, Qt::DescendingOrder);
ui->listTransactions->setModel(filter);
ui->listTransactions->setModelColumn(TransactionTableModel::ToAddress);
// Keep up to date with wallet
setBalance(model->getBalance(), model->getUnconfirmedBalance(), model->getImmatureBalance());
connect(model, SIGNAL(balanceChanged(qint64, qint64, qint64)), this, SLOT(setBalance(qint64, qint64, qint64)));
setNumTransactions(model->getNumTransactions());
connect(model, SIGNAL(numTransactionsChanged(int)), this, SLOT(setNumTransactions(int)));
connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
}
// update the display unit, to not use the default ("GEO")
updateDisplayUnit();
}
void OverviewPage::updateDisplayUnit()
{
if(model && model->getOptionsModel())
{
if(currentBalance != -1)
setBalance(currentBalance, currentUnconfirmedBalance, currentImmatureBalance);
// Update txdelegate->unit with the current unit
txdelegate->unit = model->getOptionsModel()->getDisplayUnit();
ui->listTransactions->update();
}
}
void OverviewPage::showOutOfSyncWarning(bool fShow)
{
ui->labelWalletStatus->setVisible(fShow);
ui->labelTransactionsStatus->setVisible(fShow);
}
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2011 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifdef HAVE_LIBXML2
#error HAVE_LIBXML2 defined but compiling rapidxml_loader.cpp!
#endif

// mapnik
#include <mapnik/config_error.hpp>
#include <mapnik/utils.hpp>
#include <mapnik/util/fs.hpp>
#include <mapnik/xml_loader.hpp>
#include <boost/property_tree/detail/xml_parser_read_rapidxml.hpp>
#include <mapnik/xml_node.hpp>
#include <mapnik/util/trim.hpp>
#include <mapnik/noncopyable.hpp>

// stl
#include <iostream>
#include <fstream>

namespace rapidxml = boost::property_tree::detail::rapidxml;

namespace mapnik
{
class rapidxml_loader : mapnik::noncopyable
{
public:
    rapidxml_loader() :
        filename_() {}

    ~rapidxml_loader() {}

    void load(std::string const& filename, xml_node & node)
    {
        if (!mapnik::util::exists(filename))
        {
            throw config_error(std::string("Could not load map file: File does not exist"), 0, filename);
        }
        filename_ = filename;
#ifdef _WINDOWS
        std::basic_ifstream<char> stream(mapnik::utf8_to_utf16(filename));
#else
        std::basic_ifstream<char> stream(filename.c_str());
#endif
        if (!stream)
        {
            throw config_error("Could not load map file", 0, filename);
        }
        stream.unsetf(std::ios::skipws);
        std::vector<char> v(std::istreambuf_iterator<char>(stream.rdbuf()),
                            std::istreambuf_iterator<char>());
        if (!stream.good())
        {
            throw config_error("Could not load map file", 0, filename_);
        }
        v.push_back(0); // zero-terminate
        load_array(v, node);
    }

    template <typename T>
    void load_array(T && array, xml_node & node)
    {
        try
        {
            // Parse using appropriate flags
            // https://github.com/mapnik/mapnik/issues/1856
            // const int f_tws = rapidxml::parse_normalize_whitespace;
            const int f_tws = rapidxml::parse_trim_whitespace | rapidxml::parse_validate_closing_tags;
            rapidxml::xml_document<> doc;
            doc.parse<f_tws>(&array.front());

            for (rapidxml::xml_node<char> *child = doc.first_node();
                 child; child = child->next_sibling())
            {
                populate_tree(child, node);
            }
        }
        catch (rapidxml::parse_error const& e)
        {
            long line = static_cast<long>(
                std::count(&array.front(), e.where<char>(), '\n') + 1);
            throw config_error(e.what(), line, filename_);
        }
    }

    void load_string(std::string const& buffer, xml_node & node, std::string const & )
    {
        // Note: base_path ignored because its not relevant - only needed for xml2 to load entities (see libxml2_loader.cpp)
        load_array(std::string(buffer), node);
    }
private:
    void populate_tree(rapidxml::xml_node<char> *cur_node, xml_node & node)
    {
        switch (cur_node->type())
        {
        case rapidxml::node_element:
        {
            xml_node & new_node = node.add_child(cur_node->name(), 0, false);
            // Copy attributes
            for (rapidxml::xml_attribute<char> *attr = cur_node->first_attribute();
                 attr; attr = attr->next_attribute())
            {
                new_node.add_attribute(attr->name(), attr->value());
            }

            // Copy children
            for (rapidxml::xml_node<char> *child = cur_node->first_node();
                 child; child = child->next_sibling())
            {
                populate_tree(child, new_node);
            }
        }
        break;

        // Data nodes
        case rapidxml::node_data:
        case rapidxml::node_cdata:
        {
            if (cur_node->value_size() > 0) // Don't add empty text nodes
            {
                node.add_child(cur_node->value(), 0, true);
            }
        }
        break;
        default:
            break;
        }
    }
private:
    std::string filename_;
};

void read_xml(std::string const& filename, xml_node & node)
{
    rapidxml_loader loader;
    loader.load(filename, node);
}
void read_xml_string(std::string const& str, xml_node & node, std::string const& base_path)
{
    rapidxml_loader loader;
    loader.load_string(str, node, base_path);
}

} // end of namespace mapnik
<commit_msg>fix compilation with libxml2<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2011 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef HAVE_LIBXML2

// mapnik
#include <mapnik/config_error.hpp>
#include <mapnik/utils.hpp>
#include <mapnik/util/fs.hpp>
#include <mapnik/xml_loader.hpp>
#include <boost/property_tree/detail/xml_parser_read_rapidxml.hpp>
#include <mapnik/xml_node.hpp>
#include <mapnik/util/trim.hpp>
#include <mapnik/noncopyable.hpp>

// stl
#include <iostream>
#include <fstream>

namespace rapidxml = boost::property_tree::detail::rapidxml;

namespace mapnik
{
class rapidxml_loader : mapnik::noncopyable
{
public:
    rapidxml_loader() :
        filename_() {}

    ~rapidxml_loader() {}

    void load(std::string const& filename, xml_node & node)
    {
        if (!mapnik::util::exists(filename))
        {
            throw config_error(std::string("Could not load map file: File does not exist"), 0, filename);
        }
        filename_ = filename;
#ifdef _WINDOWS
        std::basic_ifstream<char> stream(mapnik::utf8_to_utf16(filename));
#else
        std::basic_ifstream<char> stream(filename.c_str());
#endif
        if (!stream)
        {
            throw config_error("Could not load map file", 0, filename);
        }
        stream.unsetf(std::ios::skipws);
        std::vector<char> v(std::istreambuf_iterator<char>(stream.rdbuf()),
                            std::istreambuf_iterator<char>());
        if (!stream.good())
        {
            throw config_error("Could not load map file", 0, filename_);
        }
        v.push_back(0); // zero-terminate
        load_array(v, node);
    }

    template <typename T>
    void load_array(T && array, xml_node & node)
    {
        try
        {
            // Parse using appropriate flags
            // https://github.com/mapnik/mapnik/issues/1856
            // const int f_tws = rapidxml::parse_normalize_whitespace;
            const int f_tws = rapidxml::parse_trim_whitespace | rapidxml::parse_validate_closing_tags;
            rapidxml::xml_document<> doc;
            doc.parse<f_tws>(&array.front());

            for (rapidxml::xml_node<char> *child = doc.first_node();
                 child; child = child->next_sibling())
            {
                populate_tree(child, node);
            }
        }
        catch (rapidxml::parse_error const& e)
        {
            long line = static_cast<long>(
                std::count(&array.front(), e.where<char>(), '\n') + 1);
            throw config_error(e.what(), line, filename_);
        }
    }

    void load_string(std::string const& buffer, xml_node & node, std::string const & )
    {
        // Note: base_path ignored because its not relevant - only needed for xml2 to load entities (see libxml2_loader.cpp)
        load_array(std::string(buffer), node);
    }
private:
    void populate_tree(rapidxml::xml_node<char> *cur_node, xml_node & node)
    {
        switch (cur_node->type())
        {
        case rapidxml::node_element:
        {
            xml_node & new_node = node.add_child(cur_node->name(), 0, false);
            // Copy attributes
            for (rapidxml::xml_attribute<char> *attr = cur_node->first_attribute();
                 attr; attr = attr->next_attribute())
            {
                new_node.add_attribute(attr->name(), attr->value());
            }

            // Copy children
            for (rapidxml::xml_node<char> *child = cur_node->first_node();
                 child; child = child->next_sibling())
            {
                populate_tree(child, new_node);
            }
        }
        break;

        // Data nodes
        case rapidxml::node_data:
        case rapidxml::node_cdata:
        {
            if (cur_node->value_size() > 0) // Don't add empty text nodes
            {
                node.add_child(cur_node->value(), 0, true);
            }
        }
        break;
        default:
            break;
        }
    }
private:
    std::string filename_;
};

void read_xml(std::string const& filename, xml_node & node)
{
    rapidxml_loader loader;
    loader.load(filename, node);
}
void read_xml_string(std::string const& str, xml_node & node, std::string const& base_path)
{
    rapidxml_loader loader;
    loader.load_string(str, node, base_path);
}

} // end of namespace mapnik

#endif
<|endoftext|>


<commit_before>/*
 * File:   nodeannostorage.cpp
 * Author: thomas
 *
 * Created on 14. Januar 2016, 13:53
 */

#include <annis/nodeannostorage.h>

#include <annis/stringstorage.h>

#include <re2/re2.h>

#include <cmath>
#include <fstream>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/serialization/set.hpp>
#include <random>

#include "annis/annosearch/annotationsearch.h"

using namespace annis;

NodeAnnoStorage::NodeAnnoStorage(StringStorage& strings)
: strings(strings)
{
}

bool NodeAnnoStorage::load(std::string dirPath)
{
  std::ifstream in;
  in.open(dirPath + "/nodeAnnotations.btree");
  nodeAnnotations.restore(in);
  in.close();

  in.open(dirPath + "/inverseNodeAnnotations.btree");
  inverseNodeAnnotations.restore(in);
  in.close();

  in.open(dirPath + "/nodeAnnoKeys.archive");
  boost::archive::binary_iarchive iaNodeAnnoKeys(in);
  iaNodeAnnoKeys >> nodeAnnoKeys;
  in.close();
}

bool NodeAnnoStorage::save(std::string dirPath)
{
  std::ofstream out;

  out.open(dirPath + "/nodeAnnotations.btree");
  nodeAnnotations.dump(out);
  out.close();

  out.open(dirPath + "/inverseNodeAnnotations.btree");
  inverseNodeAnnotations.dump(out);
  out.close();

  out.open(dirPath + "/nodeAnnoKeys.archive");
  boost::archive::binary_oarchive oaNodeAnnoKeys(out);
  oaNodeAnnoKeys << nodeAnnoKeys;
  out.close();
}

void NodeAnnoStorage::clear()
{
  nodeAnnotations.clear();
  inverseNodeAnnotations.clear();

  histogramBounds.clear();
  nodeAnnotationKeyCount.clear();
}

bool NodeAnnoStorage::hasStatistics() const
{
  return !histogramBounds.empty() && !nodeAnnotationKeyCount.empty();
}

void NodeAnnoStorage::calculateStatistics()
{

  const int maxHistogramBuckets = 250;
  const int maxSampledAnnotations = 2500;

  histogramBounds.clear();
  nodeAnnotationKeyCount.clear();

  // collect statistics for each annotation key separatly
  std::map<AnnotationKey, std::vector<std::string>> globalValueList;
  for(const auto& annoKey : nodeAnnoKeys)
  {
    histogramBounds[annoKey] = std::vector<std::string>();
    auto& valueList = globalValueList[annoKey] = std::vector<std::string>();

    // get all annotations
    Annotation minAnno = {annoKey.name, annoKey.ns, 0};
    Annotation maxAnno = {annoKey.name, annoKey.ns, std::numeric_limits<std::uint32_t>::max()};
    auto itUpperBound = inverseNodeAnnotations.upper_bound(maxAnno);
    std::vector<Annotation> annos;
    for(auto it=inverseNodeAnnotations.lower_bound(minAnno); it != itUpperBound; it++)
    {
      annos.push_back(it.key());
      nodeAnnotationKeyCount.insert(annoKey);
    }
    std::random_shuffle(annos.begin(), annos.end());
    valueList.resize(std::min<int>(maxSampledAnnotations, annos.size()));
    for(int i=0; i < valueList.size(); i++)
    {
      valueList[i] = strings.str(annos[i].val);
    }

  }

  // create uniformly distributed histogram bounds for each node annotation key
  for(auto it=globalValueList.begin(); it != globalValueList.end(); it++)
  {
    auto& values = it->second;

    std::sort(values.begin(), values.end());

    int numValues = values.size();

    int numHistBounds = maxHistogramBuckets + 1;
    if(numValues < numHistBounds)
    {
      numHistBounds = numValues;
    }

    if(numHistBounds >= 2)
    {
      auto& h = histogramBounds[it->first];
      h.resize(numHistBounds);

      int delta = (numValues-1) / (numHistBounds -1);
      int deltaFraction = (numValues -1) % (numHistBounds - 1);

      int pos = 0;
      int posFraction = 0;
      for(int i=0; i < numHistBounds; i++)
      {
        h[i] = values[pos];
        pos += delta;
        posFraction += deltaFraction;

        if(posFraction >= (numHistBounds - 1))
        {
          pos++;
          posFraction -= (numHistBounds - 1);
        }
      }
    }
  }
}

std::int64_t NodeAnnoStorage::guessMaxCount(const std::string& ns, const std::string& name, const std::string& val) const
{
  auto nameID = strings.findID(name);
  if(nameID.first)
  {
    auto nsID = strings.findID(ns);
    if(nsID.first)
    {
      return guessMaxCount(boost::optional<std::uint32_t>(nsID.second), nameID.second,
        val, val);
    }
  }

  // if none of the conditions above is valid the annotation key does not exist
  return 0;
}

std::int64_t NodeAnnoStorage::guessMaxCount(const std::string& name, const std::string& val) const
{
  auto nameID = strings.findID(name);
  if(nameID.first)
  {
    return guessMaxCount(boost::optional<std::uint32_t>(), nameID.second, val, val);
  }
  return 0;
}

std::int64_t NodeAnnoStorage::guessMaxCountRegex(const std::string& ns, const std::string& name, const std::string& val) const
{
  auto nameID = strings.findID(name);
  if(nameID.first)
  {
    auto nsID = strings.findID(ns);
    if(nsID.first)
    {
      re2::RE2 pattern(val);
      if(pattern.ok())
      {
        std::string minMatch;
        std::string maxMatch;
        pattern.PossibleMatchRange(&minMatch, &maxMatch, 10);
        return guessMaxCount(boost::optional<std::uint32_t>(nsID.second), nameID.second, minMatch, maxMatch);
      }
    }
  }

  return 0;
}

std::int64_t NodeAnnoStorage::guessMaxCountRegex(const std::string& name, const std::string& val) const
{
  auto nameID = strings.findID(name);
  if(nameID.first)
  {
    re2::RE2 pattern(val);
    if(pattern.ok())
    {
      std::string minMatch;
      std::string maxMatch;
      pattern.PossibleMatchRange(&minMatch, &maxMatch, 10);
      return guessMaxCount(boost::optional<std::uint32_t>(), nameID.second, minMatch, maxMatch);
    }
  }
  return 0;
}

std::int64_t NodeAnnoStorage::guessMaxCount(boost::optional<std::uint32_t> nsID,
  std::uint32_t nameID,
  const std::string& lowerVal, const std::string& upperVal) const
{
  std::list<AnnotationKey> keys;
  if(nsID)
  {
    keys.push_back({nameID, *nsID});
  }
  else
  {
    // find all complete keys which have the given name
    auto itKeyUpper = nodeAnnoKeys.upper_bound({nameID, std::numeric_limits<std::uint32_t>::max()});
    for(auto itKeys = nodeAnnoKeys.lower_bound({nameID, 0}); itKeys != itKeyUpper; itKeys++)
    {
      keys.push_back(*itKeys);
    }
  }

  std::int64_t universeSize = 0;
  std::int64_t sumHistogramBuckets = 0;
  std::int64_t countMatches = 0;
  // guess for each annotation fully qualified key and return the sum of all guesses
  for(const auto& key : keys)
  {
    universeSize += nodeAnnotationKeyCount.count(key);
    auto itHisto = histogramBounds.find(key);
    if(itHisto != histogramBounds.end())
    {
      // find the range in which the value is contained
      const auto& histo = itHisto->second;

      // we need to make sure the histogram is not empty -> should have at least two bounds
      if(histo.size() >= 2)
      {
        sumHistogramBuckets += (histo.size() - 1);

        for(size_t i = 0; i < (histo.size()-1); i++)
        {
          const auto& bucketBegin = histo[i];
          const auto& bucketEnd = histo[i+1];
          // check if the range overlaps with the search range
          if(bucketBegin <= upperVal && lowerVal <= bucketEnd)
          {
            countMatches++;
          }
        }
      }
    }
  }

  if(sumHistogramBuckets > 0)
  {
    double selectivity = ((double) countMatches) / ((double) sumHistogramBuckets);
    return std::round(selectivity * ((double) universeSize));
  }
  else
  {
    return 0;
  }

}

NodeAnnoStorage::~NodeAnnoStorage()
{
}

<commit_msg>serialize node annotation statistics<commit_after>/*
 * File:   nodeannostorage.cpp
 * Author: thomas
 *
 * Created on 14. Januar 2016, 13:53
 */

#include <annis/nodeannostorage.h>

#include <annis/stringstorage.h>

#include <re2/re2.h>

#include <cmath>
#include <fstream>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/serialization/set.hpp>
#include <boost/serialization/map.hpp>
#include <boost/serialization/vector.hpp>
#include <random>

#include "annis/annosearch/annotationsearch.h"

using namespace annis;

NodeAnnoStorage::NodeAnnoStorage(StringStorage& strings)
: strings(strings)
{
}

bool NodeAnnoStorage::load(std::string dirPath)
{
  std::ifstream in;
  in.open(dirPath + "/nodeAnnotations.btree");
  nodeAnnotations.restore(in);
  in.close();

  in.open(dirPath + "/inverseNodeAnnotations.btree");
  inverseNodeAnnotations.restore(in);
  in.close();

  in.open(dirPath + "/nodeAnnoKeys.archive");
  boost::archive::binary_iarchive iaNodeAnnoKeys(in);
  iaNodeAnnoKeys >> nodeAnnoKeys;
  in.close();

  in.open(dirPath + "/histogramBounds.archive");
  if(in.is_open())
  {
    boost::archive::binary_iarchive iaHistogramBounds(in);
    iaHistogramBounds >> histogramBounds;
    in.close();
  }

  in.open(dirPath + "/nodeAnnotationKeyCount.archive");
  if(in.is_open())
  {
    boost::archive::binary_iarchive iaNodeAnnotationKeyCount(in);
    iaNodeAnnotationKeyCount >> nodeAnnotationKeyCount;
    in.close();
  }
}

bool NodeAnnoStorage::save(std::string dirPath)
{
  std::ofstream out;

  out.open(dirPath + "/nodeAnnotations.btree");
  nodeAnnotations.dump(out);
  out.close();

  out.open(dirPath + "/inverseNodeAnnotations.btree");
  inverseNodeAnnotations.dump(out);
  out.close();

  out.open(dirPath + "/nodeAnnoKeys.archive");
  boost::archive::binary_oarchive oaNodeAnnoKeys(out);
  oaNodeAnnoKeys << nodeAnnoKeys;
  out.close();

  out.open(dirPath + "/histogramBounds.archive");
  boost::archive::binary_oarchive oaHistogramBounds(out);
  oaHistogramBounds << histogramBounds;
  out.close();

  out.open(dirPath + "/nodeAnnotationKeyCount.archive");
  boost::archive::binary_oarchive oaNodeAnnotationKeyCount(out);
  oaNodeAnnotationKeyCount << nodeAnnotationKeyCount;
  out.close();
}

void NodeAnnoStorage::clear()
{
  nodeAnnotations.clear();
  inverseNodeAnnotations.clear();

  histogramBounds.clear();
  nodeAnnotationKeyCount.clear();
}

bool NodeAnnoStorage::hasStatistics() const
{
  return !histogramBounds.empty() && !nodeAnnotationKeyCount.empty();
}

void NodeAnnoStorage::calculateStatistics()
{

  const int maxHistogramBuckets = 250;
  const int maxSampledAnnotations = 2500;

  histogramBounds.clear();
  nodeAnnotationKeyCount.clear();

  // collect statistics for each annotation key separatly
  std::map<AnnotationKey, std::vector<std::string>> globalValueList;
  for(const auto& annoKey : nodeAnnoKeys)
  {
    histogramBounds[annoKey] = std::vector<std::string>();
    auto& valueList = globalValueList[annoKey] = std::vector<std::string>();

    // get all annotations
    Annotation minAnno = {annoKey.name, annoKey.ns, 0};
    Annotation maxAnno = {annoKey.name, annoKey.ns, std::numeric_limits<std::uint32_t>::max()};
    auto itUpperBound = inverseNodeAnnotations.upper_bound(maxAnno);
    std::vector<Annotation> annos;
    for(auto it=inverseNodeAnnotations.lower_bound(minAnno); it != itUpperBound; it++)
    {
      annos.push_back(it.key());
      nodeAnnotationKeyCount.insert(annoKey);
    }
    std::random_shuffle(annos.begin(), annos.end());
    valueList.resize(std::min<int>(maxSampledAnnotations, annos.size()));
    for(int i=0; i < valueList.size(); i++)
    {
      valueList[i] = strings.str(annos[i].val);
    }

  }

  // create uniformly distributed histogram bounds for each node annotation key
  for(auto it=globalValueList.begin(); it != globalValueList.end(); it++)
  {
    auto& values = it->second;

    std::sort(values.begin(), values.end());

    int numValues = values.size();

    int numHistBounds = maxHistogramBuckets + 1;
    if(numValues < numHistBounds)
    {
      numHistBounds = numValues;
    }

    if(numHistBounds >= 2)
    {
      auto& h = histogramBounds[it->first];
      h.resize(numHistBounds);

      int delta = (numValues-1) / (numHistBounds -1);
      int deltaFraction = (numValues -1) % (numHistBounds - 1);

      int pos = 0;
      int posFraction = 0;
      for(int i=0; i < numHistBounds; i++)
      {
        h[i] = values[pos];
        pos += delta;
        posFraction += deltaFraction;

        if(posFraction >= (numHistBounds - 1))
        {
          pos++;
          posFraction -= (numHistBounds - 1);
        }
      }
    }
  }
}

std::int64_t NodeAnnoStorage::guessMaxCount(const std::string& ns, const std::string& name, const std::string& val) const
{
  auto nameID = strings.findID(name);
  if(nameID.first)
  {
    auto nsID = strings.findID(ns);
    if(nsID.first)
    {
      return guessMaxCount(boost::optional<std::uint32_t>(nsID.second), nameID.second,
        val, val);
    }
  }

  // if none of the conditions above is valid the annotation key does not exist
  return 0;
}

std::int64_t NodeAnnoStorage::guessMaxCount(const std::string& name, const std::string& val) const
{
  auto nameID = strings.findID(name);
  if(nameID.first)
  {
    return guessMaxCount(boost::optional<std::uint32_t>(), nameID.second, val, val);
  }
  return 0;
}

std::int64_t NodeAnnoStorage::guessMaxCountRegex(const std::string& ns, const std::string& name, const std::string& val) const
{
  auto nameID = strings.findID(name);
  if(nameID.first)
  {
    auto nsID = strings.findID(ns);
    if(nsID.first)
    {
      re2::RE2 pattern(val);
      if(pattern.ok())
      {
        std::string minMatch;
        std::string maxMatch;
        pattern.PossibleMatchRange(&minMatch, &maxMatch, 10);
        return guessMaxCount(boost::optional<std::uint32_t>(nsID.second), nameID.second, minMatch, maxMatch);
      }
    }
  }

  return 0;
}

std::int64_t NodeAnnoStorage::guessMaxCountRegex(const std::string& name, const std::string& val) const
{
  auto nameID = strings.findID(name);
  if(nameID.first)
  {
    re2::RE2 pattern(val);
    if(pattern.ok())
    {
      std::string minMatch;
      std::string maxMatch;
      pattern.PossibleMatchRange(&minMatch, &maxMatch, 10);
      return guessMaxCount(boost::optional<std::uint32_t>(), nameID.second, minMatch, maxMatch);
    }
  }
  return 0;
}

std::int64_t NodeAnnoStorage::guessMaxCount(boost::optional<std::uint32_t> nsID,
  std::uint32_t nameID,
  const std::string& lowerVal, const std::string& upperVal) const
{
  std::list<AnnotationKey> keys;
  if(nsID)
  {
    keys.push_back({nameID, *nsID});
  }
  else
  {
    // find all complete keys which have the given name
    auto itKeyUpper = nodeAnnoKeys.upper_bound({nameID, std::numeric_limits<std::uint32_t>::max()});
    for(auto itKeys = nodeAnnoKeys.lower_bound({nameID, 0}); itKeys != itKeyUpper; itKeys++)
    {
      keys.push_back(*itKeys);
    }
  }

  std::int64_t universeSize = 0;
  std::int64_t sumHistogramBuckets = 0;
  std::int64_t countMatches = 0;
  // guess for each annotation fully qualified key and return the sum of all guesses
  for(const auto& key : keys)
  {
    universeSize += nodeAnnotationKeyCount.count(key);
    auto itHisto = histogramBounds.find(key);
    if(itHisto != histogramBounds.end())
    {
      // find the range in which the value is contained
      const auto& histo = itHisto->second;

      // we need to make sure the histogram is not empty -> should have at least two bounds
      if(histo.size() >= 2)
      {
        sumHistogramBuckets += (histo.size() - 1);

        for(size_t i = 0; i < (histo.size()-1); i++)
        {
          const auto& bucketBegin = histo[i];
          const auto& bucketEnd = histo[i+1];
          // check if the range overlaps with the search range
          if(bucketBegin <= upperVal && lowerVal <= bucketEnd)
          {
            countMatches++;
          }
        }
      }
    }
  }

  if(sumHistogramBuckets > 0)
  {
    double selectivity = ((double) countMatches) / ((double) sumHistogramBuckets);
    return std::round(selectivity * ((double) universeSize));
  }
  else
  {
    return 0;
  }

}

NodeAnnoStorage::~NodeAnnoStorage()
{
}

<|endoftext|>


<commit_before>/***************************************************************************
    copyright            : (C) 2002 - 2008 by Scott Wheeler
    email                : wheeler@kde.org
 ***************************************************************************/

/***************************************************************************
 *   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                                                                   *
 *                                                                         *
 *   Alternatively, this file is available under the Mozilla Public        *
 *   License Version 1.1.  You may obtain a copy of the License at         *
 *   http://www.mozilla.org/MPL/                                           *
 ***************************************************************************/

#include <tdebug.h>
#include <tstring.h>

#include "mpegproperties.h"
#include "mpegfile.h"
#include "xingheader.h"

using namespace TagLib;

class MPEG::Properties::PropertiesPrivate
{
public:
  PropertiesPrivate(File *f, ReadStyle s) :
    file(f),
    xingHeader(0),
    style(s),
    length(0),
    bitrate(0),
    sampleRate(0),
    channels(0),
    layer(0),
    version(Header::Version1),
    channelMode(Header::Stereo),
    protectionEnabled(false),
    isCopyrighted(false),
    isOriginal(false) {}

  ~PropertiesPrivate()
  {
    delete xingHeader;
  }

  File *file;
  XingHeader *xingHeader;
  ReadStyle style;
  int length;
  int bitrate;
  int sampleRate;
  int channels;
  int layer;
  Header::Version version;
  Header::ChannelMode channelMode;
  bool protectionEnabled;
  bool isCopyrighted;
  bool isOriginal;
};

////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////

MPEG::Properties::Properties(File *file, ReadStyle style) : AudioProperties(style)
{
  d = new PropertiesPrivate(file, style);

  if(file && file->isOpen())
    read();
}

MPEG::Properties::~Properties()
{
  delete d;
}

int MPEG::Properties::length() const
{
  return d->length;
}

int MPEG::Properties::bitrate() const
{
  return d->bitrate;
}

int MPEG::Properties::sampleRate() const
{
  return d->sampleRate;
}

int MPEG::Properties::channels() const
{
  return d->channels;
}

const MPEG::XingHeader *MPEG::Properties::xingHeader() const
{
  return d->xingHeader;
}

MPEG::Header::Version MPEG::Properties::version() const
{
  return d->version;
}

int MPEG::Properties::layer() const
{
  return d->layer;
}

bool MPEG::Properties::protectionEnabled() const
{
  return d->protectionEnabled;
}

MPEG::Header::ChannelMode MPEG::Properties::channelMode() const
{
  return d->channelMode;
}

bool MPEG::Properties::isCopyrighted() const
{
  return d->isCopyrighted;
}

bool MPEG::Properties::isOriginal() const
{
  return d->isOriginal;
}

////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////

void MPEG::Properties::read()
{
  // Since we've likely just looked for the ID3v1 tag, start at the end of the
  // file where we're least likely to have to have to move the disk head.

  long last = d->file->lastFrameOffset();

  if(last < 0) {
    debug("MPEG::Properties::read() -- Could not find a valid last MPEG frame in the stream.");
    return;
  }

  d->file->seek(last);
  Header lastHeader(d->file->readBlock(4));

  long first = d->file->firstFrameOffset();

  if(first < 0) {
    debug("MPEG::Properties::read() -- Could not find a valid first MPEG frame in the stream.");
    return;
  }

  if(!lastHeader.isValid()) {

    long pos = last;

    while(pos > first) {

      pos = d->file->previousFrameOffset(pos);

      if(pos < 0)
        break;

      d->file->seek(pos);
      Header header(d->file->readBlock(4));

      if(header.isValid()) {
        lastHeader = header;
        last = pos;
        break;
      }
    }
  }

  // Now jump back to the front of the file and read what we need from there.

  d->file->seek(first);
  Header firstHeader(d->file->readBlock(4));

  if(!firstHeader.isValid() || !lastHeader.isValid()) {
    debug("MPEG::Properties::read() -- Page headers were invalid.");
    return;
  }

  // Check for a Xing header that will help us in gathering information about a
  // VBR stream.

  int xingHeaderOffset = MPEG::XingHeader::xingHeaderOffset(firstHeader.version(),
                                                            firstHeader.channelMode());

  d->file->seek(first + xingHeaderOffset);
  d->xingHeader = new XingHeader(d->file->readBlock(16));

  // Read the length and the bitrate from the Xing header.

  if(d->xingHeader->isValid() &&
     firstHeader.sampleRate() > 0 &&
     d->xingHeader->totalFrames() > 0)
  {
      double timePerFrame =
        double(firstHeader.samplesPerFrame()) / firstHeader.sampleRate();

      d->length = int(timePerFrame * d->xingHeader->totalFrames());
      d->bitrate = d->length > 0 ? d->xingHeader->totalSize() * 8 / d->length / 1000 : 0;
  }
  else {
    // Since there was no valid Xing header found, we hope that we're in a constant
    // bitrate file.

    delete d->xingHeader;
    d->xingHeader = 0;

    // TODO: Make this more robust with audio property detection for VBR without a
    // Xing header.

    if(firstHeader.frameLength() > 0 && firstHeader.bitrate() > 0) {
      int frames = (last - first) / firstHeader.frameLength() + 1;

      d->length = int(float(firstHeader.frameLength() * frames) /
                      float(firstHeader.bitrate() * 125) + 0.5);
      d->bitrate = firstHeader.bitrate();
    }
  }

  d->sampleRate = firstHeader.sampleRate();
  d->channels = firstHeader.channelMode() == Header::SingleChannel ? 1 : 2;
  d->version = firstHeader.version();
  d->layer = firstHeader.layer();
  d->protectionEnabled = firstHeader.protectionEnabled();
  d->channelMode = firstHeader.channelMode();
  d->isCopyrighted = firstHeader.isCopyrighted();
  d->isOriginal = firstHeader.isOriginal();
}
<commit_msg>Use floting point length to calculate bitrate from the Xing header information<commit_after>/***************************************************************************
    copyright            : (C) 2002 - 2008 by Scott Wheeler
    email                : wheeler@kde.org
 ***************************************************************************/

/***************************************************************************
 *   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                                                                   *
 *                                                                         *
 *   Alternatively, this file is available under the Mozilla Public        *
 *   License Version 1.1.  You may obtain a copy of the License at         *
 *   http://www.mozilla.org/MPL/                                           *
 ***************************************************************************/

#include <tdebug.h>
#include <tstring.h>

#include "mpegproperties.h"
#include "mpegfile.h"
#include "xingheader.h"

using namespace TagLib;

class MPEG::Properties::PropertiesPrivate
{
public:
  PropertiesPrivate(File *f, ReadStyle s) :
    file(f),
    xingHeader(0),
    style(s),
    length(0),
    bitrate(0),
    sampleRate(0),
    channels(0),
    layer(0),
    version(Header::Version1),
    channelMode(Header::Stereo),
    protectionEnabled(false),
    isCopyrighted(false),
    isOriginal(false) {}

  ~PropertiesPrivate()
  {
    delete xingHeader;
  }

  File *file;
  XingHeader *xingHeader;
  ReadStyle style;
  int length;
  int bitrate;
  int sampleRate;
  int channels;
  int layer;
  Header::Version version;
  Header::ChannelMode channelMode;
  bool protectionEnabled;
  bool isCopyrighted;
  bool isOriginal;
};

////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////

MPEG::Properties::Properties(File *file, ReadStyle style) : AudioProperties(style)
{
  d = new PropertiesPrivate(file, style);

  if(file && file->isOpen())
    read();
}

MPEG::Properties::~Properties()
{
  delete d;
}

int MPEG::Properties::length() const
{
  return d->length;
}

int MPEG::Properties::bitrate() const
{
  return d->bitrate;
}

int MPEG::Properties::sampleRate() const
{
  return d->sampleRate;
}

int MPEG::Properties::channels() const
{
  return d->channels;
}

const MPEG::XingHeader *MPEG::Properties::xingHeader() const
{
  return d->xingHeader;
}

MPEG::Header::Version MPEG::Properties::version() const
{
  return d->version;
}

int MPEG::Properties::layer() const
{
  return d->layer;
}

bool MPEG::Properties::protectionEnabled() const
{
  return d->protectionEnabled;
}

MPEG::Header::ChannelMode MPEG::Properties::channelMode() const
{
  return d->channelMode;
}

bool MPEG::Properties::isCopyrighted() const
{
  return d->isCopyrighted;
}

bool MPEG::Properties::isOriginal() const
{
  return d->isOriginal;
}

////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////

void MPEG::Properties::read()
{
  // Since we've likely just looked for the ID3v1 tag, start at the end of the
  // file where we're least likely to have to have to move the disk head.

  long last = d->file->lastFrameOffset();

  if(last < 0) {
    debug("MPEG::Properties::read() -- Could not find a valid last MPEG frame in the stream.");
    return;
  }

  d->file->seek(last);
  Header lastHeader(d->file->readBlock(4));

  long first = d->file->firstFrameOffset();

  if(first < 0) {
    debug("MPEG::Properties::read() -- Could not find a valid first MPEG frame in the stream.");
    return;
  }

  if(!lastHeader.isValid()) {

    long pos = last;

    while(pos > first) {

      pos = d->file->previousFrameOffset(pos);

      if(pos < 0)
        break;

      d->file->seek(pos);
      Header header(d->file->readBlock(4));

      if(header.isValid()) {
        lastHeader = header;
        last = pos;
        break;
      }
    }
  }

  // Now jump back to the front of the file and read what we need from there.

  d->file->seek(first);
  Header firstHeader(d->file->readBlock(4));

  if(!firstHeader.isValid() || !lastHeader.isValid()) {
    debug("MPEG::Properties::read() -- Page headers were invalid.");
    return;
  }

  // Check for a Xing header that will help us in gathering information about a
  // VBR stream.

  int xingHeaderOffset = MPEG::XingHeader::xingHeaderOffset(firstHeader.version(),
                                                            firstHeader.channelMode());

  d->file->seek(first + xingHeaderOffset);
  d->xingHeader = new XingHeader(d->file->readBlock(16));

  // Read the length and the bitrate from the Xing header.

  if(d->xingHeader->isValid() &&
     firstHeader.sampleRate() > 0 &&
     d->xingHeader->totalFrames() > 0)
  {
      double timePerFrame =
        double(firstHeader.samplesPerFrame()) / firstHeader.sampleRate();

      double length = timePerFrame * d->xingHeader->totalFrames();

      d->length = int(length);
      d->bitrate = d->length > 0 ? d->xingHeader->totalSize() * 8 / length / 1000 : 0;
  }
  else {
    // Since there was no valid Xing header found, we hope that we're in a constant
    // bitrate file.

    delete d->xingHeader;
    d->xingHeader = 0;

    // TODO: Make this more robust with audio property detection for VBR without a
    // Xing header.

    if(firstHeader.frameLength() > 0 && firstHeader.bitrate() > 0) {
      int frames = (last - first) / firstHeader.frameLength() + 1;

      d->length = int(float(firstHeader.frameLength() * frames) /
                      float(firstHeader.bitrate() * 125) + 0.5);
      d->bitrate = firstHeader.bitrate();
    }
  }

  d->sampleRate = firstHeader.sampleRate();
  d->channels = firstHeader.channelMode() == Header::SingleChannel ? 1 : 2;
  d->version = firstHeader.version();
  d->layer = firstHeader.layer();
  d->protectionEnabled = firstHeader.protectionEnabled();
  d->channelMode = firstHeader.channelMode();
  d->isCopyrighted = firstHeader.isCopyrighted();
  d->isOriginal = firstHeader.isOriginal();
}
<|endoftext|>


<commit_before>#include "flake.hh"

#include <nlohmann/json.hpp>

namespace nix::flake {

// setting name -> setting value -> allow or ignore.
typedef std::map<std::string, std::map<std::string, bool>> TrustedList;

Path trustedListPath()
{
    return getDataDir() + "/nix/trusted-settings.json";
}

static TrustedList readTrustedList()
{
    auto path = trustedListPath();
    if (!pathExists(path)) return {};
    auto json = nlohmann::json::parse(readFile(path));
    return json;
}

static void writeTrustedList(const TrustedList & trustedList)
{
    writeFile(trustedListPath(), nlohmann::json(trustedList).dump());
}

void ConfigFile::apply()
{
    std::set<std::string> whitelist{"bash-prompt", "bash-prompt-suffix"};

    for (auto & [name, value] : settings) {

        auto baseName = hasPrefix(name, "extra-") ? std::string(name, 6) : name;

        // FIXME: Move into libutil/config.cc.
        std::string valueS;
        if (auto s = std::get_if<std::string>(&value))
            valueS = *s;
        else if (auto n = std::get_if<int64_t>(&value))
            valueS = fmt("%d", n);
        else if (auto b = std::get_if<Explicit<bool>>(&value))
            valueS = b->t ? "true" : "false";
        else if (auto ss = std::get_if<std::vector<std::string>>(&value))
            valueS = concatStringsSep(" ", *ss); // FIXME: evil
        else
            assert(false);

        if (!whitelist.count(baseName)) {
            auto trustedList = readTrustedList();

            bool trusted = false;

            if (auto saved = get(get(trustedList, name).value_or(std::map<std::string, bool>()), valueS)) {
                trusted = *saved;
            } else {
                // FIXME: filter ANSI escapes, newlines, \r, etc.
                if (std::tolower(logger->ask(fmt("do you want to allow configuration setting '%s' to be set to '" ANSI_RED "%s" ANSI_NORMAL "' (y/N)?", name, valueS)).value_or('n')) != 'y') {
                    if (std::tolower(logger->ask("do you want to permanently mark this value as untrusted (y/N)?").value_or('n')) == 'y') {
                        trustedList[name][valueS] = false;
                        writeTrustedList(trustedList);
                    }
                } else {
                    if (std::tolower(logger->ask("do you want to permanently mark this value as trusted (y/N)?").value_or('n')) == 'y') {
                        trustedList[name][valueS] = trusted = true;
                        writeTrustedList(trustedList);
                    }
                }
            }

            if (!trusted) {
                warn("ignoring untrusted flake configuration setting '%s'", name);
                continue;
            }
        }

        globalConfig.set(name, valueS);
    }
}

}
<commit_msg>Create parent trusted list path before writing<commit_after>#include "flake.hh"

#include <nlohmann/json.hpp>

namespace nix::flake {

// setting name -> setting value -> allow or ignore.
typedef std::map<std::string, std::map<std::string, bool>> TrustedList;

Path trustedListPath()
{
    return getDataDir() + "/nix/trusted-settings.json";
}

static TrustedList readTrustedList()
{
    auto path = trustedListPath();
    if (!pathExists(path)) return {};
    auto json = nlohmann::json::parse(readFile(path));
    return json;
}

static void writeTrustedList(const TrustedList & trustedList)
{
    auto path = trustedListPath();
    createDirs(dirOf(path));
    writeFile(path, nlohmann::json(trustedList).dump());
}

void ConfigFile::apply()
{
    std::set<std::string> whitelist{"bash-prompt", "bash-prompt-suffix"};

    for (auto & [name, value] : settings) {

        auto baseName = hasPrefix(name, "extra-") ? std::string(name, 6) : name;

        // FIXME: Move into libutil/config.cc.
        std::string valueS;
        if (auto s = std::get_if<std::string>(&value))
            valueS = *s;
        else if (auto n = std::get_if<int64_t>(&value))
            valueS = fmt("%d", n);
        else if (auto b = std::get_if<Explicit<bool>>(&value))
            valueS = b->t ? "true" : "false";
        else if (auto ss = std::get_if<std::vector<std::string>>(&value))
            valueS = concatStringsSep(" ", *ss); // FIXME: evil
        else
            assert(false);

        if (!whitelist.count(baseName)) {
            auto trustedList = readTrustedList();

            bool trusted = false;

            if (auto saved = get(get(trustedList, name).value_or(std::map<std::string, bool>()), valueS)) {
                trusted = *saved;
            } else {
                // FIXME: filter ANSI escapes, newlines, \r, etc.
                if (std::tolower(logger->ask(fmt("do you want to allow configuration setting '%s' to be set to '" ANSI_RED "%s" ANSI_NORMAL "' (y/N)?", name, valueS)).value_or('n')) != 'y') {
                    if (std::tolower(logger->ask("do you want to permanently mark this value as untrusted (y/N)?").value_or('n')) == 'y') {
                        trustedList[name][valueS] = false;
                        writeTrustedList(trustedList);
                    }
                } else {
                    if (std::tolower(logger->ask("do you want to permanently mark this value as trusted (y/N)?").value_or('n')) == 'y') {
                        trustedList[name][valueS] = trusted = true;
                        writeTrustedList(trustedList);
                    }
                }
            }

            if (!trusted) {
                warn("ignoring untrusted flake configuration setting '%s'", name);
                continue;
            }
        }

        globalConfig.set(name, valueS);
    }
}

}
<|endoftext|>