<commit_before>#include "transactiondesc.h"
#include "clientmodel.h"
#include "guiutil.h"
#include "bitcoinunits.h"
#include "main.h"
#include "wallet.h"
#include "txdb.h"
#include "ui_interface.h"
#include "base58.h"
#include "bitcoingui.h"
#include "util.h"

#include <QInputDialog>
#include <QPushButton>
#include <QMessageBox>
#include <string>

std::vector<std::pair<std::string, std::string>> GetTxStakeBoincHashInfo(const CMerkleTx& mtx);
std::vector<std::pair<std::string, std::string>> GetTxNormalBoincHashInfo(const CMerkleTx& mtx);

QString ToQString(std::string s)
{
    QString str1 = QString::fromUtf8(s.c_str());

    return str1;
}

QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx)
{
    AssertLockHeld(cs_main);

    if (!IsFinalTx(wtx, nBestHeight + 1))
    {
        if (wtx.nLockTime < LOCKTIME_THRESHOLD)
            return tr("Open for %n more block(s)", "", wtx.nLockTime - nBestHeight);

        else
            return tr("Open until %1").arg(GUIUtil::dateTimeStr(wtx.nLockTime));
    }

    else
    {
        int nDepth = wtx.GetDepthInMainChain();

        if (nDepth < 0)
            return tr("conflicted");

        else if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
            return tr("%1/offline").arg(nDepth);

        else if (nDepth < 10)
            return tr("%1/unconfirmed").arg(nDepth);

        else
            return tr("%1 confirmations").arg(nDepth);
    }
}

std::string PubKeyToGRCAddress(const CScript& scriptPubKey)
{
    txnouttype type;
    std::vector<CTxDestination> addresses;
    int nRequired;

    if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired))
    {
        return "";
    }

    std::string grcaddress = "";

    for (auto const& addr : addresses)
        grcaddress = CBitcoinAddress(addr).ToString();

    return grcaddress;
}

QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, unsigned int vout)
{
    QString strHTML;

    LOCK2(cs_main, wallet->cs_wallet);

    strHTML.reserve(9250);
    strHTML += "";

    int64_t nTime = wtx.GetTxTime();
    int64_t nCredit = wtx.GetCredit();
    int64_t nDebit = wtx.GetDebit();
    int64_t nNet = nCredit - nDebit;
    int nRequests = wtx.GetRequestCount();

    strHTML += "" + tr("Status") + ": " + FormatTxStatus(wtx);

    if (nRequests != -1)
    {
        if (nRequests == 0)
            strHTML += tr(", has not been successfully broadcast yet");

        else if (nRequests > 0)
            strHTML += tr(", broadcast through %n node(s)", "", nRequests);
    }

    strHTML += "
";
    strHTML += "" + tr("Date") + ": " + (nTime ? GUIUtil::dateTimeStr(nTime) : "") + "
";

    // From
    if (wtx.IsCoinBase())
        strHTML += "" + tr("Source") + ": " + tr("Generated in CoinBase") + "
";

    else if (wtx.IsCoinStake())
    {
        // Update support for Side Stake and correctly show POS/POR as well
        strHTML += "" + tr("Source") + ": ";

        MinedType gentype = GenerateType(wtx.GetHash(), vout);

        switch (gentype)
        {
            case MinedType::POS               :    strHTML += tr("MINED - POS");        break;
            case MinedType::POR               :    strHTML += tr("MINED - POR");        break;
            case MinedType::ORPHANED          :    strHTML += tr("MINED - ORPHANED");   break;
            case MinedType::POS_SIDE_STAKE    :    strHTML += tr("POS SIDE STAKE");     break;
            case MinedType::POR_SIDE_STAKE    :    strHTML += tr("POR SIDE STAKE");     break;
            default                           :    strHTML += tr("MINED - UNKNOWN");    break;
        }

        strHTML += "<br";
    }
    // Online transaction
    else if (wtx.mapValue.count("from") && !wtx.mapValue["from"].empty())
        strHTML += "" + tr("From") + ": " + GUIUtil::HtmlEscape(wtx.mapValue["from"]) + "
";

    else
    {
        // Offline transaction
        if (nNet > 0)
        {
            // Credit
            for (auto const& txout : wtx.vout)
            {
                if (wallet->IsMine(txout))
                {
                    CTxDestination address;

                    if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address))
                    {
                        if (wallet->mapAddressBook.count(address))
                        {
                            strHTML += "" + tr("From") + ": " + tr("unknown") + "
";
                            strHTML += "" + tr("To") + ": ";
                            strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString());

                            if (!wallet->mapAddressBook[address].empty())
                                strHTML += " (" + tr("own address") + ", " + tr("label") + ": " + GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + ")";

                            else
                                strHTML += " (" + tr("own address") + ")";

                            strHTML += "
";
                        }
                    }

                    break;
                }
            }
        }
    }

    // To
    if (wtx.mapValue.count("to") && !wtx.mapValue["to"].empty())
    {
        // Online transaction
        std::string strAddress = wtx.mapValue["to"];

        strHTML += "" + tr("To") + ": ";

        CTxDestination dest = CBitcoinAddress(strAddress).Get();

        if (wallet->mapAddressBook.count(dest) && !wallet->mapAddressBook[dest].empty())
            strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[dest]) + " ";

        strHTML += GUIUtil::HtmlEscape(strAddress) + "
";
    }

    // Amount
    if (wtx.IsCoinBase() && nCredit == 0)
    {
        // Coinbase
        int64_t nUnmatured = 0;

        for (auto const& txout : wtx.vout)
            nUnmatured += wallet->GetCredit(txout);

        strHTML += "" + tr("Credit") + ": ";

        if (wtx.IsInMainChain())
            strHTML += BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nUnmatured)+ " (" + tr("matures in %n more block(s)", "", wtx.GetBlocksToMaturity()) + ")";

        else
            strHTML += "(" + tr("not accepted") + ")";

        strHTML += "
";
    }

    else if (nNet > 0)
    {
        // Credit
        strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nNet) + "
";
    }

    else
    {
        bool fAllFromMe = true;

        for (auto const& txin : wtx.vin)
            fAllFromMe = fAllFromMe && wallet->IsMine(txin);

        bool fAllToMe = true;

        for (auto const& txout : wtx.vout)
            fAllToMe = fAllToMe && wallet->IsMine(txout);

        if (fAllFromMe)
        {
            // Debit
            for (auto const& txout : wtx.vout)
            {
                if (wallet->IsMine(txout))
                    continue;

                if (!wtx.mapValue.count("to") || wtx.mapValue["to"].empty())
                {
                    // Offline transaction
                    CTxDestination address;

                    if (ExtractDestination(txout.scriptPubKey, address))
                    {
                        strHTML += "" + tr("To") + ": ";

                        if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].empty())
                            strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + " ";

                        strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString());
                        strHTML += "
";
                    }
                }

                strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -txout.nValue) + "
";
            }

            if (fAllToMe)
            {
                // Payment to self
                int64_t nChange = wtx.GetChange();
                int64_t nValue = nCredit - nChange;

                strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -nValue) + "
";
                strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nValue) + "
";
            }

            int64_t nTxFee = nDebit - wtx.GetValueOut();

            if (nTxFee > 0)
                strHTML += "" + tr("Transaction fee") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -nTxFee) + "
";
        }

        else
        {
            // Mixed debit transaction
            for (auto const& txin : wtx.vin)

                if (wallet->IsMine(txin))
                    strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -wallet->GetDebit(txin)) + "
";

            for (auto const& txout : wtx.vout)

                if (wallet->IsMine(txout))
                    strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, wallet->GetCredit(txout)) + "
";
        }
    }

    strHTML += "" + tr("Net amount") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nNet, true) + "
";

    // Message
    if (wtx.mapValue.count("message") && !wtx.mapValue["message"].empty())
        strHTML += "
" + tr("Message") + ":
" + GUIUtil::HtmlEscape(wtx.mapValue["message"], true) + "
";

    if (wtx.mapValue.count("comment") && !wtx.mapValue["comment"].empty())
        strHTML += "
" + tr("Comment") + ":
" + GUIUtil::HtmlEscape(wtx.mapValue["comment"], true) + "
";

    strHTML += "" + tr("TX ID") + ": " + wtx.GetHash().ToString().c_str() + "
";

    std::string sHashBlock = wtx.hashBlock.ToString();

    if (wtx.hashBlock == 0)
        strHTML += "" + tr("Block Hash") + ": Not yet in chain
";

    else
        strHTML += "" + tr("Block Hash") + ": " + sHashBlock.c_str() + "
";

    if (wtx.IsCoinBase() || wtx.IsCoinStake())
    {
        strHTML += "

" + tr("Transaction Stake Data") + "

";

        std::vector<std::pair<std::string, std::string>> vTxStakeInfoIn = GetTxStakeBoincHashInfo(wtx);

        for (auto const& vTxStakeInfo : vTxStakeInfoIn)
        {
            strHTML += "";
            strHTML += MakeSafeMessage(vTxStakeInfo.first).c_str();
            strHTML += ": ";
            strHTML += MakeSafeMessage(vTxStakeInfo.second).c_str();
            strHTML += "
";
        }

        strHTML += "

" + tr("Gridcoin generated coins must mature 110 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to \"not accepted\" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.") + "
";
    }

    else if (!wtx.hashBoinc.empty())
    {
        strHTML += "

" + tr("Transaction Message Data") + "

";

        std::vector<std::pair<std::string, std::string>> vTxNormalInfoIn = GetTxNormalBoincHashInfo(wtx);

        for (auto const& vTxNormalInfo : vTxNormalInfoIn)
        {
            strHTML += "";
            strHTML += MakeSafeMessage(vTxNormalInfo.first).c_str();
            strHTML += ": ";
            strHTML += MakeSafeMessage(vTxNormalInfo.second).c_str();
            strHTML += "
";
        }
    }

    // Debug view 12-7-2014 - Halford
	// Smart Contracts

    msHashBoinc = "";

    if (fDebug || true)
    {
        strHTML += "

" + tr("Transaction Debits/Credits") + "

";

        for (auto const& txin : wtx.vin)

            if(wallet->IsMine(txin))
                strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -wallet->GetDebit(txin)) + "
";

        for (auto const& txout : wtx.vout)

            if(wallet->IsMine(txout))
                strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, wallet->GetCredit(txout)) + "
";

        strHTML += "
" + tr("Transaction Data") + "

";
        strHTML += GUIUtil::HtmlEscape(wtx.ToString(), true);

        CTxDB txdb("r"); // To fetch source txouts

        // Contracts
		//std::string sContractLength = RoundToString((double)wtx.hashBoinc.length(),0);
		//std::string sContractInfo = "";
		//if (wtx.hashBoinc.length() > 255) sContractInfo = ": " + wtx.hashBoinc.substr(0,255);

        //if (fDebug3)
        //{
				//Extract contract here from : wtx.hashBoinc - contract key
				//strHTML += "
Contracts: " + QString::fromStdString(sContractLength) + "

";
        //}

		msHashBoinc += wtx.hashBoinc;
        strHTML += "
" + tr("Transaction Inputs") + "";
        strHTML += "
";

        for (auto const& txin : wtx.vin)
        {
            COutPoint prevout = txin.prevout;

            CTransaction prev;

            if(txdb.ReadDiskTx(prevout.hash, prev))
            {
                if (prevout.n < prev.vout.size())
                {
                    strHTML += "
";

                    //Inputs: 7-31-2015
                    const CTxOut &vout = prev.vout[prevout.n];

                    CTxDestination address;

                    if (ExtractDestination(vout.scriptPubKey, address))
                        strHTML += QString::fromStdString(CBitcoinAddress(address).ToString());

                    strHTML += " " + tr("Amount") + "=" + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, vout.nValue);
                    strHTML += " IsMine=" + (wallet->IsMine(vout) ? tr("true") : tr("false")) + "
";
                }
            }
        }

        strHTML += "
";
    }

    strHTML += "";

    return strHTML;
}
<commit_msg>add missing ><commit_after>#include "transactiondesc.h"
#include "clientmodel.h"
#include "guiutil.h"
#include "bitcoinunits.h"
#include "main.h"
#include "wallet.h"
#include "txdb.h"
#include "ui_interface.h"
#include "base58.h"
#include "bitcoingui.h"
#include "util.h"

#include <QInputDialog>
#include <QPushButton>
#include <QMessageBox>
#include <string>

std::vector<std::pair<std::string, std::string>> GetTxStakeBoincHashInfo(const CMerkleTx& mtx);
std::vector<std::pair<std::string, std::string>> GetTxNormalBoincHashInfo(const CMerkleTx& mtx);

QString ToQString(std::string s)
{
    QString str1 = QString::fromUtf8(s.c_str());

    return str1;
}

QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx)
{
    AssertLockHeld(cs_main);

    if (!IsFinalTx(wtx, nBestHeight + 1))
    {
        if (wtx.nLockTime < LOCKTIME_THRESHOLD)
            return tr("Open for %n more block(s)", "", wtx.nLockTime - nBestHeight);

        else
            return tr("Open until %1").arg(GUIUtil::dateTimeStr(wtx.nLockTime));
    }

    else
    {
        int nDepth = wtx.GetDepthInMainChain();

        if (nDepth < 0)
            return tr("conflicted");

        else if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
            return tr("%1/offline").arg(nDepth);

        else if (nDepth < 10)
            return tr("%1/unconfirmed").arg(nDepth);

        else
            return tr("%1 confirmations").arg(nDepth);
    }
}

std::string PubKeyToGRCAddress(const CScript& scriptPubKey)
{
    txnouttype type;
    std::vector<CTxDestination> addresses;
    int nRequired;

    if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired))
    {
        return "";
    }

    std::string grcaddress = "";

    for (auto const& addr : addresses)
        grcaddress = CBitcoinAddress(addr).ToString();

    return grcaddress;
}

QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, unsigned int vout)
{
    QString strHTML;

    LOCK2(cs_main, wallet->cs_wallet);

    strHTML.reserve(9250);
    strHTML += "";

    int64_t nTime = wtx.GetTxTime();
    int64_t nCredit = wtx.GetCredit();
    int64_t nDebit = wtx.GetDebit();
    int64_t nNet = nCredit - nDebit;
    int nRequests = wtx.GetRequestCount();

    strHTML += "" + tr("Status") + ": " + FormatTxStatus(wtx);

    if (nRequests != -1)
    {
        if (nRequests == 0)
            strHTML += tr(", has not been successfully broadcast yet");

        else if (nRequests > 0)
            strHTML += tr(", broadcast through %n node(s)", "", nRequests);
    }

    strHTML += "
";
    strHTML += "" + tr("Date") + ": " + (nTime ? GUIUtil::dateTimeStr(nTime) : "") + "
";

    // From
    if (wtx.IsCoinBase())
        strHTML += "" + tr("Source") + ": " + tr("Generated in CoinBase") + "
";

    else if (wtx.IsCoinStake())
    {
        // Update support for Side Stake and correctly show POS/POR as well
        strHTML += "" + tr("Source") + ": ";

        MinedType gentype = GenerateType(wtx.GetHash(), vout);

        switch (gentype)
        {
            case MinedType::POS               :    strHTML += tr("MINED - POS");        break;
            case MinedType::POR               :    strHTML += tr("MINED - POR");        break;
            case MinedType::ORPHANED          :    strHTML += tr("MINED - ORPHANED");   break;
            case MinedType::POS_SIDE_STAKE    :    strHTML += tr("POS SIDE STAKE");     break;
            case MinedType::POR_SIDE_STAKE    :    strHTML += tr("POR SIDE STAKE");     break;
            default                           :    strHTML += tr("MINED - UNKNOWN");    break;
        }

        strHTML += "
";
    }
    // Online transaction
    else if (wtx.mapValue.count("from") && !wtx.mapValue["from"].empty())
        strHTML += "" + tr("From") + ": " + GUIUtil::HtmlEscape(wtx.mapValue["from"]) + "
";

    else
    {
        // Offline transaction
        if (nNet > 0)
        {
            // Credit
            for (auto const& txout : wtx.vout)
            {
                if (wallet->IsMine(txout))
                {
                    CTxDestination address;

                    if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address))
                    {
                        if (wallet->mapAddressBook.count(address))
                        {
                            strHTML += "" + tr("From") + ": " + tr("unknown") + "
";
                            strHTML += "" + tr("To") + ": ";
                            strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString());

                            if (!wallet->mapAddressBook[address].empty())
                                strHTML += " (" + tr("own address") + ", " + tr("label") + ": " + GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + ")";

                            else
                                strHTML += " (" + tr("own address") + ")";

                            strHTML += "
";
                        }
                    }

                    break;
                }
            }
        }
    }

    // To
    if (wtx.mapValue.count("to") && !wtx.mapValue["to"].empty())
    {
        // Online transaction
        std::string strAddress = wtx.mapValue["to"];

        strHTML += "" + tr("To") + ": ";

        CTxDestination dest = CBitcoinAddress(strAddress).Get();

        if (wallet->mapAddressBook.count(dest) && !wallet->mapAddressBook[dest].empty())
            strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[dest]) + " ";

        strHTML += GUIUtil::HtmlEscape(strAddress) + "
";
    }

    // Amount
    if (wtx.IsCoinBase() && nCredit == 0)
    {
        // Coinbase
        int64_t nUnmatured = 0;

        for (auto const& txout : wtx.vout)
            nUnmatured += wallet->GetCredit(txout);

        strHTML += "" + tr("Credit") + ": ";

        if (wtx.IsInMainChain())
            strHTML += BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nUnmatured)+ " (" + tr("matures in %n more block(s)", "", wtx.GetBlocksToMaturity()) + ")";

        else
            strHTML += "(" + tr("not accepted") + ")";

        strHTML += "
";
    }

    else if (nNet > 0)
    {
        // Credit
        strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nNet) + "
";
    }

    else
    {
        bool fAllFromMe = true;

        for (auto const& txin : wtx.vin)
            fAllFromMe = fAllFromMe && wallet->IsMine(txin);

        bool fAllToMe = true;

        for (auto const& txout : wtx.vout)
            fAllToMe = fAllToMe && wallet->IsMine(txout);

        if (fAllFromMe)
        {
            // Debit
            for (auto const& txout : wtx.vout)
            {
                if (wallet->IsMine(txout))
                    continue;

                if (!wtx.mapValue.count("to") || wtx.mapValue["to"].empty())
                {
                    // Offline transaction
                    CTxDestination address;

                    if (ExtractDestination(txout.scriptPubKey, address))
                    {
                        strHTML += "" + tr("To") + ": ";

                        if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].empty())
                            strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + " ";

                        strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString());
                        strHTML += "
";
                    }
                }

                strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -txout.nValue) + "
";
            }

            if (fAllToMe)
            {
                // Payment to self
                int64_t nChange = wtx.GetChange();
                int64_t nValue = nCredit - nChange;

                strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -nValue) + "
";
                strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nValue) + "
";
            }

            int64_t nTxFee = nDebit - wtx.GetValueOut();

            if (nTxFee > 0)
                strHTML += "" + tr("Transaction fee") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -nTxFee) + "
";
        }

        else
        {
            // Mixed debit transaction
            for (auto const& txin : wtx.vin)

                if (wallet->IsMine(txin))
                    strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -wallet->GetDebit(txin)) + "
";

            for (auto const& txout : wtx.vout)

                if (wallet->IsMine(txout))
                    strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, wallet->GetCredit(txout)) + "
";
        }
    }

    strHTML += "" + tr("Net amount") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nNet, true) + "
";

    // Message
    if (wtx.mapValue.count("message") && !wtx.mapValue["message"].empty())
        strHTML += "
" + tr("Message") + ":
" + GUIUtil::HtmlEscape(wtx.mapValue["message"], true) + "
";

    if (wtx.mapValue.count("comment") && !wtx.mapValue["comment"].empty())
        strHTML += "
" + tr("Comment") + ":
" + GUIUtil::HtmlEscape(wtx.mapValue["comment"], true) + "
";

    strHTML += "" + tr("TX ID") + ": " + wtx.GetHash().ToString().c_str() + "
";

    std::string sHashBlock = wtx.hashBlock.ToString();

    if (wtx.hashBlock == 0)
        strHTML += "" + tr("Block Hash") + ": Not yet in chain
";

    else
        strHTML += "" + tr("Block Hash") + ": " + sHashBlock.c_str() + "
";

    if (wtx.IsCoinBase() || wtx.IsCoinStake())
    {
        strHTML += "

" + tr("Transaction Stake Data") + "

";

        std::vector<std::pair<std::string, std::string>> vTxStakeInfoIn = GetTxStakeBoincHashInfo(wtx);

        for (auto const& vTxStakeInfo : vTxStakeInfoIn)
        {
            strHTML += "";
            strHTML += MakeSafeMessage(vTxStakeInfo.first).c_str();
            strHTML += ": ";
            strHTML += MakeSafeMessage(vTxStakeInfo.second).c_str();
            strHTML += "
";
        }

        strHTML += "

" + tr("Gridcoin generated coins must mature 110 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to \"not accepted\" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.") + "
";
    }

    else if (!wtx.hashBoinc.empty())
    {
        strHTML += "

" + tr("Transaction Message Data") + "

";

        std::vector<std::pair<std::string, std::string>> vTxNormalInfoIn = GetTxNormalBoincHashInfo(wtx);

        for (auto const& vTxNormalInfo : vTxNormalInfoIn)
        {
            strHTML += "";
            strHTML += MakeSafeMessage(vTxNormalInfo.first).c_str();
            strHTML += ": ";
            strHTML += MakeSafeMessage(vTxNormalInfo.second).c_str();
            strHTML += "
";
        }
    }

    // Debug view 12-7-2014 - Halford
	// Smart Contracts

    msHashBoinc = "";

    if (fDebug || true)
    {
        strHTML += "

" + tr("Transaction Debits/Credits") + "

";

        for (auto const& txin : wtx.vin)

            if(wallet->IsMine(txin))
                strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -wallet->GetDebit(txin)) + "
";

        for (auto const& txout : wtx.vout)

            if(wallet->IsMine(txout))
                strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, wallet->GetCredit(txout)) + "
";

        strHTML += "
" + tr("Transaction Data") + "

";
        strHTML += GUIUtil::HtmlEscape(wtx.ToString(), true);

        CTxDB txdb("r"); // To fetch source txouts

        // Contracts
		//std::string sContractLength = RoundToString((double)wtx.hashBoinc.length(),0);
		//std::string sContractInfo = "";
		//if (wtx.hashBoinc.length() > 255) sContractInfo = ": " + wtx.hashBoinc.substr(0,255);

        //if (fDebug3)
        //{
				//Extract contract here from : wtx.hashBoinc - contract key
				//strHTML += "
Contracts: " + QString::fromStdString(sContractLength) + "

";
        //}

		msHashBoinc += wtx.hashBoinc;
        strHTML += "
" + tr("Transaction Inputs") + "";
        strHTML += "
";

        for (auto const& txin : wtx.vin)
        {
            COutPoint prevout = txin.prevout;

            CTransaction prev;

            if(txdb.ReadDiskTx(prevout.hash, prev))
            {
                if (prevout.n < prev.vout.size())
                {
                    strHTML += "
";

                    //Inputs: 7-31-2015
                    const CTxOut &vout = prev.vout[prevout.n];

                    CTxDestination address;

                    if (ExtractDestination(vout.scriptPubKey, address))
                        strHTML += QString::fromStdString(CBitcoinAddress(address).ToString());

                    strHTML += " " + tr("Amount") + "=" + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, vout.nValue);
                    strHTML += " IsMine=" + (wallet->IsMine(vout) ? tr("true") : tr("false")) + "
";
                }
            }
        }

        strHTML += "
";
    }

    strHTML += "";

    return strHTML;
}
<|endoftext|>


<commit_before>// Copyright (c) 2011-2013 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "transactionview.h"

#include "transactionfilterproxy.h"
#include "transactionrecord.h"
#include "walletmodel.h"
#include "addresstablemodel.h"
#include "transactiontablemodel.h"
#include "bitcoinunits.h"
#include "csvmodelwriter.h"
#include "transactiondescdialog.h"
#include "editaddressdialog.h"
#include "optionsmodel.h"
#include "guiutil.h"

#include <QScrollBar>
#include <QComboBox>
#include <QDoubleValidator>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QLineEdit>
#include <QTableView>
#include <QHeaderView>
#include <QMessageBox>
#include <QPoint>
#include <QMenu>
#include <QLabel>
#include <QDateTimeEdit>
#include <QDesktopServices>
#include <QUrl>

TransactionView::TransactionView(QWidget *parent) :
    QWidget(parent), model(0), transactionProxyModel(0),
    transactionView(0)
{
    // Build filter row
    setContentsMargins(0,0,0,0);

    QHBoxLayout *hlayout = new QHBoxLayout();
    hlayout->setContentsMargins(0,0,0,0);
#ifdef Q_OS_MAC
    hlayout->setSpacing(5);
    hlayout->addSpacing(26);
#else
    hlayout->setSpacing(0);
    hlayout->addSpacing(23);
#endif

    dateWidget = new QComboBox(this);
#ifdef Q_OS_MAC
    dateWidget->setFixedWidth(121);
#else
    dateWidget->setFixedWidth(120);
#endif
    dateWidget->addItem(tr("All"), All);
    dateWidget->addItem(tr("Today"), Today);
    dateWidget->addItem(tr("This week"), ThisWeek);
    dateWidget->addItem(tr("This month"), ThisMonth);
    dateWidget->addItem(tr("Last month"), LastMonth);
    dateWidget->addItem(tr("This year"), ThisYear);
    dateWidget->addItem(tr("Range..."), Range);
    hlayout->addWidget(dateWidget);

    typeWidget = new QComboBox(this);
#ifdef Q_OS_MAC
    typeWidget->setFixedWidth(121);
#else
    typeWidget->setFixedWidth(120);
#endif

    typeWidget->addItem(tr("All"), TransactionFilterProxy::ALL_TYPES);
    typeWidget->addItem(tr("Received with"), TransactionFilterProxy::TYPE(TransactionRecord::RecvWithAddress) |
                                        TransactionFilterProxy::TYPE(TransactionRecord::RecvFromOther));
    typeWidget->addItem(tr("Sent to"), TransactionFilterProxy::TYPE(TransactionRecord::SendToAddress) |
                                  TransactionFilterProxy::TYPE(TransactionRecord::SendToOther));
    typeWidget->addItem(tr("To yourself"), TransactionFilterProxy::TYPE(TransactionRecord::SendToSelf));
    typeWidget->addItem(tr("Mined"), TransactionFilterProxy::TYPE(TransactionRecord::Generated));
    typeWidget->addItem(tr("Other"), TransactionFilterProxy::TYPE(TransactionRecord::Other));

    hlayout->addWidget(typeWidget);

    addressWidget = new QLineEdit(this);
#if QT_VERSION >= 0x040700
    /* Do not move this to the XML file, Qt before 4.7 will choke on it */
    addressWidget->setPlaceholderText(tr("Enter address or label to search"));
#endif
    hlayout->addWidget(addressWidget);

    amountWidget = new QLineEdit(this);
#if QT_VERSION >= 0x040700
    /* Do not move this to the XML file, Qt before 4.7 will choke on it */
    amountWidget->setPlaceholderText(tr("Min amount"));
#endif
#ifdef Q_OS_MAC
    amountWidget->setFixedWidth(97);
#else
    amountWidget->setFixedWidth(100);
#endif
    amountWidget->setValidator(new QDoubleValidator(0, 1e20, 8, this));
    hlayout->addWidget(amountWidget);

    QVBoxLayout *vlayout = new QVBoxLayout(this);
    vlayout->setContentsMargins(0,0,0,0);
    vlayout->setSpacing(0);

    QTableView *view = new QTableView(this);
    vlayout->addLayout(hlayout);
    vlayout->addWidget(createDateRangeWidget());
    vlayout->addWidget(view);
    vlayout->setSpacing(0);
    int width = view->verticalScrollBar()->sizeHint().width();
    // Cover scroll bar width with spacing
#ifdef Q_OS_MAC
    hlayout->addSpacing(width+2);
#else
    hlayout->addSpacing(width);
#endif
    // Always show scroll bar
    view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
    view->setTabKeyNavigation(false);
    view->setContextMenuPolicy(Qt::CustomContextMenu);

    transactionView = view;

    // Actions
    QAction *copyAddressAction = new QAction(tr("Copy address"), this);
    QAction *copyLabelAction = new QAction(tr("Copy label"), this);
    QAction *copyAmountAction = new QAction(tr("Copy amount"), this);
    QAction *copyTxIDAction = new QAction(tr("Copy transaction ID"), this);
    QAction *editLabelAction = new QAction(tr("Edit label"), this);
    QAction *showDetailsAction = new QAction(tr("Show transaction details"), this);
    QAction *viewOnVertExplorerAction = new QAction(tr("View on VertExplorer"), this);

    contextMenu = new QMenu();
    contextMenu->addAction(copyAddressAction);
    contextMenu->addAction(copyLabelAction);
    contextMenu->addAction(copyAmountAction);
    contextMenu->addAction(copyTxIDAction);
    contextMenu->addAction(editLabelAction);
    contextMenu->addAction(showDetailsAction);
    contextMenu->addAction(viewOnVertExplorerAction);

    // Connect actions
    connect(dateWidget, SIGNAL(activated(int)), this, SLOT(chooseDate(int)));
    connect(typeWidget, SIGNAL(activated(int)), this, SLOT(chooseType(int)));
    connect(addressWidget, SIGNAL(textChanged(QString)), this, SLOT(changedPrefix(QString)));
    connect(amountWidget, SIGNAL(textChanged(QString)), this, SLOT(changedAmount(QString)));

    connect(view, SIGNAL(doubleClicked(QModelIndex)), this, SIGNAL(doubleClicked(QModelIndex)));
    connect(view, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextualMenu(QPoint)));

    connect(copyAddressAction, SIGNAL(triggered()), this, SLOT(copyAddress()));
    connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(copyLabel()));
    connect(copyAmountAction, SIGNAL(triggered()), this, SLOT(copyAmount()));
    connect(copyTxIDAction, SIGNAL(triggered()), this, SLOT(copyTxID()));
    connect(editLabelAction, SIGNAL(triggered()), this, SLOT(editLabel()));
    connect(showDetailsAction, SIGNAL(triggered()), this, SLOT(showDetails()));
    connect(viewOnVertExplorerAction, SIGNAL(triggered()), this, SLOT(viewOnVertExplorer()));
}

void TransactionView::setModel(WalletModel *model)
{
    this->model = model;
    if(model)
    {
        transactionProxyModel = new TransactionFilterProxy(this);
        transactionProxyModel->setSourceModel(model->getTransactionTableModel());
        transactionProxyModel->setDynamicSortFilter(true);
        transactionProxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
        transactionProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);

        transactionProxyModel->setSortRole(Qt::EditRole);

        transactionView->setModel(transactionProxyModel);
        transactionView->setAlternatingRowColors(true);
        transactionView->setSelectionBehavior(QAbstractItemView::SelectRows);
        transactionView->setSelectionMode(QAbstractItemView::ExtendedSelection);
        transactionView->setSortingEnabled(true);
        transactionView->sortByColumn(TransactionTableModel::Status, Qt::DescendingOrder);
        transactionView->verticalHeader()->hide();

        transactionView->horizontalHeader()->resizeSection(TransactionTableModel::Status, 23);
        transactionView->horizontalHeader()->resizeSection(TransactionTableModel::Date, 120);
        transactionView->horizontalHeader()->resizeSection(TransactionTableModel::Type, 120);
#if QT_VERSION < 0x050000
        transactionView->horizontalHeader()->setResizeMode(TransactionTableModel::ToAddress, QHeaderView::Stretch);
#else
        transactionView->horizontalHeader()->setSectionResizeMode(TransactionTableModel::ToAddress, QHeaderView::Stretch);
#endif
        transactionView->horizontalHeader()->resizeSection(TransactionTableModel::Amount, 100);
    }
}

void TransactionView::chooseDate(int idx)
{
    if(!transactionProxyModel)
        return;
    QDate current = QDate::currentDate();
    dateRangeWidget->setVisible(false);
    switch(dateWidget->itemData(idx).toInt())
    {
    case All:
        transactionProxyModel->setDateRange(
                TransactionFilterProxy::MIN_DATE,
                TransactionFilterProxy::MAX_DATE);
        break;
    case Today:
        transactionProxyModel->setDateRange(
                QDateTime(current),
                TransactionFilterProxy::MAX_DATE);
        break;
    case ThisWeek: {
        // Find last Monday
        QDate startOfWeek = current.addDays(-(current.dayOfWeek()-1));
        transactionProxyModel->setDateRange(
                QDateTime(startOfWeek),
                TransactionFilterProxy::MAX_DATE);

        } break;
    case ThisMonth:
        transactionProxyModel->setDateRange(
                QDateTime(QDate(current.year(), current.month(), 1)),
                TransactionFilterProxy::MAX_DATE);
        break;
    case LastMonth:
        transactionProxyModel->setDateRange(
                QDateTime(QDate(current.year(), current.month()-1, 1)),
                QDateTime(QDate(current.year(), current.month(), 1)));
        break;
    case ThisYear:
        transactionProxyModel->setDateRange(
                QDateTime(QDate(current.year(), 1, 1)),
                TransactionFilterProxy::MAX_DATE);
        break;
    case Range:
        dateRangeWidget->setVisible(true);
        dateRangeChanged();
        break;
    }
}

void TransactionView::chooseType(int idx)
{
    if(!transactionProxyModel)
        return;
    transactionProxyModel->setTypeFilter(
        typeWidget->itemData(idx).toInt());
}

void TransactionView::changedPrefix(const QString &prefix)
{
    if(!transactionProxyModel)
        return;
    transactionProxyModel->setAddressPrefix(prefix);
}

void TransactionView::changedAmount(const QString &amount)
{
    if(!transactionProxyModel)
        return;
    qint64 amount_parsed = 0;
    if(BitcoinUnits::parse(model->getOptionsModel()->getDisplayUnit(), amount, &amount_parsed))
    {
        transactionProxyModel->setMinAmount(amount_parsed);
    }
    else
    {
        transactionProxyModel->setMinAmount(0);
    }
}

void TransactionView::exportClicked()
{
    // CSV is currently the only supported format
    QString filename = GUIUtil::getSaveFileName(
            this,
            tr("Export Transaction Data"), QString(),
            tr("Comma separated file (*.csv)"));

    if (filename.isNull()) return;

    CSVModelWriter writer(filename);

    // name, column, role
    writer.setModel(transactionProxyModel);
    writer.addColumn(tr("Confirmed"), 0, TransactionTableModel::ConfirmedRole);
    writer.addColumn(tr("Date"), 0, TransactionTableModel::DateRole);
    writer.addColumn(tr("Type"), TransactionTableModel::Type, Qt::EditRole);
    writer.addColumn(tr("Label"), 0, TransactionTableModel::LabelRole);
    writer.addColumn(tr("Address"), 0, TransactionTableModel::AddressRole);
    writer.addColumn(tr("Amount"), 0, TransactionTableModel::FormattedAmountRole);
    writer.addColumn(tr("ID"), 0, TransactionTableModel::TxIDRole);

    if(!writer.write())
    {
        QMessageBox::critical(this, tr("Error exporting"), tr("Could not write to file %1.").arg(filename),
                              QMessageBox::Abort, QMessageBox::Abort);
    }
}

void TransactionView::contextualMenu(const QPoint &point)
{
    QModelIndex index = transactionView->indexAt(point);
    if(index.isValid())
    {
        contextMenu->exec(QCursor::pos());
    }
}

void TransactionView::copyAddress()
{
    GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::AddressRole);
}

void TransactionView::copyLabel()
{
    GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::LabelRole);
}

void TransactionView::copyAmount()
{
    GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::FormattedAmountRole);
}

void TransactionView::copyTxID()
{
    GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::TxIDRole);
}

void TransactionView::editLabel()
{
    if(!transactionView->selectionModel() ||!model)
        return;
    QModelIndexList selection = transactionView->selectionModel()->selectedRows();
    if(!selection.isEmpty())
    {
        AddressTableModel *addressBook = model->getAddressTableModel();
        if(!addressBook)
            return;
        QString address = selection.at(0).data(TransactionTableModel::AddressRole).toString();
        if(address.isEmpty())
        {
            // If this transaction has no associated address, exit
            return;
        }
        // Is address in address book? Address book can miss address when a transaction is
        // sent from outside the UI.
        int idx = addressBook->lookupAddress(address);
        if(idx != -1)
        {
            // Edit sending / receiving address
            QModelIndex modelIdx = addressBook->index(idx, 0, QModelIndex());
            // Determine type of address, launch appropriate editor dialog type
            QString type = modelIdx.data(AddressTableModel::TypeRole).toString();

            EditAddressDialog dlg(type==AddressTableModel::Receive
                                         ? EditAddressDialog::EditReceivingAddress
                                         : EditAddressDialog::EditSendingAddress,
                                  this);
            dlg.setModel(addressBook);
            dlg.loadRow(idx);
            dlg.exec();
        }
        else
        {
            // Add sending address
            EditAddressDialog dlg(EditAddressDialog::NewSendingAddress,
                                  this);
            dlg.setModel(addressBook);
            dlg.setAddress(address);
            dlg.exec();
        }
    }
}

void TransactionView::showDetails()
{
    if(!transactionView->selectionModel())
        return;
    QModelIndexList selection = transactionView->selectionModel()->selectedRows();
    if(!selection.isEmpty())
    {
        TransactionDescDialog dlg(selection.at(0));
        dlg.exec();
    }
}

void TransactionView::viewOnVertExplorer()
{
    QModelIndexList selection = transactionView->selectionModel()->selectedRows();
    if(!selection.isEmpty())
    {
        QString format("http://vertexplorer.com/tx/");
        format += selection.at(0).data(TransactionTableModel::TxIDRole).toString();

        QDesktopServices::openUrl(QUrl(format));
    }
}

QWidget *TransactionView::createDateRangeWidget()
{
    dateRangeWidget = new QFrame();
    dateRangeWidget->setFrameStyle(QFrame::Panel | QFrame::Raised);
    dateRangeWidget->setContentsMargins(1,1,1,1);
    QHBoxLayout *layout = new QHBoxLayout(dateRangeWidget);
    layout->setContentsMargins(0,0,0,0);
    layout->addSpacing(23);
    layout->addWidget(new QLabel(tr("Range:")));

    dateFrom = new QDateTimeEdit(this);
    dateFrom->setDisplayFormat("dd/MM/yy");
    dateFrom->setCalendarPopup(true);
    dateFrom->setMinimumWidth(100);
    dateFrom->setDate(QDate::currentDate().addDays(-7));
    layout->addWidget(dateFrom);
    layout->addWidget(new QLabel(tr("to")));

    dateTo = new QDateTimeEdit(this);
    dateTo->setDisplayFormat("dd/MM/yy");
    dateTo->setCalendarPopup(true);
    dateTo->setMinimumWidth(100);
    dateTo->setDate(QDate::currentDate());
    layout->addWidget(dateTo);
    layout->addStretch();

    // Hide by default
    dateRangeWidget->setVisible(false);

    // Notify on change
    connect(dateFrom, SIGNAL(dateChanged(QDate)), this, SLOT(dateRangeChanged()));
    connect(dateTo, SIGNAL(dateChanged(QDate)), this, SLOT(dateRangeChanged()));

    return dateRangeWidget;
}

void TransactionView::dateRangeChanged()
{
    if(!transactionProxyModel)
        return;
    transactionProxyModel->setDateRange(
            QDateTime(dateFrom->date()),
            QDateTime(dateTo->date()).addDays(1));
}

void TransactionView::focusTransaction(const QModelIndex &idx)
{
    if(!transactionProxyModel)
        return;
    QModelIndex targetIdx = transactionProxyModel->mapFromSource(idx);
    transactionView->scrollTo(targetIdx);
    transactionView->setCurrentIndex(targetIdx);
    transactionView->setFocus();
}
<commit_msg>Use working block explorer.<commit_after>// Copyright (c) 2011-2013 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "transactionview.h"

#include "transactionfilterproxy.h"
#include "transactionrecord.h"
#include "walletmodel.h"
#include "addresstablemodel.h"
#include "transactiontablemodel.h"
#include "bitcoinunits.h"
#include "csvmodelwriter.h"
#include "transactiondescdialog.h"
#include "editaddressdialog.h"
#include "optionsmodel.h"
#include "guiutil.h"

#include <QScrollBar>
#include <QComboBox>
#include <QDoubleValidator>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QLineEdit>
#include <QTableView>
#include <QHeaderView>
#include <QMessageBox>
#include <QPoint>
#include <QMenu>
#include <QLabel>
#include <QDateTimeEdit>
#include <QDesktopServices>
#include <QUrl>

TransactionView::TransactionView(QWidget *parent) :
    QWidget(parent), model(0), transactionProxyModel(0),
    transactionView(0)
{
    // Build filter row
    setContentsMargins(0,0,0,0);

    QHBoxLayout *hlayout = new QHBoxLayout();
    hlayout->setContentsMargins(0,0,0,0);
#ifdef Q_OS_MAC
    hlayout->setSpacing(5);
    hlayout->addSpacing(26);
#else
    hlayout->setSpacing(0);
    hlayout->addSpacing(23);
#endif

    dateWidget = new QComboBox(this);
#ifdef Q_OS_MAC
    dateWidget->setFixedWidth(121);
#else
    dateWidget->setFixedWidth(120);
#endif
    dateWidget->addItem(tr("All"), All);
    dateWidget->addItem(tr("Today"), Today);
    dateWidget->addItem(tr("This week"), ThisWeek);
    dateWidget->addItem(tr("This month"), ThisMonth);
    dateWidget->addItem(tr("Last month"), LastMonth);
    dateWidget->addItem(tr("This year"), ThisYear);
    dateWidget->addItem(tr("Range..."), Range);
    hlayout->addWidget(dateWidget);

    typeWidget = new QComboBox(this);
#ifdef Q_OS_MAC
    typeWidget->setFixedWidth(121);
#else
    typeWidget->setFixedWidth(120);
#endif

    typeWidget->addItem(tr("All"), TransactionFilterProxy::ALL_TYPES);
    typeWidget->addItem(tr("Received with"), TransactionFilterProxy::TYPE(TransactionRecord::RecvWithAddress) |
                                        TransactionFilterProxy::TYPE(TransactionRecord::RecvFromOther));
    typeWidget->addItem(tr("Sent to"), TransactionFilterProxy::TYPE(TransactionRecord::SendToAddress) |
                                  TransactionFilterProxy::TYPE(TransactionRecord::SendToOther));
    typeWidget->addItem(tr("To yourself"), TransactionFilterProxy::TYPE(TransactionRecord::SendToSelf));
    typeWidget->addItem(tr("Mined"), TransactionFilterProxy::TYPE(TransactionRecord::Generated));
    typeWidget->addItem(tr("Other"), TransactionFilterProxy::TYPE(TransactionRecord::Other));

    hlayout->addWidget(typeWidget);

    addressWidget = new QLineEdit(this);
#if QT_VERSION >= 0x040700
    /* Do not move this to the XML file, Qt before 4.7 will choke on it */
    addressWidget->setPlaceholderText(tr("Enter address or label to search"));
#endif
    hlayout->addWidget(addressWidget);

    amountWidget = new QLineEdit(this);
#if QT_VERSION >= 0x040700
    /* Do not move this to the XML file, Qt before 4.7 will choke on it */
    amountWidget->setPlaceholderText(tr("Min amount"));
#endif
#ifdef Q_OS_MAC
    amountWidget->setFixedWidth(97);
#else
    amountWidget->setFixedWidth(100);
#endif
    amountWidget->setValidator(new QDoubleValidator(0, 1e20, 8, this));
    hlayout->addWidget(amountWidget);

    QVBoxLayout *vlayout = new QVBoxLayout(this);
    vlayout->setContentsMargins(0,0,0,0);
    vlayout->setSpacing(0);

    QTableView *view = new QTableView(this);
    vlayout->addLayout(hlayout);
    vlayout->addWidget(createDateRangeWidget());
    vlayout->addWidget(view);
    vlayout->setSpacing(0);
    int width = view->verticalScrollBar()->sizeHint().width();
    // Cover scroll bar width with spacing
#ifdef Q_OS_MAC
    hlayout->addSpacing(width+2);
#else
    hlayout->addSpacing(width);
#endif
    // Always show scroll bar
    view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
    view->setTabKeyNavigation(false);
    view->setContextMenuPolicy(Qt::CustomContextMenu);

    transactionView = view;

    // Actions
    QAction *copyAddressAction = new QAction(tr("Copy address"), this);
    QAction *copyLabelAction = new QAction(tr("Copy label"), this);
    QAction *copyAmountAction = new QAction(tr("Copy amount"), this);
    QAction *copyTxIDAction = new QAction(tr("Copy transaction ID"), this);
    QAction *editLabelAction = new QAction(tr("Edit label"), this);
    QAction *showDetailsAction = new QAction(tr("Show transaction details"), this);
    QAction *viewOnVertExplorerAction = new QAction(tr("View on VertExplorer"), this);

    contextMenu = new QMenu();
    contextMenu->addAction(copyAddressAction);
    contextMenu->addAction(copyLabelAction);
    contextMenu->addAction(copyAmountAction);
    contextMenu->addAction(copyTxIDAction);
    contextMenu->addAction(editLabelAction);
    contextMenu->addAction(showDetailsAction);
    contextMenu->addAction(viewOnVertExplorerAction);

    // Connect actions
    connect(dateWidget, SIGNAL(activated(int)), this, SLOT(chooseDate(int)));
    connect(typeWidget, SIGNAL(activated(int)), this, SLOT(chooseType(int)));
    connect(addressWidget, SIGNAL(textChanged(QString)), this, SLOT(changedPrefix(QString)));
    connect(amountWidget, SIGNAL(textChanged(QString)), this, SLOT(changedAmount(QString)));

    connect(view, SIGNAL(doubleClicked(QModelIndex)), this, SIGNAL(doubleClicked(QModelIndex)));
    connect(view, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextualMenu(QPoint)));

    connect(copyAddressAction, SIGNAL(triggered()), this, SLOT(copyAddress()));
    connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(copyLabel()));
    connect(copyAmountAction, SIGNAL(triggered()), this, SLOT(copyAmount()));
    connect(copyTxIDAction, SIGNAL(triggered()), this, SLOT(copyTxID()));
    connect(editLabelAction, SIGNAL(triggered()), this, SLOT(editLabel()));
    connect(showDetailsAction, SIGNAL(triggered()), this, SLOT(showDetails()));
    connect(viewOnVertExplorerAction, SIGNAL(triggered()), this, SLOT(viewOnVertExplorer()));
}

void TransactionView::setModel(WalletModel *model)
{
    this->model = model;
    if(model)
    {
        transactionProxyModel = new TransactionFilterProxy(this);
        transactionProxyModel->setSourceModel(model->getTransactionTableModel());
        transactionProxyModel->setDynamicSortFilter(true);
        transactionProxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
        transactionProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);

        transactionProxyModel->setSortRole(Qt::EditRole);

        transactionView->setModel(transactionProxyModel);
        transactionView->setAlternatingRowColors(true);
        transactionView->setSelectionBehavior(QAbstractItemView::SelectRows);
        transactionView->setSelectionMode(QAbstractItemView::ExtendedSelection);
        transactionView->setSortingEnabled(true);
        transactionView->sortByColumn(TransactionTableModel::Status, Qt::DescendingOrder);
        transactionView->verticalHeader()->hide();

        transactionView->horizontalHeader()->resizeSection(TransactionTableModel::Status, 23);
        transactionView->horizontalHeader()->resizeSection(TransactionTableModel::Date, 120);
        transactionView->horizontalHeader()->resizeSection(TransactionTableModel::Type, 120);
#if QT_VERSION < 0x050000
        transactionView->horizontalHeader()->setResizeMode(TransactionTableModel::ToAddress, QHeaderView::Stretch);
#else
        transactionView->horizontalHeader()->setSectionResizeMode(TransactionTableModel::ToAddress, QHeaderView::Stretch);
#endif
        transactionView->horizontalHeader()->resizeSection(TransactionTableModel::Amount, 100);
    }
}

void TransactionView::chooseDate(int idx)
{
    if(!transactionProxyModel)
        return;
    QDate current = QDate::currentDate();
    dateRangeWidget->setVisible(false);
    switch(dateWidget->itemData(idx).toInt())
    {
    case All:
        transactionProxyModel->setDateRange(
                TransactionFilterProxy::MIN_DATE,
                TransactionFilterProxy::MAX_DATE);
        break;
    case Today:
        transactionProxyModel->setDateRange(
                QDateTime(current),
                TransactionFilterProxy::MAX_DATE);
        break;
    case ThisWeek: {
        // Find last Monday
        QDate startOfWeek = current.addDays(-(current.dayOfWeek()-1));
        transactionProxyModel->setDateRange(
                QDateTime(startOfWeek),
                TransactionFilterProxy::MAX_DATE);

        } break;
    case ThisMonth:
        transactionProxyModel->setDateRange(
                QDateTime(QDate(current.year(), current.month(), 1)),
                TransactionFilterProxy::MAX_DATE);
        break;
    case LastMonth:
        transactionProxyModel->setDateRange(
                QDateTime(QDate(current.year(), current.month()-1, 1)),
                QDateTime(QDate(current.year(), current.month(), 1)));
        break;
    case ThisYear:
        transactionProxyModel->setDateRange(
                QDateTime(QDate(current.year(), 1, 1)),
                TransactionFilterProxy::MAX_DATE);
        break;
    case Range:
        dateRangeWidget->setVisible(true);
        dateRangeChanged();
        break;
    }
}

void TransactionView::chooseType(int idx)
{
    if(!transactionProxyModel)
        return;
    transactionProxyModel->setTypeFilter(
        typeWidget->itemData(idx).toInt());
}

void TransactionView::changedPrefix(const QString &prefix)
{
    if(!transactionProxyModel)
        return;
    transactionProxyModel->setAddressPrefix(prefix);
}

void TransactionView::changedAmount(const QString &amount)
{
    if(!transactionProxyModel)
        return;
    qint64 amount_parsed = 0;
    if(BitcoinUnits::parse(model->getOptionsModel()->getDisplayUnit(), amount, &amount_parsed))
    {
        transactionProxyModel->setMinAmount(amount_parsed);
    }
    else
    {
        transactionProxyModel->setMinAmount(0);
    }
}

void TransactionView::exportClicked()
{
    // CSV is currently the only supported format
    QString filename = GUIUtil::getSaveFileName(
            this,
            tr("Export Transaction Data"), QString(),
            tr("Comma separated file (*.csv)"));

    if (filename.isNull()) return;

    CSVModelWriter writer(filename);

    // name, column, role
    writer.setModel(transactionProxyModel);
    writer.addColumn(tr("Confirmed"), 0, TransactionTableModel::ConfirmedRole);
    writer.addColumn(tr("Date"), 0, TransactionTableModel::DateRole);
    writer.addColumn(tr("Type"), TransactionTableModel::Type, Qt::EditRole);
    writer.addColumn(tr("Label"), 0, TransactionTableModel::LabelRole);
    writer.addColumn(tr("Address"), 0, TransactionTableModel::AddressRole);
    writer.addColumn(tr("Amount"), 0, TransactionTableModel::FormattedAmountRole);
    writer.addColumn(tr("ID"), 0, TransactionTableModel::TxIDRole);

    if(!writer.write())
    {
        QMessageBox::critical(this, tr("Error exporting"), tr("Could not write to file %1.").arg(filename),
                              QMessageBox::Abort, QMessageBox::Abort);
    }
}

void TransactionView::contextualMenu(const QPoint &point)
{
    QModelIndex index = transactionView->indexAt(point);
    if(index.isValid())
    {
        contextMenu->exec(QCursor::pos());
    }
}

void TransactionView::copyAddress()
{
    GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::AddressRole);
}

void TransactionView::copyLabel()
{
    GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::LabelRole);
}

void TransactionView::copyAmount()
{
    GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::FormattedAmountRole);
}

void TransactionView::copyTxID()
{
    GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::TxIDRole);
}

void TransactionView::editLabel()
{
    if(!transactionView->selectionModel() ||!model)
        return;
    QModelIndexList selection = transactionView->selectionModel()->selectedRows();
    if(!selection.isEmpty())
    {
        AddressTableModel *addressBook = model->getAddressTableModel();
        if(!addressBook)
            return;
        QString address = selection.at(0).data(TransactionTableModel::AddressRole).toString();
        if(address.isEmpty())
        {
            // If this transaction has no associated address, exit
            return;
        }
        // Is address in address book? Address book can miss address when a transaction is
        // sent from outside the UI.
        int idx = addressBook->lookupAddress(address);
        if(idx != -1)
        {
            // Edit sending / receiving address
            QModelIndex modelIdx = addressBook->index(idx, 0, QModelIndex());
            // Determine type of address, launch appropriate editor dialog type
            QString type = modelIdx.data(AddressTableModel::TypeRole).toString();

            EditAddressDialog dlg(type==AddressTableModel::Receive
                                         ? EditAddressDialog::EditReceivingAddress
                                         : EditAddressDialog::EditSendingAddress,
                                  this);
            dlg.setModel(addressBook);
            dlg.loadRow(idx);
            dlg.exec();
        }
        else
        {
            // Add sending address
            EditAddressDialog dlg(EditAddressDialog::NewSendingAddress,
                                  this);
            dlg.setModel(addressBook);
            dlg.setAddress(address);
            dlg.exec();
        }
    }
}

void TransactionView::showDetails()
{
    if(!transactionView->selectionModel())
        return;
    QModelIndexList selection = transactionView->selectionModel()->selectedRows();
    if(!selection.isEmpty())
    {
        TransactionDescDialog dlg(selection.at(0));
        dlg.exec();
    }
}

void TransactionView::viewOnVertExplorer()
{
    QModelIndexList selection = transactionView->selectionModel()->selectedRows();
    if(!selection.isEmpty())
    {
        QString format("https://explorer.vertcoin.org/tx/");
        format += selection.at(0).data(TransactionTableModel::TxIDRole).toString();

        QDesktopServices::openUrl(QUrl(format));
    }
}

QWidget *TransactionView::createDateRangeWidget()
{
    dateRangeWidget = new QFrame();
    dateRangeWidget->setFrameStyle(QFrame::Panel | QFrame::Raised);
    dateRangeWidget->setContentsMargins(1,1,1,1);
    QHBoxLayout *layout = new QHBoxLayout(dateRangeWidget);
    layout->setContentsMargins(0,0,0,0);
    layout->addSpacing(23);
    layout->addWidget(new QLabel(tr("Range:")));

    dateFrom = new QDateTimeEdit(this);
    dateFrom->setDisplayFormat("dd/MM/yy");
    dateFrom->setCalendarPopup(true);
    dateFrom->setMinimumWidth(100);
    dateFrom->setDate(QDate::currentDate().addDays(-7));
    layout->addWidget(dateFrom);
    layout->addWidget(new QLabel(tr("to")));

    dateTo = new QDateTimeEdit(this);
    dateTo->setDisplayFormat("dd/MM/yy");
    dateTo->setCalendarPopup(true);
    dateTo->setMinimumWidth(100);
    dateTo->setDate(QDate::currentDate());
    layout->addWidget(dateTo);
    layout->addStretch();

    // Hide by default
    dateRangeWidget->setVisible(false);

    // Notify on change
    connect(dateFrom, SIGNAL(dateChanged(QDate)), this, SLOT(dateRangeChanged()));
    connect(dateTo, SIGNAL(dateChanged(QDate)), this, SLOT(dateRangeChanged()));

    return dateRangeWidget;
}

void TransactionView::dateRangeChanged()
{
    if(!transactionProxyModel)
        return;
    transactionProxyModel->setDateRange(
            QDateTime(dateFrom->date()),
            QDateTime(dateTo->date()).addDays(1));
}

void TransactionView::focusTransaction(const QModelIndex &idx)
{
    if(!transactionProxyModel)
        return;
    QModelIndex targetIdx = transactionProxyModel->mapFromSource(idx);
    transactionView->scrollTo(targetIdx);
    transactionView->setCurrentIndex(targetIdx);
    transactionView->setFocus();
}
<|endoftext|>


<commit_before>#pragma once
//=====================================================================//
/*!	@file
	@brief	RX24T グループ・CMPC 定義
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2016 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include "common/io_utils.hpp"
#include "RX24T/peripheral.hpp"
#include "RX24T/icu.hpp"

namespace device {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  コンパレータ C（CMPC）
		@param[in]	base	ベース・アドレス
		@param[in]	t		ペリフェラル型
		@param[in]	vec		割り込みベクタ型
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <uint32_t base, peripheral t, ICU::VECTOR vec>
	struct cmpc_t {

		//-----------------------------------------------------------------//
		/*!
			@brief  コンパレータ制御レジスタ（CMPCTL）
			@param[in]	ofs	オフセット
		*/
		//-----------------------------------------------------------------//
		template <uint32_t ofs>
		struct cmpctl_t : public rw8_t<ofs> {
			typedef rw8_t<ofs> io_;
			using io_::operator =;
			using io_::operator ();
			using io_::operator |=;
			using io_::operator &=;

			bit_rw_t <io_, bitpos::B0>     CINV;
			bit_rw_t <io_, bitpos::B1>     COE;
			bits_rw_t<io_, bitpos::B3, 2>  CEG;
			bits_rw_t<io_, bitpos::B5, 2>  CDFS;
			bit_rw_t <io_, bitpos::B7>     HCMPON;
		};
		static cmpctl_t<base + 0x00> CMPCTL;

		//-----------------------------------------------------------------//
		/*!
			@brief  コンパレータ入力切り替えレジスタ（CMPSEL0）
			@param[in]	ofs	オフセット
		*/
		//-----------------------------------------------------------------//
		template <uint32_t ofs>
		struct cmpsel0_t : public rw8_t<ofs> {
			typedef rw8_t<ofs> io_;
			using io_::operator =;
			using io_::operator ();
			using io_::operator |=;
			using io_::operator &=;

			bits_rw_t<io_, bitpos::B0, 4>  CMPSEL;
		};
		static cmpsel0_t<base + 0x04> CMPSEL0;

		//-----------------------------------------------------------------//
		/*!
			@brief  コンパレータ入力切り替えレジスタ（CMPSEL1）
			@param[in]	ofs	オフセット
		*/
		//-----------------------------------------------------------------//
		template <uint32_t ofs>
		struct cmpsel1_t : public rw8_t<ofs> {
			typedef rw8_t<ofs> io_;
			using io_::operator =;
			using io_::operator ();
			using io_::operator |=;
			using io_::operator &=;

			bits_rw_t<io_, bitpos::B0, 2>  CVRS;
		};
		static cmpsel1_t<base + 0x08> CMPSEL1;

		//-----------------------------------------------------------------//
		/*!
			@brief  コンパレータ出力モニタレジスタ（CMPMON）
			@param[in]	ofs	オフセット
		*/
		//-----------------------------------------------------------------//
		template <uint32_t ofs>
		struct cmpmon_t : public rw8_t<ofs> {
			typedef rw8_t<ofs> io_;
			using io_::operator =;
			using io_::operator ();
			using io_::operator |=;
			using io_::operator &=;

			bit_rw_t<io_, bitpos::B0>  CMPMON0;
		};
		static cmpmon_t<base + 0x0C> CMPMON;

		//-----------------------------------------------------------------//
		/*!
			@brief  コンパレータ外部出力許可レジスタ（CMPIOC）
			@param[in]	ofs	オフセット
		*/
		//-----------------------------------------------------------------//
		template <uint32_t ofs>
		struct cmpioc_t : public rw8_t<ofs> {
			typedef rw8_t<ofs> io_;
			using io_::operator =;
			using io_::operator ();
			using io_::operator |=;
			using io_::operator &=;

			bit_rw_t<io_, bitpos::B0>  CPOE;
		};
		static cmpioc_t<base + 0x10> CMPIOC;

		//-----------------------------------------------------------------//
		/*!
			@brief  ペリフェラル型を返す
			@return ペリフェラル型
		*/
		//-----------------------------------------------------------------//
		static peripheral get_peripheral() { return t; }

		//-----------------------------------------------------------------//
		/*!
			@brief  割り込みベクターを返す
			@return ベクター型
		*/
		//-----------------------------------------------------------------//
		static ICU::VECTOR get_vec() { return vec; }

	};
	typedef cmpc_t<0x000A0C80, peripheral::CMPC0, ICU::VECTOR::CMPC0> CMPC0;
	typedef cmpc_t<0x000A0CA0, peripheral::CMPC1, ICU::VECTOR::CMPC1> CMPC1;
	typedef cmpc_t<0x000A0CC0, peripheral::CMPC2, ICU::VECTOR::CMPC2> CMPC2;
	typedef cmpc_t<0x000A0CE0, peripheral::CMPC3, ICU::VECTOR::CMPC3> CMPC3;

}
<commit_msg>update: CMPC0 to CMPC5 for RX66T<commit_after>#pragma once
//=====================================================================//
/*!	@file
	@brief	RX24T/RX66T グループ・CMPC 定義
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2016, 2018 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include "common/device.hpp"

namespace device {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  コンパレータ C（CMPC）
		@param[in]	base	ベース・アドレス
		@param[in]	per		ペリフェラル型
		@param[in]	vec		割り込みベクタ型
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <uint32_t base, peripheral per, ICU::VECTOR vec>
	struct cmpc_t {

		//-----------------------------------------------------------------//
		/*!
			@brief  コンパレータ制御レジスタ（CMPCTL）
			@param[in]	ofs	オフセット
		*/
		//-----------------------------------------------------------------//
		template <uint32_t ofs>
		struct cmpctl_t : public rw8_t<ofs> {
			typedef rw8_t<ofs> io_;
			using io_::operator =;
			using io_::operator ();
			using io_::operator |=;
			using io_::operator &=;

			bit_rw_t <io_, bitpos::B0>     CINV;
			bit_rw_t <io_, bitpos::B1>     COE;
			bits_rw_t<io_, bitpos::B3, 2>  CEG;
			bits_rw_t<io_, bitpos::B5, 2>  CDFS;
			bit_rw_t <io_, bitpos::B7>     HCMPON;
		};
		static cmpctl_t<base + 0x00> CMPCTL;

		//-----------------------------------------------------------------//
		/*!
			@brief  コンパレータ入力切り替えレジスタ（CMPSEL0）
			@param[in]	ofs	オフセット
		*/
		//-----------------------------------------------------------------//
		template <uint32_t ofs>
		struct cmpsel0_t : public rw8_t<ofs> {
			typedef rw8_t<ofs> io_;
			using io_::operator =;
			using io_::operator ();
			using io_::operator |=;
			using io_::operator &=;

			bits_rw_t<io_, bitpos::B0, 4>  CMPSEL;
		};
		static cmpsel0_t<base + 0x04> CMPSEL0;

		//-----------------------------------------------------------------//
		/*!
			@brief  コンパレータ入力切り替えレジスタ（CMPSEL1）
			@param[in]	ofs	オフセット
		*/
		//-----------------------------------------------------------------//
		template <uint32_t ofs>
		struct cmpsel1_t : public rw8_t<ofs> {
			typedef rw8_t<ofs> io_;
			using io_::operator =;
			using io_::operator ();
			using io_::operator |=;
			using io_::operator &=;

			bits_rw_t<io_, bitpos::B0, 2>  CVRS;
		};
		static cmpsel1_t<base + 0x08> CMPSEL1;

		//-----------------------------------------------------------------//
		/*!
			@brief  コンパレータ出力モニタレジスタ（CMPMON）
			@param[in]	ofs	オフセット
		*/
		//-----------------------------------------------------------------//
		template <uint32_t ofs>
		struct cmpmon_t : public rw8_t<ofs> {
			typedef rw8_t<ofs> io_;
			using io_::operator =;
			using io_::operator ();
			using io_::operator |=;
			using io_::operator &=;

			bit_rw_t<io_, bitpos::B0>  CMPMON0;
		};
		static cmpmon_t<base + 0x0C> CMPMON;

		//-----------------------------------------------------------------//
		/*!
			@brief  コンパレータ外部出力許可レジスタ（CMPIOC）
			@param[in]	ofs	オフセット
		*/
		//-----------------------------------------------------------------//
		template <uint32_t ofs>
		struct cmpioc_t : public rw8_t<ofs> {
			typedef rw8_t<ofs> io_;
			using io_::operator =;
			using io_::operator ();
			using io_::operator |=;
			using io_::operator &=;

			bit_rw_t<io_, bitpos::B0>  CPOE;
		};
		static cmpioc_t<base + 0x10> CMPIOC;

		//-----------------------------------------------------------------//
		/*!
			@brief  ペリフェラル型を返す
			@return ペリフェラル型
		*/
		//-----------------------------------------------------------------//
		static peripheral get_peripheral() { return per; }

		//-----------------------------------------------------------------//
		/*!
			@brief  割り込みベクターを返す
			@return ベクター型
		*/
		//-----------------------------------------------------------------//
		static ICU::VECTOR get_vec() { return vec; }

	};
#if defined(SIG_RX24T)
	typedef cmpc_t<0x000A0C80, peripheral::CMPC0, ICU::VECTOR::CMPC0> CMPC0;
	typedef cmpc_t<0x000A0CA0, peripheral::CMPC1, ICU::VECTOR::CMPC1> CMPC1;
	typedef cmpc_t<0x000A0CC0, peripheral::CMPC2, ICU::VECTOR::CMPC2> CMPC2;
	typedef cmpc_t<0x000A0CE0, peripheral::CMPC3, ICU::VECTOR::CMPC3> CMPC3;
#elif defined(SIG_RX66T)
	typedef cmpc_t<0x000A0C80, peripheral::CMPC0, ICU::VECTOR::CMPC0> CMPC0;
	typedef cmpc_t<0x000A0CA0, peripheral::CMPC1, ICU::VECTOR::CMPC1> CMPC1;
	typedef cmpc_t<0x000A0CC0, peripheral::CMPC2, ICU::VECTOR::CMPC2> CMPC2;
	typedef cmpc_t<0x000A0C80, peripheral::CMPC3, ICU::VECTOR::CMPC3> CMPC3;
	typedef cmpc_t<0x000A0CA0, peripheral::CMPC4, ICU::VECTOR::CMPC4> CMPC4;
	typedef cmpc_t<0x000A0CC0, peripheral::CMPC5, ICU::VECTOR::CMPC5> CMPC5;
#endif
}
<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2008-2009, Image Engine Design Inc. All rights reserved.
//
//  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.
//
//     * Neither the name of Image Engine Design nor the names of any
//       other contributors to this software may be used to endorse or
//       promote products derived from this software without specific prior
//       written permission.
//
//  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 OWNER 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.
//
//////////////////////////////////////////////////////////////////////////

#ifndef IECORE_POLYGONALGO_INL
#define IECORE_POLYGONALGO_INL

#include "IECore/CircularIterator.h"

#include "OpenEXR/ImathVecAlgo.h"
#include "OpenEXR/ImathMath.h"

namespace IECore
{

template<typename Iterator>
typename std::iterator_traits<Iterator>::value_type polygonNormal( Iterator first, Iterator last )
{
	return polygonNormal( first, last, true );
}

template<typename Iterator>
typename std::iterator_traits<Iterator>::value_type polygonNormal( Iterator first, Iterator last, bool normalized )
{
	// Newell's method.
	typedef typename std::iterator_traits<Iterator>::value_type Vec;
	typedef CircularIterator<Iterator> CircularIt;

	Vec n( 0 );

	CircularIt v0It( first, last, first );
	CircularIt v1It( v0It ); v1It++;
	do
	{
		const Vec &v0 = *v0It;
		const Vec &v1 = *v1It;

		n.x += (v0.y - v1.y) * (v0.z + v1.z);
		n.y += (v0.z - v1.z) * (v0.x + v1.x);
		n.z += (v0.x - v1.x) * (v0.y + v1.y);

		v0It++;
		v1It++;
	}
	while( v0It != first );

	return normalized ? n.normalized() : n;
}

template<typename Iterator>
Winding polygonWinding( Iterator first, Iterator last )
{
	// 2d version.
	// calculate just the z coordinate of the normal using
	// newell's method.
	typedef typename std::iterator_traits<Iterator>::value_type Vec;
	typedef typename Vec::BaseType Real;
	typedef CircularIterator<Iterator> CircularIt;

	Real z( 0 );

	CircularIt v0It( first, last, first );
	CircularIt v1It( v0It ); v1It++;
	do
	{
		const Vec &v0 = *v0It;
		const Vec &v1 = *v1It;

		z += (v0.x - v1.x) * (v0.y + v1.y);

		v0It++;
		v1It++;
	}
	while( v0It != first );

	return z < Real( 0 ) ? ClockwiseWinding : CounterClockwiseWinding;
}

template<typename Iterator>
Winding polygonWinding( Iterator first, Iterator last, const typename std::iterator_traits<Iterator>::value_type &viewVector )
{
	typedef typename std::iterator_traits<Iterator>::value_type Vec;
	typedef typename Vec::BaseType Real;
	Real f = polygonNormal( first, last ).dot( viewVector );
	return f < Real( 0 ) ? CounterClockwiseWinding : ClockwiseWinding;
}

template<typename Iterator>
Imath::Box<typename std::iterator_traits<Iterator>::value_type> polygonBound( Iterator first, Iterator last )
{
	Imath::Box<typename std::iterator_traits<Iterator>::value_type> result;
	for( Iterator it=first; it!=last; it++ )
	{
		result.extendBy( *it );
	}
	return result;
}

template<typename Iterator>
typename std::iterator_traits<Iterator>::value_type::BaseType polygonArea( Iterator first, Iterator last )
{
	return polygonNormal( first, last, false ).length() / 2.0;
}

} // namespace IECore

#endif // IECORE_POLYGONALGO_INL
<commit_msg>Optimised polygonNormal and polygonWinding in PolygonAlgo.h.<commit_after>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2008-2009, Image Engine Design Inc. All rights reserved.
//
//  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.
//
//     * Neither the name of Image Engine Design nor the names of any
//       other contributors to this software may be used to endorse or
//       promote products derived from this software without specific prior
//       written permission.
//
//  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 OWNER 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.
//
//////////////////////////////////////////////////////////////////////////

#ifndef IECORE_POLYGONALGO_INL
#define IECORE_POLYGONALGO_INL

#include "IECore/CircularIterator.h"

#include "OpenEXR/ImathVecAlgo.h"
#include "OpenEXR/ImathMath.h"

namespace IECore
{

template<typename Iterator>
typename std::iterator_traits<Iterator>::value_type polygonNormal( Iterator first, Iterator last )
{
	return polygonNormal( first, last, true );
}

template<typename Iterator>
typename std::iterator_traits<Iterator>::value_type polygonNormal( Iterator first, Iterator last, bool normalized )
{
	// Newell's method.
	typedef typename std::iterator_traits<Iterator>::value_type Vec;
	typedef CircularIterator<Iterator> CircularIt;

	Vec n( 0 );

	CircularIt vIt( first, last, first );
	do
	{
		const Vec &v0 = *vIt; ++vIt;
		const Vec &v1 = *vIt;

		n.x += (v0.y - v1.y) * (v0.z + v1.z);
		n.y += (v0.z - v1.z) * (v0.x + v1.x);
		n.z += (v0.x - v1.x) * (v0.y + v1.y);
	}
	while( vIt != first );

	return normalized ? n.normalized() : n;
}

template<typename Iterator>
Winding polygonWinding( Iterator first, Iterator last )
{
	// 2d version.
	// calculate just the z coordinate of the normal using
	// newell's method.
	typedef typename std::iterator_traits<Iterator>::value_type Vec;
	typedef typename Vec::BaseType Real;
	typedef CircularIterator<Iterator> CircularIt;

	Real z( 0 );

	CircularIt vIt( first, last, first );
	do
	{
		const Vec &v0 = *vIt; ++vIt;
		const Vec &v1 = *vIt;

		z += (v0.x - v1.x) * (v0.y + v1.y);
	}
	while( vIt != first );

	return z < Real( 0 ) ? ClockwiseWinding : CounterClockwiseWinding;
}

template<typename Iterator>
Winding polygonWinding( Iterator first, Iterator last, const typename std::iterator_traits<Iterator>::value_type &viewVector )
{
	typedef typename std::iterator_traits<Iterator>::value_type Vec;
	typedef typename Vec::BaseType Real;
	Real f = polygonNormal( first, last ).dot( viewVector );
	return f < Real( 0 ) ? CounterClockwiseWinding : ClockwiseWinding;
}

template<typename Iterator>
Imath::Box<typename std::iterator_traits<Iterator>::value_type> polygonBound( Iterator first, Iterator last )
{
	Imath::Box<typename std::iterator_traits<Iterator>::value_type> result;
	for( Iterator it=first; it!=last; it++ )
	{
		result.extendBy( *it );
	}
	return result;
}

template<typename Iterator>
typename std::iterator_traits<Iterator>::value_type::BaseType polygonArea( Iterator first, Iterator last )
{
	return polygonNormal( first, last, false ).length() / 2.0;
}

} // namespace IECore

#endif // IECORE_POLYGONALGO_INL
<|endoftext|>


<commit_before>#include "logic.cpp"
#include <iostream>
#include <cstdlib>

int main( void );
void printCoords( block* );
int rotationTest( void );
void printBlock( block* );

int main( void )
{
  std::cout << "Rotation Test : " << (rotationTest())? "PASSED\n" : "FAILED\n";
  exit( EXIT_SUCCESS );
}

void printCoords( block *b )
{
  for( int i = 0; i < PIECES_PER_BLOCK; ++i )
    {
      std::cout << i << "(" << b->coord[i].x << "," << b->coord[i].y << ")" << std::endl;
    }
  std::cout << std::endl;
}

int rotationTest( void )
{
  bool success = true;
  for( int i = 0; i < NUM_TYPES_OF_BLOCKS; ++i )
    {
      auto b1 = new block( i );
      auto b2 = new block( i );;
      success = true;

      for( int j = 0; j < 4; ++j )
	{
	  b2->rotate();
	  printBlock( b2 );
	}
      for( int j = 0; j < 4; ++j )
	{
	  success = success && b1->coord[j].x == b2->coord[j].x && b1->coord[j].y == b2->coord[j].y;
	}

      std::cout << i << ": " << success << std::endl;

      delete b1;
    }

  return success;
}

void printBlock( block *b )
{
  for( int y = 20; y < 25; ++y )
    {
      for( int x = 4; x < 9; ++x )
	{
	  for( int i = 0; i < 4; ++i )
	    {
	      if( b->coord[i].x == x && b->coord[i].y == y)
		{
		  std::cout << "X";
		  break;
		} else if( i == 3 )
		{
		  std::cout << "_";
		}
	    }
	}
      std::cout << std::endl;
    }
  std::cout << std::endl;
}
<commit_msg>Update testing<commit_after>#include "logic.cpp"
#include <iostream>
#include <cstdlib>

int main( void );
void printCoords( block* );
bool rotationTest( bool );
void printBlock( block* );
bool collisionTest( bool );

int main( void ) //add verbosity flag
{
  bool rt;
  bool ct;

  bool verbose = true;

  std::cout << "Rotation Test : ";
  rt = rotateTest( verbose );

  std::cout << std::endl << "Collision Test : ";
  ct = collisionTest( verbose );

  std::cout << std::endl << "Overall results : " << std::endl;
  std::cout << "Rotation Test : " << rt ? "PASSED" : "FAILED" << std::endl;
  std::cout << "Collision Test : " << ct ? "PASSED" : "FAILED" << std::endl;

  exit( EXIT_SUCCESS );
}

void printCoords( block *b )
{
  for( int i = 0; i < PIECES_PER_BLOCK; ++i )
    {
      std::cout << i << "(" << b->coord[i].x << "," << b->coord[i].y << ")" << std::endl;
    }
  std::cout << std::endl;
}

bool rotationTest( bool verbose )
{
  bool success = true;
  for( int i = 0; i < NUM_TYPES_OF_BLOCKS; ++i )
    {
      auto b1 = new block( i );
      auto b2 = new block( i );;
      success = true;

      for( int j = 0; j < 4; ++j )
	{
	  b2->rotate();
	  if( verbose )
	    printBlock( b2 );
	}
      for( int j = 0; j < 4; ++j )
	{
	  success = success && b1->coord[j].x == b2->coord[j].x && b1->coord[j].y == b2->coord[j].y;
	}
      if( verbose )
	std::cout << i << ": " << success << std::endl;

      delete b1;
    }

  return success;
}

void printBlock( block *b )
{
  for( int y = 20; y < 25; ++y )
    {
      for( int x = 4; x < 9; ++x )
	{
	  for( int i = 0; i < 4; ++i )
	    {
	      if( b->coord[i].x == x && b->coord[i].y == y)
		{
		  std::cout << "X";
		  break;
		} else if( i == 3 )
		{
		  std::cout << "_";
		}
	    }
	}
      std::cout << std::endl;
    }
  std::cout << std::endl;
}

bool collisionTest( bool verbose )
{
  return false;
}
<|endoftext|>


<commit_before>/* -*- coding: utf-8; mode: c++; tab-width: 3; indent-tabs-mode: nil -*-

Copyright 2010, 2011, 2012, 2013, 2014, 2015
Raffaello D. Di Napoli

This file is part of Abaclade.

Abaclade is free software: you can redistribute it and/or modify it under the terms of the GNU
General Public License as published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

Abaclade 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 General
Public License for more details.

You should have received a copy of the GNU General Public License along with Abaclade. If not, see
<http://www.gnu.org/licenses/>.
--------------------------------------------------------------------------------------------------*/

#ifndef _ABACLADE_HXX_INTERNAL
   #error "Please #include <abaclade.hxx> instead of this file"
#endif

#if ABC_HOST_API_WIN32
   #include <abaclade/text/parsers/ansi_escape_sequences.hxx>
#endif

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::io::binary globals

namespace abc {
namespace io {
namespace binary {

namespace detail {

/*! Data collected by open() used to construct a file instance. This is only defined in file.cxx,
after the necessary header files have been included. */
struct file_init_data;

} //namespace detail

// Forward declarations.
class file_base;
class file_reader;
class file_writer;
class pipe_reader;
class pipe_writer;

/*! Opens a file for binary access.

@param op
   Path to the file.
@param am
   Desired access mode.
@param bAsync
   If true, the returned object will allow for I/O calls that leave the object in a “asynchronous
   operation pending” state.
@param bBypassCache
   If true, the OS will not cache any portion of the file; if false, accesses to the file will be
   backed by the OS file cache subsystem.
@return
   Pointer to a binary I/O object for the file.
*/
std::shared_ptr<file_base> open(
   os::path const & op, access_mode am, bool bAsync = false, bool bBypassCache = false
);

/*! Opens a file for binary reading.

@param op
   Path to the file.
@param bAsync
   If true, the returned object will allow for I/O calls that leave the object in a “asynchronous
   operation pending” state.
@param bBypassCache
   If true, the OS will not cache any portion of the file; if false, accesses to the file will be
   backed by the OS file cache subsystem.
@return
   Pointer to a binary reader for the file.
*/
inline std::shared_ptr<file_reader> open_reader(
   os::path const & op, bool bAsync = false, bool bBypassCache = false
) {
   return std::dynamic_pointer_cast<file_reader>(open(op, access_mode::read, bAsync, bBypassCache));
}

/*! Opens a file for binary writing.

@param op
   Path to the file.
@param bAsync
   If true, the returned object will allow for I/O calls that leave the object in a “asynchronous
   operation pending” state.
@param bBypassCache
   If true, the OS will not cache any portion of the file; if false, accesses to the file will be
   backed by the OS file cache subsystem.
@return
   Pointer to a binary writer for the file.
*/
inline std::shared_ptr<file_writer> open_writer(
   os::path const & op, bool bAsync = false, bool bBypassCache = false
) {
   return std::dynamic_pointer_cast<file_writer>(open(
      op, access_mode::write, bAsync, bBypassCache
   ));
}

/*! Creates a unidirectional pipe (FIFO), returning a reader and a writer connected to its ends.

@return
   A pair containing the reader end and the writer end of the pipe.
*/
ABACLADE_SYM std::pair<std::shared_ptr<pipe_reader>, std::shared_ptr<pipe_writer>> pipe(
   bool bAsync = false
);

/*! Returns the binary writer associated to the standard error output file (stderr).

@return
   Standard error file.
*/
ABACLADE_SYM std::shared_ptr<file_writer> stderr();

/*! Returns the binary reader associated to the standard input file (stdin).

@return
   Standard input file.
*/
ABACLADE_SYM std::shared_ptr<file_reader> stdin();

/*! Returns the binary writer associated to the standard output file (stdout).

@return
   Standard output file.
*/
ABACLADE_SYM std::shared_ptr<file_writer> stdout();

} //namespace binary
} //namespace io
} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::io::binary::base

namespace abc {
namespace io {
namespace binary {

//! Base interface for binary (non-text) I/O.
class ABACLADE_SYM base : public async {
public:
   //! Destructor. Also needed to make the class polymorphic (have a vtable).
   virtual ~base();
};

} //namespace binary
} //namespace io
} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::io::binary::reader

namespace abc {
namespace io {
namespace binary {

//! Interface for binary (non-text) input.
class ABACLADE_SYM reader : public virtual base {
public:
   /*! Reads at most cbMax bytes.

   @param p
      Address of the destination buffer.
   @param cbMax
      Size of the destination buffer, in bytes.
   @return
      Count of bytes read. For non-zero values of cbMax, a return value of 0 indicates that the end
      of the data (EOF) was reached.
   */
   virtual std::size_t read(void * p, std::size_t cbMax) = 0;
};

} //namespace binary
} //namespace io
} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::io::binary::writer

namespace abc {
namespace io {
namespace binary {

//! Interface for binary (non-text) output.
class ABACLADE_SYM writer : public virtual base {
public:
   //! Forces writing any data in the write buffer.
   virtual void flush() = 0;

   /*! Writes an array of bytes.

   @param p
      Address of the source buffer.
   @param cb
      Size of the source buffer, in bytes.
   @return
      Count of bytes written.
   */
   virtual std::size_t write(void const * p, std::size_t cb) = 0;
};

} //namespace binary
} //namespace io
} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::io::binary::seekable

namespace abc {
namespace io {
namespace binary {

//! Interface for binary I/O classes that allow random access (e.g. seek/tell operations).
class ABACLADE_SYM seekable {
public:
   /*! Changes the current read/write position.

   @param iOffset
      New position, relative to sfWhence.
   @param sfWhence
      Indicates what position iOffset is relative to.
   @return
      Resulting position.
   */
   virtual offset_t seek(offset_t ibOffset, seek_from sfWhence) = 0;

   /*! Returns the current read/write position.

   @return
      Current position.
   */
   virtual offset_t tell() const = 0;
};

} //namespace binary
} //namespace io
} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::io::binary::sized

namespace abc {
namespace io {
namespace binary {

//! Interface for binary I/O classes that access data with a known size.
class ABACLADE_SYM sized {
public:
   /*! Returns the size of the data.

   @return
      Data size, in bytes.
   */
   virtual full_size_t size() const = 0;
};

} //namespace binary
} //namespace io
} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////
<commit_msg>Add missing ABACLADE_SYM to abc::io::binary::open()<commit_after>/* -*- coding: utf-8; mode: c++; tab-width: 3; indent-tabs-mode: nil -*-

Copyright 2010, 2011, 2012, 2013, 2014, 2015
Raffaello D. Di Napoli

This file is part of Abaclade.

Abaclade is free software: you can redistribute it and/or modify it under the terms of the GNU
General Public License as published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

Abaclade 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 General
Public License for more details.

You should have received a copy of the GNU General Public License along with Abaclade. If not, see
<http://www.gnu.org/licenses/>.
--------------------------------------------------------------------------------------------------*/

#ifndef _ABACLADE_HXX_INTERNAL
   #error "Please #include <abaclade.hxx> instead of this file"
#endif

#if ABC_HOST_API_WIN32
   #include <abaclade/text/parsers/ansi_escape_sequences.hxx>
#endif

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::io::binary globals

namespace abc {
namespace io {
namespace binary {

namespace detail {

/*! Data collected by open() used to construct a file instance. This is only defined in file.cxx,
after the necessary header files have been included. */
struct file_init_data;

} //namespace detail

// Forward declarations.
class file_base;
class file_reader;
class file_writer;
class pipe_reader;
class pipe_writer;

/*! Opens a file for binary access.

@param op
   Path to the file.
@param am
   Desired access mode.
@param bAsync
   If true, the returned object will allow for I/O calls that leave the object in a “asynchronous
   operation pending” state.
@param bBypassCache
   If true, the OS will not cache any portion of the file; if false, accesses to the file will be
   backed by the OS file cache subsystem.
@return
   Pointer to a binary I/O object for the file.
*/
ABACLADE_SYM std::shared_ptr<file_base> open(
   os::path const & op, access_mode am, bool bAsync = false, bool bBypassCache = false
);

/*! Opens a file for binary reading.

@param op
   Path to the file.
@param bAsync
   If true, the returned object will allow for I/O calls that leave the object in a “asynchronous
   operation pending” state.
@param bBypassCache
   If true, the OS will not cache any portion of the file; if false, accesses to the file will be
   backed by the OS file cache subsystem.
@return
   Pointer to a binary reader for the file.
*/
inline std::shared_ptr<file_reader> open_reader(
   os::path const & op, bool bAsync = false, bool bBypassCache = false
) {
   return std::dynamic_pointer_cast<file_reader>(open(op, access_mode::read, bAsync, bBypassCache));
}

/*! Opens a file for binary writing.

@param op
   Path to the file.
@param bAsync
   If true, the returned object will allow for I/O calls that leave the object in a “asynchronous
   operation pending” state.
@param bBypassCache
   If true, the OS will not cache any portion of the file; if false, accesses to the file will be
   backed by the OS file cache subsystem.
@return
   Pointer to a binary writer for the file.
*/
inline std::shared_ptr<file_writer> open_writer(
   os::path const & op, bool bAsync = false, bool bBypassCache = false
) {
   return std::dynamic_pointer_cast<file_writer>(open(
      op, access_mode::write, bAsync, bBypassCache
   ));
}

/*! Creates a unidirectional pipe (FIFO), returning a reader and a writer connected to its ends.

@return
   A pair containing the reader end and the writer end of the pipe.
*/
ABACLADE_SYM std::pair<std::shared_ptr<pipe_reader>, std::shared_ptr<pipe_writer>> pipe(
   bool bAsync = false
);

/*! Returns the binary writer associated to the standard error output file (stderr).

@return
   Standard error file.
*/
ABACLADE_SYM std::shared_ptr<file_writer> stderr();

/*! Returns the binary reader associated to the standard input file (stdin).

@return
   Standard input file.
*/
ABACLADE_SYM std::shared_ptr<file_reader> stdin();

/*! Returns the binary writer associated to the standard output file (stdout).

@return
   Standard output file.
*/
ABACLADE_SYM std::shared_ptr<file_writer> stdout();

} //namespace binary
} //namespace io
} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::io::binary::base

namespace abc {
namespace io {
namespace binary {

//! Base interface for binary (non-text) I/O.
class ABACLADE_SYM base : public async {
public:
   //! Destructor. Also needed to make the class polymorphic (have a vtable).
   virtual ~base();
};

} //namespace binary
} //namespace io
} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::io::binary::reader

namespace abc {
namespace io {
namespace binary {

//! Interface for binary (non-text) input.
class ABACLADE_SYM reader : public virtual base {
public:
   /*! Reads at most cbMax bytes.

   @param p
      Address of the destination buffer.
   @param cbMax
      Size of the destination buffer, in bytes.
   @return
      Count of bytes read. For non-zero values of cbMax, a return value of 0 indicates that the end
      of the data (EOF) was reached.
   */
   virtual std::size_t read(void * p, std::size_t cbMax) = 0;
};

} //namespace binary
} //namespace io
} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::io::binary::writer

namespace abc {
namespace io {
namespace binary {

//! Interface for binary (non-text) output.
class ABACLADE_SYM writer : public virtual base {
public:
   //! Forces writing any data in the write buffer.
   virtual void flush() = 0;

   /*! Writes an array of bytes.

   @param p
      Address of the source buffer.
   @param cb
      Size of the source buffer, in bytes.
   @return
      Count of bytes written.
   */
   virtual std::size_t write(void const * p, std::size_t cb) = 0;
};

} //namespace binary
} //namespace io
} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::io::binary::seekable

namespace abc {
namespace io {
namespace binary {

//! Interface for binary I/O classes that allow random access (e.g. seek/tell operations).
class ABACLADE_SYM seekable {
public:
   /*! Changes the current read/write position.

   @param iOffset
      New position, relative to sfWhence.
   @param sfWhence
      Indicates what position iOffset is relative to.
   @return
      Resulting position.
   */
   virtual offset_t seek(offset_t ibOffset, seek_from sfWhence) = 0;

   /*! Returns the current read/write position.

   @return
      Current position.
   */
   virtual offset_t tell() const = 0;
};

} //namespace binary
} //namespace io
} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::io::binary::sized

namespace abc {
namespace io {
namespace binary {

//! Interface for binary I/O classes that access data with a known size.
class ABACLADE_SYM sized {
public:
   /*! Returns the size of the data.

   @return
      Data size, in bytes.
   */
   virtual full_size_t size() const = 0;
};

} //namespace binary
} //namespace io
} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////
<|endoftext|>