<commit_before>/*
 * Copyright (C) 2016 Patrizio Bekerle -- http://www.bekerle.com
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
 * for more details.
 *
 */

#include "qtexteditsearchwidget.h"
#include "ui_qtexteditsearchwidget.h"
#include <QEvent>
#include <QKeyEvent>
#include <QDebug>

QTextEditSearchWidget::QTextEditSearchWidget(QTextEdit *parent) :
    QWidget(parent),
    ui(new Ui::QTextEditSearchWidget)
{
    ui->setupUi(this);
    _textEdit = parent;
    hide();

    QObject::connect(ui->closeButton, SIGNAL(clicked()),
                     this, SLOT(deactivate()));
    QObject::connect(ui->searchLineEdit, SIGNAL(textChanged(const QString &)),
                     this, SLOT(searchLineEditTextChanged(const QString &)));
    QObject::connect(ui->searchDownButton, SIGNAL(clicked()),
                     this, SLOT(doSearchDown()));
    QObject::connect(ui->searchUpButton, SIGNAL(clicked()),
                     this, SLOT(doSearchUp()));
    QObject::connect(ui->replaceToggleButton, SIGNAL(toggled(bool)),
                     this, SLOT(setReplaceMode(bool)));
    QObject::connect(ui->replaceButton, SIGNAL(clicked()),
                     this, SLOT(doReplace()));
    QObject::connect(ui->replaceAllButton, SIGNAL(clicked()),
                     this, SLOT(doReplaceAll()));

    installEventFilter(this);
    ui->searchLineEdit->installEventFilter(this);
    ui->replaceLineEdit->installEventFilter(this);

#ifdef Q_OS_MAC
    // set the spacing to 9 for OS X
    layout()->setSpacing(9);
    ui->buttonFrame->layout()->setSpacing(9);

    // set the margin to 0 for the top buttons for OS X
    QString buttonStyle = "QPushButton {margin: 0}";
    ui->closeButton->setStyleSheet(buttonStyle);
    ui->searchDownButton->setStyleSheet(buttonStyle);
    ui->searchUpButton->setStyleSheet(buttonStyle);
    ui->replaceToggleButton->setStyleSheet(buttonStyle);
#endif
}

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

void QTextEditSearchWidget::activate() {
    setReplaceMode(false);
    show();
    ui->searchLineEdit->setFocus();
    ui->searchLineEdit->selectAll();
    doSearchDown();
}

void QTextEditSearchWidget::activateReplace() {
    activate();
    setReplaceMode(true);
}

void QTextEditSearchWidget::deactivate() {
    hide();
    _textEdit->setFocus();
}

void QTextEditSearchWidget::setReplaceMode(bool enabled) {
    ui->replaceToggleButton->setChecked(enabled);
    ui->replaceLabel->setVisible(enabled);
    ui->replaceLineEdit->setVisible(enabled);
    ui->buttonFrame->setVisible(enabled);
}

bool QTextEditSearchWidget::eventFilter(QObject *obj, QEvent *event) {
    if (event->type() == QEvent::KeyPress) {
        QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);

        if (keyEvent->key() == Qt::Key_Escape) {
            deactivate();
            return true;
        } else if ((keyEvent->modifiers().testFlag(Qt::ShiftModifier) &&
                  (keyEvent->key() == Qt::Key_Return)) ||
                 (keyEvent->key() == Qt::Key_Up)) {
            doSearchUp();
            return true;
        } else if ((keyEvent->key() == Qt::Key_Return) ||
                 (keyEvent->key() == Qt::Key_Down)) {
            doSearchDown();
            return true;
        } else if (keyEvent->key() == Qt::Key_F3) {
            doSearch(!keyEvent->modifiers().testFlag(Qt::ShiftModifier));
            return true;
        }

//        if ((obj == ui->replaceLineEdit) && (keyEvent->key() == Qt::Key_Tab)
//                && ui->replaceToggleButton->isChecked()) {
//            ui->replaceLineEdit->setFocus();
//        }

        return false;
    }

    return QWidget::eventFilter(obj, event);
}

void QTextEditSearchWidget::searchLineEditTextChanged(const QString &arg1) {
    Q_UNUSED(arg1);
    doSearchDown();
}

void QTextEditSearchWidget::doSearchUp() {
    doSearch(false);
}

void QTextEditSearchWidget::doSearchDown() {
    doSearch(true);
}

void QTextEditSearchWidget::doReplace() {
    if (_textEdit->isReadOnly()) {
        return;
    }

    QTextCursor c = _textEdit->textCursor();

    if (!c.selectedText().isEmpty()) {
        c.insertText(ui->replaceLineEdit->text());
        doSearch(true);
    }
}

void QTextEditSearchWidget::doReplaceAll() {
    if (_textEdit->isReadOnly()) {
        return;
    }

    while (doSearch(true)) {
        _textEdit->textCursor().insertText(ui->replaceLineEdit->text());
    }
}

/**
 * @brief Searches for text in the text edit
 */
bool QTextEditSearchWidget::doSearch(bool searchDown) {
    QString text = ui->searchLineEdit->text();

    if (text == "") {
        ui->searchLineEdit->setStyleSheet("* { background: none; }");
        return false;
    }

    QTextDocument::FindFlag options = searchDown ? QTextDocument::FindFlag(0)
                                                 : QTextDocument::FindBackward;
    bool found = _textEdit->find(text, options);

    // start at the top if not found
    if (!found) {
        _textEdit->moveCursor(
                searchDown ? QTextCursor::Start : QTextCursor::End);
        found = _textEdit->find(text, options);
    }

    QRect rect = _textEdit->cursorRect();
    QMargins margins = _textEdit->layout()->contentsMargins();
    int searchWidgetHotArea = _textEdit->height() - this->height();
    int marginBottom = (rect.y() > searchWidgetHotArea) ? (this->height() + 10)
                                                        : 0;

    // move the search box a bit up if we would block the search result
    if (margins.bottom() != marginBottom) {
        margins.setBottom(marginBottom);
        _textEdit->layout()->setContentsMargins(margins);
    }

    // add a background color according if we found the text or not
    QString colorCode = found ? "#D5FAE2" : "#FAE9EB";
    ui->searchLineEdit->setStyleSheet("* { background: " + colorCode + "; }");

    return found;
}

<commit_msg>when the text replace functionality is activated now the currently selected text will be entered in the search line edit<commit_after>/*
 * Copyright (C) 2016 Patrizio Bekerle -- http://www.bekerle.com
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
 * for more details.
 *
 */

#include "qtexteditsearchwidget.h"
#include "ui_qtexteditsearchwidget.h"
#include <QEvent>
#include <QKeyEvent>
#include <QDebug>

QTextEditSearchWidget::QTextEditSearchWidget(QTextEdit *parent) :
    QWidget(parent),
    ui(new Ui::QTextEditSearchWidget)
{
    ui->setupUi(this);
    _textEdit = parent;
    hide();

    QObject::connect(ui->closeButton, SIGNAL(clicked()),
                     this, SLOT(deactivate()));
    QObject::connect(ui->searchLineEdit, SIGNAL(textChanged(const QString &)),
                     this, SLOT(searchLineEditTextChanged(const QString &)));
    QObject::connect(ui->searchDownButton, SIGNAL(clicked()),
                     this, SLOT(doSearchDown()));
    QObject::connect(ui->searchUpButton, SIGNAL(clicked()),
                     this, SLOT(doSearchUp()));
    QObject::connect(ui->replaceToggleButton, SIGNAL(toggled(bool)),
                     this, SLOT(setReplaceMode(bool)));
    QObject::connect(ui->replaceButton, SIGNAL(clicked()),
                     this, SLOT(doReplace()));
    QObject::connect(ui->replaceAllButton, SIGNAL(clicked()),
                     this, SLOT(doReplaceAll()));

    installEventFilter(this);
    ui->searchLineEdit->installEventFilter(this);
    ui->replaceLineEdit->installEventFilter(this);

#ifdef Q_OS_MAC
    // set the spacing to 9 for OS X
    layout()->setSpacing(9);
    ui->buttonFrame->layout()->setSpacing(9);

    // set the margin to 0 for the top buttons for OS X
    QString buttonStyle = "QPushButton {margin: 0}";
    ui->closeButton->setStyleSheet(buttonStyle);
    ui->searchDownButton->setStyleSheet(buttonStyle);
    ui->searchUpButton->setStyleSheet(buttonStyle);
    ui->replaceToggleButton->setStyleSheet(buttonStyle);
#endif
}

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

void QTextEditSearchWidget::activate() {
    setReplaceMode(false);
    show();
    ui->searchLineEdit->setFocus();
    ui->searchLineEdit->selectAll();
    doSearchDown();
}

void QTextEditSearchWidget::activateReplace() {
    activate();
    ui->searchLineEdit->setText(_textEdit->textCursor().selectedText());
    setReplaceMode(true);
}

void QTextEditSearchWidget::deactivate() {
    hide();
    _textEdit->setFocus();
}

void QTextEditSearchWidget::setReplaceMode(bool enabled) {
    ui->replaceToggleButton->setChecked(enabled);
    ui->replaceLabel->setVisible(enabled);
    ui->replaceLineEdit->setVisible(enabled);
    ui->buttonFrame->setVisible(enabled);
}

bool QTextEditSearchWidget::eventFilter(QObject *obj, QEvent *event) {
    if (event->type() == QEvent::KeyPress) {
        QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);

        if (keyEvent->key() == Qt::Key_Escape) {
            deactivate();
            return true;
        } else if ((keyEvent->modifiers().testFlag(Qt::ShiftModifier) &&
                  (keyEvent->key() == Qt::Key_Return)) ||
                 (keyEvent->key() == Qt::Key_Up)) {
            doSearchUp();
            return true;
        } else if ((keyEvent->key() == Qt::Key_Return) ||
                 (keyEvent->key() == Qt::Key_Down)) {
            doSearchDown();
            return true;
        } else if (keyEvent->key() == Qt::Key_F3) {
            doSearch(!keyEvent->modifiers().testFlag(Qt::ShiftModifier));
            return true;
        }

//        if ((obj == ui->replaceLineEdit) && (keyEvent->key() == Qt::Key_Tab)
//                && ui->replaceToggleButton->isChecked()) {
//            ui->replaceLineEdit->setFocus();
//        }

        return false;
    }

    return QWidget::eventFilter(obj, event);
}

void QTextEditSearchWidget::searchLineEditTextChanged(const QString &arg1) {
    Q_UNUSED(arg1);
    doSearchDown();
}

void QTextEditSearchWidget::doSearchUp() {
    doSearch(false);
}

void QTextEditSearchWidget::doSearchDown() {
    doSearch(true);
}

void QTextEditSearchWidget::doReplace() {
    if (_textEdit->isReadOnly()) {
        return;
    }

    QTextCursor c = _textEdit->textCursor();

    if (!c.selectedText().isEmpty()) {
        c.insertText(ui->replaceLineEdit->text());
        doSearch(true);
    }
}

void QTextEditSearchWidget::doReplaceAll() {
    if (_textEdit->isReadOnly()) {
        return;
    }

    while (doSearch(true)) {
        _textEdit->textCursor().insertText(ui->replaceLineEdit->text());
    }
}

/**
 * @brief Searches for text in the text edit
 */
bool QTextEditSearchWidget::doSearch(bool searchDown) {
    QString text = ui->searchLineEdit->text();

    if (text == "") {
        ui->searchLineEdit->setStyleSheet("* { background: none; }");
        return false;
    }

    QTextDocument::FindFlag options = searchDown ? QTextDocument::FindFlag(0)
                                                 : QTextDocument::FindBackward;
    bool found = _textEdit->find(text, options);

    // start at the top if not found
    if (!found) {
        _textEdit->moveCursor(
                searchDown ? QTextCursor::Start : QTextCursor::End);
        found = _textEdit->find(text, options);
    }

    QRect rect = _textEdit->cursorRect();
    QMargins margins = _textEdit->layout()->contentsMargins();
    int searchWidgetHotArea = _textEdit->height() - this->height();
    int marginBottom = (rect.y() > searchWidgetHotArea) ? (this->height() + 10)
                                                        : 0;

    // move the search box a bit up if we would block the search result
    if (margins.bottom() != marginBottom) {
        margins.setBottom(marginBottom);
        _textEdit->layout()->setContentsMargins(margins);
    }

    // add a background color according if we found the text or not
    QString colorCode = found ? "#D5FAE2" : "#FAE9EB";
    ui->searchLineEdit->setStyleSheet("* { background: " + colorCode + "; }");

    return found;
}

<|endoftext|>


<commit_before>#include "QCodeHighlighter.h"

#include "xo/system/assert.h"
#include "xo/filesystem/path.h"
#include "xo/numerical/math.h"
#include "xo/string/string_tools.h"
#include "xo/utility/hash.h"
#include "xo/container/flat_map.h"
#include <string>

QCodeHighlighter::QCodeHighlighter( QObject* parent, Language l ) : QSyntaxHighlighter( parent )
{
	setLanguage( l );
}

QCodeHighlighter::QCodeHighlighter( QTextDocument* parent, Language l ) : QSyntaxHighlighter( parent )
{
	setLanguage( l );
}

void QCodeHighlighter::highlightBlock( const QString &text )
{
	for ( auto& r : rules )
		applyRule( text, r );

	// apply multi-line comments
	if ( !commentStartRegex.pattern().isEmpty() )
	{
		int commentStart = 0, searchIndex = 0;
		bool isComment = previousBlockState() == 1;

		while ( searchIndex >= 0 )
		{
			if ( isComment )
			{
				auto matchEnd = match( commentEndRegex, text, searchIndex );
				if ( !matchEnd.hasMatch() )
				{
					// multiline comment goes beyond this line
					setFormat( commentStart, text.length() - commentStart, commentFormat );
					break;
				}
				else
				{
					// multiline comment ends here
					setFormat( commentStart, matchEnd.capturedEnd() - commentStart, commentFormat );
					searchIndex = matchEnd.capturedEnd();
					isComment = false;
				}
			}
			if ( !isComment )
			{
				auto matchStart = match( commentStartRegex, text, searchIndex );
				if ( matchStart.hasMatch() )
				{
					// multiline comment starts here
					commentStart = matchStart.capturedStart();
					searchIndex = matchStart.capturedEnd();
					isComment = true;
				}
				else break; // no more comments in this line
			}
		}
		setCurrentBlockState( isComment ? 1 : 0 );
	}
}

bool QCodeHighlighter::isBetweenQuotes( const QString & text, int index )
{
	int quotes_before = 0;
	for ( int i = 0; i < index; ++i )
		quotes_before += int( text[ i ] == '\"' );
	return xo::is_odd( quotes_before );
}

QRegularExpressionMatch QCodeHighlighter::match( const QRegularExpression & regex, const QString & text, int index )
{
	auto m = regex.match( text, index );
	while ( m.hasMatch() && isBetweenQuotes( text, m.capturedStart() ) )
		m = regex.match( text, m.capturedEnd() );
	return m;
}

void QCodeHighlighter::applyRule( const QString& text, const HighlightRule& r )
{
	for ( auto m = match( r.regExp, text, 0 ); m.hasMatch(); m = match( r.regExp, text, m.capturedEnd() ) )
		setFormat( m.capturedStart(), m.capturedLength(), r.format );
}

void QCodeHighlighter::setRegexes()
{
	rules.clear();
	commentStartRegex.setPattern( "" );
	commentEndRegex.setPattern( "" );

	switch ( language )
	{
	case Language::xml:
		rules.emplace_back( "<[\\s]*[/]?[\\s]*([^\\n]\\w*)(?=[\\s/>])", elementFormat );
		rules.emplace_back( "\\w+(?=\\=)", attributeFormat );
		rules.emplace_back( "\"[^\\n\"]+\"(?=[\\s/>])", valueFormat );
		rules.emplace_back( "/.^/", specialFormat );
		rules.emplace_back( "(<\\?|/>|>|<|</|\\?>", operatorFormat );
		rules.emplace_back( "\\b([-+]?[\\.\\d]+)", numberFormat );
		commentStartRegex.setPattern( "<!--" );
		commentEndRegex.setPattern( "-->" );
		break;

	case Language::zml:
		rules.emplace_back( "\\w+\\s*\\=?\\s*[\\{\\[]", elementFormat );
		rules.emplace_back( "\\w+\\s*(\\=)", attributeFormat ); // key = value
		rules.emplace_back( "\\w+(:\\s+)", attributeFormat ); // key: value
		rules.emplace_back( "\"[^\\n\"]*\"", valueFormat );
		rules.emplace_back( "<<\\s.*\\s>>", specialFormat );
		rules.emplace_back( "([\\{\\}\\[\\]\\=]|:\\s)", operatorFormat );
		rules.emplace_back( "\\b([-+]?[\\.\\d]+)", numberFormat );
		rules.emplace_back( "\\@\\w+", macroFormat );
		rules.emplace_back( "\\$\\w+", macroFormat );

		commentLine.setPattern( "(#|//)[^\\n]*" );
		rules.emplace_back( commentLine, commentFormat );
		commentStartRegex.setPattern( "\\/\\*" );
		commentEndRegex.setPattern( "\\*\\/" );
		increaseIndentRegex.setPattern( "[\\{\\[]" );
		decreaseIndentRegex.setPattern( "[\\}\\]]" );
		lineCommentString = "#";
		break;

	case Language::lua:
		rules.emplace_back( "\\b(and|break|do|else|elseif|end|false|for|function|goto|if|in|local|nil|not|or|repeat|return|then|true|until|while)\\b", elementFormat );
		rules.emplace_back( "\"[^\\n\"]*\"", valueFormat );
		rules.emplace_back( "\\b([-+]?[\\.\\d]+)", numberFormat );
		rules.emplace_back( "[\\+\\-\\*\\/\\%\\\\#\\&\\~\\|\\<\\>\\(\\)\\{\\}\\[\\]\\=\\;\\:\\,\\.]", operatorFormat );

		commentLine.setPattern( "--[^\\n]*" );
		rules.emplace_back( commentLine, commentFormat );
		commentStartRegex.setPattern( "--\\[\\[" );
		commentEndRegex.setPattern( "\\]\\]" );
		increaseIndentRegex.setPattern( "^\\s*(for|while|repeat|if|elseif|else|function)\\b" );
		decreaseIndentRegex.setPattern( "^\\s*(end|until|else|elseif)\\b" );
		lineCommentString = "--";
		break;

	default:
		break;
	}
}

void QCodeHighlighter::setFormats()
{
	operatorFormat.setForeground( Qt::darkGray );
	elementFormat.setForeground( Qt::darkBlue );
	elementFormat.setFontWeight( QFont::Bold );
	attributeFormat.setForeground( Qt::darkBlue );
	//attributeFormat.setFontItalic( true );
	//attributeFormat.setFontWeight( QFont::Bold );
	valueFormat.setForeground( Qt::darkRed );
	commentFormat.setForeground( Qt::gray );
	commentFormat.setFontItalic( true );
	numberFormat.setForeground( Qt::darkCyan );
	macroFormat.setForeground( Qt::darkMagenta );
	//macroFormat.setFontItalic( true );
	specialFormat.setForeground( Qt::darkMagenta );
	specialFormat.setFontItalic( true );
	//specialFormat.setFontWeight( QFont::Bold );
}

void QCodeHighlighter::setLanguage( Language l )
{
	language = l;
	setFormats();
	setRegexes();
}

xo::flat_map< std::string, QCodeHighlighter::Language > g_languages{
	{ "scone", QCodeHighlighter::Language::zml },
	{ "xml", QCodeHighlighter::Language::xml },
	{ "osim", QCodeHighlighter::Language::xml },
	{ "lua", QCodeHighlighter::Language::lua },
	{ "zml", QCodeHighlighter::Language::zml },
	{ "hfd", QCodeHighlighter::Language::zml },
	{ "bp", QCodeHighlighter::Language::zml }
};

QCodeHighlighter::Language QCodeHighlighter::detectLanguage( const QString& filename )
{
	auto ext = xo::to_lower( xo::path( filename.toStdString() ).extension_no_dot().str() );
	if ( auto l = g_languages.find( ext ); l != g_languages.end() )
		return l->second;
	else return Language::unknown;
}

void QCodeHighlighter::registerLanguage( const QString& ext, Language lang )
{
	g_languages[ xo::to_lower( ext.toStdString() ) ] = lang;
}
<commit_msg>C: format<commit_after>#include "QCodeHighlighter.h"

#include "xo/system/assert.h"
#include "xo/filesystem/path.h"
#include "xo/numerical/math.h"
#include "xo/string/string_tools.h"
#include "xo/utility/hash.h"
#include "xo/container/flat_map.h"
#include <string>

QCodeHighlighter::QCodeHighlighter( QObject* parent, Language l ) : QSyntaxHighlighter( parent )
{
	setLanguage( l );
}

QCodeHighlighter::QCodeHighlighter( QTextDocument* parent, Language l ) : QSyntaxHighlighter( parent )
{
	setLanguage( l );
}

void QCodeHighlighter::highlightBlock( const QString& text )
{
	for ( auto& r : rules )
		applyRule( text, r );

	// apply multi-line comments
	if ( !commentStartRegex.pattern().isEmpty() )
	{
		int commentStart = 0, searchIndex = 0;
		bool isComment = previousBlockState() == 1;

		while ( searchIndex >= 0 )
		{
			if ( isComment )
			{
				auto matchEnd = match( commentEndRegex, text, searchIndex );
				if ( !matchEnd.hasMatch() )
				{
					// multiline comment goes beyond this line
					setFormat( commentStart, text.length() - commentStart, commentFormat );
					break;
				}
				else
				{
					// multiline comment ends here
					setFormat( commentStart, matchEnd.capturedEnd() - commentStart, commentFormat );
					searchIndex = matchEnd.capturedEnd();
					isComment = false;
				}
			}
			if ( !isComment )
			{
				auto matchStart = match( commentStartRegex, text, searchIndex );
				if ( matchStart.hasMatch() )
				{
					// multiline comment starts here
					commentStart = matchStart.capturedStart();
					searchIndex = matchStart.capturedEnd();
					isComment = true;
				}
				else break; // no more comments in this line
			}
		}
		setCurrentBlockState( isComment ? 1 : 0 );
	}
}

bool QCodeHighlighter::isBetweenQuotes( const QString& text, int index )
{
	int quotes_before = 0;
	for ( int i = 0; i < index; ++i )
		quotes_before += int( text[ i ] == '\"' );
	return xo::is_odd( quotes_before );
}

QRegularExpressionMatch QCodeHighlighter::match( const QRegularExpression& regex, const QString& text, int index )
{
	auto m = regex.match( text, index );
	while ( m.hasMatch() && isBetweenQuotes( text, m.capturedStart() ) )
		m = regex.match( text, m.capturedEnd() );
	return m;
}

void QCodeHighlighter::applyRule( const QString& text, const HighlightRule& r )
{
	for ( auto m = match( r.regExp, text, 0 ); m.hasMatch(); m = match( r.regExp, text, m.capturedEnd() ) )
		setFormat( m.capturedStart(), m.capturedLength(), r.format );
}

void QCodeHighlighter::setRegexes()
{
	rules.clear();
	commentStartRegex.setPattern( "" );
	commentEndRegex.setPattern( "" );

	switch ( language )
	{
	case Language::xml:
		rules.emplace_back( "<[\\s]*[/]?[\\s]*([^\\n]\\w*)(?=[\\s/>])", elementFormat );
		rules.emplace_back( "\\w+(?=\\=)", attributeFormat );
		rules.emplace_back( "\"[^\\n\"]+\"(?=[\\s/>])", valueFormat );
		rules.emplace_back( "/.^/", specialFormat );
		rules.emplace_back( "(<\\?|/>|>|<|</|\\?>", operatorFormat );
		rules.emplace_back( "\\b([-+]?[\\.\\d]+)", numberFormat );
		commentStartRegex.setPattern( "<!--" );
		commentEndRegex.setPattern( "-->" );
		break;

	case Language::zml:
		rules.emplace_back( "\\w+\\s*\\=?\\s*[\\{\\[]", elementFormat );
		rules.emplace_back( "\\w+\\s*(\\=)", attributeFormat ); // key = value
		rules.emplace_back( "\\w+(:\\s+)", attributeFormat ); // key: value
		rules.emplace_back( "\"[^\\n\"]*\"", valueFormat );
		rules.emplace_back( "<<\\s.*\\s>>", specialFormat );
		rules.emplace_back( "([\\{\\}\\[\\]\\=]|:\\s)", operatorFormat );
		rules.emplace_back( "\\b([-+]?[\\.\\d]+)", numberFormat );
		rules.emplace_back( "\\@\\w+", macroFormat );
		rules.emplace_back( "\\$\\w+", macroFormat );

		commentLine.setPattern( "(#|//)[^\\n]*" );
		rules.emplace_back( commentLine, commentFormat );
		commentStartRegex.setPattern( "\\/\\*" );
		commentEndRegex.setPattern( "\\*\\/" );
		increaseIndentRegex.setPattern( "[\\{\\[]" );
		decreaseIndentRegex.setPattern( "[\\}\\]]" );
		lineCommentString = "#";
		break;

	case Language::lua:
		rules.emplace_back( "\\b(and|break|do|else|elseif|end|false|for|function|goto|if|in|local|nil|not|or|repeat|return|then|true|until|while)\\b", elementFormat );
		rules.emplace_back( "\"[^\\n\"]*\"", valueFormat );
		rules.emplace_back( "\\b([-+]?[\\.\\d]+)", numberFormat );
		rules.emplace_back( "[\\+\\-\\*\\/\\%\\\\#\\&\\~\\|\\<\\>\\(\\)\\{\\}\\[\\]\\=\\;\\:\\,\\.]", operatorFormat );

		commentLine.setPattern( "--[^\\n]*" );
		rules.emplace_back( commentLine, commentFormat );
		commentStartRegex.setPattern( "--\\[\\[" );
		commentEndRegex.setPattern( "\\]\\]" );
		increaseIndentRegex.setPattern( "^\\s*(for|while|repeat|if|elseif|else|function)\\b" );
		decreaseIndentRegex.setPattern( "^\\s*(end|until|else|elseif)\\b" );
		lineCommentString = "--";
		break;

	default:
		break;
	}
}

void QCodeHighlighter::setFormats()
{
	operatorFormat.setForeground( Qt::darkGray );
	elementFormat.setForeground( Qt::darkBlue );
	elementFormat.setFontWeight( QFont::Bold );
	attributeFormat.setForeground( Qt::darkBlue );
	//attributeFormat.setFontItalic( true );
	//attributeFormat.setFontWeight( QFont::Bold );
	valueFormat.setForeground( Qt::darkRed );
	commentFormat.setForeground( Qt::gray );
	commentFormat.setFontItalic( true );
	numberFormat.setForeground( Qt::darkCyan );
	macroFormat.setForeground( Qt::darkMagenta );
	//macroFormat.setFontItalic( true );
	specialFormat.setForeground( Qt::darkMagenta );
	specialFormat.setFontItalic( true );
	//specialFormat.setFontWeight( QFont::Bold );
}

void QCodeHighlighter::setLanguage( Language l )
{
	language = l;
	setFormats();
	setRegexes();
}

xo::flat_map< std::string, QCodeHighlighter::Language > g_languages{
	{ "scone", QCodeHighlighter::Language::zml },
	{ "xml", QCodeHighlighter::Language::xml },
	{ "osim", QCodeHighlighter::Language::xml },
	{ "lua", QCodeHighlighter::Language::lua },
	{ "zml", QCodeHighlighter::Language::zml },
	{ "hfd", QCodeHighlighter::Language::zml },
	{ "bp", QCodeHighlighter::Language::zml }
};

QCodeHighlighter::Language QCodeHighlighter::detectLanguage( const QString& filename )
{
	auto ext = xo::to_lower( xo::path( filename.toStdString() ).extension_no_dot().str() );
	if ( auto l = g_languages.find( ext ); l != g_languages.end() )
		return l->second;
	else return Language::unknown;
}

void QCodeHighlighter::registerLanguage( const QString& ext, Language lang )
{
	g_languages[ xo::to_lower( ext.toStdString() ) ] = lang;
}
<|endoftext|>


<commit_before>/*****************************************************************************
 * Project: BaBar detector at the SLAC PEP-II B-factory
 * Package: RooFitTools
 *    File: $Id: RooGenCategory.cc,v 1.5 2001/08/09 01:02:14 verkerke Exp $
 * Authors:
 *   WV, Wouter Verkerke, UCSB, verkerke@slac.stanford.edu
 * History:
 *   01-Mar-2001 WV Create initial version
 *
 * Copyright (C) 2001 University of California
 *****************************************************************************/

// -- CLASS DESCRIPTION --
// RooGenCategory provides the most flexibe mapping of a series of input categories
// on a output category via a global function provided in the constructor
//
// The mapping function must have the form 'const char* mapFunc(const RooArgSet* catList)'
// and return the name of the output state for the list of categories supplied in the argument.
// The global function can be a ROOT interpreted function.
//
// RooGenCategory builds a numerical index-to-index map from the user function
// to achieve a high performance mapping.

#include <iostream.h>
#include <stdlib.h>
#include <stdio.h>
#include "TString.h"
#include "Api.h"
#include "RooFitCore/RooGenCategory.hh"
#include "RooFitCore/RooStreamParser.hh"
#include "RooFitCore/RooMapCatEntry.hh"

ClassImp(RooGenCategory)

RooGenCategory::RooGenCategory(const char *name, const char *title, void *userFunc, RooArgSet& catList) :
  RooAbsCategory(name, title), _superCat("superCat","Super Category",catList), _map(0)
{
  // Constructor with pointer to user mapping function and list of input categories

  // Convert the function pointer into a parse object using the CINT
  // dictionary in memory.
  _userFuncName = G__p2f2funcname(userFunc);
  if(_userFuncName.IsNull()) {
    cout << GetName() << ": cannot find dictionary info for (void*)"
         << (void*)userFunc << endl;
    return;
  }
  initialize() ;
}

RooGenCategory::RooGenCategory(const RooGenCategory& other, const char *name) :
  RooAbsCategory(other,name), _superCat(other._superCat), _map(0), _userFuncName(other._userFuncName)
{
  // Copy constructor
  initialize() ;
}

void RooGenCategory::initialize()
{
  // Initialization function

  // This is a static link, no need for redirection support
  addServer(_superCat,kTRUE,kTRUE) ;

  _userFunc= new TMethodCall();
  // We must use "RooArgSet*" instead of "RooArgSet&" here (why?)
  _userFunc->InitWithPrototype(_userFuncName.Data(),"RooArgSet*");

  updateIndexList() ;
}

RooGenCategory::~RooGenCategory()
{
  // Destructor

  // Server no longer exists when RooAbsArg destructor is executing
  removeServer(_superCat) ;
}

TString RooGenCategory::evalUserFunc(RooArgSet *vars)
{
  // Utility function to evaluate (interpreted) user function
  assert(0 != _userFunc);
  Long_t result;
  _userArgs[0]= (Long_t)vars ;
  _userFunc->SetParamPtrs(_userArgs);
  _userFunc->Execute(result);
  const char *text= (const char *)result;
  return TString(text);
}

void RooGenCategory::updateIndexList()
{
  // Update list of states and reevaluate input index code to output index code map

  // Recreate super-index to gen-index map ;
  if (_map) delete[] _map ;
  _map = new Int_t[_superCat.numTypes()] ;
  clearTypes() ;

  // DeepClone super category for iteration
  RooArgSet* tmp=(RooArgSet*) RooArgSet(_superCat).snapshot(kTRUE) ;
  RooSuperCategory* superClone = (RooSuperCategory*) tmp->find(_superCat.GetName()) ;

  TIterator* sIter = superClone->MakeIterator() ;
  RooArgSet *catList ;
  while (catList=(RooArgSet*)sIter->Next()) {
    // Call user function
    TString typeName = evalUserFunc(catList) ;

    // Check if type exists for given name, register otherwise
    const RooCatType* type = lookupType(typeName,kFALSE) ;
    if (!type) type = defineType(typeName) ;

    // Fill map for this super-state
    _map[_superCat.getIndex()] = type->getVal() ;
  }

  delete superClone ;
}

RooCatType
RooGenCategory::evaluate() const
{
  // Calculate current value of object
  if (isShapeDirty()) {
    const_cast<RooGenCategory*>(this)->updateIndexList() ;
  }

  return *lookupType(_map[_superCat.getIndex()]) ;
}

void RooGenCategory::printToStream(ostream& os, PrintOption opt, TString indent) const
{
  // Print info about this mapped category to the specified stream. In addition to the info
  // from RooAbsCategory::printToStream() we add:
  //
  //  Standard : input category
  //     Shape : default value
  //   Verbose : list of mapping rules

   RooAbsCategory::printToStream(os,opt,indent);

   if (opt>=Verbose) {
     os << indent << "--- RooGenCategory ---" << endl;
     os << indent << "  Input category list:" << endl ;
     TString moreIndent(indent) ;
     indent.Append("   ") ;
     _superCat.inputCatList().printToStream(os,Standard,moreIndent.Data()) ;
     os << indent << "  User mapping function is 'const char* " << _userFuncName << "(RooArgSet*)'" << endl ;
   }
}

Bool_t RooGenCategory::readFromStream(istream& is, Bool_t compact, Bool_t verbose)
{
  // Read object contents from given stream
   if (compact) {
     cout << "RooGenCategory::readFromSteam(" << GetName() << "): can't read in compact mode" << endl ;
     return kTRUE ;
   } else {
     return kFALSE ;
   }
   //return kFALSE ; //OSF: statement unreachable
}

void RooGenCategory::writeToStream(ostream& os, Bool_t compact) const
{
  // Write object contents to given stream
  if (compact) {
    // Write value only
    os << getLabel() ;
  } else {
  }
}
<commit_msg><commit_after>/*****************************************************************************
 * Project: BaBar detector at the SLAC PEP-II B-factory
 * Package: RooFitTools
 *    File: $Id: RooGenCategory.cc,v 1.6 2001/09/17 18:48:14 verkerke Exp $
 * Authors:
 *   WV, Wouter Verkerke, UCSB, verkerke@slac.stanford.edu
 * History:
 *   01-Mar-2001 WV Create initial version
 *
 * Copyright (C) 2001 University of California
 *****************************************************************************/

// -- CLASS DESCRIPTION --
// RooGenCategory provides the most flexibe mapping of a series of input categories
// on a output category via a global function provided in the constructor
//
// The mapping function must have the form 'const char* mapFunc(const RooArgSet* catList)'
// and return the name of the output state for the list of categories supplied in the argument.
// The global function can be a ROOT interpreted function.
//
// RooGenCategory builds a numerical index-to-index map from the user function
// to achieve a high performance mapping.

#include <iostream.h>
#include <stdlib.h>
#include <stdio.h>
#include "TString.h"
#include "Api.h"
#include "RooFitCore/RooGenCategory.hh"
#include "RooFitCore/RooStreamParser.hh"
#include "RooFitCore/RooMapCatEntry.hh"

ClassImp(RooGenCategory)

RooGenCategory::RooGenCategory(const char *name, const char *title, void *userFunc, RooArgSet& catList) :
  RooAbsCategory(name, title), _superCat("superCat","Super Category",catList), _map(0)
{
  // Constructor with pointer to user mapping function and list of input categories

  // Convert the function pointer into a parse object using the CINT
  // dictionary in memory.
  _userFuncName = G__p2f2funcname(userFunc);
  if(_userFuncName.IsNull()) {
    cout << GetName() << ": cannot find dictionary info for (void*)"
         << (void*)userFunc << endl;
    return;
  }
  initialize() ;
}

RooGenCategory::RooGenCategory(const RooGenCategory& other, const char *name) :
  RooAbsCategory(other,name), _superCat(other._superCat), _map(0), _userFuncName(other._userFuncName)
{
  // Copy constructor
  removeServer((RooAbsArg&)other._superCat) ;
  initialize() ;
}

void RooGenCategory::initialize()
{
  // Initialization function

  // This is a static link, no need for redirection support
  addServer(_superCat,kTRUE,kTRUE) ;

  _userFunc= new TMethodCall();
  // We must use "RooArgSet*" instead of "RooArgSet&" here (why?)
  _userFunc->InitWithPrototype(_userFuncName.Data(),"RooArgSet*");

  updateIndexList() ;
}

RooGenCategory::~RooGenCategory()
{
  // Destructor

  // Server no longer exists when RooAbsArg destructor is executing
  if (_serverList.FindObject(&_superCat)) {
    removeServer(_superCat) ;
  }
}

TString RooGenCategory::evalUserFunc(RooArgSet *vars)
{
  // Utility function to evaluate (interpreted) user function
  assert(0 != _userFunc);
  Long_t result;
  _userArgs[0]= (Long_t)vars ;
  _userFunc->SetParamPtrs(_userArgs);
  _userFunc->Execute(result);
  const char *text= (const char *)result;
  return TString(text);
}

void RooGenCategory::updateIndexList()
{
  // Update list of states and reevaluate input index code to output index code map

  // Recreate super-index to gen-index map ;
  if (_map) delete[] _map ;
  _map = new Int_t[_superCat.numTypes()] ;
  clearTypes() ;

  // DeepClone super category for iteration
  RooArgSet* tmp=(RooArgSet*) RooArgSet(_superCat).snapshot(kTRUE) ;
  RooSuperCategory* superClone = (RooSuperCategory*) tmp->find(_superCat.GetName()) ;

  TIterator* sIter = superClone->MakeIterator() ;
  RooArgSet *catList ;
  while (catList=(RooArgSet*)sIter->Next()) {
    // Call user function
    TString typeName = evalUserFunc(catList) ;

    // Check if type exists for given name, register otherwise
    const RooCatType* type = lookupType(typeName,kFALSE) ;
    if (!type) type = defineType(typeName) ;

    // Fill map for this super-state
    _map[superClone->getIndex()] = type->getVal() ;
  }

  delete superClone ;
}

RooCatType
RooGenCategory::evaluate() const
{
  // Calculate current value of object
  if (isShapeDirty()) {
    const_cast<RooGenCategory*>(this)->updateIndexList() ;
  }

  const RooCatType* ret = lookupType(_map[_superCat.getIndex()]) ;
  if (!ret) {
    cout << "RooGenCategory::evaluate(" << GetName() << ") ERROR: cannot lookup super index " << _superCat.getIndex() << endl ;
    assert(0) ;
  }

  return *ret ;
}

void RooGenCategory::printToStream(ostream& os, PrintOption opt, TString indent) const
{
  // Print info about this mapped category to the specified stream. In addition to the info
  // from RooAbsCategory::printToStream() we add:
  //
  //  Standard : input category
  //     Shape : default value
  //   Verbose : list of mapping rules

   RooAbsCategory::printToStream(os,opt,indent);

   if (opt>=Verbose) {
     os << indent << "--- RooGenCategory ---" << endl;
     os << indent << "  Input category list:" << endl ;
     TString moreIndent(indent) ;
     indent.Append("   ") ;
     _superCat.inputCatList().printToStream(os,Standard,moreIndent.Data()) ;
     os << indent << "  User mapping function is 'const char* " << _userFuncName << "(RooArgSet*)'" << endl ;
   }
}

Bool_t RooGenCategory::readFromStream(istream& is, Bool_t compact, Bool_t verbose)
{
  // Read object contents from given stream
   if (compact) {
     cout << "RooGenCategory::readFromSteam(" << GetName() << "): can't read in compact mode" << endl ;
     return kTRUE ;
   } else {
     return kFALSE ;
   }
   //return kFALSE ; //OSF: statement unreachable
}

void RooGenCategory::writeToStream(ostream& os, Bool_t compact) const
{
  // Write object contents to given stream
  if (compact) {
    // Write value only
    os << getLabel() ;
  } else {
  }
}
<|endoftext|>


<commit_before>#include <gtest/gtest.h>
#include <stan/prob/distributions/univariate/discrete/neg_binomial.hpp>

TEST(ProbDistributionsNegBinomial,NegBinomial) {
  EXPECT_FLOAT_EQ(-7.786663, stan::prob::neg_binomial_log(10,2.0,1.5));
  EXPECT_FLOAT_EQ(-142.6147, stan::prob::neg_binomial_log(100,3.0,3.5));
}
TEST(ProbDistributionsNegBinomial,Propto) {
  EXPECT_FLOAT_EQ(0.0, stan::prob::neg_binomial_log<true>(10,2.0,1.5));
  EXPECT_FLOAT_EQ(0.0, stan::prob::neg_binomial_log<true>(100,3.0,3.5));
}

using boost::math::policies::policy;
using boost::math::policies::evaluation_error;
using boost::math::policies::domain_error;
using boost::math::policies::overflow_error;
using boost::math::policies::domain_error;
using boost::math::policies::pole_error;
using boost::math::policies::errno_on_error;

typedef policy<
  domain_error<errno_on_error>,
  pole_error<errno_on_error>,
  overflow_error<errno_on_error>,
  evaluation_error<errno_on_error>
  > errno_policy;

using stan::prob::neg_binomial_log;

TEST(ProbDistributionsNegBinomial,DefaultPolicy) {
  double nan = std::numeric_limits<double>::quiet_NaN();
  double inf = std::numeric_limits<double>::infinity();

  unsigned int n = 10;
  double alpha = 2.0;
  double beta = 1.5;

  EXPECT_NO_THROW(neg_binomial_log(n,alpha,beta));

  EXPECT_THROW(neg_binomial_log(n,nan,beta), std::domain_error);
  EXPECT_THROW(neg_binomial_log(n,0.0,beta), std::domain_error);
  EXPECT_THROW(neg_binomial_log(n,-1.0,beta), std::domain_error);
  EXPECT_THROW(neg_binomial_log(n,-inf,beta), std::domain_error);
  EXPECT_THROW(neg_binomial_log(n,inf,beta), std::domain_error);

  EXPECT_THROW(neg_binomial_log(n,alpha,nan), std::domain_error);
  EXPECT_THROW(neg_binomial_log(n,alpha,0.0), std::domain_error);
  EXPECT_THROW(neg_binomial_log(n,alpha,-1.0), std::domain_error);
  EXPECT_THROW(neg_binomial_log(n,alpha,-inf), std::domain_error);
  EXPECT_THROW(neg_binomial_log(n,alpha,inf), std::domain_error);
}
TEST(ProbDistributionsNegBinomial,ErrnoPolicy) {
  double nan = std::numeric_limits<double>::quiet_NaN();
  double inf = std::numeric_limits<double>::infinity();

  double result;
  unsigned int n = 10;
  double alpha = 2.0;
  double beta = 1.5;

  result = neg_binomial_log(n,alpha,beta, errno_policy());
  EXPECT_FALSE(std::isnan(result));

  result = neg_binomial_log(n,nan,beta, errno_policy());
  EXPECT_TRUE(std::isnan(result));
  result = neg_binomial_log(n,0.0,beta, errno_policy());
  EXPECT_TRUE(std::isnan(result));
  result = neg_binomial_log(n,-1.0,beta, errno_policy());
  EXPECT_TRUE(std::isnan(result));
  result = neg_binomial_log(n,-inf,beta, errno_policy());
  EXPECT_TRUE(std::isnan(result));
  result = neg_binomial_log(n,inf,beta, errno_policy());
  EXPECT_TRUE(std::isnan(result));

  result = neg_binomial_log(n,alpha,nan, errno_policy());
  EXPECT_TRUE(std::isnan(result));
  result = neg_binomial_log(n,alpha,0.0, errno_policy());
  EXPECT_TRUE(std::isnan(result));
  result = neg_binomial_log(n,alpha,-1.0, errno_policy());
  EXPECT_TRUE(std::isnan(result));
  result = neg_binomial_log(n,alpha,-inf, errno_policy());
  EXPECT_TRUE(std::isnan(result));
  result = neg_binomial_log(n,alpha,inf, errno_policy());
  EXPECT_TRUE(std::isnan(result));
}
TEST(ProbDistributionsNegBinomial,check_values) {
  int n;
  double alpha;
  double beta;
  double result;

  alpha = 82.34;
  beta = 0.366114;
  n = 0;
  result = neg_binomial_log(n, alpha, beta);
  EXPECT_FLOAT_EQ(-108.423725446514, result);

  n = 1;
  result = neg_binomial_log(n, alpha, beta);
  EXPECT_FLOAT_EQ(-104.324838643183, result);

  n = 2;
  result = neg_binomial_log(n, alpha, beta);
  EXPECT_FLOAT_EQ(-100.907027410759, result);

  n = 4;
  result = neg_binomial_log(n, alpha, beta);
  EXPECT_FLOAT_EQ(-95.1343749604898, result);

  n = 5;
  result = neg_binomial_log(n, alpha, beta);
  EXPECT_FLOAT_EQ(-92.597490095807, result);
}
<commit_msg>updating prob neg_binomial_test<commit_after>#define _LOG_PROB_ neg_binomial_log
#include <stan/prob/distributions/univariate/discrete/neg_binomial.hpp>

#include <test/prob/distributions/distribution_test_fixture.hpp>
#include <test/prob/distributions/distribution_tests_1_discrete_2_params.hpp>

using std::vector;
using std::log;
using std::numeric_limits;

class ProbDistributionsNegBinomial : public DistributionTest {
public:
  void valid_values(vector<vector<double> >& parameters,
		    vector<double>& log_prob) {
    vector<double> param(3);

    param[0] = 10;           // n
    param[1] = 2.0;          // alpha
    param[2] = 1.5;          // beta
    parameters.push_back(param);
    log_prob.push_back(-7.786663); // expected log_prob

    param[0] = 100;          // n
    param[1] = 3.0;          // alpha
    param[2] = 3.5;          // beta
    parameters.push_back(param);
    log_prob.push_back(-142.6147); // expected log_prob
  }

  void invalid_values(vector<size_t>& index,
		      vector<double>& value) {
    // n
    index.push_back(0U);
    value.push_back(-1);

    // alpha
    index.push_back(1U);
    value.push_back(0);

    // beta
    index.push_back(2U);
    value.push_back(0);
  }
};

INSTANTIATE_TYPED_TEST_CASE_P(ProbDistributionsNegBinomial,
			      DistributionTestFixture,
			      ProbDistributionsNegBinomial);
/*

#include <gtest/gtest.h>
#include <stan/prob/distributions/univariate/discrete/neg_binomial.hpp>

TEST(ProbDistributionsNegBinomial,NegBinomial) {
  EXPECT_FLOAT_EQ(-7.786663, stan::prob::neg_binomial_log(10,2.0,1.5));
  EXPECT_FLOAT_EQ(-142.6147, stan::prob::neg_binomial_log(100,3.0,3.5));
}
TEST(ProbDistributionsNegBinomial,Propto) {
  EXPECT_FLOAT_EQ(0.0, stan::prob::neg_binomial_log<true>(10,2.0,1.5));
  EXPECT_FLOAT_EQ(0.0, stan::prob::neg_binomial_log<true>(100,3.0,3.5));
}

using boost::math::policies::policy;
using boost::math::policies::evaluation_error;
using boost::math::policies::domain_error;
using boost::math::policies::overflow_error;
using boost::math::policies::domain_error;
using boost::math::policies::pole_error;
using boost::math::policies::errno_on_error;

typedef policy<
  domain_error<errno_on_error>,
  pole_error<errno_on_error>,
  overflow_error<errno_on_error>,
  evaluation_error<errno_on_error>
  > errno_policy;

using stan::prob::neg_binomial_log;

TEST(ProbDistributionsNegBinomial,DefaultPolicy) {
  double nan = std::numeric_limits<double>::quiet_NaN();
  double inf = std::numeric_limits<double>::infinity();

  unsigned int n = 10;
  double alpha = 2.0;
  double beta = 1.5;

  EXPECT_NO_THROW(neg_binomial_log(n,alpha,beta));

  EXPECT_THROW(neg_binomial_log(n,nan,beta), std::domain_error);
  EXPECT_THROW(neg_binomial_log(n,0.0,beta), std::domain_error);
  EXPECT_THROW(neg_binomial_log(n,-1.0,beta), std::domain_error);
  EXPECT_THROW(neg_binomial_log(n,-inf,beta), std::domain_error);
  EXPECT_THROW(neg_binomial_log(n,inf,beta), std::domain_error);

  EXPECT_THROW(neg_binomial_log(n,alpha,nan), std::domain_error);
  EXPECT_THROW(neg_binomial_log(n,alpha,0.0), std::domain_error);
  EXPECT_THROW(neg_binomial_log(n,alpha,-1.0), std::domain_error);
  EXPECT_THROW(neg_binomial_log(n,alpha,-inf), std::domain_error);
  EXPECT_THROW(neg_binomial_log(n,alpha,inf), std::domain_error);
}
TEST(ProbDistributionsNegBinomial,ErrnoPolicy) {
  double nan = std::numeric_limits<double>::quiet_NaN();
  double inf = std::numeric_limits<double>::infinity();

  double result;
  unsigned int n = 10;
  double alpha = 2.0;
  double beta = 1.5;

  result = neg_binomial_log(n,alpha,beta, errno_policy());
  EXPECT_FALSE(std::isnan(result));

  result = neg_binomial_log(n,nan,beta, errno_policy());
  EXPECT_TRUE(std::isnan(result));
  result = neg_binomial_log(n,0.0,beta, errno_policy());
  EXPECT_TRUE(std::isnan(result));
  result = neg_binomial_log(n,-1.0,beta, errno_policy());
  EXPECT_TRUE(std::isnan(result));
  result = neg_binomial_log(n,-inf,beta, errno_policy());
  EXPECT_TRUE(std::isnan(result));
  result = neg_binomial_log(n,inf,beta, errno_policy());
  EXPECT_TRUE(std::isnan(result));

  result = neg_binomial_log(n,alpha,nan, errno_policy());
  EXPECT_TRUE(std::isnan(result));
  result = neg_binomial_log(n,alpha,0.0, errno_policy());
  EXPECT_TRUE(std::isnan(result));
  result = neg_binomial_log(n,alpha,-1.0, errno_policy());
  EXPECT_TRUE(std::isnan(result));
  result = neg_binomial_log(n,alpha,-inf, errno_policy());
  EXPECT_TRUE(std::isnan(result));
  result = neg_binomial_log(n,alpha,inf, errno_policy());
  EXPECT_TRUE(std::isnan(result));
}
TEST(ProbDistributionsNegBinomial,check_values) {
  int n;
  double alpha;
  double beta;
  double result;

  alpha = 82.34;
  beta = 0.366114;
  n = 0;
  result = neg_binomial_log(n, alpha, beta);
  EXPECT_FLOAT_EQ(-108.423725446514, result);

  n = 1;
  result = neg_binomial_log(n, alpha, beta);
  EXPECT_FLOAT_EQ(-104.324838643183, result);

  n = 2;
  result = neg_binomial_log(n, alpha, beta);
  EXPECT_FLOAT_EQ(-100.907027410759, result);

  n = 4;
  result = neg_binomial_log(n, alpha, beta);
  EXPECT_FLOAT_EQ(-95.1343749604898, result);

  n = 5;
  result = neg_binomial_log(n, alpha, beta);
  EXPECT_FLOAT_EQ(-92.597490095807, result);
}
*/
<|endoftext|>


<commit_before>#include <csignal>
#include <cstdio>
#include <memory>
#include <string>

#include <boost/format.hpp>
#include <boost/regex.hpp>

#include "rocksdb/db.h"
#include "rocksdb/slice.h"
#include "rocksdb/options.h"

#include "conf.h"
#include "cons.h"
#include "util.h"

using namespace std;
using namespace rocksdb;

void on_signal(int sig) {
	cout << boost::format("\nGot a signal: %d\n%s\n") % sig % Util::Indent(Util::StackTrace(1), 2);
  exit(1);
}

string _db_path;
DB* _db;

// Optimize later
string GenRandomAsciiString(const int len) {
	vector<char> s(len);
	static const char alphanum[] =
		"0123456789"
		"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
		"abcdefghijklmnopqrstuvwxyz";

	for (int i = 0; i < len; ++i) {
		s[i] = alphanum[rand() % (sizeof(alphanum) - 1)];
	}

	return string(s.begin(), s.end());
}

void Insert(const int num_keys) {
	Cons::MT _(boost::format("Inserting %d key-value pairs ...") % num_keys);
	for (int i = 0; i < num_keys; i ++) {
		string k = str(boost::format("%010d") % i);
		string v = GenRandomAsciiString(990);

		static const auto wo = WriteOptions();
		Status s = _db->Put(wo, k, v);
		if (! s.ok())
			THROW("Put failed");
	}
}

int main(int argc, char* argv[]) {
	try {
		signal(SIGSEGV, on_signal);
		signal(SIGINT, on_signal);

		Conf::Init(argc, argv);
		_db_path = boost::regex_replace(Conf::GetStr("db_path"), boost::regex("~"), Util::HomeDir());
		Cons::P(boost::format("_db_path=%s") % _db_path);

		Options options;
		// Optimize RocksDB. This is the easiest way to get RocksDB to perform well
		options.IncreaseParallelism();
		options.OptimizeLevelStyleCompaction();
		// create the DB if it's not already present
		options.create_if_missing = true;

		// Open DB
		Status s = DB::Open(options, _db_path, &_db);
		if (! s.ok())
			THROW("DB::Open failed");

		Insert(10000);

		// Get value
		//string value;
		//s = _db->Get(ReadOptions(), "key1", &value);
		//if (! s.ok())
		//	THROW("Get failed");
		//if (value != "value")
		//	THROW("Unexpected");

		delete _db;
	} catch (const exception& e) {
		cerr << "Got an exception: " << e.what() << "\n";
		return 1;
	}
	return 0;
}

// Atomically apply a set of updates
// Note: might be useful for record reinsertions
// {
//   WriteBatch batch;
//   batch.Delete("key1");
//   batch.Put("key2", value);
//   s = db->Write(WriteOptions(), &batch);
// }
<commit_msg>update<commit_after>#include <csignal>
#include <cstdio>
#include <memory>
#include <string>

#include <boost/format.hpp>
#include <boost/regex.hpp>

#include "rocksdb/db.h"
#include "rocksdb/slice.h"
#include "rocksdb/options.h"

#include "conf.h"
#include "cons.h"
#include "util.h"

using namespace std;
using namespace rocksdb;

void on_signal(int sig) {
	cout << boost::format("\nGot a signal: %d\n%s\n") % sig % Util::Indent(Util::StackTrace(1), 2);
  exit(1);
}

string _db_path;
DB* _db;

// Optimize later
string GenRandomAsciiString(const int len) {
	vector<char> s(len);
	static const char alphanum[] =
		"0123456789"
		"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
		"abcdefghijklmnopqrstuvwxyz";

	for (int i = 0; i < len; ++i) {
		s[i] = alphanum[rand() % (sizeof(alphanum) - 1)];
	}

	return string(s.begin(), s.end());
}

void Insert(const int num_keys) {
	Cons::MT _(boost::format("Inserting %d key-value pairs ...") % num_keys);
	for (int i = 0; i < num_keys; i ++) {
		string k = str(boost::format("%010d") % i);
		string v = GenRandomAsciiString(990);

		static const auto wo = WriteOptions();
		Status s = _db->Put(wo, k, v);
		if (! s.ok())
			THROW("Put failed");
	}
}

string Get(const string& k) {
	string v;
	static const auto ro = ReadOptions();
	Status s = _db->Get(ro, k, &v);
	if (! s.ok())
		THROW("Get failed");
	return v;
}

int main(int argc, char* argv[]) {
	try {
		signal(SIGSEGV, on_signal);
		signal(SIGINT, on_signal);

		Conf::Init(argc, argv);
		_db_path = boost::regex_replace(Conf::GetStr("db_path"), boost::regex("~"), Util::HomeDir());
		Cons::P(boost::format("_db_path=%s") % _db_path);

		Options options;
		// Optimize RocksDB. This is the easiest way to get RocksDB to perform well
		options.IncreaseParallelism();
		options.OptimizeLevelStyleCompaction();
		// create the DB if it's not already present
		options.create_if_missing = true;

		// Open DB
		Status s = DB::Open(options, _db_path, &_db);
		if (! s.ok())
			THROW("DB::Open failed");

		//Insert(10000);
		Cons::P(Get("0000000000"));

		delete _db;
	} catch (const exception& e) {
		cerr << "Got an exception: " << e.what() << "\n";
		return 1;
	}
	return 0;
}

// Atomically apply a set of updates
// Note: might be useful for record reinsertions
// {
//   WriteBatch batch;
//   batch.Delete("key1");
//   batch.Put("key2", value);
//   s = db->Write(WriteOptions(), &batch);
// }
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2008, Willow Garage, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the Willow Garage, Inc. nor the names of its
 *       contributors may be used to endorse or promote products derived from
 *       this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <tf/transform_listener.h>

#include <rviz/frame_manager.h>
#include <rviz/properties/bool_property.h>
#include <rviz/properties/ros_topic_property.h>
#include <rviz/selection/selection_manager.h>
#include <rviz/validate_floats.h>
#include <rviz/validate_quaternions.h>
#include <rviz/display_context.h>

#include <rviz/default_plugin/interactive_marker_display.h>

namespace rviz
{

//////////////
bool validateFloats(const visualization_msgs::InteractiveMarker& msg)
{
  bool valid = true;
  valid = valid && validateFloats(msg.pose);
  valid = valid && validateFloats(msg.scale);
  for ( unsigned c=0; c<msg.controls.size(); c++)
  {
    valid = valid && validateFloats( msg.controls[c].orientation );
    for ( unsigned m=0; m<msg.controls[c].markers.size(); m++ )
    {
      valid = valid && validateFloats(msg.controls[c].markers[m].pose);
      valid = valid && validateFloats(msg.controls[c].markers[m].scale);
      valid = valid && validateFloats(msg.controls[c].markers[m].color);
      valid = valid && validateFloats(msg.controls[c].markers[m].points);
    }
  }
  return valid;
}

bool validateQuaternions(const visualization_msgs::InteractiveMarker &marker)
{
  if ( !validateQuaternions( marker.pose.orientation )) return false;
  for ( size_t c = 0; c < marker.controls.size(); ++c )
  {
    if ( !validateQuaternions( marker.controls[c].orientation )) return false;
    for ( size_t m = 0; m < marker.controls[c].markers.size(); ++m )
    {
      if ( !validateQuaternions( marker.controls[c].markers[m].pose.orientation )) return false;
    }
  }
  return true;
}
/////////////

InteractiveMarkerDisplay::InteractiveMarkerDisplay()
  : Display()
{
  marker_update_topic_property_ = new RosTopicProperty( "Update Topic", "",
                                                        ros::message_traits::datatype<visualization_msgs::InteractiveMarkerUpdate>(),
                                                        "visualization_msgs::InteractiveMarkerUpdate topic to subscribe to.",
                                                        this, SLOT( updateTopic() ));

  show_descriptions_property_ = new BoolProperty( "Show Descriptions", true,
                                                  "Whether or not to show the descriptions of each Interactive Marker.",
                                                  this, SLOT( updateShowDescriptions() ));

  show_axes_property_ = new BoolProperty( "Show Axes", false,
                                          "Whether or not to show the axes of each Interactive Marker.",
                                          this, SLOT( updateShowAxes() ));

  show_visual_aids_property_ = new BoolProperty( "Show Visual Aids", false,
                                                 "Whether or not to show visual helpers while moving/rotating Interactive Markers.",
                                                 this, SLOT( updateShowVisualAids() ));
  enable_transparency_property_ = new BoolProperty( "Enable Transparency", true,
                                                 "Whether or not to allow transparency for auto-completed markers (e.g. rings and arrows).",
                                                 this, SLOT( updateEnableTransparency() ));
}

void InteractiveMarkerDisplay::onInitialize()
{
  // TODO(wjwwood): remove this and use tf2 interface instead
#ifndef _WIN32
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif

  tf::Transformer* tf = context_->getFrameManager()->getTFClient();

#ifndef _WIN32
# pragma GCC diagnostic pop
#endif
  im_client_.reset( new interactive_markers::InteractiveMarkerClient( *tf, fixed_frame_.toStdString() ) );

  im_client_->setInitCb( boost::bind( &InteractiveMarkerDisplay::initCb, this, _1 ) );
  im_client_->setUpdateCb( boost::bind( &InteractiveMarkerDisplay::updateCb, this, _1 ) );
  im_client_->setResetCb( boost::bind( &InteractiveMarkerDisplay::resetCb, this, _1 ) );
  im_client_->setStatusCb( boost::bind( &InteractiveMarkerDisplay::statusCb, this, _1, _2, _3 ) );

  client_id_ = ros::this_node::getName() + "/" + getNameStd();

  onEnable();
}

void InteractiveMarkerDisplay::setTopic( const QString &topic, const QString & /*datatype*/ )
{
  marker_update_topic_property_->setString( topic );
}

void InteractiveMarkerDisplay::onEnable()
{
  subscribe();
}

void InteractiveMarkerDisplay::onDisable()
{
  unsubscribe();
}

void InteractiveMarkerDisplay::updateTopic()
{
  unsubscribe();

  std::string update_topic = marker_update_topic_property_->getTopicStd();

  size_t idx = update_topic.find( "/update" );
  if ( idx != std::string::npos )
  {
    topic_ns_ = update_topic.substr( 0, idx );
    subscribe();
  }
  else
  {
    setStatusStd( StatusProperty::Error, "Topic", "Invalid topic name: " + update_topic );
  }

}

void InteractiveMarkerDisplay::subscribe()
{
  if ( isEnabled() )
  {
    im_client_->subscribe(topic_ns_);

    std::string feedback_topic = topic_ns_+"/feedback";
    feedback_pub_ = update_nh_.advertise<visualization_msgs::InteractiveMarkerFeedback>( feedback_topic, 100, false );
  }
}

void InteractiveMarkerDisplay::publishFeedback(visualization_msgs::InteractiveMarkerFeedback &feedback)
{
  feedback.client_id = client_id_;
  feedback_pub_.publish( feedback );
}

void InteractiveMarkerDisplay::onStatusUpdate( StatusProperty::Level level, const std::string& name, const std::string& text )
{
  setStatusStd(level,name,text);
}

void InteractiveMarkerDisplay::unsubscribe()
{
  if (im_client_)
  {
    im_client_->shutdown();
  }
  feedback_pub_.shutdown();
  Display::reset();
}

void InteractiveMarkerDisplay::update(float wall_dt, float  /*ros_dt*/)
{
  im_client_->update();

  M_StringToStringToIMPtr::iterator server_it;
  for ( server_it = interactive_markers_.begin(); server_it != interactive_markers_.end(); server_it++ )
  {
    M_StringToIMPtr::iterator im_it;
    for ( im_it = server_it->second.begin(); im_it != server_it->second.end(); im_it++ )
    {
      im_it->second->update( wall_dt );
    }
  }
}

InteractiveMarkerDisplay::M_StringToIMPtr& InteractiveMarkerDisplay::getImMap( std::string server_id )
{
  M_StringToStringToIMPtr::iterator im_map_it = interactive_markers_.find( server_id );

  if ( im_map_it == interactive_markers_.end() )
  {
    im_map_it = interactive_markers_.insert( std::make_pair( server_id, M_StringToIMPtr() ) ).first;
  }

  return im_map_it->second;
}

void InteractiveMarkerDisplay::updateMarkers(
    const std::string& server_id,
    const std::vector<visualization_msgs::InteractiveMarker>& markers
    )
{
  M_StringToIMPtr& im_map = getImMap( server_id );

  for ( size_t i=0; i<markers.size(); i++ )
  {
    const visualization_msgs::InteractiveMarker& marker = markers[i];

    if ( !validateFloats( marker ) )
    {
      setStatusStd( StatusProperty::Error, marker.name, "Marker contains invalid floats!" );
      //setStatusStd( StatusProperty::Error, "General", "Marker " + marker.name + " contains invalid floats!" );
      continue;
    }

    if( !validateQuaternions( marker ))
    {
      ROS_WARN_ONCE_NAMED( "quaternions", "Interactive marker '%s' contains unnormalized quaternions. "
                           "This warning will only be output once but may be true for others; "
                           "enable DEBUG messages for ros.rviz.quaternions to see more details.",
                           marker.name.c_str() );
      ROS_DEBUG_NAMED( "quaternions", "Interactive marker '%s' contains unnormalized quaternions.",
                       marker.name.c_str() );
    }
    ROS_DEBUG("Processing interactive marker '%s'. %d", marker.name.c_str(), (int)marker.controls.size() );

    std::map< std::string, IMPtr >::iterator int_marker_entry = im_map.find( marker.name );

    if ( int_marker_entry == im_map.end() )
    {
      int_marker_entry = im_map.insert( std::make_pair(marker.name, IMPtr ( new InteractiveMarker(getSceneNode(), context_) ) ) ).first;
      connect( int_marker_entry->second.get(),
               SIGNAL( userFeedback(visualization_msgs::InteractiveMarkerFeedback&) ),
               this,
               SLOT( publishFeedback(visualization_msgs::InteractiveMarkerFeedback&) ));
      connect( int_marker_entry->second.get(),
               SIGNAL( statusUpdate(StatusProperty::Level, const std::string&, const std::string&) ),
               this,
               SLOT( onStatusUpdate(StatusProperty::Level, const std::string&, const std::string&) ) );
    }

    if ( int_marker_entry->second->processMessage( marker ) )
    {
      int_marker_entry->second->setShowAxes( show_axes_property_->getBool() );
      int_marker_entry->second->setShowVisualAids( show_visual_aids_property_->getBool() );
      int_marker_entry->second->setShowDescription( show_descriptions_property_->getBool() );
    }
    else
    {
      unsubscribe();
      return;
    }
  }
}

void InteractiveMarkerDisplay::eraseMarkers(
    const std::string& server_id,
    const std::vector<std::string>& erases )
{
  M_StringToIMPtr& im_map = getImMap( server_id );

  for ( size_t i=0; i<erases.size(); i++ )
  {
    im_map.erase( erases[i] );
    deleteStatusStd( erases[i] );
  }
}

void InteractiveMarkerDisplay::updatePoses(
    const std::string& server_id,
    const std::vector<visualization_msgs::InteractiveMarkerPose>& marker_poses )
{
  M_StringToIMPtr& im_map = getImMap( server_id );

  for ( size_t i=0; i<marker_poses.size(); i++ )
  {
    const visualization_msgs::InteractiveMarkerPose& marker_pose = marker_poses[i];

    if ( !validateFloats( marker_pose.pose ) )
    {
      setStatusStd( StatusProperty::Error, marker_pose.name, "Pose message contains invalid floats!" );
      return;
    }

    if( !validateQuaternions( marker_pose.pose ))
    {
      setStatusStd( StatusProperty::Error, marker_pose.name,
                    "Pose message contains invalid quaternions (length not equal to 1)!" );
      return;
    }

    std::map< std::string, IMPtr >::iterator int_marker_entry = im_map.find( marker_pose.name );

    if ( int_marker_entry != im_map.end() )
    {
      int_marker_entry->second->processMessage( marker_pose );
    }
    else
    {
      setStatusStd( StatusProperty::Error, marker_pose.name, "Pose received for non-existing marker '" + marker_pose.name );
      unsubscribe();
      return;
    }
  }
}

void InteractiveMarkerDisplay::initCb( visualization_msgs::InteractiveMarkerInitConstPtr msg )
{
  resetCb( msg->server_id );
  updateMarkers( msg->server_id, msg->markers );
}

void InteractiveMarkerDisplay::updateCb( visualization_msgs::InteractiveMarkerUpdateConstPtr msg )
{
  updateMarkers( msg->server_id, msg->markers );
  updatePoses( msg->server_id, msg->poses );
  eraseMarkers( msg->server_id, msg->erases );
}

void InteractiveMarkerDisplay::resetCb( std::string server_id )
{
  interactive_markers_.erase( server_id );
  deleteStatusStd(server_id);
}

void InteractiveMarkerDisplay::statusCb(
    interactive_markers::InteractiveMarkerClient::StatusT status,
    const std::string& server_id,
    const std::string& msg )
{
  setStatusStd( static_cast<StatusProperty::Level>(status), server_id, msg );
}

void InteractiveMarkerDisplay::fixedFrameChanged()
{
  if (im_client_)
    im_client_->setTargetFrame( fixed_frame_.toStdString() );
  reset();
}

void InteractiveMarkerDisplay::reset()
{
  Display::reset();
  unsubscribe();
  subscribe();
}

void InteractiveMarkerDisplay::updateShowDescriptions()
{
  bool show = show_descriptions_property_->getBool();

  M_StringToStringToIMPtr::iterator server_it;
  for ( server_it = interactive_markers_.begin(); server_it != interactive_markers_.end(); server_it++ )
  {
    M_StringToIMPtr::iterator im_it;
    for ( im_it = server_it->second.begin(); im_it != server_it->second.end(); im_it++ )
    {
      im_it->second->setShowDescription( show );
    }
  }
}

void InteractiveMarkerDisplay::updateShowAxes()
{
  bool show = show_axes_property_->getBool();

  M_StringToStringToIMPtr::iterator server_it;
  for ( server_it = interactive_markers_.begin(); server_it != interactive_markers_.end(); server_it++ )
  {
    M_StringToIMPtr::iterator im_it;
    for ( im_it = server_it->second.begin(); im_it != server_it->second.end(); im_it++ )
    {
      im_it->second->setShowAxes( show );
    }
  }
}

void InteractiveMarkerDisplay::updateShowVisualAids()
{
  bool show = show_visual_aids_property_->getBool();

  M_StringToStringToIMPtr::iterator server_it;
  for ( server_it = interactive_markers_.begin(); server_it != interactive_markers_.end(); server_it++ )
  {
    M_StringToIMPtr::iterator im_it;
    for ( im_it = server_it->second.begin(); im_it != server_it->second.end(); im_it++ )
    {
      im_it->second->setShowVisualAids( show );
    }
  }
}

void InteractiveMarkerDisplay::updateEnableTransparency()
{
  // This is not very efficient... but it should do the trick.
  unsubscribe();
  im_client_->setEnableAutocompleteTransparency( enable_transparency_property_->getBool() );
  subscribe();
}

} // namespace rviz

#include <pluginlib/class_list_macros.hpp>
PLUGINLIB_EXPORT_CLASS( rviz::InteractiveMarkerDisplay, rviz::Display )
<commit_msg>tf2: Update InteractiveMarkerDisplay<commit_after>/*
 * Copyright (c) 2008, Willow Garage, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the Willow Garage, Inc. nor the names of its
 *       contributors may be used to endorse or promote products derived from
 *       this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <tf/transform_listener.h>

#include <rviz/frame_manager.h>
#include <rviz/properties/bool_property.h>
#include <rviz/properties/ros_topic_property.h>
#include <rviz/selection/selection_manager.h>
#include <rviz/validate_floats.h>
#include <rviz/validate_quaternions.h>
#include <rviz/display_context.h>

#include <rviz/default_plugin/interactive_marker_display.h>

namespace rviz
{

//////////////
bool validateFloats(const visualization_msgs::InteractiveMarker& msg)
{
  bool valid = true;
  valid = valid && validateFloats(msg.pose);
  valid = valid && validateFloats(msg.scale);
  for ( unsigned c=0; c<msg.controls.size(); c++)
  {
    valid = valid && validateFloats( msg.controls[c].orientation );
    for ( unsigned m=0; m<msg.controls[c].markers.size(); m++ )
    {
      valid = valid && validateFloats(msg.controls[c].markers[m].pose);
      valid = valid && validateFloats(msg.controls[c].markers[m].scale);
      valid = valid && validateFloats(msg.controls[c].markers[m].color);
      valid = valid && validateFloats(msg.controls[c].markers[m].points);
    }
  }
  return valid;
}

bool validateQuaternions(const visualization_msgs::InteractiveMarker &marker)
{
  if ( !validateQuaternions( marker.pose.orientation )) return false;
  for ( size_t c = 0; c < marker.controls.size(); ++c )
  {
    if ( !validateQuaternions( marker.controls[c].orientation )) return false;
    for ( size_t m = 0; m < marker.controls[c].markers.size(); ++m )
    {
      if ( !validateQuaternions( marker.controls[c].markers[m].pose.orientation )) return false;
    }
  }
  return true;
}
/////////////

InteractiveMarkerDisplay::InteractiveMarkerDisplay()
  : Display()
{
  marker_update_topic_property_ = new RosTopicProperty( "Update Topic", "",
                                                        ros::message_traits::datatype<visualization_msgs::InteractiveMarkerUpdate>(),
                                                        "visualization_msgs::InteractiveMarkerUpdate topic to subscribe to.",
                                                        this, SLOT( updateTopic() ));

  show_descriptions_property_ = new BoolProperty( "Show Descriptions", true,
                                                  "Whether or not to show the descriptions of each Interactive Marker.",
                                                  this, SLOT( updateShowDescriptions() ));

  show_axes_property_ = new BoolProperty( "Show Axes", false,
                                          "Whether or not to show the axes of each Interactive Marker.",
                                          this, SLOT( updateShowAxes() ));

  show_visual_aids_property_ = new BoolProperty( "Show Visual Aids", false,
                                                 "Whether or not to show visual helpers while moving/rotating Interactive Markers.",
                                                 this, SLOT( updateShowVisualAids() ));
  enable_transparency_property_ = new BoolProperty( "Enable Transparency", true,
                                                 "Whether or not to allow transparency for auto-completed markers (e.g. rings and arrows).",
                                                 this, SLOT( updateEnableTransparency() ));
}

void InteractiveMarkerDisplay::onInitialize()
{
  auto tf = context_->getFrameManager()->getTF2BufferPtr();
  im_client_.reset( new interactive_markers::InteractiveMarkerClient( *tf, fixed_frame_.toStdString() ) );

  im_client_->setInitCb( boost::bind( &InteractiveMarkerDisplay::initCb, this, _1 ) );
  im_client_->setUpdateCb( boost::bind( &InteractiveMarkerDisplay::updateCb, this, _1 ) );
  im_client_->setResetCb( boost::bind( &InteractiveMarkerDisplay::resetCb, this, _1 ) );
  im_client_->setStatusCb( boost::bind( &InteractiveMarkerDisplay::statusCb, this, _1, _2, _3 ) );

  client_id_ = ros::this_node::getName() + "/" + getNameStd();

  onEnable();
}

void InteractiveMarkerDisplay::setTopic( const QString &topic, const QString & /*datatype*/ )
{
  marker_update_topic_property_->setString( topic );
}

void InteractiveMarkerDisplay::onEnable()
{
  subscribe();
}

void InteractiveMarkerDisplay::onDisable()
{
  unsubscribe();
}

void InteractiveMarkerDisplay::updateTopic()
{
  unsubscribe();

  std::string update_topic = marker_update_topic_property_->getTopicStd();

  size_t idx = update_topic.find( "/update" );
  if ( idx != std::string::npos )
  {
    topic_ns_ = update_topic.substr( 0, idx );
    subscribe();
  }
  else
  {
    setStatusStd( StatusProperty::Error, "Topic", "Invalid topic name: " + update_topic );
  }

}

void InteractiveMarkerDisplay::subscribe()
{
  if ( isEnabled() )
  {
    im_client_->subscribe(topic_ns_);

    std::string feedback_topic = topic_ns_+"/feedback";
    feedback_pub_ = update_nh_.advertise<visualization_msgs::InteractiveMarkerFeedback>( feedback_topic, 100, false );
  }
}

void InteractiveMarkerDisplay::publishFeedback(visualization_msgs::InteractiveMarkerFeedback &feedback)
{
  feedback.client_id = client_id_;
  feedback_pub_.publish( feedback );
}

void InteractiveMarkerDisplay::onStatusUpdate( StatusProperty::Level level, const std::string& name, const std::string& text )
{
  setStatusStd(level,name,text);
}

void InteractiveMarkerDisplay::unsubscribe()
{
  if (im_client_)
  {
    im_client_->shutdown();
  }
  feedback_pub_.shutdown();
  Display::reset();
}

void InteractiveMarkerDisplay::update(float wall_dt, float  /*ros_dt*/)
{
  im_client_->update();

  M_StringToStringToIMPtr::iterator server_it;
  for ( server_it = interactive_markers_.begin(); server_it != interactive_markers_.end(); server_it++ )
  {
    M_StringToIMPtr::iterator im_it;
    for ( im_it = server_it->second.begin(); im_it != server_it->second.end(); im_it++ )
    {
      im_it->second->update( wall_dt );
    }
  }
}

InteractiveMarkerDisplay::M_StringToIMPtr& InteractiveMarkerDisplay::getImMap( std::string server_id )
{
  M_StringToStringToIMPtr::iterator im_map_it = interactive_markers_.find( server_id );

  if ( im_map_it == interactive_markers_.end() )
  {
    im_map_it = interactive_markers_.insert( std::make_pair( server_id, M_StringToIMPtr() ) ).first;
  }

  return im_map_it->second;
}

void InteractiveMarkerDisplay::updateMarkers(
    const std::string& server_id,
    const std::vector<visualization_msgs::InteractiveMarker>& markers
    )
{
  M_StringToIMPtr& im_map = getImMap( server_id );

  for ( size_t i=0; i<markers.size(); i++ )
  {
    const visualization_msgs::InteractiveMarker& marker = markers[i];

    if ( !validateFloats( marker ) )
    {
      setStatusStd( StatusProperty::Error, marker.name, "Marker contains invalid floats!" );
      //setStatusStd( StatusProperty::Error, "General", "Marker " + marker.name + " contains invalid floats!" );
      continue;
    }

    if( !validateQuaternions( marker ))
    {
      ROS_WARN_ONCE_NAMED( "quaternions", "Interactive marker '%s' contains unnormalized quaternions. "
                           "This warning will only be output once but may be true for others; "
                           "enable DEBUG messages for ros.rviz.quaternions to see more details.",
                           marker.name.c_str() );
      ROS_DEBUG_NAMED( "quaternions", "Interactive marker '%s' contains unnormalized quaternions.",
                       marker.name.c_str() );
    }
    ROS_DEBUG("Processing interactive marker '%s'. %d", marker.name.c_str(), (int)marker.controls.size() );

    std::map< std::string, IMPtr >::iterator int_marker_entry = im_map.find( marker.name );

    if ( int_marker_entry == im_map.end() )
    {
      int_marker_entry = im_map.insert( std::make_pair(marker.name, IMPtr ( new InteractiveMarker(getSceneNode(), context_) ) ) ).first;
      connect( int_marker_entry->second.get(),
               SIGNAL( userFeedback(visualization_msgs::InteractiveMarkerFeedback&) ),
               this,
               SLOT( publishFeedback(visualization_msgs::InteractiveMarkerFeedback&) ));
      connect( int_marker_entry->second.get(),
               SIGNAL( statusUpdate(StatusProperty::Level, const std::string&, const std::string&) ),
               this,
               SLOT( onStatusUpdate(StatusProperty::Level, const std::string&, const std::string&) ) );
    }

    if ( int_marker_entry->second->processMessage( marker ) )
    {
      int_marker_entry->second->setShowAxes( show_axes_property_->getBool() );
      int_marker_entry->second->setShowVisualAids( show_visual_aids_property_->getBool() );
      int_marker_entry->second->setShowDescription( show_descriptions_property_->getBool() );
    }
    else
    {
      unsubscribe();
      return;
    }
  }
}

void InteractiveMarkerDisplay::eraseMarkers(
    const std::string& server_id,
    const std::vector<std::string>& erases )
{
  M_StringToIMPtr& im_map = getImMap( server_id );

  for ( size_t i=0; i<erases.size(); i++ )
  {
    im_map.erase( erases[i] );
    deleteStatusStd( erases[i] );
  }
}

void InteractiveMarkerDisplay::updatePoses(
    const std::string& server_id,
    const std::vector<visualization_msgs::InteractiveMarkerPose>& marker_poses )
{
  M_StringToIMPtr& im_map = getImMap( server_id );

  for ( size_t i=0; i<marker_poses.size(); i++ )
  {
    const visualization_msgs::InteractiveMarkerPose& marker_pose = marker_poses[i];

    if ( !validateFloats( marker_pose.pose ) )
    {
      setStatusStd( StatusProperty::Error, marker_pose.name, "Pose message contains invalid floats!" );
      return;
    }

    if( !validateQuaternions( marker_pose.pose ))
    {
      setStatusStd( StatusProperty::Error, marker_pose.name,
                    "Pose message contains invalid quaternions (length not equal to 1)!" );
      return;
    }

    std::map< std::string, IMPtr >::iterator int_marker_entry = im_map.find( marker_pose.name );

    if ( int_marker_entry != im_map.end() )
    {
      int_marker_entry->second->processMessage( marker_pose );
    }
    else
    {
      setStatusStd( StatusProperty::Error, marker_pose.name, "Pose received for non-existing marker '" + marker_pose.name );
      unsubscribe();
      return;
    }
  }
}

void InteractiveMarkerDisplay::initCb( visualization_msgs::InteractiveMarkerInitConstPtr msg )
{
  resetCb( msg->server_id );
  updateMarkers( msg->server_id, msg->markers );
}

void InteractiveMarkerDisplay::updateCb( visualization_msgs::InteractiveMarkerUpdateConstPtr msg )
{
  updateMarkers( msg->server_id, msg->markers );
  updatePoses( msg->server_id, msg->poses );
  eraseMarkers( msg->server_id, msg->erases );
}

void InteractiveMarkerDisplay::resetCb( std::string server_id )
{
  interactive_markers_.erase( server_id );
  deleteStatusStd(server_id);
}

void InteractiveMarkerDisplay::statusCb(
    interactive_markers::InteractiveMarkerClient::StatusT status,
    const std::string& server_id,
    const std::string& msg )
{
  setStatusStd( static_cast<StatusProperty::Level>(status), server_id, msg );
}

void InteractiveMarkerDisplay::fixedFrameChanged()
{
  if (im_client_)
    im_client_->setTargetFrame( fixed_frame_.toStdString() );
  reset();
}

void InteractiveMarkerDisplay::reset()
{
  Display::reset();
  unsubscribe();
  subscribe();
}

void InteractiveMarkerDisplay::updateShowDescriptions()
{
  bool show = show_descriptions_property_->getBool();

  M_StringToStringToIMPtr::iterator server_it;
  for ( server_it = interactive_markers_.begin(); server_it != interactive_markers_.end(); server_it++ )
  {
    M_StringToIMPtr::iterator im_it;
    for ( im_it = server_it->second.begin(); im_it != server_it->second.end(); im_it++ )
    {
      im_it->second->setShowDescription( show );
    }
  }
}

void InteractiveMarkerDisplay::updateShowAxes()
{
  bool show = show_axes_property_->getBool();

  M_StringToStringToIMPtr::iterator server_it;
  for ( server_it = interactive_markers_.begin(); server_it != interactive_markers_.end(); server_it++ )
  {
    M_StringToIMPtr::iterator im_it;
    for ( im_it = server_it->second.begin(); im_it != server_it->second.end(); im_it++ )
    {
      im_it->second->setShowAxes( show );
    }
  }
}

void InteractiveMarkerDisplay::updateShowVisualAids()
{
  bool show = show_visual_aids_property_->getBool();

  M_StringToStringToIMPtr::iterator server_it;
  for ( server_it = interactive_markers_.begin(); server_it != interactive_markers_.end(); server_it++ )
  {
    M_StringToIMPtr::iterator im_it;
    for ( im_it = server_it->second.begin(); im_it != server_it->second.end(); im_it++ )
    {
      im_it->second->setShowVisualAids( show );
    }
  }
}

void InteractiveMarkerDisplay::updateEnableTransparency()
{
  // This is not very efficient... but it should do the trick.
  unsubscribe();
  im_client_->setEnableAutocompleteTransparency( enable_transparency_property_->getBool() );
  subscribe();
}

} // namespace rviz

#include <pluginlib/class_list_macros.hpp>
PLUGINLIB_EXPORT_CLASS( rviz::InteractiveMarkerDisplay, rviz::Display )
<|endoftext|>