<commit_before>#ifndef RPT_XMLMASTERFIELDS_HXX
#define RPT_XMLMASTERFIELDS_HXX
/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: xmlMasterFields.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: rt $ $Date: 2007-07-09 11:56:18 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _XMLOFF_XMLICTXT_HXX
#include <xmloff/xmlictxt.hxx>
#endif
namespace rptxml
{
    class ORptFilter;
    class OXMLSubDocument;
    class OXMLMasterFields : public SvXMLImportContext
    {
        OXMLSubDocument* m_pSubDocument;
        OXMLMasterFields(const OXMLMasterFields&);
        void operator =(const OXMLMasterFields&);
    public:

        OXMLMasterFields( ORptFilter& rImport, sal_uInt16 nPrfx,
                    const ::rtl::OUString& rLName,
                    const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList > & xAttrList
                    ,OXMLSubDocument* _pSubDocument);
        virtual ~OXMLMasterFields();

        virtual SvXMLImportContext *CreateChildContext( sal_uInt16 nPrefix,
                    const ::rtl::OUString& rLocalName,
                    const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList > & xAttrList );

    };
// -----------------------------------------------------------------------------
} // namespace rptxml
// -----------------------------------------------------------------------------

#endif // RPT_XMLMasterFields_HXX
<commit_msg>INTEGRATION: CWS rptchart01_DEV300 (1.2.70); FILE MERGED 2008/02/13 07:11:53 oj 1.2.70.2: #i85225# impl chart readhandler and oleproducer 2008/01/25 13:56:00 oj 1.2.70.1: #i85225# export master detail different now<commit_after>#ifndef RPT_XMLMASTERFIELDS_HXX
#define RPT_XMLMASTERFIELDS_HXX
/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: xmlMasterFields.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: kz $ $Date: 2008-03-05 18:04:30 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _XMLOFF_XMLICTXT_HXX
#include <xmloff/xmlictxt.hxx>
#endif
namespace rptxml
{
    class ORptFilter;
    class IMasterDetailFieds;
    class OXMLMasterFields : public SvXMLImportContext
    {
        IMasterDetailFieds* m_pReport;
        OXMLMasterFields(const OXMLMasterFields&);
        void operator =(const OXMLMasterFields&);
    public:

        OXMLMasterFields( ORptFilter& rImport, sal_uInt16 nPrfx,
                    const ::rtl::OUString& rLName,
                    const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList > & xAttrList
                    ,IMasterDetailFieds* _pReport);
        virtual ~OXMLMasterFields();

        virtual SvXMLImportContext *CreateChildContext( sal_uInt16 nPrefix,
                    const ::rtl::OUString& rLocalName,
                    const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList > & xAttrList );

    };
// -----------------------------------------------------------------------------
} // namespace rptxml
// -----------------------------------------------------------------------------

#endif // RPT_XMLMasterFields_HXX
<|endoftext|>


<commit_before>#include "rosplan_knowledge_base/KnowledgeComparitor.h"

#include <boost/algorithm/string.hpp>

/* implementation of KnowledgeComparitor.h */
namespace KCL_rosplan {

	/**
	 * returns true iff a matches the knowledge in b.
	 */
	bool KnowledgeComparitor::containsKnowledge(const rosplan_knowledge_msgs::KnowledgeItem &a, const rosplan_knowledge_msgs::KnowledgeItem &b) {

		int matches = 0;
		if(a.knowledge_type != b.knowledge_type) return false;

		if(a.knowledge_type == rosplan_knowledge_msgs::KnowledgeItem::INSTANCE) {

			// check instance knowledge
			if(0!=a.instance_type.compare(b.instance_type)) return false;
			if(a.instance_name!="" && !boost::iequals(a.instance_name, b.instance_name)) return false;
			return true;

		} else {

			// check fact or function
			if(a.attribute_name=="") return true;

			if(!boost::iequals(a.attribute_name, b.attribute_name)) return false;
			if(a.is_negative != b.is_negative) return false;
			if(a.values.size() != b.values.size()) return false;

			for(size_t i=0;i<a.values.size();i++) {

				// don't care about this parameter
				if("" == a.values[i].value) {
					++matches;
					continue;
				}

				// find matching object in parameters of b
				for(size_t j=0;j<b.values.size();j++) {
					if( boost::iequals(a.values[i].key, b.values[j].key) &&
						boost::iequals(a.values[i].value, b.values[j].value)) {
						++matches;
						break;
					}
				}
			}
		}
		return (matches == a.values.size());
	}

	/**
	 * returns true is the knowledge item contains the instance, as instance or attribute parameter.
	 */
	bool KnowledgeComparitor::containsInstance(const rosplan_knowledge_msgs::KnowledgeItem &a, std::string &name) {

		if(0==a.instance_name.compare(name))
			return true;

		for(size_t i=0;i<a.values.size();i++) {
			if(boost::iequals(a.values[i].value, name))
				return true;
		}

		return false;
	}

} // close namespace
<commit_msg>Relaxed the knowledge comparitor, given PDDL parameters have a fixed order.<commit_after>#include "rosplan_knowledge_base/KnowledgeComparitor.h"

#include <boost/algorithm/string.hpp>

/* implementation of KnowledgeComparitor.h */
namespace KCL_rosplan {

	/**
	 * returns true iff a matches the knowledge in b.
	 */
	bool KnowledgeComparitor::containsKnowledge(const rosplan_knowledge_msgs::KnowledgeItem &a, const rosplan_knowledge_msgs::KnowledgeItem &b) {

		int matches = 0;
		if(a.knowledge_type != b.knowledge_type) return false;

		if(a.knowledge_type == rosplan_knowledge_msgs::KnowledgeItem::INSTANCE) {

			// check instance knowledge
			if(0!=a.instance_type.compare(b.instance_type)) return false;
			if(a.instance_name!="" && !boost::iequals(a.instance_name, b.instance_name)) return false;
			return true;

		} else {

			// check fact or function
			if(a.attribute_name=="") return true;

			if(!boost::iequals(a.attribute_name, b.attribute_name)) return false;
			if(a.is_negative != b.is_negative) return false;
			if(a.values.size() != b.values.size()) return false;

			for(size_t i=0;i<a.values.size();i++) {

				if("" == a.values[i].value) {
					// don't care about this parameter
					++matches;
				} else if(boost::iequals(a.values[i].value, b.values[i].value)) {
					++matches;
				}
			}
		}
		return (matches == a.values.size());
	}

	/**
	 * returns true is the knowledge item contains the instance, as instance or attribute parameter.
	 */
	bool KnowledgeComparitor::containsInstance(const rosplan_knowledge_msgs::KnowledgeItem &a, std::string &name) {

		if(0==a.instance_name.compare(name))
			return true;

		for(size_t i=0;i<a.values.size();i++) {
			if(boost::iequals(a.values[i].value, name))
				return true;
		}

		return false;
	}

} // close namespace
<|endoftext|>


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

#if defined(HAVE_CONFIG_H)
#include <config/bitcoin-config.h>
#endif

#include <qt/addressbookpage.h>
#include <qt/forms/ui_addressbookpage.h>

#include <qt/addresstablemodel.h>
#include <qt/bitcoingui.h>
#include <qt/csvmodelwriter.h>
#include <qt/editaddressdialog.h>
#include <qt/guiutil.h>
#include <qt/platformstyle.h>

#include <QIcon>
#include <QMenu>
#include <QMessageBox>
#include <QSortFilterProxyModel>

AddressBookPage::AddressBookPage(const PlatformStyle *platformStyle, Mode _mode, Tabs _tab, QWidget *parent) :
    QDialog(parent),
    ui(new Ui::AddressBookPage),
    model(0),
    mode(_mode),
    tab(_tab)
{
    ui->setupUi(this);

    if (!platformStyle->getImagesOnButtons()) {
        ui->newAddress->setIcon(QIcon());
        ui->copyAddress->setIcon(QIcon());
        ui->deleteAddress->setIcon(QIcon());
        ui->exportButton->setIcon(QIcon());
    } else {
        ui->newAddress->setIcon(platformStyle->SingleColorIcon(":/icons/add"));
        ui->copyAddress->setIcon(platformStyle->SingleColorIcon(":/icons/editcopy"));
        ui->deleteAddress->setIcon(platformStyle->SingleColorIcon(":/icons/remove"));
        ui->exportButton->setIcon(platformStyle->SingleColorIcon(":/icons/export"));
    }

    switch(mode)
    {
    case ForSelection:
        switch(tab)
        {
        case SendingTab: setWindowTitle(tr("Choose the address to send coins to")); break;
        case ReceivingTab: setWindowTitle(tr("Choose the address to receive coins with")); break;
        }
        connect(ui->tableView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(accept()));
        ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
        ui->tableView->setFocus();
        ui->closeButton->setText(tr("C&hoose"));
        ui->exportButton->hide();
        break;
    case ForEditing:
        switch(tab)
        {
        case SendingTab: setWindowTitle(tr("Sending addresses")); break;
        case ReceivingTab: setWindowTitle(tr("Receiving addresses")); break;
        }
        break;
    }
    switch(tab)
    {
    case SendingTab:
        ui->labelExplanation->setText(tr("These are your DeepOnion addresses for sending payments. Always check the amount and the receiving address before sending coins."));
        ui->deleteAddress->setVisible(true);
        break;
    case ReceivingTab:
        ui->labelExplanation->setText(tr("These are your DeepOnion addresses for receiving payments. It is recommended to use a new receiving address for each transaction."));
        ui->deleteAddress->setVisible(false);
        break;
    }

    // Context menu actions
    QAction *copyAddressAction = new QAction(tr("&Copy Address"), this);
    QAction *copyLabelAction = new QAction(tr("Copy &Label"), this);
    QAction *editAction = new QAction(tr("&Edit"), this);
    deleteAction = new QAction(ui->deleteAddress->text(), this);

    // Build context menu
    contextMenu = new QMenu(this);
    contextMenu->addAction(copyAddressAction);
    contextMenu->addAction(copyLabelAction);
    contextMenu->addAction(editAction);
    if(tab == SendingTab)
        contextMenu->addAction(deleteAction);
    contextMenu->addSeparator();

    // Connect signals for context menu actions
    connect(copyAddressAction, SIGNAL(triggered()), this, SLOT(on_copyAddress_clicked()));
    connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(onCopyLabelAction()));
    connect(editAction, SIGNAL(triggered()), this, SLOT(onEditAction()));
    connect(deleteAction, SIGNAL(triggered()), this, SLOT(on_deleteAddress_clicked()));

    connect(ui->tableView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextualMenu(QPoint)));

    connect(ui->closeButton, SIGNAL(clicked()), this, SLOT(accept()));
}

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

void AddressBookPage::setModel(AddressTableModel *_model)
{
    this->model = _model;
    if(!_model)
        return;

    proxyModel = new QSortFilterProxyModel(this);
    proxyModel->setSourceModel(_model);
    proxyModel->setDynamicSortFilter(true);
    proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
    proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
    switch(tab)
    {
    case ReceivingTab:
        // Receive filter
        proxyModel->setFilterRole(AddressTableModel::TypeRole);
        proxyModel->setFilterFixedString(AddressTableModel::Receive);
        break;
    case SendingTab:
        // Send filter
        proxyModel->setFilterRole(AddressTableModel::TypeRole);
        proxyModel->setFilterFixedString(AddressTableModel::Send);
        break;
    }
    ui->tableView->setModel(proxyModel);
    ui->tableView->sortByColumn(0, Qt::AscendingOrder);

    // Set column widths
#if QT_VERSION < 0x050000
    ui->tableView->horizontalHeader()->setResizeMode(AddressTableModel::Label, QHeaderView::Stretch);
    ui->tableView->horizontalHeader()->setResizeMode(AddressTableModel::Address, QHeaderView::ResizeToContents);
#else
    ui->tableView->horizontalHeader()->setSectionResizeMode(AddressTableModel::Label, QHeaderView::Stretch);
    ui->tableView->horizontalHeader()->setSectionResizeMode(AddressTableModel::Address, QHeaderView::ResizeToContents);
#endif

    connect(ui->tableView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
        this, SLOT(selectionChanged()));

    // Select row for newly created address
    connect(_model, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(selectNewAddress(QModelIndex,int,int)));

    selectionChanged();
}

void AddressBookPage::on_copyAddress_clicked()
{
    GUIUtil::copyEntryData(ui->tableView, AddressTableModel::Address);
}

void AddressBookPage::onCopyLabelAction()
{
    GUIUtil::copyEntryData(ui->tableView, AddressTableModel::Label);
}

void AddressBookPage::onEditAction()
{
    if(!model)
        return;

    if(!ui->tableView->selectionModel())
        return;
    QModelIndexList indexes = ui->tableView->selectionModel()->selectedRows();
    if(indexes.isEmpty())
        return;

    EditAddressDialog dlg(
        tab == SendingTab ?
        EditAddressDialog::EditSendingAddress :
        EditAddressDialog::EditReceivingAddress, this);
    dlg.setModel(model);
    QModelIndex origIndex = proxyModel->mapToSource(indexes.at(0));
    dlg.loadRow(origIndex.row());
    dlg.exec();
}

void AddressBookPage::on_newAddress_clicked()
{
    if(!model)
        return;

    EditAddressDialog dlg(
        tab == SendingTab ?
        EditAddressDialog::NewSendingAddress :
        EditAddressDialog::NewReceivingAddress, this);
    dlg.setModel(model);
    if(dlg.exec())
    {
        newAddressToSelect = dlg.getAddress();
    }
}

void AddressBookPage::on_deleteAddress_clicked()
{
    QTableView *table = ui->tableView;
    if(!table->selectionModel())
        return;

    QModelIndexList indexes = table->selectionModel()->selectedRows();
    if(!indexes.isEmpty())
    {
        table->model()->removeRow(indexes.at(0).row());
    }
}

void AddressBookPage::selectionChanged()
{
    // Set button states based on selected tab and selection
    QTableView *table = ui->tableView;
    if(!table->selectionModel())
        return;

    if(table->selectionModel()->hasSelection())
    {
        switch(tab)
        {
        case SendingTab:
            // In sending tab, allow deletion of selection
            ui->deleteAddress->setEnabled(true);
            ui->deleteAddress->setVisible(true);
            deleteAction->setEnabled(true);
            break;
        case ReceivingTab:
            // Deleting receiving addresses, however, is not allowed
            ui->deleteAddress->setEnabled(false);
            ui->deleteAddress->setVisible(false);
            deleteAction->setEnabled(false);
            break;
        }
        ui->copyAddress->setEnabled(true);
    }
    else
    {
        ui->deleteAddress->setEnabled(false);
        ui->copyAddress->setEnabled(false);
    }
}

void AddressBookPage::done(int retval)
{
    QTableView *table = ui->tableView;
    if(!table->selectionModel() || !table->model())
        return;

    // Figure out which address was selected, and return it
    QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address);

    for (const QModelIndex& index : indexes) {
        QVariant address = table->model()->data(index);
        returnValue = address.toString();
    }

    if(returnValue.isEmpty())
    {
        // If no address entry selected, return rejected
        retval = Rejected;
    }

    QDialog::done(retval);
}

void AddressBookPage::on_exportButton_clicked()
{
    // CSV is currently the only supported format
    QString filename = GUIUtil::getSaveFileName(this,
        tr("Export Address List"), QString(),
        tr("Comma separated file (*.csv)"), nullptr);

    if (filename.isNull())
        return;

    CSVModelWriter writer(filename);

    // name, column, role
    writer.setModel(proxyModel);
    writer.addColumn("Label", AddressTableModel::Label, Qt::EditRole);
    writer.addColumn("Address", AddressTableModel::Address, Qt::EditRole);

    if(!writer.write()) {
        QMessageBox::critical(this, tr("Exporting Failed"),
            tr("There was an error trying to save the address list to %1. Please try again.").arg(filename));
    }
}

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

void AddressBookPage::selectNewAddress(const QModelIndex &parent, int begin, int /*end*/)
{
    QModelIndex idx = proxyModel->mapFromSource(model->index(begin, AddressTableModel::Address, parent));
    if(idx.isValid() && (idx.data(Qt::EditRole).toString() == newAddressToSelect))
    {
        // Select row of newly created address, once
        ui->tableView->setFocus();
        ui->tableView->selectRow(idx.row());
        newAddressToSelect.clear();
    }
}

void AddressBookPage::refreshStyle()
{

}

<commit_msg>Styled up the addressbook<commit_after>// Copyright (c) 2011-2017 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#if defined(HAVE_CONFIG_H)
#include <config/bitcoin-config.h>
#endif

#include <qt/addressbookpage.h>
#include <qt/forms/ui_addressbookpage.h>

#include <qt/addresstablemodel.h>
#include <qt/bitcoingui.h>
#include <qt/csvmodelwriter.h>
#include <qt/editaddressdialog.h>
#include <qt/guiutil.h>
#include <qt/platformstyle.h>

#include <QIcon>
#include <QMenu>
#include <QMessageBox>
#include <QSortFilterProxyModel>

AddressBookPage::AddressBookPage(const PlatformStyle *platformStyle, Mode _mode, Tabs _tab, QWidget *parent) :
    QDialog(parent),
    ui(new Ui::AddressBookPage),
    model(0),
    mode(_mode),
    tab(_tab)
{
    ui->setupUi(this);

    if (!platformStyle->getImagesOnButtons()) {
        ui->newAddress->setIcon(QIcon());
        ui->copyAddress->setIcon(QIcon());
        ui->deleteAddress->setIcon(QIcon());
        ui->exportButton->setIcon(QIcon());
    } else {
        ui->newAddress->setIcon(platformStyle->SingleColorIcon(":/icons/add"));
        ui->copyAddress->setIcon(platformStyle->SingleColorIcon(":/icons/editcopy"));
        ui->deleteAddress->setIcon(platformStyle->SingleColorIcon(":/icons/remove"));
        ui->exportButton->setIcon(platformStyle->SingleColorIcon(":/icons/export"));
    }

    switch(mode)
    {
    case ForSelection:
        switch(tab)
        {
        case SendingTab: setWindowTitle(tr("Choose the address to send coins to")); break;
        case ReceivingTab: setWindowTitle(tr("Choose the address to receive coins with")); break;
        }
        connect(ui->tableView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(accept()));
        ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
        ui->tableView->setFocus();
        ui->closeButton->setText(tr("C&hoose"));
        ui->exportButton->hide();
        break;
    case ForEditing:
        switch(tab)
        {
        case SendingTab: setWindowTitle(tr("Sending addresses")); break;
        case ReceivingTab: setWindowTitle(tr("Receiving addresses")); break;
        }
        break;
    }
    switch(tab)
    {
    case SendingTab:
        ui->labelExplanation->setText(tr("These are your DeepOnion addresses for sending payments. Always check the amount and the receiving address before sending coins."));
        ui->deleteAddress->setVisible(true);
        break;
    case ReceivingTab:
        ui->labelExplanation->setText(tr("These are your DeepOnion addresses for receiving payments. It is recommended to use a new receiving address for each transaction."));
        ui->deleteAddress->setVisible(false);
        break;
    }

    //DeepOnion: Theme
    ui->tableView->setStyleSheet(platformStyle->getThemeManager()->getCurrent()->getQTableGeneralStyle());
    ui->tableView->horizontalHeader()->setStyleSheet(platformStyle->getThemeManager()->getCurrent()->getQListHeaderGeneralStyle());

    // Context menu actions
    QAction *copyAddressAction = new QAction(tr("&Copy Address"), this);
    QAction *copyLabelAction = new QAction(tr("Copy &Label"), this);
    QAction *editAction = new QAction(tr("&Edit"), this);
    deleteAction = new QAction(ui->deleteAddress->text(), this);

    // Build context menu
    contextMenu = new QMenu(this);
    contextMenu->addAction(copyAddressAction);
    contextMenu->addAction(copyLabelAction);
    contextMenu->addAction(editAction);
    if(tab == SendingTab)
        contextMenu->addAction(deleteAction);
    contextMenu->addSeparator();

    // Connect signals for context menu actions
    connect(copyAddressAction, SIGNAL(triggered()), this, SLOT(on_copyAddress_clicked()));
    connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(onCopyLabelAction()));
    connect(editAction, SIGNAL(triggered()), this, SLOT(onEditAction()));
    connect(deleteAction, SIGNAL(triggered()), this, SLOT(on_deleteAddress_clicked()));

    connect(ui->tableView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextualMenu(QPoint)));

    connect(ui->closeButton, SIGNAL(clicked()), this, SLOT(accept()));
}

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

void AddressBookPage::setModel(AddressTableModel *_model)
{
    this->model = _model;
    if(!_model)
        return;

    proxyModel = new QSortFilterProxyModel(this);
    proxyModel->setSourceModel(_model);
    proxyModel->setDynamicSortFilter(true);
    proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
    proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
    switch(tab)
    {
    case ReceivingTab:
        // Receive filter
        proxyModel->setFilterRole(AddressTableModel::TypeRole);
        proxyModel->setFilterFixedString(AddressTableModel::Receive);
        break;
    case SendingTab:
        // Send filter
        proxyModel->setFilterRole(AddressTableModel::TypeRole);
        proxyModel->setFilterFixedString(AddressTableModel::Send);
        break;
    }
    ui->tableView->setModel(proxyModel);
    ui->tableView->sortByColumn(0, Qt::AscendingOrder);

    // Set column widths
#if QT_VERSION < 0x050000
    ui->tableView->horizontalHeader()->setResizeMode(AddressTableModel::Label, QHeaderView::Stretch);
    ui->tableView->horizontalHeader()->setResizeMode(AddressTableModel::Address, QHeaderView::ResizeToContents);
#else
    ui->tableView->horizontalHeader()->setSectionResizeMode(AddressTableModel::Label, QHeaderView::Stretch);
    ui->tableView->horizontalHeader()->setSectionResizeMode(AddressTableModel::Address, QHeaderView::ResizeToContents);
#endif

    connect(ui->tableView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
        this, SLOT(selectionChanged()));

    // Select row for newly created address
    connect(_model, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(selectNewAddress(QModelIndex,int,int)));

    selectionChanged();
}

void AddressBookPage::on_copyAddress_clicked()
{
    GUIUtil::copyEntryData(ui->tableView, AddressTableModel::Address);
}

void AddressBookPage::onCopyLabelAction()
{
    GUIUtil::copyEntryData(ui->tableView, AddressTableModel::Label);
}

void AddressBookPage::onEditAction()
{
    if(!model)
        return;

    if(!ui->tableView->selectionModel())
        return;
    QModelIndexList indexes = ui->tableView->selectionModel()->selectedRows();
    if(indexes.isEmpty())
        return;

    EditAddressDialog dlg(
        tab == SendingTab ?
        EditAddressDialog::EditSendingAddress :
        EditAddressDialog::EditReceivingAddress, this);
    dlg.setModel(model);
    QModelIndex origIndex = proxyModel->mapToSource(indexes.at(0));
    dlg.loadRow(origIndex.row());
    dlg.exec();
}

void AddressBookPage::on_newAddress_clicked()
{
    if(!model)
        return;

    EditAddressDialog dlg(
        tab == SendingTab ?
        EditAddressDialog::NewSendingAddress :
        EditAddressDialog::NewReceivingAddress, this);
    dlg.setModel(model);
    if(dlg.exec())
    {
        newAddressToSelect = dlg.getAddress();
    }
}

void AddressBookPage::on_deleteAddress_clicked()
{
    QTableView *table = ui->tableView;
    if(!table->selectionModel())
        return;

    QModelIndexList indexes = table->selectionModel()->selectedRows();
    if(!indexes.isEmpty())
    {
        table->model()->removeRow(indexes.at(0).row());
    }
}

void AddressBookPage::selectionChanged()
{
    // Set button states based on selected tab and selection
    QTableView *table = ui->tableView;
    if(!table->selectionModel())
        return;

    if(table->selectionModel()->hasSelection())
    {
        switch(tab)
        {
        case SendingTab:
            // In sending tab, allow deletion of selection
            ui->deleteAddress->setEnabled(true);
            ui->deleteAddress->setVisible(true);
            deleteAction->setEnabled(true);
            break;
        case ReceivingTab:
            // Deleting receiving addresses, however, is not allowed
            ui->deleteAddress->setEnabled(false);
            ui->deleteAddress->setVisible(false);
            deleteAction->setEnabled(false);
            break;
        }
        ui->copyAddress->setEnabled(true);
    }
    else
    {
        ui->deleteAddress->setEnabled(false);
        ui->copyAddress->setEnabled(false);
    }
}

void AddressBookPage::done(int retval)
{
    QTableView *table = ui->tableView;
    if(!table->selectionModel() || !table->model())
        return;

    // Figure out which address was selected, and return it
    QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address);

    for (const QModelIndex& index : indexes) {
        QVariant address = table->model()->data(index);
        returnValue = address.toString();
    }

    if(returnValue.isEmpty())
    {
        // If no address entry selected, return rejected
        retval = Rejected;
    }

    QDialog::done(retval);
}

void AddressBookPage::on_exportButton_clicked()
{
    // CSV is currently the only supported format
    QString filename = GUIUtil::getSaveFileName(this,
        tr("Export Address List"), QString(),
        tr("Comma separated file (*.csv)"), nullptr);

    if (filename.isNull())
        return;

    CSVModelWriter writer(filename);

    // name, column, role
    writer.setModel(proxyModel);
    writer.addColumn("Label", AddressTableModel::Label, Qt::EditRole);
    writer.addColumn("Address", AddressTableModel::Address, Qt::EditRole);

    if(!writer.write()) {
        QMessageBox::critical(this, tr("Exporting Failed"),
            tr("There was an error trying to save the address list to %1. Please try again.").arg(filename));
    }
}

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

void AddressBookPage::selectNewAddress(const QModelIndex &parent, int begin, int /*end*/)
{
    QModelIndex idx = proxyModel->mapFromSource(model->index(begin, AddressTableModel::Address, parent));
    if(idx.isValid() && (idx.data(Qt::EditRole).toString() == newAddressToSelect))
    {
        // Select row of newly created address, once
        ui->tableView->setFocus();
        ui->tableView->selectRow(idx.row());
        newAddressToSelect.clear();
    }
}

void AddressBookPage::refreshStyle()
{

}

<|endoftext|>


<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>

#include "json/json_spirit_writer_template.h"
#include "json/json_spirit_utils.h"

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)
{
    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())
        strHTML += "" + tr("Source") + ": " + tr("Generated, PoS") + "
";

    // 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>Fix strHTML properly this time.<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>

#include "json/json_spirit_writer_template.h"
#include "json/json_spirit_utils.h"

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)
{
    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())
        strHTML += "" + tr("Source") + ": " + tr("Generated, PoS") + "
";

    // 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>#pragma once

#include <algorithm>
#include <limits>
#include <vector>

#include "physics/continuous_trajectory.hpp"
#include "quantities/si.hpp"
#include "testing_utilities/numerics.hpp"

namespace principia {

using si::Metre;
using si::Second;
using testing_utilities::ULPDistance;

namespace physics {

namespace {

int const kMaxDegree = 17;
int const kMinDegree = 3;
int const kMaxDegreeAge = 100;

// Only supports 8 divisions for now.
int const kDivisions = 8;

template<typename T>
std::string VectorDebugString(std::vector<T> const& v) {
  std::string debug_string;
  for (int i = 0; i < v.size(); ++i) {
    if (i > 0) {
      debug_string.append(", ");
    }
    debug_string.append("[");
    debug_string.append(std::to_string(i));
    debug_string.append("] = ");
    debug_string.append(DebugString(v[i]));
  }
  return debug_string;
}

}  // namespace

template<typename Frame>
ContinuousTrajectory<Frame>::ContinuousTrajectory(Time const& step,
                                                  Length const& tolerance)
    : step_(step),
      tolerance_(tolerance),
      adjusted_tolerance_(tolerance_),
      is_unstable_(false),
      degree_(kMinDegree),
      degree_age_(0) {
  CHECK_LT(0 * Metre, tolerance_);
}

template<typename Frame>
bool ContinuousTrajectory<Frame>::empty() const {
  return series_.empty();
}

template<typename Frame>
Instant ContinuousTrajectory<Frame>::t_min() const {
  if (empty()) {
    return Instant(std::numeric_limits<double>::infinity() * Second);
  }
  return *first_time_;
}

template<typename Frame>
Instant ContinuousTrajectory<Frame>::t_max() const {
  if (empty()) {
    return Instant(-std::numeric_limits<double>::infinity() * Second);
  }
  return series_.back().t_max();
}

template<typename Frame>
void ContinuousTrajectory<Frame>::Append(
    Instant const& time,
    DegreesOfFreedom<Frame> const& degrees_of_freedom) {
  // Consistency checks.
  if (first_time_ == nullptr) {
    first_time_ = std::make_unique<Instant>(time);
  } else {
    Instant const t0;
    CHECK_GE(1,
             ULPDistance((last_points_.back().first + step_ - t0) /
                             SIUnit<Time>(),
                         (time - t0) / SIUnit<Time>()))
        << "Append at times that are not equally spaced";
  }

  if (last_points_.size() == kDivisions) {
    // These vectors are static to avoid deallocation/reallocation each time we
    // go through this code path.
    static std::vector<Displacement<Frame>> q(kDivisions + 1);
    static std::vector<Velocity<Frame>> v(kDivisions + 1);
    q.clear();
    v.clear();

    for (auto const& pair : last_points_) {
      DegreesOfFreedom<Frame> const& degrees_of_freedom = pair.second;
      q.push_back(degrees_of_freedom.position() - Frame::origin);
      v.push_back(degrees_of_freedom.velocity());
    }
    q.push_back(degrees_of_freedom.position() - Frame::origin);
    v.push_back(degrees_of_freedom.velocity());

    ComputeBestNewhallApproximation(
        time, q, v, &ЧебышёвSeries<Displacement<Frame>>::NewhallApproximation);

    // Wipe-out the points that have just been incorporated in a series.
    last_points_.clear();
  }

  // Note that we only insert the new point in the map *after* computing the
  // approximation, because clearing the map is much more efficient than erasing
  // every element but one.
  last_points_.emplace_back(time, degrees_of_freedom);
}

template<typename Frame>
void ContinuousTrajectory<Frame>::ForgetAfter(
    Instant const & time,
    DegreesOfFreedom<Frame> const & degrees_of_freedom) {
  if (time > t_max()) {
    return;
  }
  auto it = FindSeriesForInstant(time);
  if (it != series_.end()) {
    CHECK_EQ(time, it->t_max());
    last_points_.clear();
    last_points_.emplace_back(time, degrees_of_freedom);
    series_.erase(++it, series_.end());
  }
}

template<typename Frame>
void ContinuousTrajectory<Frame>::ForgetBefore(Instant const& time) {
  if (time < t_min()) {
    // TODO(phl): test for this case, it yielded a check failure in
    // |FindSeriesForInstant|.
    return;
  }
  series_.erase(series_.begin(), FindSeriesForInstant(time));

  // If there are no |series_| left, clear everything.  Otherwise, update the
  // first time.
  if (series_.empty()) {
    first_time_.reset();
    last_points_.clear();
  } else {
    *first_time_ = time;
  }
}

template<typename Frame>
Position<Frame> ContinuousTrajectory<Frame>::EvaluatePosition(
    Instant const& time,
    Hint* const hint) const {
  CHECK_LE(t_min(), time);
  CHECK_GE(t_max(), time);
  if (MayUseHint(time, hint)) {
    return series_[hint->index_].Evaluate(time) + Frame::origin;
  } else {
    auto const it = FindSeriesForInstant(time);
    if (hint != nullptr) {
      hint->index_ = it - series_.cbegin();
    }
    return it->Evaluate(time) + Frame::origin;
  }
}

template<typename Frame>
Velocity<Frame> ContinuousTrajectory<Frame>::EvaluateVelocity(
    Instant const& time,
    Hint* const hint) const {
  CHECK_LE(t_min(), time);
  CHECK_GE(t_max(), time);
  if (MayUseHint(time, hint)) {
    return series_[hint->index_].EvaluateDerivative(time);
  } else {
    auto const it = FindSeriesForInstant(time);
    if (hint != nullptr) {
      hint->index_ = it - series_.cbegin();
    }
    return it->EvaluateDerivative(time);
  }
}

template<typename Frame>
DegreesOfFreedom<Frame> ContinuousTrajectory<Frame>::EvaluateDegreesOfFreedom(
    Instant const& time,
    Hint* const hint) const {
  CHECK_LE(t_min(), time);
  CHECK_GE(t_max(), time);
  if (MayUseHint(time, hint)) {
    ЧебышёвSeries<Displacement<Frame>> const& series = series_[hint->index_];
    return DegreesOfFreedom<Frame>(series.Evaluate(time) + Frame::origin,
                                   series.EvaluateDerivative(time));
  } else {
    auto const it = FindSeriesForInstant(time);
    if (hint != nullptr) {
      hint->index_ = it - series_.cbegin();
    }
    return DegreesOfFreedom<Frame>(it->Evaluate(time) + Frame::origin,
                                   it->EvaluateDerivative(time));
  }
}

template<typename Frame>
void ContinuousTrajectory<Frame>::WriteToMessage(
      not_null<serialization::ContinuousTrajectory*> const message) const {
  LOG(INFO) << __FUNCTION__;
  step_.WriteToMessage(message->mutable_step());
  tolerance_.WriteToMessage(message->mutable_tolerance());
  adjusted_tolerance_.WriteToMessage(message->mutable_adjusted_tolerance());
  message->set_is_unstable(is_unstable_);
  message->set_degree(degree_);
  message->set_degree_age(degree_age_);
  for (auto const& s : series_) {
    s.WriteToMessage(message->add_series());
  }
  if (first_time_ != nullptr) {
    first_time_->WriteToMessage(message->mutable_first_time());
  }
  for (auto const& l : last_points_) {
    Instant const& instant = l.first;
    DegreesOfFreedom<Frame> degrees_of_freedom = l.second;
    not_null<
        serialization::ContinuousTrajectory::InstantaneousDegreesOfFreedom*>
        const instantaneous_degrees_of_freedom = message->add_last_point();
    instant.WriteToMessage(instantaneous_degrees_of_freedom->mutable_instant());
    degrees_of_freedom.WriteToMessage(
        instantaneous_degrees_of_freedom->mutable_degrees_of_freedom());
  }
  LOG(INFO) << NAMED(this);
  LOG(INFO) << NAMED(message->SpaceUsed());
  LOG(INFO) << NAMED(message->ByteSize());
}

template<typename Frame>
not_null<std::unique_ptr<ContinuousTrajectory<Frame>>>
ContinuousTrajectory<Frame>::ReadFromMessage(
      serialization::ContinuousTrajectory const& message) {
  not_null<std::unique_ptr<ContinuousTrajectory<Frame>>> continuous_trajectory =
      std::make_unique<ContinuousTrajectory<Frame>>(
          Time::ReadFromMessage(message.step()),
          Length::ReadFromMessage(message.tolerance()));
  continuous_trajectory->adjusted_tolerance_ =
      Length::ReadFromMessage(message.adjusted_tolerance());
  continuous_trajectory->is_unstable_ = message.is_unstable();
  continuous_trajectory->degree_ = message.degree();
  continuous_trajectory->degree_age_ = message.degree_age();
  for (auto const& s : message.series()) {
    continuous_trajectory->series_.push_back(
        ЧебышёвSeries<Displacement<Frame>>::ReadFromMessage(s));
  }
  if (message.has_first_time()) {
    continuous_trajectory->first_time_ = std::make_unique<Instant>(
        Instant::ReadFromMessage(message.first_time()));
  }
  for (auto const& l : message.last_point()) {
    continuous_trajectory->last_points_.push_back(
        {Instant::ReadFromMessage(l.instant()),
         DegreesOfFreedom<Frame>::ReadFromMessage(l.degrees_of_freedom())});
  }
  return continuous_trajectory;
}

template<typename Frame>
ContinuousTrajectory<Frame>::Hint::Hint()
    : index_(std::numeric_limits<int>::max()) {}

template<typename Frame>
void ContinuousTrajectory<Frame>::ComputeBestNewhallApproximation(
    Instant const& time,
    std::vector<Displacement<Frame>> const& q,
    std::vector<Velocity<Frame>> const& v,
    ЧебышёвSeries<Displacement<Frame>> (*newhall_approximation)(
        int const degree,
        std::vector<Displacement<Frame>> const& q,
        std::vector<Velocity<Frame>> const& v,
        Instant const& t_min,
        Instant const& t_max)) {
  Length const previous_adjusted_tolerance = adjusted_tolerance_;

  // If the degree is too old, restart from the lowest degree.  This ensures
  // that we use the lowest possible degree at a small computational cost.
  if (degree_age_ >= kMaxDegreeAge) {
    VLOG(1) << "Lowering degree for " << this <<" from " << degree_
            << " to " << kMinDegree << " because the approximation is too old";
    is_unstable_ = false;
    adjusted_tolerance_ = tolerance_;
    degree_ = kMinDegree;
    degree_age_ = 0;
  }

  // Compute the approximation with the current degree.
  series_.push_back(
      newhall_approximation(degree_, q, v, last_points_.cbegin()->first, time));

  // Estimate the error.  For initializing |previous_error_estimate|, any value
  // greater than |error_estimate| will do.
  Length error_estimate = series_.back().last_coefficient().Norm();
  Length previous_error_estimate = error_estimate + error_estimate;

  // If we are in the zone of numerical instabilities and we exceeded the
  // tolerance, restart from the lowest degree.
  if (is_unstable_ && error_estimate > adjusted_tolerance_) {
    VLOG(1) << "Lowering degree for " << this << " from " << degree_
            << " to " << kMinDegree
            << " because error estimate " << error_estimate
            << " exceeds adjusted tolerance " << adjusted_tolerance_
            << " and computations are unstable";
    is_unstable_ = false;
    adjusted_tolerance_ = tolerance_;
    degree_ = kMinDegree - 1;
    degree_age_ = 0;
    previous_error_estimate = std::numeric_limits<double>::max() * Metre;
    error_estimate = 0.5 * previous_error_estimate;
  }

  // Increase the degree if the approximation is not accurate enough.  Stop
  // when we reach the maximum degree or when the error estimate is not
  // decreasing.
  while (error_estimate > adjusted_tolerance_ &&
         error_estimate < previous_error_estimate &&
         degree_ < kMaxDegree) {
    ++degree_;
    VLOG(1) << "Increasing degree for " << this << " to " <<degree_
            << " because error estimate was " << error_estimate;
    series_.back() =
        newhall_approximation(
            degree_, q, v, last_points_.cbegin()->first, time);
    previous_error_estimate = error_estimate;
    error_estimate = series_.back().last_coefficient().Norm();
  }

  // If we have entered the zone of numerical instability, go back to the
  // point where the error was decreasing and nudge the tolerance since we
  // won't be able to reliably do better than that.
  if (error_estimate >= previous_error_estimate) {
    if (degree_ > kMinDegree) {
    --degree_;
    }
    VLOG(1) << "Reverting to degree " << degree_ << " for " << this
            << " because error estimate increased (" << error_estimate
            << " vs. " << previous_error_estimate << ")";
    is_unstable_ = true;
    error_estimate = previous_error_estimate;
    adjusted_tolerance_ = std::max(adjusted_tolerance_, error_estimate);
  } else {
    VLOG(1) << "Using degree " << degree_ << " for " << this
            << " with error estimate " << error_estimate;
  }

  // A check that the tolerance did not explode.
  CHECK_LT(adjusted_tolerance_, 1E6 * previous_adjusted_tolerance)
    << "Apocalypse occurred at " << time
    << ", displacements are: " << VectorDebugString(q)
    << ", velocities are: " << VectorDebugString(v);

  ++degree_age_;
}

template<typename Frame>
typename std::vector<ЧебышёвSeries<Displacement<Frame>>>::const_iterator
ContinuousTrajectory<Frame>::FindSeriesForInstant(Instant const& time) const {
  // Need to use |lower_bound|, not |upper_bound|, because it allows
  // heterogeneous arguments.  This returns the first series |s| such that
  // |time <= s.t_max()|.
  auto const it = std::lower_bound(
                      series_.begin(), series_.end(), time,
                      [](ЧебышёвSeries<Displacement<Frame>> const& left,
                         Instant const& right) {
                        return left.t_max() < right;
                      });
  CHECK(it != series_.end());
  return it;
}

template<typename Frame>
bool ContinuousTrajectory<Frame>::MayUseHint(Instant const& time,
                                             Hint* const hint) const {
  if (hint != nullptr) {
    // A shorthand for the index held by the |hint|.
    int& index = hint->index_;
    if (index < series_.size() && series_[index].t_min() <= time) {
      if (time <= series_[index].t_max()) {
        // Use this interval.
        return true;
      } else if (index < series_.size() - 1 &&
                 time <= series_[index + 1].t_max()) {
        // Move to the next interval.
        ++index;
        return true;
      }
    }
  }
  return false;
}

}  // namespace physics
}  // namespace principia
<commit_msg>stl logging.<commit_after>#pragma once

#include <algorithm>
#include <limits>
#include <vector>

#include "glog/stl_logging.h"
#include "physics/continuous_trajectory.hpp"
#include "quantities/si.hpp"
#include "testing_utilities/numerics.hpp"

namespace principia {

using si::Metre;
using si::Second;
using testing_utilities::ULPDistance;

namespace physics {

namespace {

int const kMaxDegree = 17;
int const kMinDegree = 3;
int const kMaxDegreeAge = 100;

// Only supports 8 divisions for now.
int const kDivisions = 8;

}  // namespace

template<typename Frame>
ContinuousTrajectory<Frame>::ContinuousTrajectory(Time const& step,
                                                  Length const& tolerance)
    : step_(step),
      tolerance_(tolerance),
      adjusted_tolerance_(tolerance_),
      is_unstable_(false),
      degree_(kMinDegree),
      degree_age_(0) {
  CHECK_LT(0 * Metre, tolerance_);
}

template<typename Frame>
bool ContinuousTrajectory<Frame>::empty() const {
  return series_.empty();
}

template<typename Frame>
Instant ContinuousTrajectory<Frame>::t_min() const {
  if (empty()) {
    return Instant(std::numeric_limits<double>::infinity() * Second);
  }
  return *first_time_;
}

template<typename Frame>
Instant ContinuousTrajectory<Frame>::t_max() const {
  if (empty()) {
    return Instant(-std::numeric_limits<double>::infinity() * Second);
  }
  return series_.back().t_max();
}

template<typename Frame>
void ContinuousTrajectory<Frame>::Append(
    Instant const& time,
    DegreesOfFreedom<Frame> const& degrees_of_freedom) {
  // Consistency checks.
  if (first_time_ == nullptr) {
    first_time_ = std::make_unique<Instant>(time);
  } else {
    Instant const t0;
    CHECK_GE(1,
             ULPDistance((last_points_.back().first + step_ - t0) /
                             SIUnit<Time>(),
                         (time - t0) / SIUnit<Time>()))
        << "Append at times that are not equally spaced";
  }

  if (last_points_.size() == kDivisions) {
    // These vectors are static to avoid deallocation/reallocation each time we
    // go through this code path.
    static std::vector<Displacement<Frame>> q(kDivisions + 1);
    static std::vector<Velocity<Frame>> v(kDivisions + 1);
    q.clear();
    v.clear();

    for (auto const& pair : last_points_) {
      DegreesOfFreedom<Frame> const& degrees_of_freedom = pair.second;
      q.push_back(degrees_of_freedom.position() - Frame::origin);
      v.push_back(degrees_of_freedom.velocity());
    }
    q.push_back(degrees_of_freedom.position() - Frame::origin);
    v.push_back(degrees_of_freedom.velocity());

    ComputeBestNewhallApproximation(
        time, q, v, &ЧебышёвSeries<Displacement<Frame>>::NewhallApproximation);

    // Wipe-out the points that have just been incorporated in a series.
    last_points_.clear();
  }

  // Note that we only insert the new point in the map *after* computing the
  // approximation, because clearing the map is much more efficient than erasing
  // every element but one.
  last_points_.emplace_back(time, degrees_of_freedom);
}

template<typename Frame>
void ContinuousTrajectory<Frame>::ForgetAfter(
    Instant const & time,
    DegreesOfFreedom<Frame> const & degrees_of_freedom) {
  if (time > t_max()) {
    return;
  }
  auto it = FindSeriesForInstant(time);
  if (it != series_.end()) {
    CHECK_EQ(time, it->t_max());
    last_points_.clear();
    last_points_.emplace_back(time, degrees_of_freedom);
    series_.erase(++it, series_.end());
  }
}

template<typename Frame>
void ContinuousTrajectory<Frame>::ForgetBefore(Instant const& time) {
  if (time < t_min()) {
    // TODO(phl): test for this case, it yielded a check failure in
    // |FindSeriesForInstant|.
    return;
  }
  series_.erase(series_.begin(), FindSeriesForInstant(time));

  // If there are no |series_| left, clear everything.  Otherwise, update the
  // first time.
  if (series_.empty()) {
    first_time_.reset();
    last_points_.clear();
  } else {
    *first_time_ = time;
  }
}

template<typename Frame>
Position<Frame> ContinuousTrajectory<Frame>::EvaluatePosition(
    Instant const& time,
    Hint* const hint) const {
  CHECK_LE(t_min(), time);
  CHECK_GE(t_max(), time);
  if (MayUseHint(time, hint)) {
    return series_[hint->index_].Evaluate(time) + Frame::origin;
  } else {
    auto const it = FindSeriesForInstant(time);
    if (hint != nullptr) {
      hint->index_ = it - series_.cbegin();
    }
    return it->Evaluate(time) + Frame::origin;
  }
}

template<typename Frame>
Velocity<Frame> ContinuousTrajectory<Frame>::EvaluateVelocity(
    Instant const& time,
    Hint* const hint) const {
  CHECK_LE(t_min(), time);
  CHECK_GE(t_max(), time);
  if (MayUseHint(time, hint)) {
    return series_[hint->index_].EvaluateDerivative(time);
  } else {
    auto const it = FindSeriesForInstant(time);
    if (hint != nullptr) {
      hint->index_ = it - series_.cbegin();
    }
    return it->EvaluateDerivative(time);
  }
}

template<typename Frame>
DegreesOfFreedom<Frame> ContinuousTrajectory<Frame>::EvaluateDegreesOfFreedom(
    Instant const& time,
    Hint* const hint) const {
  CHECK_LE(t_min(), time);
  CHECK_GE(t_max(), time);
  if (MayUseHint(time, hint)) {
    ЧебышёвSeries<Displacement<Frame>> const& series = series_[hint->index_];
    return DegreesOfFreedom<Frame>(series.Evaluate(time) + Frame::origin,
                                   series.EvaluateDerivative(time));
  } else {
    auto const it = FindSeriesForInstant(time);
    if (hint != nullptr) {
      hint->index_ = it - series_.cbegin();
    }
    return DegreesOfFreedom<Frame>(it->Evaluate(time) + Frame::origin,
                                   it->EvaluateDerivative(time));
  }
}

template<typename Frame>
void ContinuousTrajectory<Frame>::WriteToMessage(
      not_null<serialization::ContinuousTrajectory*> const message) const {
  LOG(INFO) << __FUNCTION__;
  step_.WriteToMessage(message->mutable_step());
  tolerance_.WriteToMessage(message->mutable_tolerance());
  adjusted_tolerance_.WriteToMessage(message->mutable_adjusted_tolerance());
  message->set_is_unstable(is_unstable_);
  message->set_degree(degree_);
  message->set_degree_age(degree_age_);
  for (auto const& s : series_) {
    s.WriteToMessage(message->add_series());
  }
  if (first_time_ != nullptr) {
    first_time_->WriteToMessage(message->mutable_first_time());
  }
  for (auto const& l : last_points_) {
    Instant const& instant = l.first;
    DegreesOfFreedom<Frame> degrees_of_freedom = l.second;
    not_null<
        serialization::ContinuousTrajectory::InstantaneousDegreesOfFreedom*>
        const instantaneous_degrees_of_freedom = message->add_last_point();
    instant.WriteToMessage(instantaneous_degrees_of_freedom->mutable_instant());
    degrees_of_freedom.WriteToMessage(
        instantaneous_degrees_of_freedom->mutable_degrees_of_freedom());
  }
  LOG(INFO) << NAMED(this);
  LOG(INFO) << NAMED(message->SpaceUsed());
  LOG(INFO) << NAMED(message->ByteSize());
}

template<typename Frame>
not_null<std::unique_ptr<ContinuousTrajectory<Frame>>>
ContinuousTrajectory<Frame>::ReadFromMessage(
      serialization::ContinuousTrajectory const& message) {
  not_null<std::unique_ptr<ContinuousTrajectory<Frame>>> continuous_trajectory =
      std::make_unique<ContinuousTrajectory<Frame>>(
          Time::ReadFromMessage(message.step()),
          Length::ReadFromMessage(message.tolerance()));
  continuous_trajectory->adjusted_tolerance_ =
      Length::ReadFromMessage(message.adjusted_tolerance());
  continuous_trajectory->is_unstable_ = message.is_unstable();
  continuous_trajectory->degree_ = message.degree();
  continuous_trajectory->degree_age_ = message.degree_age();
  for (auto const& s : message.series()) {
    continuous_trajectory->series_.push_back(
        ЧебышёвSeries<Displacement<Frame>>::ReadFromMessage(s));
  }
  if (message.has_first_time()) {
    continuous_trajectory->first_time_ = std::make_unique<Instant>(
        Instant::ReadFromMessage(message.first_time()));
  }
  for (auto const& l : message.last_point()) {
    continuous_trajectory->last_points_.push_back(
        {Instant::ReadFromMessage(l.instant()),
         DegreesOfFreedom<Frame>::ReadFromMessage(l.degrees_of_freedom())});
  }
  return continuous_trajectory;
}

template<typename Frame>
ContinuousTrajectory<Frame>::Hint::Hint()
    : index_(std::numeric_limits<int>::max()) {}

template<typename Frame>
void ContinuousTrajectory<Frame>::ComputeBestNewhallApproximation(
    Instant const& time,
    std::vector<Displacement<Frame>> const& q,
    std::vector<Velocity<Frame>> const& v,
    ЧебышёвSeries<Displacement<Frame>> (*newhall_approximation)(
        int const degree,
        std::vector<Displacement<Frame>> const& q,
        std::vector<Velocity<Frame>> const& v,
        Instant const& t_min,
        Instant const& t_max)) {
  Length const previous_adjusted_tolerance = adjusted_tolerance_;

  // If the degree is too old, restart from the lowest degree.  This ensures
  // that we use the lowest possible degree at a small computational cost.
  if (degree_age_ >= kMaxDegreeAge) {
    VLOG(1) << "Lowering degree for " << this <<" from " << degree_
            << " to " << kMinDegree << " because the approximation is too old";
    is_unstable_ = false;
    adjusted_tolerance_ = tolerance_;
    degree_ = kMinDegree;
    degree_age_ = 0;
  }

  // Compute the approximation with the current degree.
  series_.push_back(
      newhall_approximation(degree_, q, v, last_points_.cbegin()->first, time));

  // Estimate the error.  For initializing |previous_error_estimate|, any value
  // greater than |error_estimate| will do.
  Length error_estimate = series_.back().last_coefficient().Norm();
  Length previous_error_estimate = error_estimate + error_estimate;

  // If we are in the zone of numerical instabilities and we exceeded the
  // tolerance, restart from the lowest degree.
  if (is_unstable_ && error_estimate > adjusted_tolerance_) {
    VLOG(1) << "Lowering degree for " << this << " from " << degree_
            << " to " << kMinDegree
            << " because error estimate " << error_estimate
            << " exceeds adjusted tolerance " << adjusted_tolerance_
            << " and computations are unstable";
    is_unstable_ = false;
    adjusted_tolerance_ = tolerance_;
    degree_ = kMinDegree - 1;
    degree_age_ = 0;
    previous_error_estimate = std::numeric_limits<double>::max() * Metre;
    error_estimate = 0.5 * previous_error_estimate;
  }

  // Increase the degree if the approximation is not accurate enough.  Stop
  // when we reach the maximum degree or when the error estimate is not
  // decreasing.
  while (error_estimate > adjusted_tolerance_ &&
         error_estimate < previous_error_estimate &&
         degree_ < kMaxDegree) {
    ++degree_;
    VLOG(1) << "Increasing degree for " << this << " to " <<degree_
            << " because error estimate was " << error_estimate;
    series_.back() =
        newhall_approximation(
            degree_, q, v, last_points_.cbegin()->first, time);
    previous_error_estimate = error_estimate;
    error_estimate = series_.back().last_coefficient().Norm();
  }

  // If we have entered the zone of numerical instability, go back to the
  // point where the error was decreasing and nudge the tolerance since we
  // won't be able to reliably do better than that.
  if (error_estimate >= previous_error_estimate) {
    if (degree_ > kMinDegree) {
    --degree_;
    }
    VLOG(1) << "Reverting to degree " << degree_ << " for " << this
            << " because error estimate increased (" << error_estimate
            << " vs. " << previous_error_estimate << ")";
    is_unstable_ = true;
    error_estimate = previous_error_estimate;
    adjusted_tolerance_ = std::max(adjusted_tolerance_, error_estimate);
  } else {
    VLOG(1) << "Using degree " << degree_ << " for " << this
            << " with error estimate " << error_estimate;
  }

  // A check that the tolerance did not explode.
  CHECK_LT(adjusted_tolerance_, 1E6 * previous_adjusted_tolerance)
      << "Apocalypse occurred at " << time
      << ", displacements are: " << q
      << ", velocities are: " << v;

  ++degree_age_;
}

template<typename Frame>
typename std::vector<ЧебышёвSeries<Displacement<Frame>>>::const_iterator
ContinuousTrajectory<Frame>::FindSeriesForInstant(Instant const& time) const {
  // Need to use |lower_bound|, not |upper_bound|, because it allows
  // heterogeneous arguments.  This returns the first series |s| such that
  // |time <= s.t_max()|.
  auto const it = std::lower_bound(
                      series_.begin(), series_.end(), time,
                      [](ЧебышёвSeries<Displacement<Frame>> const& left,
                         Instant const& right) {
                        return left.t_max() < right;
                      });
  CHECK(it != series_.end());
  return it;
}

template<typename Frame>
bool ContinuousTrajectory<Frame>::MayUseHint(Instant const& time,
                                             Hint* const hint) const {
  if (hint != nullptr) {
    // A shorthand for the index held by the |hint|.
    int& index = hint->index_;
    if (index < series_.size() && series_[index].t_min() <= time) {
      if (time <= series_[index].t_max()) {
        // Use this interval.
        return true;
      } else if (index < series_.size() - 1 &&
                 time <= series_[index + 1].t_max()) {
        // Move to the next interval.
        ++index;
        return true;
      }
    }
  }
  return false;
}

}  // namespace physics
}  // namespace principia
<|endoftext|>