<commit_before>/****************************************************************************
 **
 ** Copyright (C) Qxt Foundation. Some rights reserved.
 **
 ** This file is part of the QxtGui module of the Qxt library.
 **
 ** This library is free software; you can redistribute it and/or modify it
 ** under the terms of the Common Public License, version 1.0, as published
 ** by IBM, and/or under the terms of the GNU Lesser General Public License,
 ** version 2.1, as published by the Free Software Foundation.
 **
 ** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY
 ** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
 ** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR
 ** FITNESS FOR A PARTICULAR PURPOSE.
 **
 ** You should have received a copy of the CPL and the LGPL along with this
 ** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files
 ** included with the source distribution for more information.
 ** If you did not receive a copy of the licenses, contact the Qxt Foundation.
 **
 ** <http://libqxt.org>  <foundation@libqxt.org>
 **
 ****************************************************************************/

#include "qxtcrumbview.h"
#include "qxtcrumbview_p.h"
#include <QApplication>
#include <QPaintEvent>
#include <QListView>
#include <QToolButton>
#include <QBoxLayout>
#include <QModelIndex>
#include <QAbstractItemDelegate>
#include <QStyle>
#include <QStylePainter>
#include <QSize>
#include <QFont>
#include <QtAlgorithms>
#include <QtDebug>

// This class exists only to grant access to QListView's protected members
class QxtCrumbViewList : public QListView {
friend class QxtCrumbView;
public:
    QxtCrumbViewList(QWidget* parent) : QListView(parent) {
    }
};

QxtCrumbViewDelegate::QxtCrumbViewDelegate(QAbstractItemDelegate* other, QObject* parent) : QAbstractItemDelegate(parent), delegate(other) {
    QObject::connect(other, SIGNAL(closeEditor(QWidget*, QAbstractItemDelegate::EndEditHint)),
                     this, SIGNAL(closeEditor(QWidget*, QAbstractItemDelegate::EndEditHint)));
    QObject::connect(other, SIGNAL(commitData(QWidget*)), this, SIGNAL(commitData(QWidget*)));
    QObject::connect(other, SIGNAL(sizeHintChanged(QModelIndex)), this, SIGNAL(sizeHintChanged(QModelIndex)));

}

void QxtCrumbViewDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const {
    delegate->paint(painter, option, index);

    if(!index.model()->hasChildren(index)) return;

    int arrow = 8;
    int pad = (option.rect.height() - arrow) / 2;
    QStyleOption arrowOption;
    arrowOption = option;
    arrowOption.rect = QRect(option.rect.right() - arrow, option.rect.top() + pad, arrow, arrow);
    QApplication::style()->drawPrimitive(QStyle::PE_IndicatorArrowRight, &arrowOption, painter);
}

QSize QxtCrumbViewDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const {
    return delegate->sizeHint(option, index) + QSize(8, 0);
}

QWidget* QxtCrumbViewDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) {
    return delegate->createEditor(parent, option, index);
}

void QxtCrumbViewDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const {
    delegate->setEditorData(editor, index);
}

void QxtCrumbViewDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const {
    delegate->setModelData(editor, model, index);
}

void QxtCrumbViewDelegate::updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index) const {
    delegate->updateEditorGeometry(editor, option, index);
}

bool QxtCrumbViewDelegate::editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index) {
    return delegate->editorEvent(event, model, option, index);
}

class QxtCrumbViewButton : public QAbstractButton {
public:
    QxtCrumbViewButton(const QModelIndex& idx, QxtCrumbView* parent) : QAbstractButton(parent), index(idx) {
        // initializers only
    }

    QModelIndex index;

    QSize sizeHint() const {
        QStyleOptionViewItem itemOption;
        itemOption.initFrom(this);
        int border = style()->pixelMetric(QStyle::PM_DefaultFrameWidth) * 2;
        int arrow = 8;
        if(index.isValid())
            return static_cast<QxtCrumbView*>(parent())->itemDelegate()->sizeHint(itemOption, index) + QSize(border + arrow, border);
        else
            return QSize(border + arrow, border + arrow);
    }

protected:
    void enterEvent(QEvent* event) {
        Q_UNUSED(event);
        update();
    }

    void leaveEvent(QEvent* event) {
        Q_UNUSED(event);
        update();
    }

    void paintEvent(QPaintEvent* event) {
        Q_UNUSED(event);
        QStylePainter painter(this);
        QStyleOptionButton option;
        option.initFrom(this);
        if(rect().contains(mapFromGlobal(QCursor::pos()))) {
            painter.drawPrimitive(QStyle::PE_PanelButtonTool, option);
        }
        int border = painter.style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
        option.rect = option.rect.adjusted(border, border, -border, -border);
        if(index.isValid()) {
            QAbstractItemDelegate* delegate = static_cast<QxtCrumbView*>(parent())->crumbDelegate();
            QStyleOptionViewItem itemOption;
            itemOption.initFrom(this);
            itemOption.rect = option.rect;
            delegate->paint(&painter, itemOption, index);
        }
        int arrow = 8;
        int pad = (height() - (2 * border) - arrow) / 2;
        QStyleOption arrowOption;
        arrowOption.initFrom(this);
        arrowOption.rect = QRect(width() - border - arrow, pad, arrow, arrow);
        painter.drawPrimitive(QStyle::PE_IndicatorArrowRight, arrowOption);
    }
};

QxtCrumbViewPrivate::QxtCrumbViewPrivate() : crumbDelegate(0) {
    // initializers only
}

void QxtCrumbViewPrivate::addCrumb(const QModelIndex& index) {
    crumbs.append(index);
    QxtCrumbViewButton* button = new QxtCrumbViewButton(index, &qxt_p());
    button->setFocusPolicy(Qt::NoFocus);
    button->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
    buttons.append(button);
    buttonLayout->insertWidget(buttons.count() - 1, button, 0);
    QObject::connect(button, SIGNAL(clicked()), this, SLOT(buttonPressed()));
}

void QxtCrumbViewPrivate::buttonPressed() {
    qxt_p().enterTree(static_cast<QxtCrumbViewButton*>(sender())->index);
}

QxtCrumbView::QxtCrumbView(QWidget* parent) : QAbstractItemView(parent) {
    QXT_INIT_PRIVATE(QxtCrumbView);
    setAutoFillBackground(false);
    setBackgroundRole(QPalette::Window);
    viewport()->setAutoFillBackground(false);
    viewport()->setBackgroundRole(QPalette::Window);
    setFrameStyle(QFrame::NoFrame);
    QVBoxLayout* layout = new QVBoxLayout(this);
    qxt_d().buttonLayout = new QHBoxLayout;
    qxt_d().buttonLayout->setSpacing(0);
    qxt_d().buttonLayout->addStretch(1);
    QToolButton* backButton = new QToolButton(this);
    backButton->setIcon(style()->standardPixmap(QStyle::SP_FileDialogBack));
    backButton->setAutoRaise(true);
    backButton->setFocusPolicy(Qt::NoFocus);
    qxt_d().buttonLayout->addWidget(backButton);
    layout->addLayout(qxt_d().buttonLayout, 0);
    qxt_d().view = new QxtCrumbViewList(this);
    layout->addWidget(qxt_d().view, 1);
    qxt_d().addCrumb(QModelIndex());

    QObject::connect(qxt_d().view, SIGNAL(activated(QModelIndex)), this, SLOT(enterTree(QModelIndex)));
    QObject::connect(backButton, SIGNAL(clicked()), this, SLOT(back()));
}

void QxtCrumbView::setModel(QAbstractItemModel* model) {
    qxt_d().view->setModel(model);
    QAbstractItemView::setModel(model);
    delete qxt_d().view->itemDelegate();
    qxt_d().view->setItemDelegate(new QxtCrumbViewDelegate(itemDelegate(), this));
}

void QxtCrumbView::reset() {
    QAbstractItemView::reset();
    qDeleteAll(qxt_d().buttons);
    qxt_d().crumbs.clear();
    qxt_d().buttons.clear();
    qxt_d().addCrumb(QModelIndex());
    qxt_d().view->reset();
}

int QxtCrumbView::horizontalOffset() const {
    return qxt_d().view->horizontalOffset();
}

int QxtCrumbView::verticalOffset() const {
    return qxt_d().view->verticalOffset();
}

QModelIndex QxtCrumbView::indexAt(const QPoint& point) const {
    return qxt_d().view->indexAt(qxt_d().view->mapFromParent(point));
}

bool QxtCrumbView::isIndexHidden(const QModelIndex& index) const {
    return qxt_d().view->isIndexHidden(index);
}

QModelIndex QxtCrumbView::moveCursor(CursorAction action, Qt::KeyboardModifiers mods) {
    return qxt_d().view->moveCursor(action, mods);
}

void QxtCrumbView::scrollTo(const QModelIndex& index, ScrollHint hint) {
    if(index.parent() != qxt_d().view->rootIndex()) {
        // TODO: set the breadcrumbs and the view's root index correctly
    }
    qxt_d().view->scrollTo(index, hint);
}

void QxtCrumbView::setSelection(const QRect& rect, QItemSelectionModel::SelectionFlags flags) {
    QPoint tl = qxt_d().view->mapFromParent(rect.topLeft());
    qxt_d().view->setSelection(QRect(tl, rect.size()), flags);
}

QRect QxtCrumbView::visualRect(const QModelIndex& index) const {
    QRect rect = qxt_d().view->visualRect(index);
    return QRect(qxt_d().view->mapToParent(rect.topLeft()), rect.size());
}

QRegion QxtCrumbView::visualRegionForSelection(const QItemSelection& selection) const {
    QRegion region = qxt_d().view->visualRegionForSelection(selection);
    return region.translated(qxt_d().view->pos());
}

void QxtCrumbView::enterTree(const QModelIndex& index) {
    if(!model()) return;
    if(!model()->hasChildren(index)) {
        emit activated(index);
        return;
    }
    if(index == qxt_d().view->rootIndex()) {
        // do nothing but reload the view
    } else if(index.parent() != qxt_d().view->rootIndex()) {
        foreach(QxtCrumbViewButton* b, qxt_d().buttons) b->deleteLater();
        qxt_d().crumbs.clear();
        qxt_d().buttons.clear();
        qxt_d().addCrumb(QModelIndex());
        QList<QModelIndex> chain;
        QModelIndex pos = index;
        while(pos.isValid()) {
            chain.append(pos);
            pos = pos.parent();
        }
        while(!chain.isEmpty()) {
            qxt_d().addCrumb(chain.last());
            chain.removeLast();
        }
    } else {
        qxt_d().addCrumb(index);
    }
    qxt_d().view->setRootIndex(index);
}

void QxtCrumbView::back() {
    if(qxt_d().crumbs.count() <= 1) return;
    qxt_d().buttons.last()->deleteLater();
    qxt_d().buttons.removeLast();
    qxt_d().crumbs.removeLast();
    qxt_d().view->setRootIndex(qxt_d().crumbs.last());
}

void QxtCrumbView::setItemDelegate(QAbstractItemDelegate* delegate) {
    QAbstractItemView::setItemDelegate(delegate);
    //delete qxt_d().view->itemDelegate();
    //qxt_d().view->setItemDelegate(new QxtCrumbViewDelegate(itemDelegate(), this));
}

QAbstractItemView* QxtCrumbView::itemView() const {
    return qxt_d().view;
}

void QxtCrumbView::showEvent(QShowEvent* event) {
    QxtCrumbViewDelegate* viewDelegate = qobject_cast<QxtCrumbViewDelegate*>(qxt_d().view->itemDelegate());
    if(viewDelegate->delegate != itemDelegate()) {
        qxt_d().view->setItemDelegate(new QxtCrumbViewDelegate(itemDelegate(), this));
        delete viewDelegate;
        qxt_d().view->reset();
    }
    QAbstractItemView::showEvent(event);
}

void QxtCrumbView::paintEvent(QPaintEvent* event) {
    QxtCrumbViewDelegate* viewDelegate = qobject_cast<QxtCrumbViewDelegate*>(qxt_d().view->itemDelegate());
    if(viewDelegate->delegate != itemDelegate()) {
        qxt_d().view->setItemDelegate(new QxtCrumbViewDelegate(itemDelegate(), this));
        delete viewDelegate;
        qxt_d().view->reset();
    }
    QAbstractItemView::paintEvent(event);
}

QAbstractItemDelegate* QxtCrumbView::crumbDelegate() const {
    QAbstractItemDelegate* rv = qxt_d().crumbDelegate;
    if(!rv) return itemDelegate();
    return rv;
}

void QxtCrumbView::setCrumbDelegate(QAbstractItemDelegate* delegate) {
    qxt_d().crumbDelegate = delegate;
    update();
    foreach(QxtCrumbViewButton* button, qxt_d().buttons) {
        button->update();
    }
}

<commit_msg>QxtCrumbView: remove unnecessary padding<commit_after>/****************************************************************************
 **
 ** Copyright (C) Qxt Foundation. Some rights reserved.
 **
 ** This file is part of the QxtGui module of the Qxt library.
 **
 ** This library is free software; you can redistribute it and/or modify it
 ** under the terms of the Common Public License, version 1.0, as published
 ** by IBM, and/or under the terms of the GNU Lesser General Public License,
 ** version 2.1, as published by the Free Software Foundation.
 **
 ** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY
 ** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
 ** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR
 ** FITNESS FOR A PARTICULAR PURPOSE.
 **
 ** You should have received a copy of the CPL and the LGPL along with this
 ** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files
 ** included with the source distribution for more information.
 ** If you did not receive a copy of the licenses, contact the Qxt Foundation.
 **
 ** <http://libqxt.org>  <foundation@libqxt.org>
 **
 ****************************************************************************/

#include "qxtcrumbview.h"
#include "qxtcrumbview_p.h"
#include <QApplication>
#include <QPaintEvent>
#include <QListView>
#include <QToolButton>
#include <QBoxLayout>
#include <QModelIndex>
#include <QAbstractItemDelegate>
#include <QStyle>
#include <QStylePainter>
#include <QSize>
#include <QFont>
#include <QtAlgorithms>
#include <QtDebug>

// This class exists only to grant access to QListView's protected members
class QxtCrumbViewList : public QListView {
friend class QxtCrumbView;
public:
    QxtCrumbViewList(QWidget* parent) : QListView(parent) {
    }
};

QxtCrumbViewDelegate::QxtCrumbViewDelegate(QAbstractItemDelegate* other, QObject* parent) : QAbstractItemDelegate(parent), delegate(other) {
    QObject::connect(other, SIGNAL(closeEditor(QWidget*, QAbstractItemDelegate::EndEditHint)),
                     this, SIGNAL(closeEditor(QWidget*, QAbstractItemDelegate::EndEditHint)));
    QObject::connect(other, SIGNAL(commitData(QWidget*)), this, SIGNAL(commitData(QWidget*)));
    QObject::connect(other, SIGNAL(sizeHintChanged(QModelIndex)), this, SIGNAL(sizeHintChanged(QModelIndex)));

}

void QxtCrumbViewDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const {
    delegate->paint(painter, option, index);

    if(!index.model()->hasChildren(index)) return;

    int arrow = 8;
    int pad = (option.rect.height() - arrow) / 2;
    QStyleOption arrowOption;
    arrowOption = option;
    arrowOption.rect = QRect(option.rect.right() - arrow, option.rect.top() + pad, arrow, arrow);
    QApplication::style()->drawPrimitive(QStyle::PE_IndicatorArrowRight, &arrowOption, painter);
}

QSize QxtCrumbViewDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const {
    return delegate->sizeHint(option, index) + QSize(8, 0);
}

QWidget* QxtCrumbViewDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) {
    return delegate->createEditor(parent, option, index);
}

void QxtCrumbViewDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const {
    delegate->setEditorData(editor, index);
}

void QxtCrumbViewDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const {
    delegate->setModelData(editor, model, index);
}

void QxtCrumbViewDelegate::updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index) const {
    delegate->updateEditorGeometry(editor, option, index);
}

bool QxtCrumbViewDelegate::editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index) {
    return delegate->editorEvent(event, model, option, index);
}

class QxtCrumbViewButton : public QAbstractButton {
public:
    QxtCrumbViewButton(const QModelIndex& idx, QxtCrumbView* parent) : QAbstractButton(parent), index(idx) {
        // initializers only
    }

    QModelIndex index;

    QSize sizeHint() const {
        QStyleOptionViewItem itemOption;
        itemOption.initFrom(this);
        int border = style()->pixelMetric(QStyle::PM_DefaultFrameWidth) * 2;
        int arrow = 8;
        if(index.isValid())
            return static_cast<QxtCrumbView*>(parent())->itemDelegate()->sizeHint(itemOption, index) + QSize(border + arrow, border);
        else
            return QSize(border + arrow, border + arrow);
    }

protected:
    void enterEvent(QEvent* event) {
        Q_UNUSED(event);
        update();
    }

    void leaveEvent(QEvent* event) {
        Q_UNUSED(event);
        update();
    }

    void paintEvent(QPaintEvent* event) {
        Q_UNUSED(event);
        QStylePainter painter(this);
        QStyleOptionButton option;
        option.initFrom(this);
        if(rect().contains(mapFromGlobal(QCursor::pos()))) {
            painter.drawPrimitive(QStyle::PE_PanelButtonTool, option);
        }
        int border = painter.style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
        option.rect = option.rect.adjusted(border, border, -border, -border);
        if(index.isValid()) {
            QAbstractItemDelegate* delegate = static_cast<QxtCrumbView*>(parent())->crumbDelegate();
            QStyleOptionViewItem itemOption;
            itemOption.initFrom(this);
            itemOption.rect = option.rect;
            delegate->paint(&painter, itemOption, index);
        }
        int arrow = 8;
        int pad = (height() - (2 * border) - arrow) / 2;
        QStyleOption arrowOption;
        arrowOption.initFrom(this);
        arrowOption.rect = QRect(width() - border - arrow, pad, arrow, arrow);
        painter.drawPrimitive(QStyle::PE_IndicatorArrowRight, arrowOption);
    }
};

QxtCrumbViewPrivate::QxtCrumbViewPrivate() : crumbDelegate(0) {
    // initializers only
}

void QxtCrumbViewPrivate::addCrumb(const QModelIndex& index) {
    crumbs.append(index);
    QxtCrumbViewButton* button = new QxtCrumbViewButton(index, &qxt_p());
    button->setFocusPolicy(Qt::NoFocus);
    button->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
    buttons.append(button);
    buttonLayout->insertWidget(buttons.count() - 1, button, 0);
    QObject::connect(button, SIGNAL(clicked()), this, SLOT(buttonPressed()));
}

void QxtCrumbViewPrivate::buttonPressed() {
    qxt_p().enterTree(static_cast<QxtCrumbViewButton*>(sender())->index);
}

QxtCrumbView::QxtCrumbView(QWidget* parent) : QAbstractItemView(parent) {
    QXT_INIT_PRIVATE(QxtCrumbView);
    setAutoFillBackground(false);
    setBackgroundRole(QPalette::Window);
    viewport()->setAutoFillBackground(false);
    viewport()->setBackgroundRole(QPalette::Window);
    setFrameStyle(QFrame::NoFrame);
    QVBoxLayout* layout = new QVBoxLayout(this);
    layout->setContentsMargins(0, 0, 0, 0);
    qxt_d().buttonLayout = new QHBoxLayout;
    qxt_d().buttonLayout->setContentsMargins(0, 0, 0, 0);
    qxt_d().buttonLayout->setSpacing(0);
    qxt_d().buttonLayout->addStretch(1);
    QToolButton* backButton = new QToolButton(this);
    backButton->setIcon(style()->standardPixmap(QStyle::SP_FileDialogBack));
    backButton->setAutoRaise(true);
    backButton->setFocusPolicy(Qt::NoFocus);
    qxt_d().buttonLayout->addWidget(backButton);
    layout->addLayout(qxt_d().buttonLayout, 0);
    qxt_d().view = new QxtCrumbViewList(this);
    layout->addWidget(qxt_d().view, 1);
    qxt_d().addCrumb(QModelIndex());

    QObject::connect(qxt_d().view, SIGNAL(activated(QModelIndex)), this, SLOT(enterTree(QModelIndex)));
    QObject::connect(backButton, SIGNAL(clicked()), this, SLOT(back()));
}

void QxtCrumbView::setModel(QAbstractItemModel* model) {
    qxt_d().view->setModel(model);
    QAbstractItemView::setModel(model);
    delete qxt_d().view->itemDelegate();
    qxt_d().view->setItemDelegate(new QxtCrumbViewDelegate(itemDelegate(), this));
}

void QxtCrumbView::reset() {
    QAbstractItemView::reset();
    qDeleteAll(qxt_d().buttons);
    qxt_d().crumbs.clear();
    qxt_d().buttons.clear();
    qxt_d().addCrumb(QModelIndex());
    qxt_d().view->reset();
}

int QxtCrumbView::horizontalOffset() const {
    return qxt_d().view->horizontalOffset();
}

int QxtCrumbView::verticalOffset() const {
    return qxt_d().view->verticalOffset();
}

QModelIndex QxtCrumbView::indexAt(const QPoint& point) const {
    return qxt_d().view->indexAt(qxt_d().view->mapFromParent(point));
}

bool QxtCrumbView::isIndexHidden(const QModelIndex& index) const {
    return qxt_d().view->isIndexHidden(index);
}

QModelIndex QxtCrumbView::moveCursor(CursorAction action, Qt::KeyboardModifiers mods) {
    return qxt_d().view->moveCursor(action, mods);
}

void QxtCrumbView::scrollTo(const QModelIndex& index, ScrollHint hint) {
    if(index.parent() != qxt_d().view->rootIndex()) {
        // TODO: set the breadcrumbs and the view's root index correctly
    }
    qxt_d().view->scrollTo(index, hint);
}

void QxtCrumbView::setSelection(const QRect& rect, QItemSelectionModel::SelectionFlags flags) {
    QPoint tl = qxt_d().view->mapFromParent(rect.topLeft());
    qxt_d().view->setSelection(QRect(tl, rect.size()), flags);
}

QRect QxtCrumbView::visualRect(const QModelIndex& index) const {
    QRect rect = qxt_d().view->visualRect(index);
    return QRect(qxt_d().view->mapToParent(rect.topLeft()), rect.size());
}

QRegion QxtCrumbView::visualRegionForSelection(const QItemSelection& selection) const {
    QRegion region = qxt_d().view->visualRegionForSelection(selection);
    return region.translated(qxt_d().view->pos());
}

void QxtCrumbView::enterTree(const QModelIndex& index) {
    if(!model()) return;
    if(!model()->hasChildren(index)) {
        emit activated(index);
        return;
    }
    if(index == qxt_d().view->rootIndex()) {
        // do nothing but reload the view
    } else if(index.parent() != qxt_d().view->rootIndex()) {
        foreach(QxtCrumbViewButton* b, qxt_d().buttons) b->deleteLater();
        qxt_d().crumbs.clear();
        qxt_d().buttons.clear();
        qxt_d().addCrumb(QModelIndex());
        QList<QModelIndex> chain;
        QModelIndex pos = index;
        while(pos.isValid()) {
            chain.append(pos);
            pos = pos.parent();
        }
        while(!chain.isEmpty()) {
            qxt_d().addCrumb(chain.last());
            chain.removeLast();
        }
    } else {
        qxt_d().addCrumb(index);
    }
    qxt_d().view->setRootIndex(index);
}

void QxtCrumbView::back() {
    if(qxt_d().crumbs.count() <= 1) return;
    qxt_d().buttons.last()->deleteLater();
    qxt_d().buttons.removeLast();
    qxt_d().crumbs.removeLast();
    qxt_d().view->setRootIndex(qxt_d().crumbs.last());
}

void QxtCrumbView::setItemDelegate(QAbstractItemDelegate* delegate) {
    QAbstractItemView::setItemDelegate(delegate);
    //delete qxt_d().view->itemDelegate();
    //qxt_d().view->setItemDelegate(new QxtCrumbViewDelegate(itemDelegate(), this));
}

QAbstractItemView* QxtCrumbView::itemView() const {
    return qxt_d().view;
}

void QxtCrumbView::showEvent(QShowEvent* event) {
    QxtCrumbViewDelegate* viewDelegate = qobject_cast<QxtCrumbViewDelegate*>(qxt_d().view->itemDelegate());
    if(viewDelegate->delegate != itemDelegate()) {
        qxt_d().view->setItemDelegate(new QxtCrumbViewDelegate(itemDelegate(), this));
        delete viewDelegate;
        qxt_d().view->reset();
    }
    QAbstractItemView::showEvent(event);
}

void QxtCrumbView::paintEvent(QPaintEvent* event) {
    QxtCrumbViewDelegate* viewDelegate = qobject_cast<QxtCrumbViewDelegate*>(qxt_d().view->itemDelegate());
    if(viewDelegate->delegate != itemDelegate()) {
        qxt_d().view->setItemDelegate(new QxtCrumbViewDelegate(itemDelegate(), this));
        delete viewDelegate;
        qxt_d().view->reset();
    }
    QAbstractItemView::paintEvent(event);
}

QAbstractItemDelegate* QxtCrumbView::crumbDelegate() const {
    QAbstractItemDelegate* rv = qxt_d().crumbDelegate;
    if(!rv) return itemDelegate();
    return rv;
}

void QxtCrumbView::setCrumbDelegate(QAbstractItemDelegate* delegate) {
    qxt_d().crumbDelegate = delegate;
    update();
    foreach(QxtCrumbViewButton* button, qxt_d().buttons) {
        button->update();
    }
}

<|endoftext|>


<commit_before>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/preferences.h"

#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/cros/language_library.h"
#include "chrome/browser/chromeos/cros/synaptics_library.h"
#include "chrome/browser/pref_member.h"
#include "chrome/browser/pref_service.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
#include "unicode/timezone.h"

namespace chromeos {

// static
void Preferences::RegisterUserPrefs(PrefService* prefs) {
  prefs->RegisterStringPref(prefs::kTimeZone, L"US/Pacific");
  prefs->RegisterBooleanPref(prefs::kTapToClickEnabled, false);
  prefs->RegisterBooleanPref(prefs::kVertEdgeScrollEnabled, false);
  prefs->RegisterIntegerPref(prefs::kTouchpadSpeedFactor, 5);
  prefs->RegisterIntegerPref(prefs::kTouchpadSensitivity, 5);
  prefs->RegisterStringPref(prefs::kLanguageHotkeyNextEngineInMenu,
                            kHotkeyNextEngineInMenu);
  prefs->RegisterStringPref(prefs::kLanguageHotkeyPreviousEngine,
                            kHotkeyPreviousEngine);
  prefs->RegisterStringPref(prefs::kLanguagePreloadEngines,
                            UTF8ToWide(kFallbackInputMethodId));  // EN layout
  prefs->RegisterStringPref(prefs::kLanguageHangulKeyboard,
                            kHangulKeyboardNameIDPairs[0].keyboard_id);
  for (size_t i = 0; i < kNumPinyinBooleanPrefs; ++i) {
    prefs->RegisterBooleanPref(kPinyinBooleanPrefs[i].pref_name,
                               kPinyinBooleanPrefs[i].default_pref_value);
  }
  for (size_t i = 0; i < kNumPinyinIntegerPrefs; ++i) {
    prefs->RegisterIntegerPref(kPinyinIntegerPrefs[i].pref_name,
                               kPinyinIntegerPrefs[i].default_pref_value);
  }
  for (size_t i = 0; i < kNumMozcMultipleChoicePrefs; ++i) {
    prefs->RegisterStringPref(kMozcMultipleChoicePrefs[i].pref_name,
                              kMozcMultipleChoicePrefs[i].default_pref_value);
  }
}

void Preferences::Init(PrefService* prefs) {
  timezone_.Init(prefs::kTimeZone, prefs, this);
  tap_to_click_enabled_.Init(prefs::kTapToClickEnabled, prefs, this);
  vert_edge_scroll_enabled_.Init(prefs::kVertEdgeScrollEnabled, prefs, this);
  speed_factor_.Init(prefs::kTouchpadSpeedFactor, prefs, this);
  sensitivity_.Init(prefs::kTouchpadSensitivity, prefs, this);
  language_hotkey_next_engine_in_menu_.Init(
      prefs::kLanguageHotkeyNextEngineInMenu, prefs, this);
  language_hotkey_previous_engine_.Init(
      prefs::kLanguageHotkeyPreviousEngine, prefs, this);
  language_preload_engines_.Init(prefs::kLanguagePreloadEngines, prefs, this);
  language_hangul_keyboard_.Init(prefs::kLanguageHangulKeyboard, prefs, this);
  for (size_t i = 0; i < kNumPinyinBooleanPrefs; ++i) {
    language_pinyin_boolean_prefs_[i].Init(
        kPinyinBooleanPrefs[i].pref_name, prefs, this);
  }
  for (size_t i = 0; i < kNumPinyinIntegerPrefs; ++i) {
    language_pinyin_int_prefs_[i].Init(
        kPinyinIntegerPrefs[i].pref_name, prefs, this);
  }
  for (size_t i = 0; i < kNumMozcMultipleChoicePrefs; ++i) {
    language_mozc_multiple_choice_prefs_[i].Init(
        kMozcMultipleChoicePrefs[i].pref_name, prefs, this);
  }

  // Initialize touchpad settings to what's saved in user preferences.
  NotifyPrefChanged(NULL);
}

void Preferences::Observe(NotificationType type,
                          const NotificationSource& source,
                          const NotificationDetails& details) {
  if (type == NotificationType::PREF_CHANGED)
    NotifyPrefChanged(Details<std::wstring>(details).ptr());
}

void Preferences::NotifyPrefChanged(const std::wstring* pref_name) {
  if (!pref_name || *pref_name == prefs::kTimeZone)
    SetTimeZone(timezone_.GetValue());
  if (!pref_name || *pref_name == prefs::kTapToClickEnabled) {
    CrosLibrary::Get()->GetSynapticsLibrary()->SetBoolParameter(
        PARAM_BOOL_TAP_TO_CLICK,
        tap_to_click_enabled_.GetValue());
  }
  if (!pref_name || *pref_name == prefs::kVertEdgeScrollEnabled) {
    CrosLibrary::Get()->GetSynapticsLibrary()->SetBoolParameter(
        PARAM_BOOL_VERTICAL_EDGE_SCROLLING,
        vert_edge_scroll_enabled_.GetValue());
  }
  if (!pref_name || *pref_name == prefs::kTouchpadSpeedFactor) {
    CrosLibrary::Get()->GetSynapticsLibrary()->SetRangeParameter(
        PARAM_RANGE_SPEED_SENSITIVITY,
        speed_factor_.GetValue());
  }
  if (!pref_name || *pref_name == prefs::kTouchpadSensitivity) {
    CrosLibrary::Get()->GetSynapticsLibrary()->SetRangeParameter(
          PARAM_RANGE_TOUCH_SENSITIVITY,
          sensitivity_.GetValue());
  }
  if (!pref_name || *pref_name == prefs::kLanguageHotkeyNextEngineInMenu) {
    SetLanguageConfigStringListAsCSV(kHotKeySectionName,
                             kNextEngineInMenuConfigName,
                             language_hotkey_next_engine_in_menu_.GetValue());
  }
  if (!pref_name || *pref_name == prefs::kLanguageHotkeyPreviousEngine) {
    SetLanguageConfigStringListAsCSV(kHotKeySectionName,
                             kPreviousEngineConfigName,
                             language_hotkey_previous_engine_.GetValue());
  }
  if (!pref_name || *pref_name == prefs::kLanguagePreloadEngines) {
    SetLanguageConfigStringListAsCSV(kGeneralSectionName,
                                     kPreloadEnginesConfigName,
                                     language_preload_engines_.GetValue());
  }
  if (!pref_name || *pref_name == prefs::kLanguageHangulKeyboard) {
    SetLanguageConfigString(kHangulSectionName, kHangulKeyboardConfigName,
                            language_hangul_keyboard_.GetValue());
  }
  for (size_t i = 0; i < kNumPinyinBooleanPrefs; ++i) {
    if (!pref_name || *pref_name == kPinyinBooleanPrefs[i].pref_name) {
      SetLanguageConfigBoolean(kPinyinSectionName,
                               kPinyinBooleanPrefs[i].ibus_config_name,
                               language_pinyin_boolean_prefs_[i].GetValue());
    }
  }
  for (size_t i = 0; i < kNumPinyinIntegerPrefs; ++i) {
    if (!pref_name || *pref_name == kPinyinIntegerPrefs[i].pref_name) {
      SetLanguageConfigInteger(kPinyinSectionName,
                               kPinyinIntegerPrefs[i].ibus_config_name,
                               language_pinyin_int_prefs_[i].GetValue());
    }
  }
  for (size_t i = 0; i < kNumMozcMultipleChoicePrefs; ++i) {
    if (!pref_name || *pref_name == kMozcMultipleChoicePrefs[i].pref_name) {
      SetLanguageConfigString(
          kMozcSectionName,
          kMozcMultipleChoicePrefs[i].ibus_config_name,
          language_mozc_multiple_choice_prefs_[i].GetValue());
    }
  }
}

void Preferences::SetTimeZone(const std::wstring& id) {
  icu::TimeZone* timezone = icu::TimeZone::createTimeZone(
      icu::UnicodeString::fromUTF8(WideToASCII(id)));
  icu::TimeZone::adoptDefault(timezone);
}

void Preferences::SetLanguageConfigBoolean(const char* section,
                                           const char* name,
                                           bool value) {
  ImeConfigValue config;
  config.type = ImeConfigValue::kValueTypeBool;
  config.bool_value = value;
  CrosLibrary::Get()->GetLanguageLibrary()->SetImeConfig(section, name, config);
}

void Preferences::SetLanguageConfigInteger(const char* section,
                                           const char* name,
                                           int value) {
  ImeConfigValue config;
  config.type = ImeConfigValue::kValueTypeInt;
  config.int_value = value;
  CrosLibrary::Get()->GetLanguageLibrary()->SetImeConfig(section, name, config);
}

void Preferences::SetLanguageConfigString(const char* section,
                                          const char* name,
                                          const std::wstring& value) {
  ImeConfigValue config;
  config.type = ImeConfigValue::kValueTypeString;
  config.string_value = WideToUTF8(value);
  CrosLibrary::Get()->GetLanguageLibrary()->SetImeConfig(section, name, config);
}

void Preferences::SetLanguageConfigStringList(
    const char* section,
    const char* name,
    const std::vector<std::wstring>& values) {
  ImeConfigValue config;
  config.type = ImeConfigValue::kValueTypeStringList;
  for (size_t i = 0; i < values.size(); ++i) {
    config.string_list_value.push_back(WideToUTF8(values[i]));
  }
  CrosLibrary::Get()->GetLanguageLibrary()->SetImeConfig(section, name, config);
}

void Preferences::SetLanguageConfigStringListAsCSV(const char* section,
                                                   const char* name,
                                                   const std::wstring& value) {
  LOG(INFO) << "Setting " << name << " to '" << value << "'";

  std::vector<std::wstring> split_values;
  if (!value.empty()) {
    SplitString(value, L',', &split_values);
  }
  // We should call the cros API even when |value| is empty, to disable default
  // config.
  SetLanguageConfigStringList(section, name, split_values);
}

}  // namespace chromeos
<commit_msg>Increase default mouse speed sensitivity BUG=chromium-os:3601 TEST=Log in as new user, confirm mouse is faster (can check with "synclient -l" on the command line...MaxSpeed should be "1")<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/preferences.h"

#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/cros/language_library.h"
#include "chrome/browser/chromeos/cros/synaptics_library.h"
#include "chrome/browser/pref_member.h"
#include "chrome/browser/pref_service.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
#include "unicode/timezone.h"

namespace chromeos {

// static
void Preferences::RegisterUserPrefs(PrefService* prefs) {
  prefs->RegisterStringPref(prefs::kTimeZone, L"US/Pacific");
  prefs->RegisterBooleanPref(prefs::kTapToClickEnabled, false);
  prefs->RegisterBooleanPref(prefs::kVertEdgeScrollEnabled, false);
  prefs->RegisterIntegerPref(prefs::kTouchpadSpeedFactor, 9);
  prefs->RegisterIntegerPref(prefs::kTouchpadSensitivity, 5);
  prefs->RegisterStringPref(prefs::kLanguageHotkeyNextEngineInMenu,
                            kHotkeyNextEngineInMenu);
  prefs->RegisterStringPref(prefs::kLanguageHotkeyPreviousEngine,
                            kHotkeyPreviousEngine);
  prefs->RegisterStringPref(prefs::kLanguagePreloadEngines,
                            UTF8ToWide(kFallbackInputMethodId));  // EN layout
  prefs->RegisterStringPref(prefs::kLanguageHangulKeyboard,
                            kHangulKeyboardNameIDPairs[0].keyboard_id);
  for (size_t i = 0; i < kNumPinyinBooleanPrefs; ++i) {
    prefs->RegisterBooleanPref(kPinyinBooleanPrefs[i].pref_name,
                               kPinyinBooleanPrefs[i].default_pref_value);
  }
  for (size_t i = 0; i < kNumPinyinIntegerPrefs; ++i) {
    prefs->RegisterIntegerPref(kPinyinIntegerPrefs[i].pref_name,
                               kPinyinIntegerPrefs[i].default_pref_value);
  }
  for (size_t i = 0; i < kNumMozcMultipleChoicePrefs; ++i) {
    prefs->RegisterStringPref(kMozcMultipleChoicePrefs[i].pref_name,
                              kMozcMultipleChoicePrefs[i].default_pref_value);
  }
}

void Preferences::Init(PrefService* prefs) {
  timezone_.Init(prefs::kTimeZone, prefs, this);
  tap_to_click_enabled_.Init(prefs::kTapToClickEnabled, prefs, this);
  vert_edge_scroll_enabled_.Init(prefs::kVertEdgeScrollEnabled, prefs, this);
  speed_factor_.Init(prefs::kTouchpadSpeedFactor, prefs, this);
  sensitivity_.Init(prefs::kTouchpadSensitivity, prefs, this);
  language_hotkey_next_engine_in_menu_.Init(
      prefs::kLanguageHotkeyNextEngineInMenu, prefs, this);
  language_hotkey_previous_engine_.Init(
      prefs::kLanguageHotkeyPreviousEngine, prefs, this);
  language_preload_engines_.Init(prefs::kLanguagePreloadEngines, prefs, this);
  language_hangul_keyboard_.Init(prefs::kLanguageHangulKeyboard, prefs, this);
  for (size_t i = 0; i < kNumPinyinBooleanPrefs; ++i) {
    language_pinyin_boolean_prefs_[i].Init(
        kPinyinBooleanPrefs[i].pref_name, prefs, this);
  }
  for (size_t i = 0; i < kNumPinyinIntegerPrefs; ++i) {
    language_pinyin_int_prefs_[i].Init(
        kPinyinIntegerPrefs[i].pref_name, prefs, this);
  }
  for (size_t i = 0; i < kNumMozcMultipleChoicePrefs; ++i) {
    language_mozc_multiple_choice_prefs_[i].Init(
        kMozcMultipleChoicePrefs[i].pref_name, prefs, this);
  }

  // Initialize touchpad settings to what's saved in user preferences.
  NotifyPrefChanged(NULL);
}

void Preferences::Observe(NotificationType type,
                          const NotificationSource& source,
                          const NotificationDetails& details) {
  if (type == NotificationType::PREF_CHANGED)
    NotifyPrefChanged(Details<std::wstring>(details).ptr());
}

void Preferences::NotifyPrefChanged(const std::wstring* pref_name) {
  if (!pref_name || *pref_name == prefs::kTimeZone)
    SetTimeZone(timezone_.GetValue());
  if (!pref_name || *pref_name == prefs::kTapToClickEnabled) {
    CrosLibrary::Get()->GetSynapticsLibrary()->SetBoolParameter(
        PARAM_BOOL_TAP_TO_CLICK,
        tap_to_click_enabled_.GetValue());
  }
  if (!pref_name || *pref_name == prefs::kVertEdgeScrollEnabled) {
    CrosLibrary::Get()->GetSynapticsLibrary()->SetBoolParameter(
        PARAM_BOOL_VERTICAL_EDGE_SCROLLING,
        vert_edge_scroll_enabled_.GetValue());
  }
  if (!pref_name || *pref_name == prefs::kTouchpadSpeedFactor) {
    CrosLibrary::Get()->GetSynapticsLibrary()->SetRangeParameter(
        PARAM_RANGE_SPEED_SENSITIVITY,
        speed_factor_.GetValue());
  }
  if (!pref_name || *pref_name == prefs::kTouchpadSensitivity) {
    CrosLibrary::Get()->GetSynapticsLibrary()->SetRangeParameter(
          PARAM_RANGE_TOUCH_SENSITIVITY,
          sensitivity_.GetValue());
  }
  if (!pref_name || *pref_name == prefs::kLanguageHotkeyNextEngineInMenu) {
    SetLanguageConfigStringListAsCSV(kHotKeySectionName,
                             kNextEngineInMenuConfigName,
                             language_hotkey_next_engine_in_menu_.GetValue());
  }
  if (!pref_name || *pref_name == prefs::kLanguageHotkeyPreviousEngine) {
    SetLanguageConfigStringListAsCSV(kHotKeySectionName,
                             kPreviousEngineConfigName,
                             language_hotkey_previous_engine_.GetValue());
  }
  if (!pref_name || *pref_name == prefs::kLanguagePreloadEngines) {
    SetLanguageConfigStringListAsCSV(kGeneralSectionName,
                                     kPreloadEnginesConfigName,
                                     language_preload_engines_.GetValue());
  }
  if (!pref_name || *pref_name == prefs::kLanguageHangulKeyboard) {
    SetLanguageConfigString(kHangulSectionName, kHangulKeyboardConfigName,
                            language_hangul_keyboard_.GetValue());
  }
  for (size_t i = 0; i < kNumPinyinBooleanPrefs; ++i) {
    if (!pref_name || *pref_name == kPinyinBooleanPrefs[i].pref_name) {
      SetLanguageConfigBoolean(kPinyinSectionName,
                               kPinyinBooleanPrefs[i].ibus_config_name,
                               language_pinyin_boolean_prefs_[i].GetValue());
    }
  }
  for (size_t i = 0; i < kNumPinyinIntegerPrefs; ++i) {
    if (!pref_name || *pref_name == kPinyinIntegerPrefs[i].pref_name) {
      SetLanguageConfigInteger(kPinyinSectionName,
                               kPinyinIntegerPrefs[i].ibus_config_name,
                               language_pinyin_int_prefs_[i].GetValue());
    }
  }
  for (size_t i = 0; i < kNumMozcMultipleChoicePrefs; ++i) {
    if (!pref_name || *pref_name == kMozcMultipleChoicePrefs[i].pref_name) {
      SetLanguageConfigString(
          kMozcSectionName,
          kMozcMultipleChoicePrefs[i].ibus_config_name,
          language_mozc_multiple_choice_prefs_[i].GetValue());
    }
  }
}

void Preferences::SetTimeZone(const std::wstring& id) {
  icu::TimeZone* timezone = icu::TimeZone::createTimeZone(
      icu::UnicodeString::fromUTF8(WideToASCII(id)));
  icu::TimeZone::adoptDefault(timezone);
}

void Preferences::SetLanguageConfigBoolean(const char* section,
                                           const char* name,
                                           bool value) {
  ImeConfigValue config;
  config.type = ImeConfigValue::kValueTypeBool;
  config.bool_value = value;
  CrosLibrary::Get()->GetLanguageLibrary()->SetImeConfig(section, name, config);
}

void Preferences::SetLanguageConfigInteger(const char* section,
                                           const char* name,
                                           int value) {
  ImeConfigValue config;
  config.type = ImeConfigValue::kValueTypeInt;
  config.int_value = value;
  CrosLibrary::Get()->GetLanguageLibrary()->SetImeConfig(section, name, config);
}

void Preferences::SetLanguageConfigString(const char* section,
                                          const char* name,
                                          const std::wstring& value) {
  ImeConfigValue config;
  config.type = ImeConfigValue::kValueTypeString;
  config.string_value = WideToUTF8(value);
  CrosLibrary::Get()->GetLanguageLibrary()->SetImeConfig(section, name, config);
}

void Preferences::SetLanguageConfigStringList(
    const char* section,
    const char* name,
    const std::vector<std::wstring>& values) {
  ImeConfigValue config;
  config.type = ImeConfigValue::kValueTypeStringList;
  for (size_t i = 0; i < values.size(); ++i) {
    config.string_list_value.push_back(WideToUTF8(values[i]));
  }
  CrosLibrary::Get()->GetLanguageLibrary()->SetImeConfig(section, name, config);
}

void Preferences::SetLanguageConfigStringListAsCSV(const char* section,
                                                   const char* name,
                                                   const std::wstring& value) {
  LOG(INFO) << "Setting " << name << " to '" << value << "'";

  std::vector<std::wstring> split_values;
  if (!value.empty()) {
    SplitString(value, L',', &split_values);
  }
  // We should call the cros API even when |value| is empty, to disable default
  // config.
  SetLanguageConfigStringList(section, name, split_values);
}

}  // namespace chromeos
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2007-2012, Timothy Stack
 *
 * 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 Timothy Stack 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 REGENTS 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 REGENTS 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.
 *
 * @file logfile.cc
 */

#include "config.h"

#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <errno.h>
#include <fcntl.h>
#include <assert.h>
#include <unistd.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>

#include <time.h>

#include "logfile.hh"

using namespace std;

logfile::logfile(string filename, auto_fd fd)
throw (error)
    : lf_filename(filename),
      lf_index_time(0),
      lf_index_size(0)
{
    int reserve_size = 100;

    assert(filename.size() > 0);

    memset(&this->lf_stat, 0, sizeof(this->lf_stat));
    if (fd == -1) {
        char resolved_path[PATH_MAX];

        errno = 0;
        if (realpath(filename.c_str(), resolved_path) == NULL) {
            throw error(resolved_path, errno);
        }
        filename = resolved_path;

        if (stat(filename.c_str(), &this->lf_stat) == -1) {
            throw error(filename, errno);
        }
        reserve_size = this->lf_stat.st_size / 100;

        if (!S_ISREG(this->lf_stat.st_mode)) {
            throw error(filename, EINVAL);
        }

        if ((fd = open(filename.c_str(), O_RDONLY)) == -1) {
            throw error(filename, errno);
        }

        this->lf_valid_filename = true;
    }
    else {
        fstat(fd, &this->lf_stat);
        this->lf_valid_filename = false;
    }

    this->lf_line_buffer.set_fd(fd);
    this->lf_index.reserve(reserve_size);

    assert(this->invariant());
}

logfile::~logfile()
{ }

bool logfile::exists(void) const
{
    struct stat st;

    if (!this->lf_valid_filename) {
        return true;
    }

    if (::stat(this->lf_filename.c_str(), &st) == -1) {
        return false;
    }

    return this->lf_stat.st_dev == st.st_dev &&
           this->lf_stat.st_ino == st.st_ino;
}

void logfile::process_prefix(off_t offset, char *prefix, int len)
{
    bool found = false;

    if (this->lf_format.get() != NULL) {
        /* We've locked onto a format, just use that scanner. */
        found = this->lf_format->scan(this->lf_index, offset, prefix, len);
    }
    else {
        vector<log_format *> &root_formats =
            log_format::get_root_formats();
        vector<log_format *>::iterator iter;

        /*
         * Try each scanner until we get a match.  Fortunately, all the formats
         * are sufficiently different that there are no ambiguities...
         */
        for (iter = root_formats.begin();
             iter != root_formats.end() && !found;
             ++iter) {
            (*iter)->lf_base_time = this->lf_line_buffer.get_file_time();
            if ((*iter)->lf_base_time == 0) {
                (*iter)->lf_base_time = this->lf_stat.st_mtimespec.tv_sec;
            }
            (*iter)->clear();
            if ((*iter)->scan(this->lf_index, offset, prefix, len)) {
#if 0
                assert(this->lf_index.size() == 1 ||
                       (this->lf_index[this->lf_index.size() - 2] <
                        this->lf_index[this->lf_index.size() - 1]));
#endif

                this->lf_format =
                    auto_ptr<log_format>((*iter)->specialized());
                found = true;

                /*
                 * We'll go ahead and assume that any previous lines were
                 * written out at the same time as the last one, so we need to
                 * go back and update everything.
                 */
                logline &last_line = this->lf_index[this->lf_index.size() - 1];

                for (size_t lpc = 0; lpc < this->lf_index.size() - 1; lpc++) {
                    this->lf_index[lpc].set_time(last_line.get_time());
                    this->lf_index[lpc].set_millis(last_line.get_millis());
                }
            }
        }
    }

    if (found) {
        if (this->lf_index.size() >= 2) {
            logline &second_to_last = this->lf_index[this->lf_index.size() - 2];
            logline &latest = this->lf_index.back();

            if (latest < second_to_last) {
                latest.set_time(second_to_last.get_time());
                latest.set_millis(second_to_last.get_millis());
            }
        }
    }

    /* If the scanner didn't match, than we need to add it. */
    if (!found) {
        logline::level_t last_level  = logline::LEVEL_UNKNOWN;
        time_t           last_time   = this->lf_index_time;
        short            last_millis = 0;

        if (!this->lf_index.empty()) {
            logline &ll = this->lf_index.back();

            /*
             * Assume this line is part of the previous one(s) and copy the
             * metadata over.
             */
            ll.set_multiline();
            last_time   = ll.get_time();
            last_millis = ll.get_millis();
            if (this->lf_format.get() != NULL) {
                last_level = (logline::level_t)
                             (ll.get_level() | logline::LEVEL_CONTINUED);
            }
        }
        this->lf_index.push_back(logline(offset,
                                         last_time,
                                         last_millis,
                                         last_level));
    }
}

bool logfile::rebuild_index(logfile_observer *lo)
throw (line_buffer::error)
{
    bool        retval = false;
    struct stat st;

    if (fstat(this->lf_line_buffer.get_fd(), &st) == -1) {
        throw error(this->lf_filename, errno);
    }

    /* Check for new data based on the file size. */
    if (this->lf_index_size < st.st_size) {
        off_t  last_off, off;
        char * line;
        size_t len;

        if (!this->lf_index.empty()) {
            off = this->lf_index.back().get_offset();

            /*
             * Drop the last line we read since it might have been a partial
             * read.
             */
            this->lf_index.pop_back();
        }
        else {
            off = 0;
        }
        last_off = off;
        while ((line = this->lf_line_buffer.read_line(off, len)) != NULL) {
            line[len] = '\0';
            this->process_prefix(last_off, line, len);
            last_off = off;

            if (lo != NULL) {
                lo->logfile_indexing(*this,
                                     this->lf_line_buffer.get_read_offset(off),
                                     st.st_size);
            }
        }

        /*
         * The file can still grow between the above fstat and when we're
         * doing the scanning, so use the line buffer's notion of the file
         * size.
         */
        this->lf_index_size = this->lf_line_buffer.get_file_size();

        this->lf_line_buffer.invalidate();

        retval = true;
    }

    this->lf_index_time = this->lf_line_buffer.get_file_time();
    if (!this->lf_index_time)
        this->lf_index_time = st.st_mtime;

    return retval;
}

logfile_filter::type_t logfile::check_filter(iterator ll,
                                             uint8_t generation,
                                             const filter_stack_t &filters)
{
    logfile_filter::type_t retval;
    uint8_t this_generation = ll->get_filter_generation();

    if (this_generation == generation) {
        return ll->get_filter_state();
    }
    else {
        retval = logfile_filter::MAYBE;
    }

    if (retval == logfile_filter::MAYBE) {
        string line_value;

        for (size_t lpc = 0; lpc < filters.size(); lpc++) {
            logfile_filter *filter = filters[lpc];
            bool matched;

            if (!filter->is_enabled())
                continue;

            if (line_value.empty())
                this->read_line(ll, line_value);
            matched = filter->matches(line_value);

            switch (filter->get_type()) {
            case logfile_filter::INCLUDE:
                if (matched) {
                    retval = logfile_filter::INCLUDE;
                }
                else if (retval == logfile_filter::MAYBE) {
                    retval = logfile_filter::EXCLUDE;
                }
                break;

            case logfile_filter::EXCLUDE:
                if (matched) {
                    retval = logfile_filter::EXCLUDE;
                }
                break;

            default:
                assert(0);
                break;
            }
        }
    }

    if (retval == logfile_filter::MAYBE) {
        retval = logfile_filter::INCLUDE;
    }

    ll->set_filter_state(generation, retval);

    return retval;
}

void logfile::read_line(logfile::iterator ll, string &line_out)
{
    try {
        off_t       off = ll->get_offset();
        const char *line;
        size_t      len;

        line_out.clear();
        if ((line = this->lf_line_buffer.read_line(off, len)) != NULL) {
            line_out.append(line, len);
        }
        else {
            /* XXX */
        }
    }
    catch (line_buffer::error & e) {
        /* ... */
    }
}
<commit_msg>[build] fix for linux<commit_after>/**
 * Copyright (c) 2007-2012, Timothy Stack
 *
 * 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 Timothy Stack 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 REGENTS 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 REGENTS 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.
 *
 * @file logfile.cc
 */

#include "config.h"

#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <errno.h>
#include <fcntl.h>
#include <assert.h>
#include <unistd.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>

#include <time.h>

#include "logfile.hh"

using namespace std;

logfile::logfile(string filename, auto_fd fd)
throw (error)
    : lf_filename(filename),
      lf_index_time(0),
      lf_index_size(0)
{
    int reserve_size = 100;

    assert(filename.size() > 0);

    memset(&this->lf_stat, 0, sizeof(this->lf_stat));
    if (fd == -1) {
        char resolved_path[PATH_MAX];

        errno = 0;
        if (realpath(filename.c_str(), resolved_path) == NULL) {
            throw error(resolved_path, errno);
        }
        filename = resolved_path;

        if (stat(filename.c_str(), &this->lf_stat) == -1) {
            throw error(filename, errno);
        }
        reserve_size = this->lf_stat.st_size / 100;

        if (!S_ISREG(this->lf_stat.st_mode)) {
            throw error(filename, EINVAL);
        }

        if ((fd = open(filename.c_str(), O_RDONLY)) == -1) {
            throw error(filename, errno);
        }

        this->lf_valid_filename = true;
    }
    else {
        fstat(fd, &this->lf_stat);
        this->lf_valid_filename = false;
    }

    this->lf_line_buffer.set_fd(fd);
    this->lf_index.reserve(reserve_size);

    assert(this->invariant());
}

logfile::~logfile()
{ }

bool logfile::exists(void) const
{
    struct stat st;

    if (!this->lf_valid_filename) {
        return true;
    }

    if (::stat(this->lf_filename.c_str(), &st) == -1) {
        return false;
    }

    return this->lf_stat.st_dev == st.st_dev &&
           this->lf_stat.st_ino == st.st_ino;
}

void logfile::process_prefix(off_t offset, char *prefix, int len)
{
    bool found = false;

    if (this->lf_format.get() != NULL) {
        /* We've locked onto a format, just use that scanner. */
        found = this->lf_format->scan(this->lf_index, offset, prefix, len);
    }
    else {
        vector<log_format *> &root_formats =
            log_format::get_root_formats();
        vector<log_format *>::iterator iter;

        /*
         * Try each scanner until we get a match.  Fortunately, all the formats
         * are sufficiently different that there are no ambiguities...
         */
        for (iter = root_formats.begin();
             iter != root_formats.end() && !found;
             ++iter) {
            (*iter)->lf_base_time = this->lf_line_buffer.get_file_time();
            if ((*iter)->lf_base_time == 0) {
                (*iter)->lf_base_time = this->lf_stat.st_mtime;
            }
            (*iter)->clear();
            if ((*iter)->scan(this->lf_index, offset, prefix, len)) {
#if 0
                assert(this->lf_index.size() == 1 ||
                       (this->lf_index[this->lf_index.size() - 2] <
                        this->lf_index[this->lf_index.size() - 1]));
#endif

                this->lf_format =
                    auto_ptr<log_format>((*iter)->specialized());
                found = true;

                /*
                 * We'll go ahead and assume that any previous lines were
                 * written out at the same time as the last one, so we need to
                 * go back and update everything.
                 */
                logline &last_line = this->lf_index[this->lf_index.size() - 1];

                for (size_t lpc = 0; lpc < this->lf_index.size() - 1; lpc++) {
                    this->lf_index[lpc].set_time(last_line.get_time());
                    this->lf_index[lpc].set_millis(last_line.get_millis());
                }
            }
        }
    }

    if (found) {
        if (this->lf_index.size() >= 2) {
            logline &second_to_last = this->lf_index[this->lf_index.size() - 2];
            logline &latest = this->lf_index.back();

            if (latest < second_to_last) {
                latest.set_time(second_to_last.get_time());
                latest.set_millis(second_to_last.get_millis());
            }
        }
    }

    /* If the scanner didn't match, than we need to add it. */
    if (!found) {
        logline::level_t last_level  = logline::LEVEL_UNKNOWN;
        time_t           last_time   = this->lf_index_time;
        short            last_millis = 0;

        if (!this->lf_index.empty()) {
            logline &ll = this->lf_index.back();

            /*
             * Assume this line is part of the previous one(s) and copy the
             * metadata over.
             */
            ll.set_multiline();
            last_time   = ll.get_time();
            last_millis = ll.get_millis();
            if (this->lf_format.get() != NULL) {
                last_level = (logline::level_t)
                             (ll.get_level() | logline::LEVEL_CONTINUED);
            }
        }
        this->lf_index.push_back(logline(offset,
                                         last_time,
                                         last_millis,
                                         last_level));
    }
}

bool logfile::rebuild_index(logfile_observer *lo)
throw (line_buffer::error)
{
    bool        retval = false;
    struct stat st;

    if (fstat(this->lf_line_buffer.get_fd(), &st) == -1) {
        throw error(this->lf_filename, errno);
    }

    /* Check for new data based on the file size. */
    if (this->lf_index_size < st.st_size) {
        off_t  last_off, off;
        char * line;
        size_t len;

        if (!this->lf_index.empty()) {
            off = this->lf_index.back().get_offset();

            /*
             * Drop the last line we read since it might have been a partial
             * read.
             */
            this->lf_index.pop_back();
        }
        else {
            off = 0;
        }
        last_off = off;
        while ((line = this->lf_line_buffer.read_line(off, len)) != NULL) {
            line[len] = '\0';
            this->process_prefix(last_off, line, len);
            last_off = off;

            if (lo != NULL) {
                lo->logfile_indexing(*this,
                                     this->lf_line_buffer.get_read_offset(off),
                                     st.st_size);
            }
        }

        /*
         * The file can still grow between the above fstat and when we're
         * doing the scanning, so use the line buffer's notion of the file
         * size.
         */
        this->lf_index_size = this->lf_line_buffer.get_file_size();

        this->lf_line_buffer.invalidate();

        retval = true;
    }

    this->lf_index_time = this->lf_line_buffer.get_file_time();
    if (!this->lf_index_time)
        this->lf_index_time = st.st_mtime;

    return retval;
}

logfile_filter::type_t logfile::check_filter(iterator ll,
                                             uint8_t generation,
                                             const filter_stack_t &filters)
{
    logfile_filter::type_t retval;
    uint8_t this_generation = ll->get_filter_generation();

    if (this_generation == generation) {
        return ll->get_filter_state();
    }
    else {
        retval = logfile_filter::MAYBE;
    }

    if (retval == logfile_filter::MAYBE) {
        string line_value;

        for (size_t lpc = 0; lpc < filters.size(); lpc++) {
            logfile_filter *filter = filters[lpc];
            bool matched;

            if (!filter->is_enabled())
                continue;

            if (line_value.empty())
                this->read_line(ll, line_value);
            matched = filter->matches(line_value);

            switch (filter->get_type()) {
            case logfile_filter::INCLUDE:
                if (matched) {
                    retval = logfile_filter::INCLUDE;
                }
                else if (retval == logfile_filter::MAYBE) {
                    retval = logfile_filter::EXCLUDE;
                }
                break;

            case logfile_filter::EXCLUDE:
                if (matched) {
                    retval = logfile_filter::EXCLUDE;
                }
                break;

            default:
                assert(0);
                break;
            }
        }
    }

    if (retval == logfile_filter::MAYBE) {
        retval = logfile_filter::INCLUDE;
    }

    ll->set_filter_state(generation, retval);

    return retval;
}

void logfile::read_line(logfile::iterator ll, string &line_out)
{
    try {
        off_t       off = ll->get_offset();
        const char *line;
        size_t      len;

        line_out.clear();
        if ((line = this->lf_line_buffer.read_line(off, len)) != NULL) {
            line_out.append(line, len);
        }
        else {
            /* XXX */
        }
    }
    catch (line_buffer::error & e) {
        /* ... */
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2008, Google 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 Google 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 "config.h"

#if ENABLE(WORKERS)

#include "WorkerScriptController.h"

#include "ScriptSourceCode.h"
#include "ScriptValue.h"
#include "DOMTimer.h"
#include "WorkerContext.h"
#include "WorkerContextExecutionProxy.h"
#include "WorkerMessagingProxy.h"
#include "WorkerThread.h"

namespace WebCore {

WorkerScriptController::WorkerScriptController(WorkerContext* workerContext)
    : m_workerContext(workerContext)
    , m_proxy(new WorkerContextExecutionProxy(workerContext))
    , m_executionForbidden(false)
{
}

WorkerScriptController::~WorkerScriptController()
{
}

ScriptValue WorkerScriptController::evaluate(const ScriptSourceCode& sourceCode)
{
    {
        MutexLocker lock(m_sharedDataMutex);
        if (m_executionForbidden)
            return ScriptValue();
    }

    v8::Local<v8::Value> result =
        m_proxy->Evaluate(sourceCode.source(),
                          sourceCode.url().string(),
                          sourceCode.startLine() - 1);

    m_workerContext->thread()->messagingProxy()->
        reportPendingActivity(m_workerContext->hasPendingActivity());

    return ScriptValue();
}

void WorkerScriptController::forbidExecution()
{
    // This function is called from another thread.
    MutexLocker lock(m_sharedDataMutex);
    m_executionForbidden = true;
}

} // namespace WebCore

#endif // ENABLE(WORKERS)
<commit_msg>Fix build break when ENABLE_WORKERS is defined.<commit_after>// Copyright (c) 2008, Google 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 Google 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 "config.h"

#if ENABLE(WORKERS)

#include "WorkerScriptController.h"

#include "ScriptSourceCode.h"
#include "ScriptValue.h"
#include "DOMTimer.h"
#include "WorkerContext.h"
#include "WorkerContextExecutionProxy.h"
#include "WorkerObjectProxy.h"
#include "WorkerThread.h"

namespace WebCore {

WorkerScriptController::WorkerScriptController(WorkerContext* workerContext)
    : m_workerContext(workerContext)
    , m_proxy(new WorkerContextExecutionProxy(workerContext))
    , m_executionForbidden(false)
{
}

WorkerScriptController::~WorkerScriptController()
{
}

ScriptValue WorkerScriptController::evaluate(const ScriptSourceCode& sourceCode)
{
    {
        MutexLocker lock(m_sharedDataMutex);
        if (m_executionForbidden)
            return ScriptValue();
    }

    v8::Local<v8::Value> result =
        m_proxy->Evaluate(sourceCode.source(),
                          sourceCode.url().string(),
                          sourceCode.startLine() - 1);

    m_workerContext->thread()->workerObjectProxy()->
        reportPendingActivity(m_workerContext->hasPendingActivity());

    return ScriptValue();
}

void WorkerScriptController::forbidExecution()
{
    // This function is called from another thread.
    MutexLocker lock(m_sharedDataMutex);
    m_executionForbidden = true;
}

} // namespace WebCore

#endif // ENABLE(WORKERS)
<|endoftext|>


<commit_before>/*
 * SchemeShell.c
 *
 * Simple scheme shell
 * Copyright (c) 2008 Linas Vepstas <linas@linas.org>
 */

#ifdef HAVE_GUILE

#include "SchemeShell.h"

#include <libguile.h>
#include <libguile/backtrace.h>
#include <libguile/lang.h>

#include "platform.h"
#include "SchemeSmob.h"

using namespace opencog;

bool SchemeShell::is_inited = false;

SchemeShell::SchemeShell(void)
{
	if (!is_inited)
	{
		is_inited = true;
		scm_init_guile();
		scm_init_debug();
		scm_init_backtrace();
		scm_init_strports(); // is this really needed ?
	}

	funcs = new SchemeSmob();
	pending_input = false;
	show_output = true;
	input_line = "";
	normal_prompt = "guile> ";
	pending_prompt = "... ";

	outport = scm_open_output_string();
	scm_set_current_output_port(outport);
}

void SchemeShell::hush_output(bool hush)
{
	show_output = !hush;
}

/* ============================================================== */

std::string SchemeShell::prt(SCM node)
{
	if (scm_is_pair(node))
	{
		std::string str = "(";
      SCM node_list = node;
		const char * sp = "";
      do
      {
			str += sp;
			sp = " ";
         node = SCM_CAR (node_list);
         str += prt (node);
         node_list = SCM_CDR (node_list);
      }
      while (scm_is_pair(node_list));

		// Print the rest -- the CDR part
		if (!scm_is_null(node_list))
		{
			str += " . ";
			str += prt (node_list);
		}
		str += ")";
		return str;
   }
	else if (scm_is_true(scm_symbol_p(node)))
	{
		node = scm_symbol_to_string(node);
		char * str = scm_to_locale_string(node);
		// std::string rv = "'";  // print the symbol escape
		std::string rv = "";      // err .. don't print it
		rv += str;
		free(str);
		return rv;
	}
	else if (scm_is_true(scm_string_p(node)))
	{
		char * str = scm_to_locale_string(node);
		std::string rv = "\"";
		rv += str;
		rv += "\"";
		free(str);
		return rv;
	}

	else if (SCM_SMOB_PREDICATE(SchemeSmob::cog_handle_tag, node))
	{
		return SchemeSmob::handle_to_string(node);
	}

	else if (SCM_SMOB_PREDICATE(SchemeSmob::cog_misc_tag, node))
	{
		return SchemeSmob::misc_to_string(node);
	}

	else if (scm_is_number(node))
	{
		#define NUMBUFSZ 60
		char buff[NUMBUFSZ];
		if (scm_is_signed_integer(node, INT_MIN, INT_MAX))
		{
			snprintf (buff, NUMBUFSZ, "%ld", (long) scm_to_long(node));
		}
		else if (scm_is_unsigned_integer(node, 0, UINT_MAX))
		{
			snprintf (buff, NUMBUFSZ, "%lu", (unsigned long) scm_to_ulong(node));
		}
		else if (scm_is_real(node))
		{
			snprintf (buff, NUMBUFSZ, "%g", scm_to_double(node));
		}
		else if (scm_is_complex(node))
		{
			snprintf (buff, NUMBUFSZ, "%g +i %g",
				scm_c_real_part(node),
				scm_c_imag_part(node));
		}
		else if (scm_is_rational(node))
		{
			std::string rv;
			rv = prt(scm_numerator(node));
			rv += "/";
			rv += prt(scm_denominator(node));
			return rv;
		}
		return buff;
	}
	else if (scm_is_true(scm_char_p(node)))
	{
		std::string rv;
		rv = (char) scm_to_char(node);
		return rv;
	}
	else if (scm_is_true(scm_boolean_p(node)))
	{
		if (scm_to_bool(node)) return "#t";
		return "#f";
	}
	else if (SCM_NULL_OR_NIL_P(node))
	{
		// scm_is_null(x) is true when x is SCM_EOL
		// SCM_NILP(x) is true when x is SCM_ELISP_NIL
		return "()";
	}
	else if (scm_is_eq(node, SCM_UNDEFINED))
	{
		return "undefined";
	}
	else if (scm_is_eq(node, SCM_EOF_VAL))
	{
		return "eof";
	}
	else if (scm_is_eq(node, SCM_UNSPECIFIED))
	{
		return "";
	}
	else if (scm_is_true(scm_dynamic_object_p(node)))
	{
		return "#<dynamic object (XXX add name here)>";
	}
	else if (scm_is_true(scm_port_p(node)))
	{
		return "#<port (XXX add name here)>";
	}
	else if (scm_is_true(scm_procedure_p(node)))
	{
		return "#<port (XXX add name here)>";
	}
	else if (scm_subr_p(node))
	{
		return "#<subr (XXX add name here)>";
	}
	else if (scm_is_true(scm_operator_p(node)))
	{
		return "#<operator (XXX add name here)>";
	}
	else if (scm_is_true(scm_entity_p(node)))
	{
		return "#<entity (XXX add name here)>";
	}
	else if (scm_is_true(scm_variable_p(node)))
	{
		return "#<variable (XXX add name here)>";
	}
	else
	{
		fprintf (stderr, "Error: unhandled type for guile printing: %p\n",
			node);
		return "#opencog-guile-error: unknown type";
	}

	return "";
}

/* ============================================================== */

SCM SchemeShell::catch_handler_wrapper (void *data, SCM tag, SCM throw_args)
{
	SchemeShell *ss = (SchemeShell *)data;
	return ss->catch_handler(tag, throw_args);
}

SCM SchemeShell::catch_handler (SCM tag, SCM throw_args)
{
	// Check for read error. If a read error, then wait for user to correct it.
	SCM re = scm_symbol_to_string(tag);
	char * restr = scm_to_locale_string(re);
	pending_input = false;
	if (0 == strcmp(restr, "read-error"))
	{
		pending_input = true;
		free(restr);

		// quit accumulating text on escape (^[), cancel (^X) or ^C
		char c = input_line[input_line.length()-1];
		if ((0x6 == c) || (0x16 == c) || (0x18 == c) || (0x1b == c))
		{
			pending_input = false;
			input_line = "";
		}
		return SCM_EOL;
	}
	free(restr);

	// If its not a read error, then its a regular error; report it.
	caught_error = true;

	/* get string port into which we write the error message and stack. */
	error_string_port = scm_open_output_string();
	SCM port = error_string_port;

	if (scm_is_true(scm_list_p(throw_args)) && (scm_ilength(throw_args) >= 4))
	{
		SCM stack   = scm_make_stack (SCM_BOOL_T, SCM_EOL);
		SCM subr    = SCM_CAR (throw_args);
		SCM message = SCM_CADR (throw_args);
		SCM parts   = SCM_CADDR (throw_args);
		SCM rest    = SCM_CADDDR (throw_args);
		if (scm_is_true (stack))
		{
			SCM highlights;

			if (scm_is_eq (tag, scm_arg_type_key) ||
			    scm_is_eq (tag, scm_out_of_range_key))
				highlights = rest;
			else
				highlights = SCM_EOL;

			scm_puts ("Backtrace:\n", port);
			scm_display_backtrace_with_highlights (stack, port,
			      SCM_BOOL_F, SCM_BOOL_F, highlights);
			scm_newline (port);
		}
		scm_i_display_error (stack, port, subr, message, parts, rest);
	}
	else
	{
		printf("ERROR: thow args are unexpectedly short!\n");
	}

#if 0
	/* find the stack, and conditionally display it */
	SCM the_stack = scm_fluid_ref(SCM_CDR(scm_the_last_stack_fluid_var));
	if (the_stack != SCM_BOOL_F)
	{
		scm_display_backtrace(the_stack, port, SCM_UNDEFINED, SCM_UNDEFINED);
	}
#endif

	return SCM_BOOL_F;
}

/* ============================================================== */

/**
 * Evaluate the expression
 */
std::string SchemeShell::eval(const std::string &expr)
{
	input_line += expr;

	caught_error = false;
	pending_input = false;
	SCM rc = scm_internal_catch (SCM_BOOL_T,
	            (scm_t_catch_body) scm_c_eval_string, (void *) input_line.c_str(),
	            SchemeShell::catch_handler_wrapper, this);

	if (pending_input)
	{
		if (show_output)
			return pending_prompt;
		else
			return "";
	}
	pending_input = false;
	input_line = "";

	if (caught_error)
	{
		std::string rv;
		rc = scm_get_output_string(error_string_port);
		char * str = scm_to_locale_string(rc);
		rv = str;
		free(str);
		scm_close_port(error_string_port);

		rv += "\n";
		rv += normal_prompt;
		return rv;
	}
	else
	{
		if (show_output)
		{
			// First, we print the "interpreter" output.
			std::string rv;
			rv = prt(rc);
			rv += "\n";

			// Next, we get the contents of the output port,
			// and pass that on.
			rc = scm_get_output_string(outport);
			char * str = scm_to_locale_string(rc);
			rv += str;
			free(str);
			scm_truncate_file(outport, scm_from_uint16(0));

			rv += normal_prompt;
			return rv;
		}
		else
			return "";
	}
	return "#<Error: Unreachable statement reached>";
}

#endif
/* ===================== END OF FILE ============================ */
<commit_msg>reverse order of the displayed and the interpreted output.<commit_after>/*
 * SchemeShell.c
 *
 * Simple scheme shell
 * Copyright (c) 2008 Linas Vepstas <linas@linas.org>
 */

#ifdef HAVE_GUILE

#include "SchemeShell.h"

#include <libguile.h>
#include <libguile/backtrace.h>
#include <libguile/lang.h>

#include "platform.h"
#include "SchemeSmob.h"

using namespace opencog;

bool SchemeShell::is_inited = false;

SchemeShell::SchemeShell(void)
{
	if (!is_inited)
	{
		is_inited = true;
		scm_init_guile();
		scm_init_debug();
		scm_init_backtrace();
		scm_init_strports(); // is this really needed ?
	}

	funcs = new SchemeSmob();
	pending_input = false;
	show_output = true;
	input_line = "";
	normal_prompt = "guile> ";
	pending_prompt = "... ";

	outport = scm_open_output_string();
	scm_set_current_output_port(outport);
}

void SchemeShell::hush_output(bool hush)
{
	show_output = !hush;
}

/* ============================================================== */

std::string SchemeShell::prt(SCM node)
{
	if (scm_is_pair(node))
	{
		std::string str = "(";
      SCM node_list = node;
		const char * sp = "";
      do
      {
			str += sp;
			sp = " ";
         node = SCM_CAR (node_list);
         str += prt (node);
         node_list = SCM_CDR (node_list);
      }
      while (scm_is_pair(node_list));

		// Print the rest -- the CDR part
		if (!scm_is_null(node_list))
		{
			str += " . ";
			str += prt (node_list);
		}
		str += ")";
		return str;
   }
	else if (scm_is_true(scm_symbol_p(node)))
	{
		node = scm_symbol_to_string(node);
		char * str = scm_to_locale_string(node);
		// std::string rv = "'";  // print the symbol escape
		std::string rv = "";      // err .. don't print it
		rv += str;
		free(str);
		return rv;
	}
	else if (scm_is_true(scm_string_p(node)))
	{
		char * str = scm_to_locale_string(node);
		std::string rv = "\"";
		rv += str;
		rv += "\"";
		free(str);
		return rv;
	}

	else if (SCM_SMOB_PREDICATE(SchemeSmob::cog_handle_tag, node))
	{
		return SchemeSmob::handle_to_string(node);
	}

	else if (SCM_SMOB_PREDICATE(SchemeSmob::cog_misc_tag, node))
	{
		return SchemeSmob::misc_to_string(node);
	}

	else if (scm_is_number(node))
	{
		#define NUMBUFSZ 60
		char buff[NUMBUFSZ];
		if (scm_is_signed_integer(node, INT_MIN, INT_MAX))
		{
			snprintf (buff, NUMBUFSZ, "%ld", (long) scm_to_long(node));
		}
		else if (scm_is_unsigned_integer(node, 0, UINT_MAX))
		{
			snprintf (buff, NUMBUFSZ, "%lu", (unsigned long) scm_to_ulong(node));
		}
		else if (scm_is_real(node))
		{
			snprintf (buff, NUMBUFSZ, "%g", scm_to_double(node));
		}
		else if (scm_is_complex(node))
		{
			snprintf (buff, NUMBUFSZ, "%g +i %g",
				scm_c_real_part(node),
				scm_c_imag_part(node));
		}
		else if (scm_is_rational(node))
		{
			std::string rv;
			rv = prt(scm_numerator(node));
			rv += "/";
			rv += prt(scm_denominator(node));
			return rv;
		}
		return buff;
	}
	else if (scm_is_true(scm_char_p(node)))
	{
		std::string rv;
		rv = (char) scm_to_char(node);
		return rv;
	}
	else if (scm_is_true(scm_boolean_p(node)))
	{
		if (scm_to_bool(node)) return "#t";
		return "#f";
	}
	else if (SCM_NULL_OR_NIL_P(node))
	{
		// scm_is_null(x) is true when x is SCM_EOL
		// SCM_NILP(x) is true when x is SCM_ELISP_NIL
		return "()";
	}
	else if (scm_is_eq(node, SCM_UNDEFINED))
	{
		return "undefined";
	}
	else if (scm_is_eq(node, SCM_EOF_VAL))
	{
		return "eof";
	}
	else if (scm_is_eq(node, SCM_UNSPECIFIED))
	{
		return "";
	}
	else if (scm_is_true(scm_dynamic_object_p(node)))
	{
		return "#<dynamic object (XXX add name here)>";
	}
	else if (scm_is_true(scm_port_p(node)))
	{
		return "#<port (XXX add name here)>";
	}
	else if (scm_is_true(scm_procedure_p(node)))
	{
		return "#<port (XXX add name here)>";
	}
	else if (scm_subr_p(node))
	{
		return "#<subr (XXX add name here)>";
	}
	else if (scm_is_true(scm_operator_p(node)))
	{
		return "#<operator (XXX add name here)>";
	}
	else if (scm_is_true(scm_entity_p(node)))
	{
		return "#<entity (XXX add name here)>";
	}
	else if (scm_is_true(scm_variable_p(node)))
	{
		return "#<variable (XXX add name here)>";
	}
	else
	{
		fprintf (stderr, "Error: unhandled type for guile printing: %p\n",
			node);
		return "#opencog-guile-error: unknown type";
	}

	return "";
}

/* ============================================================== */

SCM SchemeShell::catch_handler_wrapper (void *data, SCM tag, SCM throw_args)
{
	SchemeShell *ss = (SchemeShell *)data;
	return ss->catch_handler(tag, throw_args);
}

SCM SchemeShell::catch_handler (SCM tag, SCM throw_args)
{
	// Check for read error. If a read error, then wait for user to correct it.
	SCM re = scm_symbol_to_string(tag);
	char * restr = scm_to_locale_string(re);
	pending_input = false;
	if (0 == strcmp(restr, "read-error"))
	{
		pending_input = true;
		free(restr);

		// quit accumulating text on escape (^[), cancel (^X) or ^C
		char c = input_line[input_line.length()-1];
		if ((0x6 == c) || (0x16 == c) || (0x18 == c) || (0x1b == c))
		{
			pending_input = false;
			input_line = "";
		}
		return SCM_EOL;
	}
	free(restr);

	// If its not a read error, then its a regular error; report it.
	caught_error = true;

	/* get string port into which we write the error message and stack. */
	error_string_port = scm_open_output_string();
	SCM port = error_string_port;

	if (scm_is_true(scm_list_p(throw_args)) && (scm_ilength(throw_args) >= 4))
	{
		SCM stack   = scm_make_stack (SCM_BOOL_T, SCM_EOL);
		SCM subr    = SCM_CAR (throw_args);
		SCM message = SCM_CADR (throw_args);
		SCM parts   = SCM_CADDR (throw_args);
		SCM rest    = SCM_CADDDR (throw_args);
		if (scm_is_true (stack))
		{
			SCM highlights;

			if (scm_is_eq (tag, scm_arg_type_key) ||
			    scm_is_eq (tag, scm_out_of_range_key))
				highlights = rest;
			else
				highlights = SCM_EOL;

			scm_puts ("Backtrace:\n", port);
			scm_display_backtrace_with_highlights (stack, port,
			      SCM_BOOL_F, SCM_BOOL_F, highlights);
			scm_newline (port);
		}
		scm_i_display_error (stack, port, subr, message, parts, rest);
	}
	else
	{
		printf("ERROR: thow args are unexpectedly short!\n");
	}

#if 0
	/* find the stack, and conditionally display it */
	SCM the_stack = scm_fluid_ref(SCM_CDR(scm_the_last_stack_fluid_var));
	if (the_stack != SCM_BOOL_F)
	{
		scm_display_backtrace(the_stack, port, SCM_UNDEFINED, SCM_UNDEFINED);
	}
#endif

	return SCM_BOOL_F;
}

/* ============================================================== */

/**
 * Evaluate the expression
 */
std::string SchemeShell::eval(const std::string &expr)
{
	input_line += expr;

	caught_error = false;
	pending_input = false;
	SCM rc = scm_internal_catch (SCM_BOOL_T,
	            (scm_t_catch_body) scm_c_eval_string, (void *) input_line.c_str(),
	            SchemeShell::catch_handler_wrapper, this);

	if (pending_input)
	{
		if (show_output)
			return pending_prompt;
		else
			return "";
	}
	pending_input = false;
	input_line = "";

	if (caught_error)
	{
		std::string rv;
		rc = scm_get_output_string(error_string_port);
		char * str = scm_to_locale_string(rc);
		rv = str;
		free(str);
		scm_close_port(error_string_port);

		rv += "\n";
		rv += normal_prompt;
		return rv;
	}
	else
	{
		if (show_output)
		{
			std::string rv;
			// First, we get the contents of the output port,
			// and pass that on.
			SCM out = scm_get_output_string(outport);
			char * str = scm_to_locale_string(out);
			rv = str;
			free(str);
			scm_truncate_file(outport, scm_from_uint16(0));

			// Next, we append the "interpreter" output
			rv += prt(rc);
			rv += "\n";

			rv += normal_prompt;
			return rv;
		}
		else
			return "";
	}
	return "#<Error: Unreachable statement reached>";
}

#endif
/* ===================== END OF FILE ============================ */
<|endoftext|>


<commit_before>#include"../header/CThreadPool.h"
#include<memory>	//make_unique
#include<mutex>
#include<utility>	//move
#include<vector>
#include"../../lib/header/algorithm/algorithm.h"
using namespace std;

namespace nThread
{
	CThreadPool::CThreadPool(const size_t count)
		:mut_{new mutex()},size_{count},thr_{new CThreadPoolItem<void>[count]()}
	{
		nAlgorithm::for_each(thr_,thr_+count,[&](const auto p){
			p->setCommun(make_unique<CThreadPoolCommun>(p,join_anyList_,waitingQue_,id_++));
			waitingQue_.emplace(id_.get(),p);
		});
	}

	void CThreadPool::join_all()
	{
		for(size_t i{0};i!=count();++i)
			if(joinable(i))
				join(i);
	}

	size_t CThreadPool::join_any()
	{
		auto temp{join_anyList_.wait_and_pop()};
		const auto id{temp.first};
		temp.second->join();
		return id;
	}

	void CThreadPool::wait_until_all_available() const
	{
		lock_guard<mutex> lock{*mut_};
		vector<typename CThreadPoolCommun::pair> vec;
		vec.reserve(count());
		for(size_t i{0};i!=count();++i)
			vec.emplace_back(waitingQue_.wait_and_pop());
		for(auto &val:vec)
			waitingQue_.emplace(move(val));
	}

	CThreadPool::~CThreadPool()
	{
		delete []thr_;	//CThreadPoolItem is RAII, you don't have to call join_all()
		delete mut_;
	}
}<commit_msg>update join_all<commit_after>#include"../header/CThreadPool.h"
#include<memory>	//make_unique
#include<mutex>
#include<utility>	//move
#include<vector>
#include"../../lib/header/algorithm/algorithm.h"
using namespace std;

namespace nThread
{
	CThreadPool::CThreadPool(const size_t count)
		:mut_{new mutex()},size_{count},thr_{new CThreadPoolItem<void>[count]()}
	{
		nAlgorithm::for_each(thr_,thr_+count,[&](const auto p){
			p->setCommun(make_unique<CThreadPoolCommun>(p,join_anyList_,waitingQue_,id_++));
			waitingQue_.emplace(id_.get(),p);
		});
	}

	void CThreadPool::join_all()
	{
		nAlgorithm::for_each<size_t>(0,count(),[&](const auto i){
			if(joinable(i))
				join(i);
		});
	}

	size_t CThreadPool::join_any()
	{
		auto temp{join_anyList_.wait_and_pop()};
		const auto id{temp.first};
		temp.second->join();
		return id;
	}

	void CThreadPool::wait_until_all_available() const
	{
		lock_guard<mutex> lock{*mut_};
		vector<typename CThreadPoolCommun::pair> vec;
		vec.reserve(count());
		for(size_t i{0};i!=count();++i)
			vec.emplace_back(waitingQue_.wait_and_pop());
		for(auto &val:vec)
			waitingQue_.emplace(move(val));
	}

	CThreadPool::~CThreadPool()
	{
		delete []thr_;	//CThreadPoolItem is RAII, you don't have to call join_all()
		delete mut_;
	}
}<|endoftext|>


<commit_before>/*
**
** Copyright (C) 2012 Aldebaran Robotics
*/

#include <map>
#include <gtest/gtest.h>
#include <qi/qi.hpp>
#include <qi/application.hpp>
#include <qimessaging/object.hpp>
#include <qimessaging/session.hpp>

#include <qimessaging/service_directory.hpp>

qi::ServiceDirectory sd;
qi::Session          session1, session2;
qi::Object           oserver1, oserver2;
qi::Object          *oclient1, *oclient2;
static qi::Promise<bool> payload;
void onFire1(const int& pl)
{
  if (pl)
    oclient2->call<void>("onFire2", pl-1);
  else
    payload.setValue(true);
}

void onFire2(const int& pl)
{
  if (pl)
    oclient1->call<void>("onFire1", pl-1);
  else
    payload.setValue(true);
}

TEST(Test, Recurse)
{
  // Two objects with a fire event and a onFire method.
  ASSERT_TRUE(sd.listen("tcp://127.0.0.1:0"));
  ASSERT_TRUE(session1.connect(sd.listenUrl()));
  ASSERT_TRUE(session1.waitForConnected());
  ASSERT_TRUE(session2.connect(sd.listenUrl()));
  ASSERT_TRUE(session2.waitForConnected());
  oserver1.advertiseMethod("onFire1", &onFire1);
  oserver2.advertiseMethod("onFire2", &onFire2);
  ASSERT_TRUE(session1.listen("tcp://0.0.0.0:0"));
  ASSERT_TRUE(session2.listen("tcp://0.0.0.0:0"));
  ASSERT_GT(session1.registerService("coin1", &oserver1).wait(), 0);
  ASSERT_GT(session2.registerService("coin2", &oserver2).wait(), 0);
  EXPECT_EQ(1U, session1.registeredServices().size());
  EXPECT_EQ(1U, session2.registeredServices().size());
  oclient1 = session2.service("coin1");
  oclient2 = session1.service("coin2");
  int niter = 10000;
  if (getenv("VALGRIND"))
  {
    std::cerr << "Valgrind detected, reducing iteration count" << std::endl;
    niter = 50;
  }
  oclient1->call<void>("onFire1", niter);
  ASSERT_TRUE(payload.future().wait(3000));
  session1.close();
  session2.close();
  // We must force delete, otherwise destruction order is undefined.
  // And deleting a registered service is undefined behavior.
  session1.disconnect();
  session2.disconnect();
}

int main(int argc, char **argv) {
  qi::Application app(argc, argv);
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
<commit_msg>test_call_many: remove globals<commit_after>/*
**
** Copyright (C) 2012 Aldebaran Robotics
*/

#include <map>
#include <gtest/gtest.h>
#include <qi/qi.hpp>
#include <qi/application.hpp>
#include <qimessaging/object.hpp>
#include <qimessaging/session.hpp>

#include <qimessaging/service_directory.hpp>

qi::Object          *oclient1, *oclient2;
static qi::Promise<bool> payload;

void onFire1(const int& pl)
{
  if (pl)
    oclient2->call<void>("onFire2", pl-1);
  else
    payload.setValue(true);
}

void onFire2(const int& pl)
{
  if (pl)
    oclient1->call<void>("onFire1", pl-1);
  else
    payload.setValue(true);
}

TEST(Test, Recurse)
{
  qi::ServiceDirectory sd;
  qi::Session          session1, session2;
  qi::Object           oserver1, oserver2;

  // Two objects with a fire event and a onFire method.
  ASSERT_TRUE(sd.listen("tcp://127.0.0.1:0"));
  ASSERT_TRUE(session1.connect(sd.listenUrl()));
  ASSERT_TRUE(session1.waitForConnected());
  ASSERT_TRUE(session2.connect(sd.listenUrl()));
  ASSERT_TRUE(session2.waitForConnected());
  oserver1.advertiseMethod("onFire1", &onFire1);
  oserver2.advertiseMethod("onFire2", &onFire2);
  ASSERT_TRUE(session1.listen("tcp://0.0.0.0:0"));
  ASSERT_TRUE(session2.listen("tcp://0.0.0.0:0"));
  ASSERT_GT(session1.registerService("coin1", &oserver1).wait(), 0);
  ASSERT_GT(session2.registerService("coin2", &oserver2).wait(), 0);
  EXPECT_EQ(1U, session1.registeredServices().size());
  EXPECT_EQ(1U, session2.registeredServices().size());
  oclient1 = session2.service("coin1");
  oclient2 = session1.service("coin2");
  int niter = 10000;
  if (getenv("VALGRIND"))
  {
    std::cerr << "Valgrind detected, reducing iteration count" << std::endl;
    niter = 50;
  }
  oclient1->call<void>("onFire1", niter);
  ASSERT_TRUE(payload.future().wait(3000));

  session1.close();
  session2.close();
  // We must force delete, otherwise destruction order is undefined.
  // And deleting a registered service is undefined behavior.
  session1.disconnect();
  session2.disconnect();
  sd.close();
  delete oclient1;
  delete oclient2;
}

int main(int argc, char **argv) {
  qi::Application app(argc, argv);
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
<|endoftext|>