<commit_before>#include "offeracceptdialogbtc.h"
#include "ui_offeracceptdialogbtc.h"
#include "init.h"
#include "util.h"
#include "offerpaydialog.h"
#include "guiconstants.h"
#include "guiutil.h"
#include "platformstyle.h"
#include "syscoingui.h"
#include <QMessageBox>
#include "rpcserver.h"
#include "pubkey.h"
#include "wallet/wallet.h"
#include "main.h"
#include "utilmoneystr.h"
#include <QDesktopServices>
#if QT_VERSION < 0x050000
#include <QUrl>
#else
#include <QUrlQuery>
#endif
#include <QPixmap>
#if defined(HAVE_CONFIG_H)
#include "config/syscoin-config.h" /* for USE_QRCODE */
#endif

#ifdef USE_QRCODE
#include <qrencode.h>
#endif
using namespace std;
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>

extern const CRPCTable tableRPC;
OfferAcceptDialogBTC::OfferAcceptDialogBTC(const PlatformStyle *platformStyle, QString alias, QString offer, QString quantity, QString notes, QString title, QString currencyCode, QString qstrPrice, QString sellerAlias, QString address, QWidget *parent) :
    QDialog(parent),
    ui(new Ui::OfferAcceptDialogBTC), platformStyle(platformStyle), alias(alias), offer(offer), notes(notes), quantity(quantity), title(title), sellerAlias(sellerAlias), address(address)
{
    ui->setupUi(this);
	QString theme = GUIUtil::getThemeName();
	ui->aboutShadeBTC->setPixmap(QPixmap(":/images/" + theme + "/about_btc"));
	double dblPrice = qstrPrice.toDouble()*quantity.toUInt();
	string strfPrice = strprintf("%f", dblPrice);
	QString fprice = QString::fromStdString(strfPrice);
	string strCurrencyCode = currencyCode.toStdString();
	ui->escrowDisclaimer->setText(tr("Please note escrow is not available since you are paying in BTC, only SYS payments can be escrowed. "));
	ui->bitcoinInstructionLabel->setText(tr("After paying for this item, please enter the Bitcoin Transaction ID and click on the confirm button below. You may use the QR Code to the left to scan the payment request into your wallet or click on the Open BTC Wallet if you are on the desktop and have Bitcoin Core installed."));
	ui->acceptMessage->setText(tr("Are you sure you want to purchase %1 of '%2' from merchant: '%3'? To complete your purchase please pay %4 BTC using your Bitcoin wallet.").arg(quantity).arg(title).arg(sellerAlias).arg(fprice));
	string strPrice = strprintf("%f", dblPrice);
	price = QString::fromStdString(strPrice);

	if (!platformStyle->getImagesOnButtons())
	{
		ui->confirmButton->setIcon(QIcon());
		ui->openBtcWalletButton->setIcon(QIcon());
		ui->cancelButton->setIcon(QIcon());

	}
	else
	{
		ui->confirmButton->setIcon(platformStyle->SingleColorIcon(":/icons/" + theme + "/transaction_confirmed"));
		ui->openBtcWalletButton->setIcon(platformStyle->SingleColorIcon(":/icons/" + theme + "/send"));
		ui->cancelButton->setIcon(platformStyle->SingleColorIcon(":/icons/" + theme + "/quit"));
	}
	this->offerPaid = false;
	connect(ui->confirmButton, SIGNAL(clicked()), this, SLOT(acceptPayment()));
	connect(ui->openBtcWalletButton, SIGNAL(clicked()), this, SLOT(openBTCWallet()));

#ifdef USE_QRCODE
	QString message = "Payment for offer ID " + this->offer + " on Syscoin Decentralized Marketplace";
	QString uri = "bitcoin:" + this->address + "?amount=" + price + "&label=" + this->sellerAlias + "&message=" + GUIUtil::HtmlEscape(message);

	ui->lblQRCode->setText("");
    if(!uri.isEmpty())
    {
        // limit URI length
        if (uri.length() > MAX_URI_LENGTH)
        {
            ui->lblQRCode->setText(tr("Resulting URI too long, try to reduce the text for label / message."));
        } else {
            QRcode *code = QRcode_encodeString(uri.toUtf8().constData(), 0, QR_ECLEVEL_L, QR_MODE_8, 1);
            if (!code)
            {
                ui->lblQRCode->setText(tr("Error encoding URI into QR Code."));
                return;
            }
            QImage myImage = QImage(code->width + 8, code->width + 8, QImage::Format_RGB32);
            myImage.fill(0xffffff);
            unsigned char *p = code->data;
            for (int y = 0; y width; y++)
            {
                for (int x = 0; x width; x++)
                {
                    myImage.setPixel(x + 4, y + 4, ((*p & 1) ? 0x0 : 0xffffff));
                    p++;
                }
            }
            QRcode_free(code);
            ui->lblQRCode->setPixmap(QPixmap::fromImage(myImage).scaled(128, 128));
        }
    }
#endif
}
void OfferAcceptDialogBTC::on_cancelButton_clicked()
{
    reject();
}
OfferAcceptDialogBTC::~OfferAcceptDialogBTC()
{
    delete ui;
}

void OfferAcceptDialogBTC::acceptPayment()
{
	acceptOffer();
}
bool OfferAcceptDialogBTC::CheckPaymentInBTC(const QString &strBTCTxId, const QString& address, const QString& price, int& height, long& time)
{
	QNetworkAccessManager *nam = new QNetworkAccessManager(this);
	QUrl url("https://blockchain.info/tx/" + strBTCTxId + "?format=json");
	QNetworkRequest request(url);
	request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
	QNetworkReply* reply = nam->get(request);
	reply->ignoreSslErrors();
	CAmount valueAmount = 0;
	CAmount priceAmount = 0;
	if(!ParseMoney(price.toStdString(), priceAmount))
		return false;
	int totalTime = 0;
	while(!reply->isFinished())
	{
		qApp->processEvents();
		totalTime += 100;
		MilliSleep(100);
		if(totalTime > 30000)
			throw runtime_error("Timeout connecting to blockchain.info!");
	}
	bool doubleSpend = false;
	if(reply->error() == QNetworkReply::NoError) {

		UniValue outerValue;
		bool read = outerValue.read(reply->readAll().toStdString());
		if (read)
		{
			UniValue outerObj = outerValue.get_obj();
			UniValue heightValue = find_value(outerObj, "block_height");
			if (heightValue.isNum())
				height = heightValue.get_num();
			UniValue timeValue = find_value(outerObj, "time");
			if (timeValue.isNum())
				time = timeValue.get_num();

			UniValue outerObj = outerValue.get_obj();
			UniValue doubleSpendValue = find_value(outerObj, "double_spend");
			if (doubleSpendValue.isBool())
			{
				doubleSpend = doubleSpendValue.get_bool();
				if(doubleSpend)
					return false;
			}
			UniValue outputsValue = find_value(outerObj, "out");
			if (outputsValue.isArray())
			{
				UniValue outputs = outputsValue.get_array();
				for (unsigned int idx = 0; idx < outputs.size(); idx++) {
					const UniValue& output = outputs[idx];
					UniValue addressValue = find_value(output, "addr");
					if(addressValue.isStr())
					{
						LogPrintf("address: %s\n", address.toStdString().c_str());
						if(addressValue.get_str() == address.toStdString())
						{
							UniValue paymentValue = find_value(output, "value");
							LogPrintf("value: %lld\n", paymentValue.get_int64());
							if(paymentValue.isNum())
							{
								valueAmount += paymentValue.get_int64();
								if(valueAmount >= priceAmount)
									return true;
							}
						}

					}
				}
			}
		}
	}
	reply->deleteLater();
	return false;

}

bool OfferAcceptDialogBTC::lookup(const QString &lookupid, QString& address, QString& price)
{
	string strError;
	string strMethod = string("offerinfo");
	UniValue params(UniValue::VARR);
	UniValue result;
	params.push_back(lookupid.toStdString());

    try {
        result = tableRPC.execute(strMethod, params);

		if (result.type() == UniValue::VOBJ)
		{
			const UniValue &offerObj = result.get_obj();

			const string &strAddress = find_value(offerObj, "address").get_str();
			const string &strPrice = find_value(offerObj, "price").get_str();
			address = QString::fromStdString(strAddress);
			price = QString::fromStdString(strPrice);
			return true;
		}
	}
	catch (UniValue& objError)
	{
		QMessageBox::critical(this, windowTitle(),
			tr("Could not find this offer, please check the offer ID and that it has been confirmed by the blockchain: ") + lookupid,
				QMessageBox::Ok, QMessageBox::Ok);
		return true;

	}
	catch(std::exception& e)
	{
		QMessageBox::critical(this, windowTitle(),
			tr("There was an exception trying to locate this offer, please check the offer ID and that it has been confirmed by the blockchain: ") + QString::fromStdString(e.what()),
				QMessageBox::Ok, QMessageBox::Ok);
		return true;
	}
	return false;

}
// send offeraccept with offer guid/qty as params and then send offerpay with wtxid (first param of response) as param, using RPC commands.
void OfferAcceptDialogBTC::acceptOffer()
{
		QString address, price;
		if (ui->btctxidEdit->text().trimmed().isEmpty()) {
            ui->btctxidEdit->setText("");
            QMessageBox::information(this, windowTitle(),
            tr("Please enter a valid Bitcoin Transaction ID into the input box and try again"),
                QMessageBox::Ok, QMessageBox::Ok);
            return;
        }
		if(!lookup(this->offer, address, price))
		{
            QMessageBox::information(this, windowTitle(),
            tr("Could not find this offer, please check the offer ID and that it has been confirmed by the blockchain: ") + this->offer,
                QMessageBox::Ok, QMessageBox::Ok);
            return;
		}
		int height;
		long time;
		if(!CheckPaymentInBTC(ui->btctxidEdit->text().trimmed(), address, price, height, time))
		{
            QMessageBox::information(this, windowTitle(),
            tr("Could not find this payment, please check the Transaction ID and that it has been confirmed by the Bitcoin blockchain: ") + ui->btctxidEdit->text().trimmed(),
                QMessageBox::Ok, QMessageBox::Ok);
            return;
		}

		UniValue params(UniValue::VARR);
		UniValue valError;
		UniValue valResult;
		UniValue valId;
		UniValue result ;
		string strReply;
		string strError;

		string strMethod = string("offeraccept");
		if(this->quantity.toLong() <= 0)
		{
			QMessageBox::critical(this, windowTitle(),
				tr("Invalid quantity when trying to accept offer!"),
				QMessageBox::Ok, QMessageBox::Ok);
			return;
		}
		this->offerPaid = false;
		params.push_back(this->alias.toStdString());
		params.push_back(this->offer.toStdString());
		params.push_back(this->quantity.toStdString());
		params.push_back(this->notes.toStdString());
		params.push_back(ui->btctxidEdit->text().toStdString());

	    try {
            result = tableRPC.execute(strMethod, params);
			if (result.type() != UniValue::VNULL)
			{
				const UniValue &arr = result.get_array();
				string strResult = arr[0].get_str();
				QString offerAcceptTXID = QString::fromStdString(strResult);
				if(offerAcceptTXID != QString(""))
				{
					OfferPayDialog dlg(platformStyle, this->title, this->quantity, this->price, "BTC", this);
					dlg.exec();
					this->offerPaid = true;
					OfferAcceptDialogBTC::accept();
					return;

				}
			}
		}
		catch (UniValue& objError)
		{
			strError = find_value(objError, "message").get_str();
			QMessageBox::critical(this, windowTitle(),
			tr("Error accepting offer: \"%1\"").arg(QString::fromStdString(strError)),
				QMessageBox::Ok, QMessageBox::Ok);
			return;
		}
		catch(std::exception& e)
		{
			QMessageBox::critical(this, windowTitle(),
				tr("General exception when accepting offer"),
				QMessageBox::Ok, QMessageBox::Ok);
			return;
		}

}
void OfferAcceptDialogBTC::openBTCWallet()
{
	QString message = "Payment for offer ID " + this->offer + " on Syscoin Decentralized Marketplace";
	QString uri = "bitcoin:" + this->address + "?amount=" + price + "&label=" + this->sellerAlias + "&message=" + GUIUtil::HtmlEscape(message);
	QDesktopServices::openUrl(QUrl(uri, QUrl::TolerantMode));
}
bool OfferAcceptDialogBTC::getPaymentStatus()
{
	return this->offerPaid;
}
<commit_msg>fix compile<commit_after>#include "offeracceptdialogbtc.h"
#include "ui_offeracceptdialogbtc.h"
#include "init.h"
#include "util.h"
#include "offerpaydialog.h"
#include "guiconstants.h"
#include "guiutil.h"
#include "platformstyle.h"
#include "syscoingui.h"
#include <QMessageBox>
#include "rpcserver.h"
#include "pubkey.h"
#include "wallet/wallet.h"
#include "main.h"
#include "utilmoneystr.h"
#include <QDesktopServices>
#if QT_VERSION < 0x050000
#include <QUrl>
#else
#include <QUrlQuery>
#endif
#include <QPixmap>
#if defined(HAVE_CONFIG_H)
#include "config/syscoin-config.h" /* for USE_QRCODE */
#endif

#ifdef USE_QRCODE
#include <qrencode.h>
#endif
using namespace std;
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>

extern const CRPCTable tableRPC;
OfferAcceptDialogBTC::OfferAcceptDialogBTC(const PlatformStyle *platformStyle, QString alias, QString offer, QString quantity, QString notes, QString title, QString currencyCode, QString qstrPrice, QString sellerAlias, QString address, QWidget *parent) :
    QDialog(parent),
    ui(new Ui::OfferAcceptDialogBTC), platformStyle(platformStyle), alias(alias), offer(offer), notes(notes), quantity(quantity), title(title), sellerAlias(sellerAlias), address(address)
{
    ui->setupUi(this);
	QString theme = GUIUtil::getThemeName();
	ui->aboutShadeBTC->setPixmap(QPixmap(":/images/" + theme + "/about_btc"));
	double dblPrice = qstrPrice.toDouble()*quantity.toUInt();
	string strfPrice = strprintf("%f", dblPrice);
	QString fprice = QString::fromStdString(strfPrice);
	string strCurrencyCode = currencyCode.toStdString();
	ui->escrowDisclaimer->setText(tr("Please note escrow is not available since you are paying in BTC, only SYS payments can be escrowed. "));
	ui->bitcoinInstructionLabel->setText(tr("After paying for this item, please enter the Bitcoin Transaction ID and click on the confirm button below. You may use the QR Code to the left to scan the payment request into your wallet or click on the Open BTC Wallet if you are on the desktop and have Bitcoin Core installed."));
	ui->acceptMessage->setText(tr("Are you sure you want to purchase %1 of '%2' from merchant: '%3'? To complete your purchase please pay %4 BTC using your Bitcoin wallet.").arg(quantity).arg(title).arg(sellerAlias).arg(fprice));
	string strPrice = strprintf("%f", dblPrice);
	price = QString::fromStdString(strPrice);

	if (!platformStyle->getImagesOnButtons())
	{
		ui->confirmButton->setIcon(QIcon());
		ui->openBtcWalletButton->setIcon(QIcon());
		ui->cancelButton->setIcon(QIcon());

	}
	else
	{
		ui->confirmButton->setIcon(platformStyle->SingleColorIcon(":/icons/" + theme + "/transaction_confirmed"));
		ui->openBtcWalletButton->setIcon(platformStyle->SingleColorIcon(":/icons/" + theme + "/send"));
		ui->cancelButton->setIcon(platformStyle->SingleColorIcon(":/icons/" + theme + "/quit"));
	}
	this->offerPaid = false;
	connect(ui->confirmButton, SIGNAL(clicked()), this, SLOT(acceptPayment()));
	connect(ui->openBtcWalletButton, SIGNAL(clicked()), this, SLOT(openBTCWallet()));

#ifdef USE_QRCODE
	QString message = "Payment for offer ID " + this->offer + " on Syscoin Decentralized Marketplace";
	QString uri = "bitcoin:" + this->address + "?amount=" + price + "&label=" + this->sellerAlias + "&message=" + GUIUtil::HtmlEscape(message);

	ui->lblQRCode->setText("");
    if(!uri.isEmpty())
    {
        // limit URI length
        if (uri.length() > MAX_URI_LENGTH)
        {
            ui->lblQRCode->setText(tr("Resulting URI too long, try to reduce the text for label / message."));
        } else {
            QRcode *code = QRcode_encodeString(uri.toUtf8().constData(), 0, QR_ECLEVEL_L, QR_MODE_8, 1);
            if (!code)
            {
                ui->lblQRCode->setText(tr("Error encoding URI into QR Code."));
                return;
            }
            QImage myImage = QImage(code->width + 8, code->width + 8, QImage::Format_RGB32);
            myImage.fill(0xffffff);
            unsigned char *p = code->data;
            for (int y = 0; y width; y++)
            {
                for (int x = 0; x width; x++)
                {
                    myImage.setPixel(x + 4, y + 4, ((*p & 1) ? 0x0 : 0xffffff));
                    p++;
                }
            }
            QRcode_free(code);
            ui->lblQRCode->setPixmap(QPixmap::fromImage(myImage).scaled(128, 128));
        }
    }
#endif
}
void OfferAcceptDialogBTC::on_cancelButton_clicked()
{
    reject();
}
OfferAcceptDialogBTC::~OfferAcceptDialogBTC()
{
    delete ui;
}

void OfferAcceptDialogBTC::acceptPayment()
{
	acceptOffer();
}
bool OfferAcceptDialogBTC::CheckPaymentInBTC(const QString &strBTCTxId, const QString& address, const QString& price, int& height, long& time)
{
	QNetworkAccessManager *nam = new QNetworkAccessManager(this);
	QUrl url("https://blockchain.info/tx/" + strBTCTxId + "?format=json");
	QNetworkRequest request(url);
	request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
	QNetworkReply* reply = nam->get(request);
	reply->ignoreSslErrors();
	CAmount valueAmount = 0;
	CAmount priceAmount = 0;
	if(!ParseMoney(price.toStdString(), priceAmount))
		return false;
	int totalTime = 0;
	while(!reply->isFinished())
	{
		qApp->processEvents();
		totalTime += 100;
		MilliSleep(100);
		if(totalTime > 30000)
			throw runtime_error("Timeout connecting to blockchain.info!");
	}
	bool doubleSpend = false;
	if(reply->error() == QNetworkReply::NoError) {

		UniValue outerValue;
		bool read = outerValue.read(reply->readAll().toStdString());
		if (read)
		{
			UniValue outerObj = outerValue.get_obj();
			UniValue heightValue = find_value(outerObj, "block_height");
			if (heightValue.isNum())
				height = heightValue.get_int();
			UniValue timeValue = find_value(outerObj, "time");
			if (timeValue.isNum())
				time = timeValue.get_int64();
			LogPrintf("height: %d time: %lld\n",height, time);
			UniValue doubleSpendValue = find_value(outerObj, "double_spend");
			if (doubleSpendValue.isBool())
			{
				doubleSpend = doubleSpendValue.get_bool();
				if(doubleSpend)
					return false;
			}
			UniValue outputsValue = find_value(outerObj, "out");
			if (outputsValue.isArray())
			{
				UniValue outputs = outputsValue.get_array();
				for (unsigned int idx = 0; idx < outputs.size(); idx++) {
					const UniValue& output = outputs[idx];
					UniValue addressValue = find_value(output, "addr");
					if(addressValue.isStr())
					{
						LogPrintf("address: %s\n", address.toStdString().c_str());
						if(addressValue.get_str() == address.toStdString())
						{
							UniValue paymentValue = find_value(output, "value");
							LogPrintf("value: %lld\n", paymentValue.get_int64());
							if(paymentValue.isNum())
							{
								valueAmount += paymentValue.get_int64();
								if(valueAmount >= priceAmount)
									return true;
							}
						}

					}
				}
			}
		}
	}
	reply->deleteLater();
	return false;

}

bool OfferAcceptDialogBTC::lookup(const QString &lookupid, QString& address, QString& price)
{
	string strError;
	string strMethod = string("offerinfo");
	UniValue params(UniValue::VARR);
	UniValue result;
	params.push_back(lookupid.toStdString());

    try {
        result = tableRPC.execute(strMethod, params);

		if (result.type() == UniValue::VOBJ)
		{
			const UniValue &offerObj = result.get_obj();

			const string &strAddress = find_value(offerObj, "address").get_str();
			const string &strPrice = find_value(offerObj, "price").get_str();
			address = QString::fromStdString(strAddress);
			price = QString::fromStdString(strPrice);
			return true;
		}
	}
	catch (UniValue& objError)
	{
		QMessageBox::critical(this, windowTitle(),
			tr("Could not find this offer, please check the offer ID and that it has been confirmed by the blockchain: ") + lookupid,
				QMessageBox::Ok, QMessageBox::Ok);
		return true;

	}
	catch(std::exception& e)
	{
		QMessageBox::critical(this, windowTitle(),
			tr("There was an exception trying to locate this offer, please check the offer ID and that it has been confirmed by the blockchain: ") + QString::fromStdString(e.what()),
				QMessageBox::Ok, QMessageBox::Ok);
		return true;
	}
	return false;

}
// send offeraccept with offer guid/qty as params and then send offerpay with wtxid (first param of response) as param, using RPC commands.
void OfferAcceptDialogBTC::acceptOffer()
{
		QString address, price;
		if (ui->btctxidEdit->text().trimmed().isEmpty()) {
            ui->btctxidEdit->setText("");
            QMessageBox::information(this, windowTitle(),
            tr("Please enter a valid Bitcoin Transaction ID into the input box and try again"),
                QMessageBox::Ok, QMessageBox::Ok);
            return;
        }
		if(!lookup(this->offer, address, price))
		{
            QMessageBox::information(this, windowTitle(),
            tr("Could not find this offer, please check the offer ID and that it has been confirmed by the blockchain: ") + this->offer,
                QMessageBox::Ok, QMessageBox::Ok);
            return;
		}
		int height;
		long time;
		if(!CheckPaymentInBTC(ui->btctxidEdit->text().trimmed(), address, price, height, time))
		{
            QMessageBox::information(this, windowTitle(),
            tr("Could not find this payment, please check the Transaction ID and that it has been confirmed by the Bitcoin blockchain: ") + ui->btctxidEdit->text().trimmed(),
                QMessageBox::Ok, QMessageBox::Ok);
            return;
		}

		UniValue params(UniValue::VARR);
		UniValue valError;
		UniValue valResult;
		UniValue valId;
		UniValue result ;
		string strReply;
		string strError;

		string strMethod = string("offeraccept");
		if(this->quantity.toLong() <= 0)
		{
			QMessageBox::critical(this, windowTitle(),
				tr("Invalid quantity when trying to accept offer!"),
				QMessageBox::Ok, QMessageBox::Ok);
			return;
		}
		this->offerPaid = false;
		params.push_back(this->alias.toStdString());
		params.push_back(this->offer.toStdString());
		params.push_back(this->quantity.toStdString());
		params.push_back(this->notes.toStdString());
		params.push_back(ui->btctxidEdit->text().toStdString());

	    try {
            result = tableRPC.execute(strMethod, params);
			if (result.type() != UniValue::VNULL)
			{
				const UniValue &arr = result.get_array();
				string strResult = arr[0].get_str();
				QString offerAcceptTXID = QString::fromStdString(strResult);
				if(offerAcceptTXID != QString(""))
				{
					OfferPayDialog dlg(platformStyle, this->title, this->quantity, this->price, "BTC", this);
					dlg.exec();
					this->offerPaid = true;
					OfferAcceptDialogBTC::accept();
					return;

				}
			}
		}
		catch (UniValue& objError)
		{
			strError = find_value(objError, "message").get_str();
			QMessageBox::critical(this, windowTitle(),
			tr("Error accepting offer: \"%1\"").arg(QString::fromStdString(strError)),
				QMessageBox::Ok, QMessageBox::Ok);
			return;
		}
		catch(std::exception& e)
		{
			QMessageBox::critical(this, windowTitle(),
				tr("General exception when accepting offer"),
				QMessageBox::Ok, QMessageBox::Ok);
			return;
		}

}
void OfferAcceptDialogBTC::openBTCWallet()
{
	QString message = "Payment for offer ID " + this->offer + " on Syscoin Decentralized Marketplace";
	QString uri = "bitcoin:" + this->address + "?amount=" + price + "&label=" + this->sellerAlias + "&message=" + GUIUtil::HtmlEscape(message);
	QDesktopServices::openUrl(QUrl(uri, QUrl::TolerantMode));
}
bool OfferAcceptDialogBTC::getPaymentStatus()
{
	return this->offerPaid;
}
<|endoftext|>


<commit_before>#ifndef RDB_PROTOCOL_EXCEPTIONS_HPP_
#define RDB_PROTOCOL_EXCEPTIONS_HPP_

#include <string>

#include "rdb_protocol/backtrace.hpp"

namespace query_language {

/* Thrown if the client sends a malformed or nonsensical query (e.g. a
   protocol buffer that doesn't match our schema or STOP for an
   unknown token). */
class meaningless_query_exc_t : public std::exception {
public:
    meaningless_query_exc_t(const std::string &_what) : message(_what) { }
    ~meaningless_query_exc_t() throw () { }

    const char *what() const throw () {
        return message.c_str();
    }

    std::string message;
};

/* `bad_query_exc_t` is thrown if the user writes a query that accesses
undefined variables or that has mismatched types. The difference between this
and `bad_protobuf_exc_t` is that `bad_protobuf_exc_t` is the client's fault and
`bad_query_exc_t` is the client's user's fault. */

class bad_query_exc_t : public std::exception {
public:
    bad_query_exc_t(const std::string &s, const backtrace_t &bt) : message(s), backtrace(bt) { }

    ~bad_query_exc_t() throw () { }

    const char *what() const throw () {
        return message.c_str();
    }

    std::string message;
    backtrace_t backtrace;
};

class runtime_exc_t {
public:
    runtime_exc_t(const std::string &_what, const backtrace_t &bt)
        : message(_what), backtrace(bt)
    { }

    std::string what() const throw() {
        return message;
    }

    std::string message;
    backtrace_t backtrace;
};

}// namespace query_language
#endif
<commit_msg>Fixed comments.<commit_after>#ifndef RDB_PROTOCOL_EXCEPTIONS_HPP_
#define RDB_PROTOCOL_EXCEPTIONS_HPP_

#include <string>

#include "rdb_protocol/backtrace.hpp"

namespace query_language {

/* Thrown if the client sends a malformed or nonsensical query (e.g. a
   protocol buffer that doesn't match our schema or STOP for an
   unknown token). */
class meaningless_query_exc_t : public std::exception {
public:
    meaningless_query_exc_t(const std::string &_what) : message(_what) { }
    ~meaningless_query_exc_t() throw () { }

    const char *what() const throw () {
        return message.c_str();
    }

    std::string message;
};

/* `bad_query_exc_t` is thrown if the user writes a query that
   accesses undefined variables or that has mismatched types. The
   difference between this and `meaningless_query_exc_t` is that
   `meaningless_query_exc_t` is the client's fault and
   `bad_query_exc_t` is the client's user's fault. */

class bad_query_exc_t : public std::exception {
public:
    bad_query_exc_t(const std::string &s, const backtrace_t &bt) : message(s), backtrace(bt) { }

    ~bad_query_exc_t() throw () { }

    const char *what() const throw () {
        return message.c_str();
    }

    std::string message;
    backtrace_t backtrace;
};

class runtime_exc_t {
public:
    runtime_exc_t(const std::string &_what, const backtrace_t &bt)
        : message(_what), backtrace(bt)
    { }

    std::string what() const throw() {
        return message;
    }

    std::string message;
    backtrace_t backtrace;
};

}// namespace query_language
#endif
<|endoftext|>


<commit_before>#include <StdAfx.h>
#include <UI/Controls/FakeSplitter.h>
#include <UI/UIFunctions.h>
#include <UI/DoubleBuffer.h>
#include <core/utility/output.h>

namespace controls
{
	static std::wstring CLASS = L"CFakeSplitter";

	enum FakesSplitHitTestValue
	{
		noHit = 0,
		SplitterHit = 1
	};

	CFakeSplitter::~CFakeSplitter()
	{
		TRACE_DESTRUCTOR(CLASS);
		static_cast<void>(DestroyCursor(m_hSplitCursorH));
		static_cast<void>(DestroyCursor(m_hSplitCursorV));
		CWnd::DestroyWindow();
	}

	void CFakeSplitter::Init(HWND hWnd)
	{
		m_hwndParent = hWnd;
		WNDCLASSEX wc = {};
		const auto hInst = AfxGetInstanceHandle();
		if (!::GetClassInfoEx(hInst, _T("FakeSplitter"), &wc)) // STRING_OK
		{
			wc.cbSize = sizeof wc;
			wc.style = 0; // not passing CS_VREDRAW | CS_HREDRAW fixes flicker
			wc.lpszClassName = _T("FakeSplitter"); // STRING_OK
			wc.lpfnWndProc = ::DefWindowProc;
			wc.hbrBackground = GetSysBrush(ui::uiColor::Background); // helps spot flashing

			RegisterClassEx(&wc);
		}

		// WS_CLIPCHILDREN is used to reduce flicker
		EC_B_S(CreateEx(
			0,
			_T("FakeSplitter"), // STRING_OK
			_T("FakeSplitter"), // STRING_OK
			WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE,
			0,
			0,
			0,
			0,
			m_hwndParent,
			reinterpret_cast<HMENU>(static_cast<INT_PTR>(IDC_FAKE_SPLITTER)),
			nullptr));

		// Necessary for TAB to work. Without this, all TABS get stuck on the fake splitter control
		// instead of passing to the children. Haven't tested with nested splitters.
		EC_B_S(ModifyStyleEx(0, WS_EX_CONTROLPARENT));

		// Load split cursors
		m_hSplitCursorV = EC_D(HCURSOR, ::LoadCursor(GetModuleHandle(nullptr), MAKEINTRESOURCE(IDC_SPLITV)));
		m_hSplitCursorH = EC_D(HCURSOR, ::LoadCursor(GetModuleHandle(nullptr), MAKEINTRESOURCE(IDC_SPLITH)));
	}

	BEGIN_MESSAGE_MAP(CFakeSplitter, CWnd)
	ON_WM_MOUSEMOVE()
	ON_WM_SIZE()
	ON_WM_PAINT()
	END_MESSAGE_MAP()

	LRESULT CFakeSplitter::WindowProc(const UINT message, const WPARAM wParam, const LPARAM lParam)
	{
		LRESULT lRes = 0;
		if (ui::HandleControlUI(message, wParam, lParam, &lRes)) return lRes;

		switch (message)
		{
		case WM_CLOSE:
			::SendMessage(m_hwndParent, message, wParam, lParam);
			return true;
		case WM_HELP:
			return true;
		case WM_LBUTTONUP:
		case WM_CANCELMODE: // Called if focus changes while we're adjusting the splitter
			StopTracking();
			return NULL;
		case WM_LBUTTONDOWN:
			if (m_bTracking) return true;
			StartTracking(HitTest(LOWORD(lParam), HIWORD(lParam)));
			return NULL;
		case WM_SETCURSOR:
			if (LOWORD(lParam) == HTCLIENT && reinterpret_cast<HWND>(wParam) == this->m_hWnd && !m_bTracking)
				return true; // we will handle it in the mouse move
			break;
		case WM_COMMAND:
		{
			const auto nCode = HIWORD(wParam);
			if (EN_CHANGE == nCode || CBN_SELCHANGE == nCode || CBN_EDITCHANGE == nCode || BN_CLICKED == nCode)
			{
				::SendMessage(m_hwndParent, message, wParam, lParam);
			}

			break;
		}
		}

		return CWnd::WindowProc(message, wParam, lParam);
	}

	void CFakeSplitter::SetPaneOne(HWND paneOne) noexcept
	{
		m_PaneOne = paneOne;
		if (m_PaneOne)
		{
			m_iSplitWidth = 7;
		}
		else
		{
			m_iSplitWidth = 0;
		}
	}

	void CFakeSplitter::SetPaneTwo(HWND paneTwo) noexcept { m_PaneTwo = paneTwo; }

	void CFakeSplitter::OnSize(UINT /*nType*/, const int cx, const int cy)
	{
		CalcSplitPos();

		auto hdwp = WC_D(HDWP, BeginDeferWindowPos(2));
		if (hdwp)
		{
			hdwp = EC_D(HDWP, DeferWindowPos(hdwp, 0, 0, cx, cy));
			EC_B_S(EndDeferWindowPos(hdwp));
		}
	}

	HDWP CFakeSplitter::DeferWindowPos(
		_In_ HDWP hWinPosInfo,
		_In_ const int x,
		_In_ const int y,
		_In_ const int width,
		_In_ const int height)
	{
		output::DebugPrint(
			output::dbgLevel::Draw,
			L"CFakeSplitter::DeferWindowPos x:%d y:%d width:%d height:%d v:%d\n",
			x,
			y,
			width,
			height,
			IsWindowVisible());
		InvalidateRect(CRect(x, y, width, height), false);
		if (m_PaneOne || m_ViewPaneOne)
		{
			CRect r1;
			if (m_SplitType == splitType::horizontal)
			{
				r1.SetRect(x, y, m_iSplitPos, height);
			}
			else
			{
				r1.SetRect(x, y, width, m_iSplitPos);
			}

			if (m_PaneOne)
			{
				hWinPosInfo = ui::DeferWindowPos(hWinPosInfo, m_PaneOne, x, y, r1.Width(), r1.Height(), L"CFakeSplitter::DeferWindowPos pane 1");
			}

			if (m_ViewPaneOne)
			{
				output::DebugPrint(
					output::dbgLevel::Draw,
					L"CFakeSplitter::DeferWindowPos viewpane 1 x:%d y:%d width:%d height:%d\n",
					x,
					y,
					width,
					height);
				hWinPosInfo = EC_D(HDWP, m_ViewPaneOne->DeferWindowPos(hWinPosInfo, x, y, r1.Width(), r1.Height()));
			}
		}

		if (m_PaneTwo || m_ViewPaneTwo)
		{
			CRect r2;
			if (m_SplitType == splitType::horizontal)
			{
				r2.SetRect(
					x + m_iSplitPos + m_iSplitWidth, // new x
					y, // new y
					width, // bottom right corner
					height); // bottom right corner
			}
			else
			{
				r2.SetRect(
					x, // new x
					y + m_iSplitPos + m_iSplitWidth, // new y
					width, // bottom right corner
					height); // bottom right corner
			}

			if (m_PaneTwo)
			{
				hWinPosInfo = ui::DeferWindowPos(hWinPosInfo, m_PaneTwo, r2.left, r2.top, r2.Width(), r2.Height(), L"CFakeSplitter::DeferWindowPos pane 2");
			}

			if (m_ViewPaneTwo)
			{
				output::DebugPrint(
					output::dbgLevel::Draw,
					L"CFakeSplitter::DeferWindowPos view pane 2 x:%d y:%d width:%d height:%d\n",
					x,
					y,
					width,
					height);
				hWinPosInfo =
					EC_D(HDWP, m_ViewPaneTwo->DeferWindowPos(hWinPosInfo, r2.left, r2.top, r2.Width(), r2.Height()));
			}
		}

		output::DebugPrint(output::dbgLevel::Draw, L"CFakeSplitter::DeferWindowPos end\n");
		return hWinPosInfo;
	}

	void CFakeSplitter::CalcSplitPos()
	{
		if (!m_PaneOne && !m_ViewPaneOne)
		{
			m_iSplitPos = 0;
			return;
		}

		int iCurSpan = 0;
		CRect rect;
		GetClientRect(rect);
		if (m_SplitType == splitType::horizontal)
		{
			iCurSpan = rect.Width();
		}
		else
		{
			iCurSpan = rect.Height();
		}

		m_iSplitPos = static_cast<int>(static_cast<FLOAT>(iCurSpan) * m_flSplitPercent);
		auto paneOneMinSpan = PaneOneMinSpanCallback ? PaneOneMinSpanCallback() : 0;
		auto paneTwoMinSpan = PaneTwoMinSpanCallback ? PaneTwoMinSpanCallback() : 0;
		if (paneOneMinSpan + paneTwoMinSpan + m_iSplitWidth + 1 >= iCurSpan)
		{
			paneOneMinSpan = 0;
			paneTwoMinSpan = 0;
		}

		if (m_iSplitPos < paneOneMinSpan)
		{
			m_iSplitPos = paneOneMinSpan;
		}
		else if (iCurSpan - m_iSplitPos < paneTwoMinSpan)
		{
			m_iSplitPos = iCurSpan - paneTwoMinSpan;
		}

		if (m_iSplitPos + m_iSplitWidth + 1 >= iCurSpan)
		{
			m_iSplitPos = m_iSplitPos - m_iSplitWidth - 1;
		}

		if (m_iSplitPos < 0) m_iSplitPos = 0;
	}

	void CFakeSplitter::SetPercent(const FLOAT iNewPercent)
	{
		if (iNewPercent < 0.0 || iNewPercent > 1.0) return;
		m_flSplitPercent = iNewPercent;

		CalcSplitPos();

		CRect rect;
		GetClientRect(rect);

		// Recalculate our layout
		OnSize(0, rect.Width(), rect.Height());
	}

	void CFakeSplitter::SetSplitType(const splitType stSplitType) noexcept { m_SplitType = stSplitType; }

	_Check_return_ int CFakeSplitter::HitTest(const LONG x, const LONG y) const noexcept
	{
		if (!m_PaneOne && !m_ViewPaneOne) return noHit;

		LONG lTestPos = 0;

		if (m_SplitType == splitType::horizontal)
		{
			lTestPos = x;
		}
		else
		{
			lTestPos = y;
		}

		if (lTestPos >= m_iSplitPos && lTestPos <= m_iSplitPos + m_iSplitWidth) return SplitterHit;

		return noHit;
	}

	void CFakeSplitter::OnMouseMove(UINT /*nFlags*/, const CPoint point)
	{
		if (!m_PaneOne && !m_ViewPaneOne) return;

		// If we don't have GetCapture, then we don't want to track right now.
		if (GetCapture() != this) StopTracking();

		if (SplitterHit == HitTest(point.x, point.y))
		{
			// This looks backwards, but it is not. A horizontal split needs the vertical cursor
			SetCursor(m_SplitType == splitType::horizontal ? m_hSplitCursorV : m_hSplitCursorH);
		}

		if (m_bTracking)
		{
			CRect Rect;
			FLOAT flNewPercent = {};
			GetWindowRect(Rect);

			if (m_SplitType == splitType::horizontal)
			{
				flNewPercent = point.x / static_cast<FLOAT>(Rect.Width());
			}
			else
			{
				flNewPercent = point.y / static_cast<FLOAT>(Rect.Height());
			}
			SetPercent(flNewPercent);

			// Force child windows to refresh now
			EC_B_S(RedrawWindow(nullptr, nullptr, RDW_ALLCHILDREN | RDW_UPDATENOW));
		}
	}

	void CFakeSplitter::StartTracking(const int ht)
	{
		if (ht == noHit) return;

		// steal focus and capture
		SetCapture();
		SetFocus();

		// make sure no updates are pending
		// CSplitterWnd does this...not sure why
		EC_B_S(RedrawWindow(nullptr, nullptr, RDW_ALLCHILDREN | RDW_UPDATENOW));

		// set tracking state and appropriate cursor
		m_bTracking = true;

		// Force redraw to get our tracking gripper
		SetPercent(m_flSplitPercent);
	}

	void CFakeSplitter::StopTracking()
	{
		if (!m_bTracking) return;

		ReleaseCapture();

		m_bTracking = false;

		// Force redraw to get our non-tracking gripper
		SetPercent(m_flSplitPercent);
	}

	void CFakeSplitter::OnPaint()
	{
		auto ps = PAINTSTRUCT{};
		::BeginPaint(m_hWnd, &ps);
		if (ps.hdc)
		{
			auto rcWin = RECT{};
			::GetClientRect(m_hWnd, &rcWin);
			ui::CDoubleBuffer db;
			auto hdc = ps.hdc;
			db.Begin(hdc, rcWin);

			auto rcSplitter = rcWin;
			FillRect(hdc, &rcSplitter, GetSysBrush(ui::uiColor::Background));

			POINT pts[2] = {}; // 0 is left top, 1 is right bottom
			if (m_SplitType == splitType::horizontal)
			{
				pts[0].x = m_iSplitPos + m_iSplitWidth / 2;
				pts[0].y = rcSplitter.top;
				pts[1].x = pts[0].x;
				pts[1].y = rcSplitter.bottom;
			}
			else
			{
				pts[0].x = rcSplitter.left;
				pts[0].y = m_iSplitPos + m_iSplitWidth / 2;
				pts[1].x = rcSplitter.right;
				pts[1].y = pts[0].y;
			}

			// Draw the splitter bar
			const auto hpenOld = SelectObject(hdc, GetPen(m_bTracking ? ui::uiPen::SolidPen : ui::uiPen::DashedPen));
			MoveToEx(hdc, pts[0].x, pts[0].y, nullptr);
			LineTo(hdc, pts[1].x, pts[1].y);
			static_cast<void>(SelectObject(hdc, hpenOld));

			db.End(hdc);
		}

		::EndPaint(m_hWnd, &ps);
	}
} // namespace controls<commit_msg>Fix tabs in splitter controls<commit_after>#include <StdAfx.h>
#include <UI/Controls/FakeSplitter.h>
#include <UI/UIFunctions.h>
#include <UI/DoubleBuffer.h>
#include <core/utility/output.h>

namespace controls
{
	static std::wstring CLASS = L"CFakeSplitter";

	enum FakesSplitHitTestValue
	{
		noHit = 0,
		SplitterHit = 1
	};

	CFakeSplitter::~CFakeSplitter()
	{
		TRACE_DESTRUCTOR(CLASS);
		static_cast<void>(DestroyCursor(m_hSplitCursorH));
		static_cast<void>(DestroyCursor(m_hSplitCursorV));
		CWnd::DestroyWindow();
	}

	void CFakeSplitter::Init(HWND hWnd)
	{
		m_hwndParent = hWnd;
		WNDCLASSEX wc = {};
		const auto hInst = AfxGetInstanceHandle();
		if (!::GetClassInfoEx(hInst, _T("FakeSplitter"), &wc)) // STRING_OK
		{
			wc.cbSize = sizeof wc;
			wc.style = 0; // not passing CS_VREDRAW | CS_HREDRAW fixes flicker
			wc.lpszClassName = _T("FakeSplitter"); // STRING_OK
			wc.lpfnWndProc = ::DefWindowProc;
			wc.hbrBackground = GetSysBrush(ui::uiColor::Background); // helps spot flashing

			RegisterClassEx(&wc);
		}

		// WS_CLIPCHILDREN is used to reduce flicker
		EC_B_S(CreateEx(
			0,
			_T("FakeSplitter"), // STRING_OK
			_T("FakeSplitter"), // STRING_OK
			WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE,
			0,
			0,
			0,
			0,
			m_hwndParent,
			reinterpret_cast<HMENU>(static_cast<INT_PTR>(IDC_FAKE_SPLITTER)),
			nullptr));

		// Necessary for TAB to work. Without this, all TABS get stuck on the fake splitter control
		// instead of passing to the children. Haven't tested with nested splitters.
		EC_B_S(ModifyStyleEx(0, WS_EX_CONTROLPARENT));

		// Load split cursors
		m_hSplitCursorV = EC_D(HCURSOR, ::LoadCursor(GetModuleHandle(nullptr), MAKEINTRESOURCE(IDC_SPLITV)));
		m_hSplitCursorH = EC_D(HCURSOR, ::LoadCursor(GetModuleHandle(nullptr), MAKEINTRESOURCE(IDC_SPLITH)));
	}

	BEGIN_MESSAGE_MAP(CFakeSplitter, CWnd)
	ON_WM_MOUSEMOVE()
	ON_WM_SIZE()
	ON_WM_PAINT()
	END_MESSAGE_MAP()

	LRESULT CFakeSplitter::WindowProc(const UINT message, const WPARAM wParam, const LPARAM lParam)
	{
		LRESULT lRes = 0;
		if (ui::HandleControlUI(message, wParam, lParam, &lRes)) return lRes;

		switch (message)
		{
		case WM_CLOSE:
			::SendMessage(m_hwndParent, message, wParam, lParam);
			return true;
		case WM_HELP:
			return true;
		case WM_LBUTTONUP:
		case WM_CANCELMODE: // Called if focus changes while we're adjusting the splitter
			StopTracking();
			return NULL;
		case WM_LBUTTONDOWN:
			if (m_bTracking) return true;
			StartTracking(HitTest(LOWORD(lParam), HIWORD(lParam)));
			return NULL;
		case WM_SETCURSOR:
			if (LOWORD(lParam) == HTCLIENT && reinterpret_cast<HWND>(wParam) == this->m_hWnd && !m_bTracking)
				return true; // we will handle it in the mouse move
			break;
		case WM_NEXTDLGCTL:
			// Ensure tabs are handled by parent dialog
			return ::SendMessage(m_hwndParent, message, wParam, lParam);
		case WM_COMMAND:
		{
			const auto nCode = HIWORD(wParam);
			if (EN_CHANGE == nCode || CBN_SELCHANGE == nCode || CBN_EDITCHANGE == nCode || BN_CLICKED == nCode)
			{
				::SendMessage(m_hwndParent, message, wParam, lParam);
			}

			break;
		}
		}

		return CWnd::WindowProc(message, wParam, lParam);
	}

	void CFakeSplitter::SetPaneOne(HWND paneOne) noexcept
	{
		m_PaneOne = paneOne;
		if (m_PaneOne)
		{
			m_iSplitWidth = 7;
		}
		else
		{
			m_iSplitWidth = 0;
		}
	}

	void CFakeSplitter::SetPaneTwo(HWND paneTwo) noexcept { m_PaneTwo = paneTwo; }

	void CFakeSplitter::OnSize(UINT /*nType*/, const int cx, const int cy)
	{
		CalcSplitPos();

		auto hdwp = WC_D(HDWP, BeginDeferWindowPos(2));
		if (hdwp)
		{
			hdwp = EC_D(HDWP, DeferWindowPos(hdwp, 0, 0, cx, cy));
			EC_B_S(EndDeferWindowPos(hdwp));
		}
	}

	HDWP CFakeSplitter::DeferWindowPos(
		_In_ HDWP hWinPosInfo,
		_In_ const int x,
		_In_ const int y,
		_In_ const int width,
		_In_ const int height)
	{
		output::DebugPrint(
			output::dbgLevel::Draw,
			L"CFakeSplitter::DeferWindowPos x:%d y:%d width:%d height:%d v:%d\n",
			x,
			y,
			width,
			height,
			IsWindowVisible());
		InvalidateRect(CRect(x, y, width, height), false);
		if (m_PaneOne || m_ViewPaneOne)
		{
			CRect r1;
			if (m_SplitType == splitType::horizontal)
			{
				r1.SetRect(x, y, m_iSplitPos, height);
			}
			else
			{
				r1.SetRect(x, y, width, m_iSplitPos);
			}

			if (m_PaneOne)
			{
				hWinPosInfo = ui::DeferWindowPos(hWinPosInfo, m_PaneOne, x, y, r1.Width(), r1.Height(), L"CFakeSplitter::DeferWindowPos pane 1");
			}

			if (m_ViewPaneOne)
			{
				output::DebugPrint(
					output::dbgLevel::Draw,
					L"CFakeSplitter::DeferWindowPos viewpane 1 x:%d y:%d width:%d height:%d\n",
					x,
					y,
					width,
					height);
				hWinPosInfo = EC_D(HDWP, m_ViewPaneOne->DeferWindowPos(hWinPosInfo, x, y, r1.Width(), r1.Height()));
			}
		}

		if (m_PaneTwo || m_ViewPaneTwo)
		{
			CRect r2;
			if (m_SplitType == splitType::horizontal)
			{
				r2.SetRect(
					x + m_iSplitPos + m_iSplitWidth, // new x
					y, // new y
					width, // bottom right corner
					height); // bottom right corner
			}
			else
			{
				r2.SetRect(
					x, // new x
					y + m_iSplitPos + m_iSplitWidth, // new y
					width, // bottom right corner
					height); // bottom right corner
			}

			if (m_PaneTwo)
			{
				hWinPosInfo = ui::DeferWindowPos(hWinPosInfo, m_PaneTwo, r2.left, r2.top, r2.Width(), r2.Height(), L"CFakeSplitter::DeferWindowPos pane 2");
			}

			if (m_ViewPaneTwo)
			{
				output::DebugPrint(
					output::dbgLevel::Draw,
					L"CFakeSplitter::DeferWindowPos view pane 2 x:%d y:%d width:%d height:%d\n",
					x,
					y,
					width,
					height);
				hWinPosInfo =
					EC_D(HDWP, m_ViewPaneTwo->DeferWindowPos(hWinPosInfo, r2.left, r2.top, r2.Width(), r2.Height()));
			}
		}

		output::DebugPrint(output::dbgLevel::Draw, L"CFakeSplitter::DeferWindowPos end\n");
		return hWinPosInfo;
	}

	void CFakeSplitter::CalcSplitPos()
	{
		if (!m_PaneOne && !m_ViewPaneOne)
		{
			m_iSplitPos = 0;
			return;
		}

		int iCurSpan = 0;
		CRect rect;
		GetClientRect(rect);
		if (m_SplitType == splitType::horizontal)
		{
			iCurSpan = rect.Width();
		}
		else
		{
			iCurSpan = rect.Height();
		}

		m_iSplitPos = static_cast<int>(static_cast<FLOAT>(iCurSpan) * m_flSplitPercent);
		auto paneOneMinSpan = PaneOneMinSpanCallback ? PaneOneMinSpanCallback() : 0;
		auto paneTwoMinSpan = PaneTwoMinSpanCallback ? PaneTwoMinSpanCallback() : 0;
		if (paneOneMinSpan + paneTwoMinSpan + m_iSplitWidth + 1 >= iCurSpan)
		{
			paneOneMinSpan = 0;
			paneTwoMinSpan = 0;
		}

		if (m_iSplitPos < paneOneMinSpan)
		{
			m_iSplitPos = paneOneMinSpan;
		}
		else if (iCurSpan - m_iSplitPos < paneTwoMinSpan)
		{
			m_iSplitPos = iCurSpan - paneTwoMinSpan;
		}

		if (m_iSplitPos + m_iSplitWidth + 1 >= iCurSpan)
		{
			m_iSplitPos = m_iSplitPos - m_iSplitWidth - 1;
		}

		if (m_iSplitPos < 0) m_iSplitPos = 0;
	}

	void CFakeSplitter::SetPercent(const FLOAT iNewPercent)
	{
		if (iNewPercent < 0.0 || iNewPercent > 1.0) return;
		m_flSplitPercent = iNewPercent;

		CalcSplitPos();

		CRect rect;
		GetClientRect(rect);

		// Recalculate our layout
		OnSize(0, rect.Width(), rect.Height());
	}

	void CFakeSplitter::SetSplitType(const splitType stSplitType) noexcept { m_SplitType = stSplitType; }

	_Check_return_ int CFakeSplitter::HitTest(const LONG x, const LONG y) const noexcept
	{
		if (!m_PaneOne && !m_ViewPaneOne) return noHit;

		LONG lTestPos = 0;

		if (m_SplitType == splitType::horizontal)
		{
			lTestPos = x;
		}
		else
		{
			lTestPos = y;
		}

		if (lTestPos >= m_iSplitPos && lTestPos <= m_iSplitPos + m_iSplitWidth) return SplitterHit;

		return noHit;
	}

	void CFakeSplitter::OnMouseMove(UINT /*nFlags*/, const CPoint point)
	{
		if (!m_PaneOne && !m_ViewPaneOne) return;

		// If we don't have GetCapture, then we don't want to track right now.
		if (GetCapture() != this) StopTracking();

		if (SplitterHit == HitTest(point.x, point.y))
		{
			// This looks backwards, but it is not. A horizontal split needs the vertical cursor
			SetCursor(m_SplitType == splitType::horizontal ? m_hSplitCursorV : m_hSplitCursorH);
		}

		if (m_bTracking)
		{
			CRect Rect;
			FLOAT flNewPercent = {};
			GetWindowRect(Rect);

			if (m_SplitType == splitType::horizontal)
			{
				flNewPercent = point.x / static_cast<FLOAT>(Rect.Width());
			}
			else
			{
				flNewPercent = point.y / static_cast<FLOAT>(Rect.Height());
			}
			SetPercent(flNewPercent);

			// Force child windows to refresh now
			EC_B_S(RedrawWindow(nullptr, nullptr, RDW_ALLCHILDREN | RDW_UPDATENOW));
		}
	}

	void CFakeSplitter::StartTracking(const int ht)
	{
		if (ht == noHit) return;

		// steal focus and capture
		SetCapture();
		SetFocus();

		// make sure no updates are pending
		// CSplitterWnd does this...not sure why
		EC_B_S(RedrawWindow(nullptr, nullptr, RDW_ALLCHILDREN | RDW_UPDATENOW));

		// set tracking state and appropriate cursor
		m_bTracking = true;

		// Force redraw to get our tracking gripper
		SetPercent(m_flSplitPercent);
	}

	void CFakeSplitter::StopTracking()
	{
		if (!m_bTracking) return;

		ReleaseCapture();

		m_bTracking = false;

		// Force redraw to get our non-tracking gripper
		SetPercent(m_flSplitPercent);
	}

	void CFakeSplitter::OnPaint()
	{
		auto ps = PAINTSTRUCT{};
		::BeginPaint(m_hWnd, &ps);
		if (ps.hdc)
		{
			auto rcWin = RECT{};
			::GetClientRect(m_hWnd, &rcWin);
			ui::CDoubleBuffer db;
			auto hdc = ps.hdc;
			db.Begin(hdc, rcWin);

			auto rcSplitter = rcWin;
			FillRect(hdc, &rcSplitter, GetSysBrush(ui::uiColor::Background));

			POINT pts[2] = {}; // 0 is left top, 1 is right bottom
			if (m_SplitType == splitType::horizontal)
			{
				pts[0].x = m_iSplitPos + m_iSplitWidth / 2;
				pts[0].y = rcSplitter.top;
				pts[1].x = pts[0].x;
				pts[1].y = rcSplitter.bottom;
			}
			else
			{
				pts[0].x = rcSplitter.left;
				pts[0].y = m_iSplitPos + m_iSplitWidth / 2;
				pts[1].x = rcSplitter.right;
				pts[1].y = pts[0].y;
			}

			// Draw the splitter bar
			const auto hpenOld = SelectObject(hdc, GetPen(m_bTracking ? ui::uiPen::SolidPen : ui::uiPen::DashedPen));
			MoveToEx(hdc, pts[0].x, pts[0].y, nullptr);
			LineTo(hdc, pts[1].x, pts[1].y);
			static_cast<void>(SelectObject(hdc, hpenOld));

			db.End(hdc);
		}

		::EndPaint(m_hWnd, &ps);
	}
} // namespace controls<|endoftext|>


<commit_before>/*
 * CommonESP8266.cpp
 *
 *  Created on: Nov 13, 2015
 *      Author: Supun Jayathilake (supunj@gmail.com)
 */

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266mDNS.h>
#include <ESP8266WebServer.h>
#include "base64.h"
#include "esp8266util.h"
//#include <ArduinoJson.h>
#include "eepromutil.h"

MDNSResponder mdns;
ESP8266WebServer server(80);
WiFiClient client;

ESP8266Util::ESP8266Util(char* sid, char* pwd, const int ind_led) :
		ssid(sid), password(pwd), indicator_led(ind_led) {
}

/**
 * Connect to the wifi
 */
void ESP8266Util::wifiConnect() {
	// set WiFi mode to station (client)
	WiFi.mode(WIFI_STA);

	// initiate
	WiFi.begin(ssid, password);
	Serial.println("");

	// Wait for connection
	while (WiFi.status() != WL_CONNECTED) {
		delay(500);
		Serial.print(".");
	}

	// get the ip address
	ip = WiFi.localIP();
	Serial.println("");
	Serial.print("Connected to ");
	Serial.println(ssid);
	Serial.print("IP address: ");
	Serial.println(ip);

	if (mdns.begin("esp8266", ip)) {
		Serial.println("MDNS responder started");
	}
}

/**
 * Keep updating dns
 */
void ESP8266Util::mdnsUpdate() {
	mdns.update();
}

bool ESP8266Util::startWebServer() {
	// bind non-memeber functions
	std::function<void(void)> handleRoot(
			std::bind(&ESP8266Util::handleRoot, this));
	std::function<void(void)> handleNotFound(
			std::bind(&ESP8266Util::handleNotFound, this));
	std::function<void(void)> resetDevice(
			std::bind(&ESP8266Util::resetDevice, this));
	std::function<void(void)> restartDevice(
			std::bind(&ESP8266Util::restartDevice, this));
	std::function<void(void)> store(std::bind(&ESP8266Util::store, this));
	std::function<String(void)> readAll(std::bind(&ESP8266Util::readAll, this));
	std::function<void(void)> clearEEPROM(
			std::bind(&ESP8266Util::clearEEPROM, this));

	server.on("/", handleRoot);
	server.on("/reset", resetDevice);
	server.on("/restart", restartDevice);
	server.on("/store", store);
	server.on("/readall", readAll);
	server.on("/clear", clearEEPROM);
	server.onNotFound(handleNotFound);
	server.begin();
	Serial.println("HTTP server started");
	return true;
}

/**
 * handle web server root
 */
void ESP8266Util::handleRoot() {
	digitalWrite(indicator_led, 1);
	char temp[400];
	int sec = millis() / 1000;
	int min = sec / 60;
	int hr = min / 60;

	snprintf(temp, 400,

			"\
  \
    <meta http-equiv='refresh' content='5'/>\
    <title>ESP8266 Demo</title>\
    \
  \
  \

Hello from ESP8266!
\

Uptime: %02d:%02d:%02d
\
    \
  \
",

			hr, min % 60, sec % 60);
	server.send(200, "text/html", temp);
	digitalWrite(indicator_led, 0);
}

/**
 * handle resource not found
 */
void ESP8266Util::handleNotFound() {
	digitalWrite(indicator_led, 1);
	String message = "File Not Found\n\n";
	message += "URI: ";
	message += server.uri();
	message += "\nMethod: ";
	message += (server.method() == HTTP_GET) ? "GET" : "POST";
	message += "\nArguments: ";
	message += server.args();
	message += "\n";

	for (uint8_t i = 0; i < server.args(); i++) {
		message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
	}

	server.send(404, "text/plain", message);
	digitalWrite(indicator_led, 0);
}

/**
 * handle web requests
 */
void ESP8266Util::handleWebClient() {
	server.handleClient();
}

/**
 * reset the device
 */
void ESP8266Util::resetDevice() {
	server.send(200, "text/plain", "device reset called");
	wdt_enable(WDTO_0MS);
	while (1) {
	}
}

/**
 * restart the device
 */
void ESP8266Util::restartDevice() {
	server.send(200, "text/plain", "device restart called");
	digitalWrite(12, LOW);
	delay(100);
	digitalWrite(12, HIGH);
}

/**
 * send http get request
 */
String ESP8266Util::httpGET(char* host, int port, String uri, const int wait) {
	if (!client.connect(host, port)) {
		Serial.println("connection failed");
		return "";
	}

	// this will send the request to the server
	client.print(
			String("GET ") + uri + " HTTP/1.1\r\n" + "Host: " + host + "\r\n"
					+ "Connection: close\r\n\r\n");

	// wait till response comes
	delay(wait);

	// read all the lines of the reply from server and print them to Serial
	String response = "";
	while (client.available()) {
		response.concat(client.readString());
		response.concat(client.readStringUntil('\r'));
	}

	//Serial.print(response);
	//Serial.println();
	Serial.println("closing connection");
	return response;
}

/**
 * send http post request
 */
String ESP8266Util::httpPOST(char* host, int port, String uri, String payload,
		const int wait) {
	if (!client.connect(host, port)) {
		Serial.println("connection failed");
		return "";
	}

	String enc = base64_encode(
			reinterpret_cast<const unsigned char*>(payload.c_str()),
			payload.length());

	// this will send the request to the server
	client.print(
			String("POST ") + uri + " HTTP/1.1\r\n" + "Host: " + host + "\r\n"
					+ "Accept: */*\r\n" + "Content-Length: " + enc.length()
					+ "\r\n"
					+ "Content-Type: application/x-www-form-urlencoded\r\n"
					+ "Connection: close\r\n\r\n" + enc);

	// wait till response comes
	delay(wait);

	// read all the lines of the reply from server and print them to Serial
	String response = "";
	while (client.available()) {
		response.concat(client.readStringUntil('\r'));
	}

	//Serial.print(response);
	//Serial.println();
	Serial.println("closing connection");
	return response;
}

void ESP8266Util::store() {
	EEPROMUtility.put("key1", "test");
	server.send(200, "text/plain", "key/value stored");
	Serial.println(EEPROMUtility.get("key1"));
}

String ESP8266Util::readAll() {
	String str = EEPROMUtility.readAll();
	Serial.println(str);
	server.send(200, "text/plain", str);
	return str;
}

void ESP8266Util::clearEEPROM() {
	EEPROMUtility.clear();
	server.send(200, "text/plain", "EEPROM cleared");
}

ESP8266Util::~ESP8266Util() {

}
<commit_msg>Web console related changes<commit_after>/*
 * CommonESP8266.cpp
 *
 *  Created on: Nov 13, 2015
 *      Author: Supun Jayathilake (supunj@gmail.com)
 */

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266mDNS.h>
#include <ESP8266WebServer.h>
#include "base64.h"
#include "esp8266util.h"
//#include <ArduinoJson.h>
#include "eepromutil.h"

MDNSResponder mdns;
ESP8266WebServer server(80);
WiFiClient client;

ESP8266Util::ESP8266Util(char* sid, char* pwd, const int ind_led) :
		ssid(sid), password(pwd), indicator_led(ind_led) {
}

/**
 * Connect to the wifi
 */
void ESP8266Util::wifiConnect() {
	// set WiFi mode to station (client)
	WiFi.mode(WIFI_STA);

	// initiate
	WiFi.begin(ssid, password);
	Serial.println("");

	// Wait for connection
	while (WiFi.status() != WL_CONNECTED) {
		delay(500);
		Serial.print(".");
	}

	// get the ip address
	ip = WiFi.localIP();
	Serial.println("");
	Serial.print("Connected to ");
	Serial.println(ssid);
	Serial.print("IP address: ");
	Serial.println(ip);

	if (mdns.begin("esp8266", ip)) {
		Serial.println("MDNS responder started");
	}
}

/**
 * Keep updating dns
 */
void ESP8266Util::mdnsUpdate() {
	mdns.update();
}

bool ESP8266Util::startWebServer() {
	// bind non-memeber functions
	std::function<void(void)> handleRoot(
			std::bind(&ESP8266Util::handleRoot, this));
	std::function<void(void)> handleNotFound(
			std::bind(&ESP8266Util::handleNotFound, this));
	std::function<void(void)> resetDevice(
			std::bind(&ESP8266Util::resetDevice, this));
	std::function<void(void)> restartDevice(
			std::bind(&ESP8266Util::restartDevice, this));
	std::function<void(void)> store(std::bind(&ESP8266Util::store, this));
	std::function<String(void)> readAll(std::bind(&ESP8266Util::readAll, this));
	std::function<void(void)> clearEEPROM(
			std::bind(&ESP8266Util::clearEEPROM, this));

	server.on("/", handleRoot);
	server.on("/reset", resetDevice);
	server.on("/restart", restartDevice);
	server.on("/store", store);
	server.on("/readall", readAll);
	server.on("/clear", clearEEPROM);
	server.onNotFound(handleNotFound);
	server.begin();
	Serial.println("HTTP server started");
	return true;
}

/**
 * handle web server root
 */
void ESP8266Util::handleRoot() {
	digitalWrite(indicator_led, 1);
	char temp[1000];
	int sec = millis() / 1000;
	int min = sec / 60;
	int hr = min / 60;

	snprintf(temp, 1000,
			"\
			  \
				<meta http-equiv='refresh' content='5'/>\
				<title>ESP8266 Based IoT Platform</title>\
			   \
			  \

ESP8266 Based IoT Platform
\

Reset the device
\

Re-start the device
\

Store value on EEPROM
\

Read all the values on EEPROM
\

Clear EEPROM
\

Uptime: %02d:%02d:%02d
\
			  \
			",
			hr, min % 60, sec % 60);
	server.send(200, "text/html", temp);
	digitalWrite(indicator_led, 0);
}

/**
 * handle resource not found
 */
void ESP8266Util::handleNotFound() {
	digitalWrite(indicator_led, 1);
	String message = "Resource not found\n\n";
	message += "URI: ";
	message += server.uri();
	message += "\nMethod: ";
	message += (server.method() == HTTP_GET) ? "GET" : "POST";
	message += "\nArguments: ";
	message += server.args();
	message += "\n";

	for (uint8_t i = 0; i < server.args(); i++) {
		message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
	}

	server.send(404, "text/plain", message);
	digitalWrite(indicator_led, 0);
}

/**
 * handle web requests
 */
void ESP8266Util::handleWebClient() {
	server.handleClient();
}

/**
 * reset the device
 */
void ESP8266Util::resetDevice() {
	server.send(200, "text/plain", "device reset called");
	wdt_enable(WDTO_0MS);
	while (1) {
	}
}

/**
 * restart the device
 */
void ESP8266Util::restartDevice() {
	server.send(200, "text/plain", "device restart called");
	digitalWrite(12, LOW);
	delay(100);
	digitalWrite(12, HIGH);
}

/**
 * send http get request
 */
String ESP8266Util::httpGET(char* host, int port, String uri, const int wait) {
	if (!client.connect(host, port)) {
		Serial.println("connection failed");
		return "";
	}

	// this will send the request to the server
	client.print(
			String("GET ") + uri + " HTTP/1.1\r\n" + "Host: " + host + "\r\n"
					+ "Connection: close\r\n\r\n");

	// wait till response comes
	delay(wait);

	// read all the lines of the reply from server and print them to Serial
	String response = "";
	while (client.available()) {
		response.concat(client.readString());
		response.concat(client.readStringUntil('\r'));
	}

	//Serial.print(response);
	//Serial.println();
	Serial.println("closing connection");
	return response;
}

/**
 * send http post request
 */
String ESP8266Util::httpPOST(char* host, int port, String uri, String payload,
		const int wait) {
	if (!client.connect(host, port)) {
		Serial.println("connection failed");
		return "";
	}

	String enc = base64_encode(
			reinterpret_cast<const unsigned char*>(payload.c_str()),
			payload.length());

	// this will send the request to the server
	client.print(
			String("POST ") + uri + " HTTP/1.1\r\n" + "Host: " + host + "\r\n"
					+ "Accept: */*\r\n" + "Content-Length: " + enc.length()
					+ "\r\n"
					+ "Content-Type: application/x-www-form-urlencoded\r\n"
					+ "Connection: close\r\n\r\n" + enc);

	// wait till response comes
	delay(wait);

	// read all the lines of the reply from server and print them to Serial
	String response = "";
	while (client.available()) {
		response.concat(client.readStringUntil('\r'));
	}

	//Serial.print(response);
	//Serial.println();
	Serial.println("closing connection");
	return response;
}

void ESP8266Util::store() {
	digitalWrite(indicator_led, 1);
	char temp[1000];
	int sec = millis() / 1000;
	int min = sec / 60;
	int hr = min / 60;

	snprintf(temp, 1000,
			"\
				  \
					<title>ESP8266 Based IoT Platform</title>\
				   \
				  \

Store key/value in the EEPROM
\
						<form action=\"/eepromstore\">\

\

\

\
								Key	\
								<input type=\"text\" name=\"key\"/>	\

\

\
								Value	\
								<input type=\"text\" name=\"value\"/>	\

\

\
									\
								<input type=\"submit\" name=\"store\" value=\"Store\"/>	\

\

\

\
				  \
				");
	server.send(200, "text/html", temp);
	digitalWrite(indicator_led, 0);

	EEPROMUtility.put("key1", "test");
	server.send(200, "text/plain", "key/value stored");
	Serial.println(EEPROMUtility.get("key1"));
}

String ESP8266Util::readAll() {
	String str = EEPROMUtility.readAll();
	Serial.println(str);
	server.send(200, "text/plain", str);
	return str;
}

void ESP8266Util::clearEEPROM() {
	EEPROMUtility.clear();
	server.send(200, "text/plain", "EEPROM cleared");
}

ESP8266Util::~ESP8266Util() {

}
<|endoftext|>


<commit_before>// Copyright (c) 2013, German Neuroinformatics Node (G-Node)
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted under the terms of the BSD License. See
// LICENSE file in the root of the Project.

#include "H5Group.hpp"
#include <nix/util/util.hpp>
#include "H5Exception.hpp"

namespace nix {
namespace hdf5 {

optGroup::optGroup(const H5Group &parent, const std::string &g_name)
    : parent(parent), g_name(g_name)
{}

boost::optional<H5Group> optGroup::operator() (bool create) const {
    if (parent.hasGroup(g_name)) {
        g = boost::optional<H5Group>(parent.openGroup(g_name));
    } else if (create) {
        g = boost::optional<H5Group>(parent.openGroup(g_name, true));
    }
    return g;
}

H5Group::H5Group() : LocID() {}

H5Group::H5Group(hid_t hid) : LocID(hid) {}

H5Group::H5Group(const H5Group &other) : LocID(other) {}

bool H5Group::hasObject(const std::string &name) const {
    // empty string should return false, not exception (which H5Lexists would)
    if (name.empty()) {
        return false;
    }

    HTri res = H5Lexists(hid, name.c_str(), H5P_DEFAULT);
    return res.check("H5Group::hasObject(): H5Lexists failed");
}

bool H5Group::objectOfType(const std::string &name, H5O_type_t type) const {
    H5O_info_t info;

    hid_t obj = H5Oopen(hid, name.c_str(), H5P_DEFAULT);

    if (!H5Iis_valid(obj)) {
        return false;
    }

    HErr err = H5Oget_info(obj, &info);
    err.check("Could not obtain object info");

    bool res = info.type == type;

    H5Oclose(obj);
    return res;
}

ndsize_t H5Group::objectCount() const {
    hsize_t n_objs;
    HErr res = H5Gget_num_objs(hid, &n_objs);
    res.check("Could not get object count");
    return n_objs;
}

boost::optional<H5Group> H5Group::findGroupByAttribute(const std::string &attribute, const std::string &value) const {
    boost::optional<H5Group> ret;

    // look up first direct sub-group that has given attribute with given value
    for (ndsize_t index = 0; index < objectCount(); index++) {
        std::string obj_name = objectName(index);
        if(hasGroup(obj_name)) {
            H5Group group = openGroup(obj_name, false);
            if(group.hasAttr(attribute)) {
                std::string attr_value;
                group.getAttr(attribute, attr_value);
                if (attr_value == value) {
                    ret = group;
                    break;
                }
            }
        }
    }

    return ret;
}

boost::optional<DataSet> H5Group::findDataByAttribute(const std::string &attribute, const std::string &value) const {
    std::vector<DataSet> dsets;
    boost::optional<DataSet> ret;

    // look up all direct sub-datasets that have the given attribute
    for (ndsize_t index = 0; index < objectCount(); index++) {
        std::string obj_name = objectName(index);
        if(hasData(obj_name)) {
            DataSet ds = openData(obj_name);

            if (ds.hasAttr(attribute)) {
                dsets.push_back(ds);
            }
        }
    }
    // look for first dataset with given attribute set to given value
    auto found = std::find_if(dsets.begin(), dsets.end(),
                 [value, attribute](DataSet &dset) {
                     std::string attr_value;
                     dset.getAttr(attribute, attr_value);
                     return attr_value == value; });
    if(found != dsets.end()) ret = *found;

    return ret;
}

std::string H5Group::objectName(ndsize_t index) const {
    // check if index valid
    if(index > objectCount()) {
        throw OutOfBounds("No object at given index",
			              static_cast<size_t>(index));
    }

    std::string str_name;
    // check whether name is found by index
    ssize_t name_len = H5Lget_name_by_idx(hid,
                                          ".",
                                          H5_INDEX_NAME,
                                          H5_ITER_NATIVE,
                                          (hsize_t) index,
                                          NULL,
                                          0,
                                          H5P_DEFAULT);
    if (name_len > 0) {
        char* name = new char[name_len+1];
        name_len = H5Lget_name_by_idx(hid,
                                      ".",
                                      H5_INDEX_NAME,
                                      H5_ITER_NATIVE,
                                      (hsize_t) index,
                                      name,
                                      name_len+1,
                                      H5P_DEFAULT);
        str_name = name;
        delete [] name;
    } else {
        throw H5Exception("objectName: No object found, H5Lget_name_by_idx returned no name");
    }

    return str_name;
}

bool H5Group::hasData(const std::string &name) const {
    return hasObject(name) && objectOfType(name, H5O_TYPE_DATASET);
}

void H5Group::removeData(const std::string &name) {
    if (hasData(name)) {
        HErr res = H5Gunlink(hid, name.c_str());
        res.check("H5Group::removeData(): Could not unlink DataSet");
    }
}

DataSet H5Group::createData(const std::string &name,
                            const h5x::DataType &fileType,
                            const NDSize &size,
                            const NDSize &maxsize,
                            NDSize chunks,
                            bool max_size_unlimited,
                            bool guess_chunks) const
{
    DataSpace space;

    if (size) {
        if (maxsize) {
            space = DataSpace::create(size, maxsize);
        } else {
            space = DataSpace::create(size, max_size_unlimited);
        }
    }

    H5Object dcpl = H5Pcreate(H5P_DATASET_CREATE);
    dcpl.check("Could not create data creation plist");

    if (!chunks && guess_chunks) {
        chunks = DataSet::guessChunking(size, fileType.size());
    }

    if (chunks) {
        int rank = static_cast<int>(chunks.size());
        HErr res = H5Pset_chunk(dcpl.h5id(), rank, chunks.data());
        res.check("Could not set chunk size on data set creation plist");
    }

    DataSet ds = H5Dcreate(hid, name.c_str(), fileType.h5id(), space.h5id(), H5P_DEFAULT, dcpl.h5id(), H5P_DEFAULT);
    ds.check("H5Group::createData: Could not create DataSet with name " + name);

    return ds;
}

DataSet H5Group::openData(const std::string &name) const {
    DataSet ds = H5Dopen(hid, name.c_str(), H5P_DEFAULT);
    ds.check("H5Group::openData(): Could not open DataSet");
    return ds;
}

bool H5Group::hasGroup(const std::string &name) const {
    return hasObject(name) && objectOfType(name, H5O_TYPE_GROUP);
}

H5Group H5Group::openGroup(const std::string &name, bool create) const {
    check_h5_arg_name(name);

    H5Group g;

    if (hasGroup(name)) {
        g = H5Group(H5Gopen(hid, name.c_str(), H5P_DEFAULT));
        g.check("H5Group::openGroup(): Could not open group: " + name);
    } else if (create) {
        H5Object gcpl = H5Pcreate(H5P_GROUP_CREATE);
        gcpl.check("Unable to create group with name '" + name + "'! (H5Pcreate)");

        //we want hdf5 to keep track of the order in which links were created so that
        //the order for indexed based accessors is stable cf. issue #387
        HErr res = H5Pset_link_creation_order(gcpl.h5id(), H5P_CRT_ORDER_TRACKED|H5P_CRT_ORDER_INDEXED);
        res.check("Unable to create group with name '" + name + "'! (H5Pset_link_cr...)");

        g = H5Group(H5Gcreate2(hid, name.c_str(), H5P_DEFAULT, gcpl.h5id(), H5P_DEFAULT));
        g.check("Unable to create group with name '" + name + "'! (H5Gcreate2)");

    } else {
        throw H5Exception("Unable to open group with name '" + name + "'!");
    }

    return g;
}

optGroup H5Group::openOptGroup(const std::string &name) {
    check_h5_arg_name(name);
    return optGroup(*this, name);
}

void H5Group::removeGroup(const std::string &name) {
    if (hasGroup(name))
        H5Gunlink(hid, name.c_str());
}

void H5Group::renameGroup(const std::string &old_name, const std::string &new_name) {
    check_h5_arg_name(new_name);

    if (hasGroup(old_name)) {
        H5Gmove(hid, old_name.c_str(), new_name.c_str()); //FIXME: H5Gmove is deprecated
    }
}

H5Group H5Group::createLink(const H5Group &target, const std::string &link_name) {
    check_h5_arg_name(link_name);

    HErr res = H5Lcreate_hard(target.hid, ".", hid, link_name.c_str(),
                              H5L_SAME_LOC, H5L_SAME_LOC);
    res.check("Unable to create link " + link_name);
    return openGroup(link_name, false);
}

// TODO implement some kind of roll-back in order to avoid half renamed links.
bool H5Group::renameAllLinks(const std::string &old_name, const std::string &new_name) {
    check_h5_arg_name(new_name);

    bool renamed = false;

    if (hasGroup(old_name)) {
        std::vector<std::string> links;

        H5Group group     = openGroup(old_name, false);
        std::string gname = group.name();

        while (! gname.empty()) {
            deleteLink(gname);
            links.push_back(gname);
            gname = group.name();
        }

        renamed = links.size() > 0;
        for (std::string curr_name: links) {
            size_t pos = curr_name.find_last_of('/') + 1;

            if (curr_name.substr(pos) == old_name) {
                curr_name.replace(curr_name.begin() + pos, curr_name.end(), new_name.begin(), new_name.end());
            }

            HErr res = H5Lcreate_hard(group.hid, ".", hid, curr_name.c_str(),
                                      H5L_SAME_LOC, H5L_SAME_LOC);
            renamed = renamed && res;
        }
    }

    return renamed;
}

// TODO implement some kind of roll-back in order to avoid half removed links.
bool H5Group::removeAllLinks(const std::string &name) {
    bool removed = false;

    if (hasGroup(name)) {
        H5Group group      = openGroup(name, false);

        std::string gname = group.name();

        while (! gname.empty()) {
            deleteLink(gname);
            gname = group.name();
        }

        removed = true;
    }

    return removed;
}

boost::optional<H5Group> H5Group::findGroupByNameOrAttribute(std::string const &attr, std::string const &value) const {

    if (hasObject(value)) {
        return boost::make_optional(openGroup(value, false));
    } else if (util::looksLikeUUID(value)) {
        return findGroupByAttribute(attr, value);
    } else {
        return boost::optional<H5Group>();
    }
}

boost::optional<DataSet> H5Group::findDataByNameOrAttribute(std::string const &attr, std::string const &value) const {

    if (hasObject(value)) {
        return boost::make_optional(openData(value));
    } else if (util::looksLikeUUID(value)) {
        return findDataByAttribute(attr, value);
    } else {
        return boost::optional<DataSet>();
    }
}

H5Group::~H5Group()
{}

} // namespace hdf5
} // namespace nix
<commit_msg>Set Group iteration order to tracked creation order<commit_after>// Copyright (c) 2013, German Neuroinformatics Node (G-Node)
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted under the terms of the BSD License. See
// LICENSE file in the root of the Project.

#include "H5Group.hpp"
#include <nix/util/util.hpp>
#include "H5Exception.hpp"

namespace nix {
namespace hdf5 {

optGroup::optGroup(const H5Group &parent, const std::string &g_name)
    : parent(parent), g_name(g_name)
{}

boost::optional<H5Group> optGroup::operator() (bool create) const {
    if (parent.hasGroup(g_name)) {
        g = boost::optional<H5Group>(parent.openGroup(g_name));
    } else if (create) {
        g = boost::optional<H5Group>(parent.openGroup(g_name, true));
    }
    return g;
}

H5Group::H5Group() : LocID() {}

H5Group::H5Group(hid_t hid) : LocID(hid) {}

H5Group::H5Group(const H5Group &other) : LocID(other) {}

bool H5Group::hasObject(const std::string &name) const {
    // empty string should return false, not exception (which H5Lexists would)
    if (name.empty()) {
        return false;
    }

    HTri res = H5Lexists(hid, name.c_str(), H5P_DEFAULT);
    return res.check("H5Group::hasObject(): H5Lexists failed");
}

bool H5Group::objectOfType(const std::string &name, H5O_type_t type) const {
    H5O_info_t info;

    hid_t obj = H5Oopen(hid, name.c_str(), H5P_DEFAULT);

    if (!H5Iis_valid(obj)) {
        return false;
    }

    HErr err = H5Oget_info(obj, &info);
    err.check("Could not obtain object info");

    bool res = info.type == type;

    H5Oclose(obj);
    return res;
}

ndsize_t H5Group::objectCount() const {
    hsize_t n_objs;
    HErr res = H5Gget_num_objs(hid, &n_objs);
    res.check("Could not get object count");
    return n_objs;
}

boost::optional<H5Group> H5Group::findGroupByAttribute(const std::string &attribute, const std::string &value) const {
    boost::optional<H5Group> ret;

    // look up first direct sub-group that has given attribute with given value
    for (ndsize_t index = 0; index < objectCount(); index++) {
        std::string obj_name = objectName(index);
        if(hasGroup(obj_name)) {
            H5Group group = openGroup(obj_name, false);
            if(group.hasAttr(attribute)) {
                std::string attr_value;
                group.getAttr(attribute, attr_value);
                if (attr_value == value) {
                    ret = group;
                    break;
                }
            }
        }
    }

    return ret;
}

boost::optional<DataSet> H5Group::findDataByAttribute(const std::string &attribute, const std::string &value) const {
    std::vector<DataSet> dsets;
    boost::optional<DataSet> ret;

    // look up all direct sub-datasets that have the given attribute
    for (ndsize_t index = 0; index < objectCount(); index++) {
        std::string obj_name = objectName(index);
        if(hasData(obj_name)) {
            DataSet ds = openData(obj_name);

            if (ds.hasAttr(attribute)) {
                dsets.push_back(ds);
            }
        }
    }
    // look for first dataset with given attribute set to given value
    auto found = std::find_if(dsets.begin(), dsets.end(),
                 [value, attribute](DataSet &dset) {
                     std::string attr_value;
                     dset.getAttr(attribute, attr_value);
                     return attr_value == value; });
    if(found != dsets.end()) ret = *found;

    return ret;
}

std::string H5Group::objectName(ndsize_t index) const {
    // check if index valid
    if(index > objectCount()) {
        throw OutOfBounds("No object at given index",
			              static_cast<size_t>(index));
    }

    std::string str_name;
    // check whether name is found by index
    ssize_t name_len = H5Lget_name_by_idx(hid,
                                          ".",
                                          H5_INDEX_CRT_ORDER,
                                          H5_ITER_INC,
                                          (hsize_t) index,
                                          NULL,
                                          0,
                                          H5P_DEFAULT);
    if (name_len > 0) {
        char* name = new char[name_len+1];
        name_len = H5Lget_name_by_idx(hid,
                                      ".",
                                      H5_INDEX_CRT_ORDER,
                                      H5_ITER_INC,
                                      (hsize_t) index,
                                      name,
                                      name_len+1,
                                      H5P_DEFAULT);
        str_name = name;
        delete [] name;
    } else {
        throw H5Exception("objectName: No object found, H5Lget_name_by_idx returned no name");
    }

    return str_name;
}

bool H5Group::hasData(const std::string &name) const {
    return hasObject(name) && objectOfType(name, H5O_TYPE_DATASET);
}

void H5Group::removeData(const std::string &name) {
    if (hasData(name)) {
        HErr res = H5Gunlink(hid, name.c_str());
        res.check("H5Group::removeData(): Could not unlink DataSet");
    }
}

DataSet H5Group::createData(const std::string &name,
                            const h5x::DataType &fileType,
                            const NDSize &size,
                            const NDSize &maxsize,
                            NDSize chunks,
                            bool max_size_unlimited,
                            bool guess_chunks) const
{
    DataSpace space;

    if (size) {
        if (maxsize) {
            space = DataSpace::create(size, maxsize);
        } else {
            space = DataSpace::create(size, max_size_unlimited);
        }
    }

    H5Object dcpl = H5Pcreate(H5P_DATASET_CREATE);
    dcpl.check("Could not create data creation plist");

    if (!chunks && guess_chunks) {
        chunks = DataSet::guessChunking(size, fileType.size());
    }

    if (chunks) {
        int rank = static_cast<int>(chunks.size());
        HErr res = H5Pset_chunk(dcpl.h5id(), rank, chunks.data());
        res.check("Could not set chunk size on data set creation plist");
    }

    DataSet ds = H5Dcreate(hid, name.c_str(), fileType.h5id(), space.h5id(), H5P_DEFAULT, dcpl.h5id(), H5P_DEFAULT);
    ds.check("H5Group::createData: Could not create DataSet with name " + name);

    return ds;
}

DataSet H5Group::openData(const std::string &name) const {
    DataSet ds = H5Dopen(hid, name.c_str(), H5P_DEFAULT);
    ds.check("H5Group::openData(): Could not open DataSet");
    return ds;
}

bool H5Group::hasGroup(const std::string &name) const {
    return hasObject(name) && objectOfType(name, H5O_TYPE_GROUP);
}

H5Group H5Group::openGroup(const std::string &name, bool create) const {
    check_h5_arg_name(name);

    H5Group g;

    if (hasGroup(name)) {
        g = H5Group(H5Gopen(hid, name.c_str(), H5P_DEFAULT));
        g.check("H5Group::openGroup(): Could not open group: " + name);
    } else if (create) {
        H5Object gcpl = H5Pcreate(H5P_GROUP_CREATE);
        gcpl.check("Unable to create group with name '" + name + "'! (H5Pcreate)");

        //we want hdf5 to keep track of the order in which links were created so that
        //the order for indexed based accessors is stable cf. issue #387
        HErr res = H5Pset_link_creation_order(gcpl.h5id(), H5P_CRT_ORDER_TRACKED|H5P_CRT_ORDER_INDEXED);
        res.check("Unable to create group with name '" + name + "'! (H5Pset_link_cr...)");

        g = H5Group(H5Gcreate2(hid, name.c_str(), H5P_DEFAULT, gcpl.h5id(), H5P_DEFAULT));
        g.check("Unable to create group with name '" + name + "'! (H5Gcreate2)");

    } else {
        throw H5Exception("Unable to open group with name '" + name + "'!");
    }

    return g;
}

optGroup H5Group::openOptGroup(const std::string &name) {
    check_h5_arg_name(name);
    return optGroup(*this, name);
}

void H5Group::removeGroup(const std::string &name) {
    if (hasGroup(name))
        H5Gunlink(hid, name.c_str());
}

void H5Group::renameGroup(const std::string &old_name, const std::string &new_name) {
    check_h5_arg_name(new_name);

    if (hasGroup(old_name)) {
        H5Gmove(hid, old_name.c_str(), new_name.c_str()); //FIXME: H5Gmove is deprecated
    }
}

H5Group H5Group::createLink(const H5Group &target, const std::string &link_name) {
    check_h5_arg_name(link_name);

    HErr res = H5Lcreate_hard(target.hid, ".", hid, link_name.c_str(),
                              H5L_SAME_LOC, H5L_SAME_LOC);
    res.check("Unable to create link " + link_name);
    return openGroup(link_name, false);
}

// TODO implement some kind of roll-back in order to avoid half renamed links.
bool H5Group::renameAllLinks(const std::string &old_name, const std::string &new_name) {
    check_h5_arg_name(new_name);

    bool renamed = false;

    if (hasGroup(old_name)) {
        std::vector<std::string> links;

        H5Group group     = openGroup(old_name, false);
        std::string gname = group.name();

        while (! gname.empty()) {
            deleteLink(gname);
            links.push_back(gname);
            gname = group.name();
        }

        renamed = links.size() > 0;
        for (std::string curr_name: links) {
            size_t pos = curr_name.find_last_of('/') + 1;

            if (curr_name.substr(pos) == old_name) {
                curr_name.replace(curr_name.begin() + pos, curr_name.end(), new_name.begin(), new_name.end());
            }

            HErr res = H5Lcreate_hard(group.hid, ".", hid, curr_name.c_str(),
                                      H5L_SAME_LOC, H5L_SAME_LOC);
            renamed = renamed && res;
        }
    }

    return renamed;
}

// TODO implement some kind of roll-back in order to avoid half removed links.
bool H5Group::removeAllLinks(const std::string &name) {
    bool removed = false;

    if (hasGroup(name)) {
        H5Group group      = openGroup(name, false);

        std::string gname = group.name();

        while (! gname.empty()) {
            deleteLink(gname);
            gname = group.name();
        }

        removed = true;
    }

    return removed;
}

boost::optional<H5Group> H5Group::findGroupByNameOrAttribute(std::string const &attr, std::string const &value) const {

    if (hasObject(value)) {
        return boost::make_optional(openGroup(value, false));
    } else if (util::looksLikeUUID(value)) {
        return findGroupByAttribute(attr, value);
    } else {
        return boost::optional<H5Group>();
    }
}

boost::optional<DataSet> H5Group::findDataByNameOrAttribute(std::string const &attr, std::string const &value) const {

    if (hasObject(value)) {
        return boost::make_optional(openData(value));
    } else if (util::looksLikeUUID(value)) {
        return findDataByAttribute(attr, value);
    } else {
        return boost::optional<DataSet>();
    }
}

H5Group::~H5Group()
{}

} // namespace hdf5
} // namespace nix
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "CppUnitTest.h"

using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace NP_DATETIME;

namespace CSS133Assignment1Tests
{
	TEST_CLASS(CTimeTests)
	{
	public:

		TEST_METHOD(EmptyConstructorTest)
		{
			validateTime(CTime());
		}

		TEST_METHOD(MaxHourConstructorTest)
		{
			CTime time = CTime(23);
			validateTime(time);
			Assert::AreEqual(time.getHour(), (short)23);
		}

		TEST_METHOD(OverflowMaxHourConstructorTest)
		{
			CTime time = CTime(24);
			validateTime(time);
			Assert::AreNotEqual(time.getHour(), (short)24);
		}

		TEST_METHOD(MaxMinuteConstructorTest)
		{
			CTime time = CTime(1, 59);
			validateTime(time);
			Assert::AreEqual(time.getHour(), (short)1);
			Assert::AreEqual(time.getMinute(), (short)59);
		}

		TEST_METHOD(OverflowMaxMinuteConstructorTest)
		{
			CTime time = CTime(1, 60);
			validateTime(time);
			Assert::AreEqual(time.getHour(), (short)1);
			Assert::AreNotEqual(time.getMinute(), (short)60);
		}

		TEST_METHOD(MaxSecondConstructorTest)
		{
			CTime time = CTime(1, 1, 59);
			validateTime(time);
			Assert::AreEqual(time.getHour(), (short)1);
			Assert::AreEqual(time.getMinute(), (short)1);
			Assert::AreEqual(time.getSecond(), (short)59);
		}

		TEST_METHOD(OverflowMaxSecondConstructorTest)
		{
			CTime time = CTime(1, 1, 60);
			validateTime(time);
			Assert::AreEqual(time.getHour(), (short)1);
			Assert::AreEqual(time.getMinute(), (short)1);
			Assert::AreNotEqual(time.getSecond(), (short)60);
		}

		TEST_METHOD(SetHourValidValues)
		{
			CTime time = CTime(0,0,0);
			for (short hour = 0; hour < 24; hour++) {
				time.setHour(hour);
				validateTime(time);
				Assert::AreEqual(time.getHour(), hour);
			}
		}

		/*TEST_METHOD(SetHourInValidValues)
		{
			CTime time = CTime(0, 0, 0);
			for (short hour = 0; hour < 24; hour++) {
				time.setHour(hour);
				validateTime(time);
				Assert::AreEqual(time.getHour(), hour);
			}
		}*/

	private:
		void validateTime(CTime time) {
			Assert::IsTrue(time.getHour() >= 0 && time.getHour() < 24);
			Assert::IsTrue(time.getMinute() >= 0 && time.getMinute() < 60);
			Assert::IsTrue(time.getSecond() >= 0 && time.getSecond() < 60);
		}

	};
}<commit_msg>Minute validation tests<commit_after>#include "stdafx.h"
#include "CppUnitTest.h"

using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace NP_DATETIME;

namespace CSS133Assignment1Tests
{
	TEST_CLASS(CTimeTests)
	{
	public:

		TEST_METHOD(EmptyConstructorTest)
		{
			validateTime(CTime());
		}

		TEST_METHOD(MaxHourConstructorTest)
		{
			CTime time = CTime(23);
			validateTime(time);
			Assert::AreEqual(time.getHour(), (short)23);
		}

		TEST_METHOD(OverflowMaxHourConstructorTest)
		{
			CTime time = CTime(24);
			validateTime(time);
			Assert::AreNotEqual(time.getHour(), (short)24);
		}

		TEST_METHOD(MaxMinuteConstructorTest)
		{
			CTime time = CTime(1, 59);
			validateTime(time);
			Assert::AreEqual(time.getHour(), (short)1);
			Assert::AreEqual(time.getMinute(), (short)59);
		}

		TEST_METHOD(OverflowMaxMinuteConstructorTest)
		{
			CTime time = CTime(1, 60);
			validateTime(time);
			Assert::AreEqual(time.getHour(), (short)1);
			Assert::AreNotEqual(time.getMinute(), (short)60);
		}

		TEST_METHOD(MaxSecondConstructorTest)
		{
			CTime time = CTime(1, 1, 59);
			validateTime(time);
			Assert::AreEqual(time.getHour(), (short)1);
			Assert::AreEqual(time.getMinute(), (short)1);
			Assert::AreEqual(time.getSecond(), (short)59);
		}

		TEST_METHOD(OverflowMaxSecondConstructorTest)
		{
			CTime time = CTime(1, 1, 60);
			validateTime(time);
			Assert::AreEqual(time.getHour(), (short)1);
			Assert::AreEqual(time.getMinute(), (short)1);
			Assert::AreNotEqual(time.getSecond(), (short)60);
		}

		TEST_METHOD(SetHourValidValues)
		{
			CTime time = CTime(0,0,0);
			for (short hour = 0; hour < 24; hour++) {
				time.setHour(hour);
				validateTime(time);
				Assert::AreEqual(time.getHour(), hour);
			}
		}

		TEST_METHOD(SetHourInValidValues)
		{
			CTime time = CTime(0, 0, 0);
			for (short hour = 24; hour < 100; hour++) {
				time.setHour(hour);
				validateTime(time);
				Assert::AreEqual(time.getHour(), (short)0);
			}
		}

		TEST_METHOD(SetMinuteValidValues)
		{
			CTime time = CTime(0, 0, 0);
			for (short minute = 0; minute < 60; minute++) {
				time.setMinute(minute);
				validateTime(time);
				Assert::AreEqual(time.getMinute(), minute);
			}
		}

		TEST_METHOD(SetMinuteInValidValues)
		{
			CTime time = CTime(0, 0, 0);
			for (short minute = 60; minute < 100; minute++) {
				time.setMinute(minute);
				validateTime(time);
				Assert::AreEqual(time.getMinute(), (short)0);
			}
		}

	private:
		void validateTime(CTime time) {
			Assert::IsTrue(time.getHour() >= 0 && time.getHour() < 24);
			Assert::IsTrue(time.getMinute() >= 0 && time.getMinute() < 60);
			Assert::IsTrue(time.getSecond() >= 0 && time.getSecond() < 60);
		}

	};
}<|endoftext|>