<commit_before>/***************************************************************************
 *   Copyright (c) 2002 Juergen Riegel <juergen.riegel@web.de>             *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   This library  is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"
#ifndef _PreComp_
# include <QGridLayout>
# include <QHeaderView>
# include <QEvent>
#endif

#include <boost/bind.hpp>

/// Here the FreeCAD includes sorted by Base,App,Gui......
#include <Base/Parameter.h>
#include <App/PropertyStandard.h>
#include <App/PropertyGeo.h>
#include <App/PropertyLinks.h>
#include <App/PropertyContainer.h>
#include <App/DocumentObject.h>
#include <App/Document.h>

#include "PropertyView.h"
#include "Application.h"
#include "Document.h"
#include "BitmapFactory.h"
#include "ViewProvider.h"

#include "propertyeditor/PropertyEditor.h"

using namespace std;
using namespace Gui;
using namespace Gui::DockWnd;
using namespace Gui::PropertyEditor;

/* TRANSLATOR Gui::PropertyView */

/*! Property Editor Widget
 *
 * Provides two Gui::PropertyEditor::PropertyEditor widgets, for "View" and "Data",
 * in two tabs.
 */
PropertyView::PropertyView(QWidget *parent)
  : QWidget(parent)
{
    QGridLayout* pLayout = new QGridLayout( this );
    pLayout->setSpacing(0);
    pLayout->setMargin (0);

    tabs = new QTabWidget (this);
    tabs->setObjectName(QString::fromUtf8("propertyTab"));
    tabs->setTabPosition(QTabWidget::South);
#if defined(Q_OS_WIN32)
    tabs->setTabShape(QTabWidget::Triangular);
#endif
    pLayout->addWidget(tabs, 0, 0);

    propertyEditorView = new Gui::PropertyEditor::PropertyEditor();
    propertyEditorView->setAutomaticDocumentUpdate(false);
    tabs->addTab(propertyEditorView, tr("View"));

    propertyEditorData = new Gui::PropertyEditor::PropertyEditor();
    propertyEditorData->setAutomaticDocumentUpdate(true);
    tabs->addTab(propertyEditorData, tr("Data"));

    ParameterGrp::handle hGrp = App::GetApplication().GetUserParameter().
        GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("PropertyView");
    if ( hGrp ) {
        int preferredTab = hGrp->GetInt("LastTabIndex", 1);

        if ( preferredTab > 0 && preferredTab < tabs->count() )
            tabs->setCurrentIndex(preferredTab);
    }

    // connect after adding all tabs, so adding doesn't thrash the parameter
    connect(tabs, SIGNAL(currentChanged(int)), this, SLOT(tabChanged(int)));

    this->connectPropData =
    App::GetApplication().signalChangedObject.connect(boost::bind
        (&PropertyView::slotChangePropertyData, this, _1, _2));
    this->connectPropView =
    Gui::Application::Instance->signalChangedObject.connect(boost::bind
        (&PropertyView::slotChangePropertyView, this, _1, _2));
    this->connectPropAppend =
    App::GetApplication().signalAppendDynamicProperty.connect(boost::bind
        (&PropertyView::slotAppendDynamicProperty, this, _1));
    this->connectPropRemove =
    App::GetApplication().signalRemoveDynamicProperty.connect(boost::bind
        (&PropertyView::slotRemoveDynamicProperty, this, _1));
    this->connectPropChange =
    App::GetApplication().signalChangePropertyEditor.connect(boost::bind
        (&PropertyView::slotChangePropertyEditor, this, _1));
    this->connectActiveDoc =
    Application::Instance->signalActiveDocument.connect(boost::bind
        (&PropertyView::slotActiveDocument, this, _1));
}

PropertyView::~PropertyView()
{
    this->connectPropData.disconnect();
    this->connectPropView.disconnect();
    this->connectPropAppend.disconnect();
    this->connectPropRemove.disconnect();
    this->connectPropChange.disconnect();
    this->connectActiveDoc.disconnect();
}

void PropertyView::slotChangePropertyData(const App::DocumentObject&, const App::Property& prop)
{
    propertyEditorData->updateProperty(prop);
}

void PropertyView::slotChangePropertyView(const Gui::ViewProvider&, const App::Property& prop)
{
    propertyEditorView->updateProperty(prop);
}

void PropertyView::slotAppendDynamicProperty(const App::Property& prop)
{
    App::PropertyContainer* parent = prop.getContainer();
    if (parent->isHidden(&prop))
        return;

    if (parent->isDerivedFrom(App::DocumentObject::getClassTypeId())) {
        propertyEditorData->appendProperty(prop);
    }
    else if (parent->isDerivedFrom(Gui::ViewProvider::getClassTypeId())) {
        propertyEditorView->appendProperty(prop);
    }
}

void PropertyView::slotRemoveDynamicProperty(const App::Property& prop)
{
    App::PropertyContainer* parent = prop.getContainer();
    if (parent && parent->isDerivedFrom(App::DocumentObject::getClassTypeId())) {
        propertyEditorData->removeProperty(prop);
    }
    else if (parent && parent->isDerivedFrom(Gui::ViewProvider::getClassTypeId())) {
        propertyEditorView->removeProperty(prop);
    }
}

void PropertyView::slotChangePropertyEditor(const App::Property& prop)
{
    App::PropertyContainer* parent = prop.getContainer();
    if (parent && parent->isDerivedFrom(App::DocumentObject::getClassTypeId())) {
        propertyEditorData->updateEditorMode(prop);
    }
    else if (parent && parent->isDerivedFrom(Gui::ViewProvider::getClassTypeId())) {
        propertyEditorView->updateEditorMode(prop);
    }
}

void PropertyView::slotActiveDocument(const Gui::Document &doc)
{
    bool enableEditor = false;

    // check if at least one selected object is part of the active document
    std::vector<SelectionSingleton::SelObj> array = Gui::Selection().getCompleteSelection();
    for (std::vector<SelectionSingleton::SelObj>::const_iterator it = array.begin(); it != array.end(); ++it) {
        if (Gui::Application::Instance->getDocument(it->pDoc) == &doc) {
            enableEditor = true;
            break;
        }
    }
    setEnabled(enableEditor || array.empty());
}

struct PropertyView::PropInfo
{
    std::string propName;
    int propId;
    std::vector<App::Property*> propList;
};

struct PropertyView::PropFind {
    const PropInfo& item;
    PropFind(const PropInfo& item) : item(item) {}
    bool operator () (const PropInfo& elem) const
    {
        return (elem.propId == item.propId) &&
               (elem.propName == item.propName);
    }
};

void PropertyView::onSelectionChanged(const SelectionChanges& msg)
{
    if (msg.Type != SelectionChanges::AddSelection &&
        msg.Type != SelectionChanges::RmvSelection &&
        msg.Type != SelectionChanges::SetSelection &&
        msg.Type != SelectionChanges::ClrSelection)
        return;

    bool enableEditor = false;
    Gui::Document *activeDoc = Application::Instance->activeDocument();

    // group the properties by <name,id>
    std::vector<PropInfo> propDataMap;
    std::vector<PropInfo> propViewMap;
    std::vector<SelectionSingleton::SelObj> array = Gui::Selection().getCompleteSelection();
    for (std::vector<SelectionSingleton::SelObj>::const_iterator it = array.begin(); it != array.end(); ++it) {
        App::DocumentObject *ob=0;
        ViewProvider *vp=0;

        std::vector<App::Property*> dataList;
        std::map<std::string, App::Property*> viewList;
        if ((*it).pObject) {
            (*it).pObject->getPropertyList(dataList);
            ob = (*it).pObject;

            // get also the properties of the associated view provider
            Gui::Document* doc = Gui::Application::Instance->getDocument(it->pDoc);
            vp = doc->getViewProvider((*it).pObject);
            if(!vp) continue;
            // get the properties as map here because it doesn't matter to have them sorted alphabetically
            vp->getPropertyMap(viewList);
            if (activeDoc == doc) {
                enableEditor = true;
            }
        }

        // store the properties with <name,id> as key in a map
        std::vector<App::Property*>::iterator pt;
        if (ob) {
            for (pt = dataList.begin(); pt != dataList.end(); ++pt) {
                PropInfo nameType;
                nameType.propName = ob->getPropertyName(*pt);
                nameType.propId = (*pt)->getTypeId().getKey();

                if (!ob->isHidden(*pt)) {
                    std::vector<PropInfo>::iterator pi = std::find_if(propDataMap.begin(), propDataMap.end(), PropFind(nameType));
                    if (pi != propDataMap.end()) {
                        pi->propList.push_back(*pt);
                    }
                    else {
                        nameType.propList.push_back(*pt);
                        propDataMap.push_back(nameType);
                    }
                }
            }
        }
        // the same for the view properties
        if (vp) {
            std::map<std::string, App::Property*>::iterator pt;
            for (pt = viewList.begin(); pt != viewList.end(); ++pt) {
                PropInfo nameType;
                nameType.propName = pt->first;
                nameType.propId = pt->second->getTypeId().getKey();

                if (!vp->isHidden(pt->second)) {
                    std::vector<PropInfo>::iterator pi = std::find_if(propViewMap.begin(), propViewMap.end(), PropFind(nameType));
                    if (pi != propViewMap.end()) {
                        pi->propList.push_back(pt->second);
                    }
                    else {
                        nameType.propList.push_back(pt->second);
                        propViewMap.push_back(nameType);
                    }
                }
            }
        }
    }

    // the property must be part of each selected object, i.e. the number
    // of selected objects is equal to the number of properties with same
    // name and id
    std::vector<PropInfo>::const_iterator it;
    PropertyModel::PropertyList dataProps;
    for (it = propDataMap.begin(); it != propDataMap.end(); ++it) {
        if (it->propList.size() == array.size()) {
            dataProps.push_back(std::make_pair(it->propName, it->propList));
        }
    }
    propertyEditorData->buildUp(dataProps);

    PropertyModel::PropertyList viewProps;
    for (it = propViewMap.begin(); it != propViewMap.end(); ++it) {
        if (it->propList.size() == array.size()) {
            viewProps.push_back(std::make_pair(it->propName, it->propList));
        }
    }
    propertyEditorView->buildUp(viewProps);

    // make sure the editors are enabled/disabled properly
    setEnabled(enableEditor || array.empty());
}

void PropertyView::tabChanged(int index)
{
    ParameterGrp::handle hGrp = App::GetApplication().GetUserParameter().
        GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("PropertyView");
    if (hGrp) {
        hGrp->SetInt("LastTabIndex", index);
    }
}

void PropertyView::changeEvent(QEvent *e)
{
    if (e->type() == QEvent::LanguageChange) {
        tabs->setTabText(0, trUtf8("View"));
        tabs->setTabText(1, trUtf8("Data"));
    }

    QWidget::changeEvent(e);
}

/* TRANSLATOR Gui::DockWnd::PropertyDockView */

PropertyDockView::PropertyDockView(Gui::Document* pcDocument, QWidget *parent)
  : DockWindow(pcDocument,parent)
{
    setWindowTitle(tr("Property View"));

    PropertyView* view = new PropertyView(this);
    QGridLayout* pLayout = new QGridLayout(this);
    pLayout->setSpacing(0);
    pLayout->setMargin (0);
    pLayout->addWidget(view, 0, 0);

    resize( 200, 400 );
}

PropertyDockView::~PropertyDockView()
{
}

#include "moc_PropertyView.cpp"
<commit_msg>add option to disable auto-deactivation of property view for inactive document<commit_after>/***************************************************************************
 *   Copyright (c) 2002 Juergen Riegel <juergen.riegel@web.de>             *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   This library  is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"
#ifndef _PreComp_
# include <QGridLayout>
# include <QHeaderView>
# include <QEvent>
#endif

#include <boost/bind.hpp>

/// Here the FreeCAD includes sorted by Base,App,Gui......
#include <Base/Parameter.h>
#include <App/PropertyStandard.h>
#include <App/PropertyGeo.h>
#include <App/PropertyLinks.h>
#include <App/PropertyContainer.h>
#include <App/DocumentObject.h>
#include <App/Document.h>

#include "PropertyView.h"
#include "Application.h"
#include "Document.h"
#include "BitmapFactory.h"
#include "ViewProvider.h"

#include "propertyeditor/PropertyEditor.h"

using namespace std;
using namespace Gui;
using namespace Gui::DockWnd;
using namespace Gui::PropertyEditor;

/* TRANSLATOR Gui::PropertyView */

/*! Property Editor Widget
 *
 * Provides two Gui::PropertyEditor::PropertyEditor widgets, for "View" and "Data",
 * in two tabs.
 */
PropertyView::PropertyView(QWidget *parent)
  : QWidget(parent)
{
    QGridLayout* pLayout = new QGridLayout( this );
    pLayout->setSpacing(0);
    pLayout->setMargin (0);

    tabs = new QTabWidget (this);
    tabs->setObjectName(QString::fromUtf8("propertyTab"));
    tabs->setTabPosition(QTabWidget::South);
#if defined(Q_OS_WIN32)
    tabs->setTabShape(QTabWidget::Triangular);
#endif
    pLayout->addWidget(tabs, 0, 0);

    propertyEditorView = new Gui::PropertyEditor::PropertyEditor();
    propertyEditorView->setAutomaticDocumentUpdate(false);
    tabs->addTab(propertyEditorView, tr("View"));

    propertyEditorData = new Gui::PropertyEditor::PropertyEditor();
    propertyEditorData->setAutomaticDocumentUpdate(true);
    tabs->addTab(propertyEditorData, tr("Data"));

    ParameterGrp::handle hGrp = App::GetApplication().GetUserParameter().
        GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("PropertyView");
    if ( hGrp ) {
        int preferredTab = hGrp->GetInt("LastTabIndex", 1);

        if ( preferredTab > 0 && preferredTab < tabs->count() )
            tabs->setCurrentIndex(preferredTab);
    }

    // connect after adding all tabs, so adding doesn't thrash the parameter
    connect(tabs, SIGNAL(currentChanged(int)), this, SLOT(tabChanged(int)));

    this->connectPropData =
    App::GetApplication().signalChangedObject.connect(boost::bind
        (&PropertyView::slotChangePropertyData, this, _1, _2));
    this->connectPropView =
    Gui::Application::Instance->signalChangedObject.connect(boost::bind
        (&PropertyView::slotChangePropertyView, this, _1, _2));
    this->connectPropAppend =
    App::GetApplication().signalAppendDynamicProperty.connect(boost::bind
        (&PropertyView::slotAppendDynamicProperty, this, _1));
    this->connectPropRemove =
    App::GetApplication().signalRemoveDynamicProperty.connect(boost::bind
        (&PropertyView::slotRemoveDynamicProperty, this, _1));
    this->connectPropChange =
    App::GetApplication().signalChangePropertyEditor.connect(boost::bind
        (&PropertyView::slotChangePropertyEditor, this, _1));
    this->connectActiveDoc =
    Application::Instance->signalActiveDocument.connect(boost::bind
        (&PropertyView::slotActiveDocument, this, _1));
}

PropertyView::~PropertyView()
{
    this->connectPropData.disconnect();
    this->connectPropView.disconnect();
    this->connectPropAppend.disconnect();
    this->connectPropRemove.disconnect();
    this->connectPropChange.disconnect();
    this->connectActiveDoc.disconnect();
}

void PropertyView::slotChangePropertyData(const App::DocumentObject&, const App::Property& prop)
{
    propertyEditorData->updateProperty(prop);
}

void PropertyView::slotChangePropertyView(const Gui::ViewProvider&, const App::Property& prop)
{
    propertyEditorView->updateProperty(prop);
}

void PropertyView::slotAppendDynamicProperty(const App::Property& prop)
{
    App::PropertyContainer* parent = prop.getContainer();
    if (parent->isHidden(&prop))
        return;

    if (parent->isDerivedFrom(App::DocumentObject::getClassTypeId())) {
        propertyEditorData->appendProperty(prop);
    }
    else if (parent->isDerivedFrom(Gui::ViewProvider::getClassTypeId())) {
        propertyEditorView->appendProperty(prop);
    }
}

void PropertyView::slotRemoveDynamicProperty(const App::Property& prop)
{
    App::PropertyContainer* parent = prop.getContainer();
    if (parent && parent->isDerivedFrom(App::DocumentObject::getClassTypeId())) {
        propertyEditorData->removeProperty(prop);
    }
    else if (parent && parent->isDerivedFrom(Gui::ViewProvider::getClassTypeId())) {
        propertyEditorView->removeProperty(prop);
    }
}

void PropertyView::slotChangePropertyEditor(const App::Property& prop)
{
    App::PropertyContainer* parent = prop.getContainer();
    if (parent && parent->isDerivedFrom(App::DocumentObject::getClassTypeId())) {
        propertyEditorData->updateEditorMode(prop);
    }
    else if (parent && parent->isDerivedFrom(Gui::ViewProvider::getClassTypeId())) {
        propertyEditorView->updateEditorMode(prop);
    }
}

void PropertyView::slotActiveDocument(const Gui::Document &doc)
{
    // allow to disable the auto-deactivation
    ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View");
    bool enableEditor = hGrp->GetBool("EnablePropertyViewForInactiveDocument", false);
    if (enableEditor) {
        setEnabled(true);
        return;
    }

    // check if at least one selected object is part of the active document
    std::vector<SelectionSingleton::SelObj> array = Gui::Selection().getCompleteSelection();
    for (std::vector<SelectionSingleton::SelObj>::const_iterator it = array.begin(); it != array.end(); ++it) {
        if (Gui::Application::Instance->getDocument(it->pDoc) == &doc) {
            enableEditor = true;
            break;
        }
    }
    setEnabled(enableEditor || array.empty());
}

struct PropertyView::PropInfo
{
    std::string propName;
    int propId;
    std::vector<App::Property*> propList;
};

struct PropertyView::PropFind {
    const PropInfo& item;
    PropFind(const PropInfo& item) : item(item) {}
    bool operator () (const PropInfo& elem) const
    {
        return (elem.propId == item.propId) &&
               (elem.propName == item.propName);
    }
};

void PropertyView::onSelectionChanged(const SelectionChanges& msg)
{
    if (msg.Type != SelectionChanges::AddSelection &&
        msg.Type != SelectionChanges::RmvSelection &&
        msg.Type != SelectionChanges::SetSelection &&
        msg.Type != SelectionChanges::ClrSelection)
        return;

    // allow to disable the auto-deactivation
    ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View");
    bool enableEditor = hGrp->GetBool("EnablePropertyViewForInactiveDocument", false);
    Gui::Document *activeDoc = Application::Instance->activeDocument();

    // group the properties by <name,id>
    std::vector<PropInfo> propDataMap;
    std::vector<PropInfo> propViewMap;
    std::vector<SelectionSingleton::SelObj> array = Gui::Selection().getCompleteSelection();
    for (std::vector<SelectionSingleton::SelObj>::const_iterator it = array.begin(); it != array.end(); ++it) {
        App::DocumentObject *ob=0;
        ViewProvider *vp=0;

        std::vector<App::Property*> dataList;
        std::map<std::string, App::Property*> viewList;
        if ((*it).pObject) {
            (*it).pObject->getPropertyList(dataList);
            ob = (*it).pObject;

            // get also the properties of the associated view provider
            Gui::Document* doc = Gui::Application::Instance->getDocument(it->pDoc);
            vp = doc->getViewProvider((*it).pObject);
            if(!vp) continue;
            // get the properties as map here because it doesn't matter to have them sorted alphabetically
            vp->getPropertyMap(viewList);
            if (activeDoc == doc) {
                enableEditor = true;
            }
        }

        // store the properties with <name,id> as key in a map
        std::vector<App::Property*>::iterator pt;
        if (ob) {
            for (pt = dataList.begin(); pt != dataList.end(); ++pt) {
                PropInfo nameType;
                nameType.propName = ob->getPropertyName(*pt);
                nameType.propId = (*pt)->getTypeId().getKey();

                if (!ob->isHidden(*pt)) {
                    std::vector<PropInfo>::iterator pi = std::find_if(propDataMap.begin(), propDataMap.end(), PropFind(nameType));
                    if (pi != propDataMap.end()) {
                        pi->propList.push_back(*pt);
                    }
                    else {
                        nameType.propList.push_back(*pt);
                        propDataMap.push_back(nameType);
                    }
                }
            }
        }
        // the same for the view properties
        if (vp) {
            std::map<std::string, App::Property*>::iterator pt;
            for (pt = viewList.begin(); pt != viewList.end(); ++pt) {
                PropInfo nameType;
                nameType.propName = pt->first;
                nameType.propId = pt->second->getTypeId().getKey();

                if (!vp->isHidden(pt->second)) {
                    std::vector<PropInfo>::iterator pi = std::find_if(propViewMap.begin(), propViewMap.end(), PropFind(nameType));
                    if (pi != propViewMap.end()) {
                        pi->propList.push_back(pt->second);
                    }
                    else {
                        nameType.propList.push_back(pt->second);
                        propViewMap.push_back(nameType);
                    }
                }
            }
        }
    }

    // the property must be part of each selected object, i.e. the number
    // of selected objects is equal to the number of properties with same
    // name and id
    std::vector<PropInfo>::const_iterator it;
    PropertyModel::PropertyList dataProps;
    for (it = propDataMap.begin(); it != propDataMap.end(); ++it) {
        if (it->propList.size() == array.size()) {
            dataProps.push_back(std::make_pair(it->propName, it->propList));
        }
    }
    propertyEditorData->buildUp(dataProps);

    PropertyModel::PropertyList viewProps;
    for (it = propViewMap.begin(); it != propViewMap.end(); ++it) {
        if (it->propList.size() == array.size()) {
            viewProps.push_back(std::make_pair(it->propName, it->propList));
        }
    }
    propertyEditorView->buildUp(viewProps);

    // make sure the editors are enabled/disabled properly
    setEnabled(enableEditor || array.empty());
}

void PropertyView::tabChanged(int index)
{
    ParameterGrp::handle hGrp = App::GetApplication().GetUserParameter().
        GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("PropertyView");
    if (hGrp) {
        hGrp->SetInt("LastTabIndex", index);
    }
}

void PropertyView::changeEvent(QEvent *e)
{
    if (e->type() == QEvent::LanguageChange) {
        tabs->setTabText(0, trUtf8("View"));
        tabs->setTabText(1, trUtf8("Data"));
    }

    QWidget::changeEvent(e);
}

/* TRANSLATOR Gui::DockWnd::PropertyDockView */

PropertyDockView::PropertyDockView(Gui::Document* pcDocument, QWidget *parent)
  : DockWindow(pcDocument,parent)
{
    setWindowTitle(tr("Property View"));

    PropertyView* view = new PropertyView(this);
    QGridLayout* pLayout = new QGridLayout(this);
    pLayout->setSpacing(0);
    pLayout->setMargin (0);
    pLayout->addWidget(view, 0, 0);

    resize( 200, 400 );
}

PropertyDockView::~PropertyDockView()
{
}

#include "moc_PropertyView.cpp"
<|endoftext|>


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

#include "IECore/ChannelOp.h"
#include "IECore/TypeTraits.h"
#include "IECore/DespatchTypedData.h"
#include "IECore/CompoundParameter.h"

#include "boost/format.hpp"

using namespace IECore;
using namespace std;
using namespace boost;

ChannelOp::ChannelOp( const std::string &name, const std::string &description )
	:	ImagePrimitiveOp( name, description )
{

	StringVectorDataPtr defaultChannels = new StringVectorData;
	defaultChannels->writable().push_back( "R" );
	defaultChannels->writable().push_back( "G" );
	defaultChannels->writable().push_back( "B" );

	m_channelNamesParameter = new StringVectorParameter(
		"channels",
		"The names of the channels to modify.",
		defaultChannels
	);

	parameters()->addParameter( m_channelNamesParameter );
}

ChannelOp::~ChannelOp()
{
}

StringVectorParameterPtr ChannelOp::channelNamesParameter()
{
	return m_channelNamesParameter;
}

ConstStringVectorParameterPtr ChannelOp::channelNamesParameter() const
{
	return m_channelNamesParameter;
}

void ChannelOp::modifyTypedPrimitive( ImagePrimitivePtr image, ConstCompoundObjectPtr operands )
{
	if( image->getDataWindow().isEmpty() )
	{
		return;
	}

	ChannelVector channels;

	/// \todo Just use ImagePrimitive::channelValid. We don't want to do that right now
	/// as it imposes loose restrictions on the channel datatype - in the future it should perhaps
	/// impose the restrictions we have here (float, int or half vector data).
	size_t numPixels = image->variableSize( PrimitiveVariable::Vertex );
	const vector<string> channelNames = channelNamesParameter()->getTypedValue();
	for( unsigned i=0; i<channelNames.size(); i++ )
	{
		PrimitiveVariableMap::iterator it = image->variables.find( channelNames[i] );
		if( it==image->variables.end() )
		{
			throw Exception( str( format( "Channel \"%s\" does not exist." ) % channelNames[i] ) );
		}

		if( it->second.interpolation!=PrimitiveVariable::Vertex &&
			it->second.interpolation!=PrimitiveVariable::Varying &&
			it->second.interpolation!=PrimitiveVariable::FaceVarying )
		{
			throw Exception( str( format( "Primitive variable \"%s\" has inappropriate interpolation." ) % channelNames[i] ) );
		}

		if( !it->second.data )
		{
			throw Exception( str( format( "Primitive variable \"%s\" has no data." ) % channelNames[i] ) );
		}

		if( !it->second.data->isInstanceOf( FloatVectorData::staticTypeId() ) &&
			!it->second.data->isInstanceOf( HalfVectorData::staticTypeId() ) &&
			!it->second.data->isInstanceOf( IntVectorData::staticTypeId() ) )
		{
			throw Exception( str( format( "Primitive variable \"%s\" has inappropriate type." ) % channelNames[i] ) );
		}

		size_t size = despatchTypedData<TypedDataSize>( it->second.data );
		if( size!=numPixels )
		{
			throw Exception( str( format( "Primitive variable \"%s\" has wrong size (%d but should be %d)." ) % channelNames[i] % size % numPixels ) );
		}

		channels.push_back( it->second.data );
	}

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

#include "IECore/ChannelOp.h"
#include "IECore/TypeTraits.h"
#include "IECore/DespatchTypedData.h"
#include "IECore/CompoundParameter.h"

#include "boost/format.hpp"

using namespace IECore;
using namespace std;
using namespace boost;

ChannelOp::ChannelOp( const std::string &name, const std::string &description )
	:	ImagePrimitiveOp( name, description )
{

	StringVectorDataPtr defaultChannels = new StringVectorData;
	defaultChannels->writable().push_back( "R" );
	defaultChannels->writable().push_back( "G" );
	defaultChannels->writable().push_back( "B" );

	m_channelNamesParameter = new StringVectorParameter(
		"channels",
		"The names of the channels to modify.",
		defaultChannels
	);

	parameters()->addParameter( m_channelNamesParameter );
}

ChannelOp::~ChannelOp()
{
}

StringVectorParameterPtr ChannelOp::channelNamesParameter()
{
	return m_channelNamesParameter;
}

ConstStringVectorParameterPtr ChannelOp::channelNamesParameter() const
{
	return m_channelNamesParameter;
}

void ChannelOp::modifyTypedPrimitive( ImagePrimitivePtr image, ConstCompoundObjectPtr operands )
{
	if( image->getDataWindow().isEmpty() )
	{
		return;
	}

	ChannelVector channels;

	/// \todo Just use ImagePrimitive::channelValid. We don't want to do that right now
	/// as it imposes loose restrictions on the channel datatype - in the future it should perhaps
	/// impose the restrictions we have here (float, int or half vector data).
	/// Would be useful to add a TypeTraits class which can test compatiblity againt ImagePrimitive-supported channels, too.
	size_t numPixels = image->variableSize( PrimitiveVariable::Vertex );
	const vector<string> channelNames = channelNamesParameter()->getTypedValue();
	for( unsigned i=0; i<channelNames.size(); i++ )
	{
		PrimitiveVariableMap::iterator it = image->variables.find( channelNames[i] );
		if( it==image->variables.end() )
		{
			throw Exception( str( format( "Channel \"%s\" does not exist." ) % channelNames[i] ) );
		}

		if( it->second.interpolation!=PrimitiveVariable::Vertex &&
			it->second.interpolation!=PrimitiveVariable::Varying &&
			it->second.interpolation!=PrimitiveVariable::FaceVarying )
		{
			throw Exception( str( format( "Primitive variable \"%s\" has inappropriate interpolation." ) % channelNames[i] ) );
		}

		if( !it->second.data )
		{
			throw Exception( str( format( "Primitive variable \"%s\" has no data." ) % channelNames[i] ) );
		}

		if( !it->second.data->isInstanceOf( FloatVectorData::staticTypeId() ) &&
			!it->second.data->isInstanceOf( HalfVectorData::staticTypeId() ) &&
			!it->second.data->isInstanceOf( IntVectorData::staticTypeId() ) )
		{
			throw Exception( str( format( "Primitive variable \"%s\" has inappropriate type." ) % channelNames[i] ) );
		}

		size_t size = despatchTypedData<TypedDataSize>( it->second.data );
		if( size!=numPixels )
		{
			throw Exception( str( format( "Primitive variable \"%s\" has wrong size (%d but should be %d)." ) % channelNames[i] % size % numPixels ) );
		}

		channels.push_back( it->second.data );
	}

	modifyChannels( image->getDisplayWindow(), image->getDataWindow(), channels );
}
<|endoftext|>


<commit_before>/* bzflag
 * Copyright (c) 1993 - 2009 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* interface header */
#include "ComposeDefaultKey.h"

/* system headers */
#include <string>
#include <set>

/* common implementation headers */
#include "BzfEvent.h"
#include "KeyManager.h"
#include "EventHandler.h"

/* local implementation headers */
#include "LocalPlayer.h"
#include "HUDRenderer.h"
#include "LocalCommand.h"
#include "playing.h"
#include "HUDui.h"

#define MAX_MESSAGE_HISTORY (20)

MessageQueue messageHistory;
unsigned int messageHistoryIndex = 0;

static bool isWordCompletion(const BzfKeyEvent& key)
{
  if ((key.chr == 6) || // ^F
      (key.chr== 9) || // <TAB>
      ((key.shift == 0) && (key.button == BzfKeyEvent::F2))) {
    return true;
  } else {
    return false;
  }
}

bool ComposeDefaultKey::keyPress(const BzfKeyEvent& key)
{
  bool sendIt;
  LocalPlayer *myTank = LocalPlayer::getMyTank();
  if (myTank && KEYMGR.get(key, true) == "jump" && BZDB.isTrue("jumpTyping")) {
    // jump while typing
    myTank->setJump();
    return false;
  }

  if (myTank &&
      ((myTank->getInputMethod() != LocalPlayer::Keyboard) ||
       (myTank->getTeam() == ObserverTeam))) {
    if ((key.button == BzfKeyEvent::Up) ||
	(key.button == BzfKeyEvent::Down)) {
      return true;
    }
  }

  if (isWordCompletion(key)) {
    const std::string line = hud->getComposeString();
    std::set<std::string> partials;
    if (!BZDB.isTrue("noDefaultWordComplete")) {
      completer.complete(line, partials);
    }
    eventHandler.WordComplete(line, partials);
    if (!partials.empty()) {
      // find the longest common string
      const std::string first = *(partials.begin());
      const std::string last = *(partials.rbegin());
      size_t i;
      const size_t minLen = std::min(first.size(), last.size());
      for (i = 0; i < minLen; i++) {
        if (first[i] != last[i]) {
          break;
        }
      }
      hud->setComposeString(line + first.substr(0, i));

      if (partials.size() >= 2) {
        const int lastSpace = line.find_last_of(" \t");
        const std::string lastWord = line.substr(lastSpace + 1);

        std::string matches;
        std::set<std::string>::const_iterator it;
        for (it = partials.begin(); it != partials.end(); ++it) {
          matches += "  ";
          matches += lastWord + it->substr(i);
        }
        controlPanel->addMessage(matches, ControlPanel::MessageCurrent);
      }
    }
    return true;
  }

  switch (key.chr) {
    case 3: // ^C
    case 27: { // escape
      sendIt = false; // finished composing -- don't send
      break;
    }
    case 4: // ^D
    case 13: { // return
      sendIt = true;
      break;
    }
    default: {
      return false;
    }
  }

  if (sendIt) {
    std::string message = hud->getComposeString();
    if (message.length() > 0) {
      const char* cmd = message.c_str();
      if (!LocalCommand::execute(cmd)) {
        if (!myTank) {
          std::string msg = std::string("unknown local command: ") + cmd;
          controlPanel->addMessage(msg, ControlPanel::MessageCurrent);
        }
        else if (serverLink) {
          char messageBuffer[MessageLen];
          memset(messageBuffer, 0, MessageLen);
          strncpy(messageBuffer, message.c_str(), MessageLen);
          serverLink->sendMessage(msgDestination, messageBuffer);
        }
      }

      // record message in history
      const size_t mhLen = messageHistory.size();
      size_t i;
      for (i = 0; i < mhLen; i++) {
	if (messageHistory[i] == message) {
	  messageHistory.erase(messageHistory.begin() + i);
	  messageHistory.push_front(message);
	  break;
	}
      }
      if (i == mhLen) {
	if (mhLen >= MAX_MESSAGE_HISTORY) {
	  messageHistory.pop_back();
	}
	messageHistory.push_front(message);
      }
    }
  }

  messageHistoryIndex = 0;
  hud->setComposing(std::string());
  HUDui::setDefaultKey(NULL);
  return true;
}

bool ComposeDefaultKey::keyRelease(const BzfKeyEvent& key)
{
  LocalPlayer* myTank = LocalPlayer::getMyTank();
  if (!myTank ||
      (myTank->getInputMethod() != LocalPlayer::Keyboard) ||
      (myTank->getTeam() == ObserverTeam)) {
    if (key.button == BzfKeyEvent::Up) {
      if (messageHistoryIndex < messageHistory.size()) {
	hud->setComposeString(messageHistory[messageHistoryIndex]);
	messageHistoryIndex++;
      } else {
	hud->setComposeString(std::string());
      }
      return true;
    } else if (key.button == BzfKeyEvent::Down) {
      if (messageHistoryIndex > 0) {
	messageHistoryIndex--;
	hud->setComposeString(messageHistory[messageHistoryIndex]);
      } else {
	hud->setComposeString(std::string());
      }
      return true;
    }
    else if (myTank && ((key.shift == BzfKeyEvent::ShiftKey
			 || (hud->getComposeString().length() == 0)) &&
			(key.button == BzfKeyEvent::Left
			 || key.button == BzfKeyEvent::Right))) {
      // exclude robot from private message recipient.
      // No point sending messages to robot (now)
      selectNextRecipient(key.button != BzfKeyEvent::Left, false);
      const Player *recipient = myTank->getRecipient();
      if (recipient) {
	msgDestination = recipient->getId();
	std::string composePrompt = "Send to ";
	composePrompt += recipient->getCallSign();
	composePrompt += ": ";
	hud->setComposing(composePrompt);
      }
      return false;
    }
  }

  if ((key.chr == 4) || // ^D
      (key.chr == 6) || // ^F
      (key.chr == 13) || // return
      isWordCompletion(key)) {
    return true;
  }

  return keyPress(key);
}

// Local Variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<commit_msg>quell warning<commit_after>/* bzflag
 * Copyright (c) 1993 - 2009 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* interface header */
#include "ComposeDefaultKey.h"

/* system headers */
#include <string>
#include <set>

/* common implementation headers */
#include "BzfEvent.h"
#include "KeyManager.h"
#include "EventHandler.h"

/* local implementation headers */
#include "LocalPlayer.h"
#include "HUDRenderer.h"
#include "LocalCommand.h"
#include "playing.h"
#include "HUDui.h"

#define MAX_MESSAGE_HISTORY (20)

MessageQueue messageHistory;
unsigned int messageHistoryIndex = 0;

static bool isWordCompletion(const BzfKeyEvent& key)
{
  if ((key.chr == 6) || // ^F
      (key.chr== 9) || // <TAB>
      ((key.shift == 0) && (key.button == BzfKeyEvent::F2))) {
    return true;
  } else {
    return false;
  }
}

bool ComposeDefaultKey::keyPress(const BzfKeyEvent& key)
{
  bool sendIt;
  LocalPlayer *myTank = LocalPlayer::getMyTank();
  if (myTank && KEYMGR.get(key, true) == "jump" && BZDB.isTrue("jumpTyping")) {
    // jump while typing
    myTank->setJump();
    return false;
  }

  if (myTank &&
      ((myTank->getInputMethod() != LocalPlayer::Keyboard) ||
       (myTank->getTeam() == ObserverTeam))) {
    if ((key.button == BzfKeyEvent::Up) ||
	(key.button == BzfKeyEvent::Down)) {
      return true;
    }
  }

  if (isWordCompletion(key)) {
    const std::string line = hud->getComposeString();
    std::set<std::string> partials;
    if (!BZDB.isTrue("noDefaultWordComplete")) {
      completer.complete(line, partials);
    }
    eventHandler.WordComplete(line, partials);
    if (!partials.empty()) {
      // find the longest common string
      const std::string first = *(partials.begin());
      const std::string last = *(partials.rbegin());
      size_t i;
      const size_t minLen = std::min(first.size(), last.size());
      for (i = 0; i < minLen; i++) {
        if (first[i] != last[i]) {
          break;
        }
      }
      hud->setComposeString(line + first.substr(0, i));

      if (partials.size() >= 2) {
        const size_t lastSpace = line.find_last_of(" \t");
        const std::string lastWord = line.substr(lastSpace + 1);

        std::string matches;
        std::set<std::string>::const_iterator it;
        for (it = partials.begin(); it != partials.end(); ++it) {
          matches += "  ";
          matches += lastWord + it->substr(i);
        }
        controlPanel->addMessage(matches, ControlPanel::MessageCurrent);
      }
    }
    return true;
  }

  switch (key.chr) {
    case 3: // ^C
    case 27: { // escape
      sendIt = false; // finished composing -- don't send
      break;
    }
    case 4: // ^D
    case 13: { // return
      sendIt = true;
      break;
    }
    default: {
      return false;
    }
  }

  if (sendIt) {
    std::string message = hud->getComposeString();
    if (message.length() > 0) {
      const char* cmd = message.c_str();
      if (!LocalCommand::execute(cmd)) {
        if (!myTank) {
          std::string msg = std::string("unknown local command: ") + cmd;
          controlPanel->addMessage(msg, ControlPanel::MessageCurrent);
        }
        else if (serverLink) {
          char messageBuffer[MessageLen];
          memset(messageBuffer, 0, MessageLen);
          strncpy(messageBuffer, message.c_str(), MessageLen);
          serverLink->sendMessage(msgDestination, messageBuffer);
        }
      }

      // record message in history
      const size_t mhLen = messageHistory.size();
      size_t i;
      for (i = 0; i < mhLen; i++) {
	if (messageHistory[i] == message) {
	  messageHistory.erase(messageHistory.begin() + i);
	  messageHistory.push_front(message);
	  break;
	}
      }
      if (i == mhLen) {
	if (mhLen >= MAX_MESSAGE_HISTORY) {
	  messageHistory.pop_back();
	}
	messageHistory.push_front(message);
      }
    }
  }

  messageHistoryIndex = 0;
  hud->setComposing(std::string());
  HUDui::setDefaultKey(NULL);
  return true;
}

bool ComposeDefaultKey::keyRelease(const BzfKeyEvent& key)
{
  LocalPlayer* myTank = LocalPlayer::getMyTank();
  if (!myTank ||
      (myTank->getInputMethod() != LocalPlayer::Keyboard) ||
      (myTank->getTeam() == ObserverTeam)) {
    if (key.button == BzfKeyEvent::Up) {
      if (messageHistoryIndex < messageHistory.size()) {
	hud->setComposeString(messageHistory[messageHistoryIndex]);
	messageHistoryIndex++;
      } else {
	hud->setComposeString(std::string());
      }
      return true;
    } else if (key.button == BzfKeyEvent::Down) {
      if (messageHistoryIndex > 0) {
	messageHistoryIndex--;
	hud->setComposeString(messageHistory[messageHistoryIndex]);
      } else {
	hud->setComposeString(std::string());
      }
      return true;
    }
    else if (myTank && ((key.shift == BzfKeyEvent::ShiftKey
			 || (hud->getComposeString().length() == 0)) &&
			(key.button == BzfKeyEvent::Left
			 || key.button == BzfKeyEvent::Right))) {
      // exclude robot from private message recipient.
      // No point sending messages to robot (now)
      selectNextRecipient(key.button != BzfKeyEvent::Left, false);
      const Player *recipient = myTank->getRecipient();
      if (recipient) {
	msgDestination = recipient->getId();
	std::string composePrompt = "Send to ";
	composePrompt += recipient->getCallSign();
	composePrompt += ": ";
	hud->setComposing(composePrompt);
      }
      return false;
    }
  }

  if ((key.chr == 4) || // ^D
      (key.chr == 6) || // ^F
      (key.chr == 13) || // return
      isWordCompletion(key)) {
    return true;
  }

  return keyPress(key);
}

// Local Variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<|endoftext|>


<commit_before>/*

Copyright (c) 2012, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author 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 "libtorrent/config.hpp"
#include "libtorrent/rss.hpp"
#include "libtorrent/fingerprint.hpp"
#include "libtorrent/aux_/session_impl.hpp"
#include "libtorrent/http_parser.hpp"

#include "test.hpp"

using namespace libtorrent;

void print_feed(feed_status const& f)
{
	fprintf(stderr, "FEED: %s\n",f.url.c_str());
	if (f.error)
		fprintf(stderr, "ERROR: %s\n", f.error.message().c_str());

	fprintf(stderr, "   %s\n   %s\n", f.title.c_str(), f.description.c_str());
	fprintf(stderr, "   ttl: %d minutes\n", f.ttl);
	fprintf(stderr, "   num items: %d\n", int(f.items.size()));

	for (std::vector<feed_item>::const_iterator i = f.items.begin()
		, end(f.items.end()); i != end; ++i)
	{
		fprintf(stderr, "\033[32m%s\033[0m\n------------------------------------------------------\n"
			"   url: %s\n   size: %"PRId64"\n   info-hash: %s\n   uuid: %s\n   description: %s\n"
			"   comment: %s\n   category: %s\n"
			, i->title.c_str(), i->url.c_str(), i->size
			, i->info_hash.is_all_zeros() ? "" : to_hex(i->info_hash.to_string()).c_str()
			, i->uuid.c_str(), i->description.c_str(), i->comment.c_str(), i->category.c_str());
	}
}

struct rss_expect
{
	rss_expect(int nitems, std::string url, std::string title, size_type size)
		: num_items(nitems), first_url(url), first_title(title), first_size(size)
	{}

	int num_items;
	std::string first_url;
	std::string first_title;
	size_type first_size;
};

void test_feed(std::string const& filename, rss_expect const& expect)
{
	std::vector<char> buffer;
	error_code ec;
	load_file(filename, buffer, ec);
	TEST_CHECK(!ec);

	char* buf = &buffer[0];
	int len = buffer.size();

	char const header[] = "HTTP/1.1 200 OK\r\n"
		"\r\n";

	boost::shared_ptr<aux::session_impl> s = boost::shared_ptr<aux::session_impl>(new aux::session_impl(
		std::make_pair(100, 200), fingerprint("TT", 0, 0, 0 ,0), NULL, 0
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
				, "."
#endif
		));
	s->start_session();

	feed_settings sett;
	sett.auto_download = false;
	sett.auto_map_handles = false;
	boost::shared_ptr<feed> f = boost::shared_ptr<feed>(new feed(*s, sett));
	http_parser parser;
	bool err = false;
	parser.incoming(buffer::const_interval(header, header + sizeof(header)-1), err);
	TEST_CHECK(err == false);

	f->on_feed(error_code(), parser, buf, len);

	feed_status st;
	f->get_feed_status(&st);
	TEST_CHECK(!st.error);

	print_feed(st);

	TEST_CHECK(st.items.size() == expect.num_items);
	if (st.items.size() > 0)
	{
		TEST_CHECK(st.items[0].url == expect.first_url);
		TEST_CHECK(st.items[0].size == expect.first_size);
		TEST_CHECK(st.items[0].title == expect.first_title);
	}

	entry state;
	f->save_state(state);

	fprintf(stderr, "feed_state:\n");
#ifdef TORRENT_DEBUG
	state.print(std::cerr);
#endif

	// TODO: verify some key state is saved in 'state'
}

int test_main()
{
	test_feed("eztv.xml", rss_expect(30, "http://torrent.zoink.it/The.Daily.Show.2012.02.16.(HDTV-LMAO)[VTV].torrent", "The Daily Show 2012-02-16 [HDTV - LMAO]", 183442338));
	test_feed("cb.xml", rss_expect(50, "http://www.clearbits.net/get/1911-norbergfestival-2011.torrent", "Norbergfestival 2011", 1160773632));
	test_feed("kat.xml", rss_expect(25, "http://kat.ph/torrents/benito-di-paula-1975-benito-di-paula-lp-rip-ogg-at-500-jarax4u-t6194897/", "Benito Di Paula - 1975 - Benito Di Paula (LP Rip OGG at 500) [jarax4u]", 168773863));
	test_feed("mn.xml", rss_expect(20, "http://www.mininova.org/get/13203100", "Dexcell - January TwentyTwelve Mix", 137311179));
	test_feed("pb.xml", rss_expect(60, "magnet:?xt=urn:btih:FD4CDDB7BBE722D17A018EFD875EB0695ED7159C&dn=Thompson+Twins+-+1989+-+Big+Trash+%5BMP3%5D", "Thompson Twins - 1989 - Big Trash [MP3]", 100160904));
	return 0;
}

<commit_msg>fix test_rss build<commit_after>/*

Copyright (c) 2012, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author 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 "libtorrent/config.hpp"
#include "libtorrent/rss.hpp"
#include "libtorrent/fingerprint.hpp"
#include "libtorrent/aux_/session_impl.hpp"
#include "libtorrent/http_parser.hpp"

#include "test.hpp"

using namespace libtorrent;

void print_feed(feed_status const& f)
{
	fprintf(stderr, "FEED: %s\n",f.url.c_str());
	if (f.error)
		fprintf(stderr, "ERROR: %s\n", f.error.message().c_str());

	fprintf(stderr, "   %s\n   %s\n", f.title.c_str(), f.description.c_str());
	fprintf(stderr, "   ttl: %d minutes\n", f.ttl);
	fprintf(stderr, "   num items: %d\n", int(f.items.size()));

	for (std::vector<feed_item>::const_iterator i = f.items.begin()
		, end(f.items.end()); i != end; ++i)
	{
		fprintf(stderr, "\033[32m%s\033[0m\n------------------------------------------------------\n"
			"   url: %s\n   size: %"PRId64"\n   info-hash: %s\n   uuid: %s\n   description: %s\n"
			"   comment: %s\n   category: %s\n"
			, i->title.c_str(), i->url.c_str(), i->size
			, i->info_hash.is_all_zeros() ? "" : to_hex(i->info_hash.to_string()).c_str()
			, i->uuid.c_str(), i->description.c_str(), i->comment.c_str(), i->category.c_str());
	}
}

struct rss_expect
{
	rss_expect(int nitems, std::string url, std::string title, size_type size)
		: num_items(nitems), first_url(url), first_title(title), first_size(size)
	{}

	int num_items;
	std::string first_url;
	std::string first_title;
	size_type first_size;
};

void test_feed(std::string const& filename, rss_expect const& expect)
{
	std::vector<char> buffer;
	error_code ec;
	load_file(filename, buffer, ec);
	TEST_CHECK(!ec);

	char* buf = &buffer[0];
	int len = buffer.size();

	char const header[] = "HTTP/1.1 200 OK\r\n"
		"\r\n";

	boost::shared_ptr<aux::session_impl> s = boost::shared_ptr<aux::session_impl>(new aux::session_impl(
		std::make_pair(100, 200), fingerprint("TT", 0, 0, 0 ,0), NULL, 0));
	s->start_session();

	feed_settings sett;
	sett.auto_download = false;
	sett.auto_map_handles = false;
	boost::shared_ptr<feed> f = boost::shared_ptr<feed>(new feed(*s, sett));
	http_parser parser;
	bool err = false;
	parser.incoming(buffer::const_interval(header, header + sizeof(header)-1), err);
	TEST_CHECK(err == false);

	f->on_feed(error_code(), parser, buf, len);

	feed_status st;
	f->get_feed_status(&st);
	TEST_CHECK(!st.error);

	print_feed(st);

	TEST_CHECK(st.items.size() == expect.num_items);
	if (st.items.size() > 0)
	{
		TEST_CHECK(st.items[0].url == expect.first_url);
		TEST_CHECK(st.items[0].size == expect.first_size);
		TEST_CHECK(st.items[0].title == expect.first_title);
	}

	entry state;
	f->save_state(state);

	fprintf(stderr, "feed_state:\n");
#ifdef TORRENT_DEBUG
	state.print(std::cerr);
#endif

	// TODO: verify some key state is saved in 'state'
}

int test_main()
{
	test_feed("eztv.xml", rss_expect(30, "http://torrent.zoink.it/The.Daily.Show.2012.02.16.(HDTV-LMAO)[VTV].torrent", "The Daily Show 2012-02-16 [HDTV - LMAO]", 183442338));
	test_feed("cb.xml", rss_expect(50, "http://www.clearbits.net/get/1911-norbergfestival-2011.torrent", "Norbergfestival 2011", 1160773632));
	test_feed("kat.xml", rss_expect(25, "http://kat.ph/torrents/benito-di-paula-1975-benito-di-paula-lp-rip-ogg-at-500-jarax4u-t6194897/", "Benito Di Paula - 1975 - Benito Di Paula (LP Rip OGG at 500) [jarax4u]", 168773863));
	test_feed("mn.xml", rss_expect(20, "http://www.mininova.org/get/13203100", "Dexcell - January TwentyTwelve Mix", 137311179));
	test_feed("pb.xml", rss_expect(60, "magnet:?xt=urn:btih:FD4CDDB7BBE722D17A018EFD875EB0695ED7159C&dn=Thompson+Twins+-+1989+-+Big+Trash+%5BMP3%5D", "Thompson Twins - 1989 - Big Trash [MP3]", 100160904));
	return 0;
}

<|endoftext|>


<commit_before>/*

Copyright (c) 2013, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author 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 "libtorrent/session.hpp"
#include "libtorrent/alert_types.hpp"
#include "libtorrent/thread.hpp"
#include "libtorrent/file.hpp"
#include <boost/bind.hpp>
#include <boost/tuple/tuple.hpp>

#include "test.hpp"
#include "setup_transfer.hpp"
#include <fstream>
#include <iostream>

using namespace libtorrent;
using boost::tuples::ignore;

int const alert_mask = alert::all_categories
& ~alert::progress_notification
& ~alert::stats_notification;

struct test_config_t
{
	char const* name;
	bool use_ssl_ports;
	bool seed_has_cert;
	bool downloader_has_cert;
	bool expected_to_complete;
};

test_config_t test_config[] =
{
	{"nobody has a cert (connect to regular port)", false, false, false, false},
	{"nobody has a cert (connect to ssl port)", true, false, false, false},
	{"seed has a cert, but not downloader (connect to regular port)", false, true, false, false},
	{"seed has a cert, but not downloader (connect to ssl port)", true, true, false, false},
	{"downloader has a cert, but not seed (connect to regular port)", false, false, true, false},
	{"downloader has a cert, but not seed (connect to ssl port)", true, false, true, false},
	{"both downloader and seed has a cert (connect to regular port)", false, true, true, false},
#ifdef TORRENT_USE_OPENSSL
	{"both downloader and seed has a cert (connect to ssl port)", true, true, true, true},
#else
	{"both downloader and seed has a cert (connect to ssl port)", true, true, true, false},
#endif
};

int peer_disconnects = 0;

bool predicate(alert* a)
{
	if (peer_disconnected_alert* p = alert_cast<peer_disconnected_alert>(a))
		++peer_disconnects;
	return false;
}

void test_ssl(int test_idx)
{
	test_config_t const& test = test_config[test_idx];

	fprintf(stderr, "\n%s TEST: %s\n\n", time_now_string(), test.name);

	// in case the previous run was terminated
	error_code ec;
	remove_all("tmp1_ssl", ec);
	remove_all("tmp2_ssl", ec);

	session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48075, 49000), "0.0.0.0", 0, alert_mask);
	session ses2(fingerprint("LT", 0, 1, 0, 0), std::make_pair(49075, 50000), "0.0.0.0", 0, alert_mask);

	session_settings sett;
	// this disables outgoing SSL connections
	sett.ssl_listen = 0;
	if (!test.downloader_has_cert) ses2.set_settings(sett);

	torrent_handle tor1;
	torrent_handle tor2;

	create_directory("tmp1_ssl", ec);
	std::ofstream file("tmp1_ssl/temporary");
	boost::intrusive_ptr<torrent_info> t = ::create_torrent(&file, 16 * 1024, 13, false, "ssl/root_ca_cert.pem");
	file.close();

	add_torrent_params addp;
	addp.flags &= ~add_torrent_params::flag_paused;
	addp.flags &= ~add_torrent_params::flag_auto_managed;

	wait_for_listen(ses1, "ses1");
	wait_for_listen(ses2, "ses1");

	peer_disconnects = 0;

	boost::tie(tor1, tor2, ignore) = setup_transfer(&ses1, &ses2, 0
		, true, false, true, "_ssl", 16 * 1024, &t, false, NULL, true, test.use_ssl_ports);

	if (test.seed_has_cert)
	{
		tor1.set_ssl_certificate(combine_path("ssl", "peer_certificate.pem")
			, combine_path("ssl", "peer_private_key.pem")
			, combine_path("ssl", "dhparams.pem")
			, "test");
	}

	if (test.downloader_has_cert)
	{
		tor2.set_ssl_certificate(combine_path("ssl", "peer_certificate.pem")
			, combine_path("ssl", "peer_private_key.pem")
			, combine_path("ssl", "dhparams.pem")
			, "test");
	}

	for (int i = 0; i < 15; ++i)
	{
		print_alerts(ses1, "ses1", true, true, true, &predicate);
		print_alerts(ses2, "ses2", true, true, true, &predicate);

		torrent_status st1 = tor1.status();
		torrent_status st2 = tor2.status();

		if (i % 10 == 0)
		{
			std::cerr << time_now_string() << " "
				<< "\033[32m" << int(st1.download_payload_rate / 1000.f) << "kB/s "
				<< "\033[33m" << int(st1.upload_payload_rate / 1000.f) << "kB/s "
				<< "\033[0m" << int(st1.progress * 100) << "% "
				<< st1.num_peers
				<< ": "
				<< "\033[32m" << int(st2.download_payload_rate / 1000.f) << "kB/s "
				<< "\033[31m" << int(st2.upload_payload_rate / 1000.f) << "kB/s "
				<< "\033[0m" << int(st2.progress * 100) << "% "
				<< st2.num_peers
				<< " cc: " << st2.connect_candidates
				<< std::endl;
		}

		if (peer_disconnects == 2) break;

		if (st2.is_finished) break;

		if (st2.state != torrent_status::downloading)
		{
			static char const* state_str[] =
				{"checking (q)", "checking", "dl metadata"
				, "downloading", "finished", "seeding", "allocating", "checking (r)"};
			std::cerr << "st2 state: " << state_str[st2.state] << std::endl;
		}

		TEST_CHECK(st1.state == torrent_status::seeding
			|| st1.state == torrent_status::checking_files);
		TEST_CHECK(st2.state == torrent_status::downloading);

		test_sleep(100);
	}

	TEST_CHECK(tor2.status().is_seeding == test.expected_to_complete);
}

int test_main()
{
	using namespace libtorrent;

	for (int i = 0; i < sizeof(test_config)/sizeof(test_config[0]); ++i)
		test_ssl(i);

	error_code ec;
	remove_all("tmp1_ssl", ec);
	remove_all("tmp2_ssl", ec);

	return 0;
}

<commit_msg>fix test_ssl for trunk, where tests are run in separate directories<commit_after>/*

Copyright (c) 2013, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author 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 "libtorrent/session.hpp"
#include "libtorrent/alert_types.hpp"
#include "libtorrent/thread.hpp"
#include "libtorrent/file.hpp"
#include <boost/bind.hpp>
#include <boost/tuple/tuple.hpp>

#include "test.hpp"
#include "setup_transfer.hpp"
#include <fstream>
#include <iostream>

using namespace libtorrent;
using boost::tuples::ignore;

int const alert_mask = alert::all_categories
& ~alert::progress_notification
& ~alert::stats_notification;

struct test_config_t
{
	char const* name;
	bool use_ssl_ports;
	bool seed_has_cert;
	bool downloader_has_cert;
	bool expected_to_complete;
};

test_config_t test_config[] =
{
	{"nobody has a cert (connect to regular port)", false, false, false, false},
	{"nobody has a cert (connect to ssl port)", true, false, false, false},
	{"seed has a cert, but not downloader (connect to regular port)", false, true, false, false},
	{"seed has a cert, but not downloader (connect to ssl port)", true, true, false, false},
	{"downloader has a cert, but not seed (connect to regular port)", false, false, true, false},
	{"downloader has a cert, but not seed (connect to ssl port)", true, false, true, false},
	{"both downloader and seed has a cert (connect to regular port)", false, true, true, false},
#ifdef TORRENT_USE_OPENSSL
	{"both downloader and seed has a cert (connect to ssl port)", true, true, true, true},
#else
	{"both downloader and seed has a cert (connect to ssl port)", true, true, true, false},
#endif
};

int peer_disconnects = 0;

bool predicate(alert* a)
{
	if (peer_disconnected_alert* p = alert_cast<peer_disconnected_alert>(a))
		++peer_disconnects;
	return false;
}

void test_ssl(int test_idx)
{
	test_config_t const& test = test_config[test_idx];

	fprintf(stderr, "\n%s TEST: %s\n\n", time_now_string(), test.name);

	// in case the previous run was terminated
	error_code ec;
	remove_all("tmp1_ssl", ec);
	remove_all("tmp2_ssl", ec);

	session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48075, 49000), "0.0.0.0", 0, alert_mask);
	session ses2(fingerprint("LT", 0, 1, 0, 0), std::make_pair(49075, 50000), "0.0.0.0", 0, alert_mask);

	session_settings sett;
	// this disables outgoing SSL connections
	sett.ssl_listen = 0;
	if (!test.downloader_has_cert) ses2.set_settings(sett);

	torrent_handle tor1;
	torrent_handle tor2;

	create_directory("tmp1_ssl", ec);
	std::ofstream file("tmp1_ssl/temporary");
	boost::intrusive_ptr<torrent_info> t = ::create_torrent(&file, 16 * 1024, 13, false, "../ssl/root_ca_cert.pem");
	file.close();

	add_torrent_params addp;
	addp.flags &= ~add_torrent_params::flag_paused;
	addp.flags &= ~add_torrent_params::flag_auto_managed;

	wait_for_listen(ses1, "ses1");
	wait_for_listen(ses2, "ses1");

	peer_disconnects = 0;

	boost::tie(tor1, tor2, ignore) = setup_transfer(&ses1, &ses2, 0
		, true, false, true, "_ssl", 16 * 1024, &t, false, NULL, true, test.use_ssl_ports);

	if (test.seed_has_cert)
	{
		tor1.set_ssl_certificate(
			combine_path("..", combine_path("ssl", "peer_certificate.pem"))
			, combine_path("..", combine_path("ssl", "peer_private_key.pem"))
			, combine_path("..", combine_path("ssl", "dhparams.pem"))
			, "test");
	}

	if (test.downloader_has_cert)
	{
		tor2.set_ssl_certificate(
			combine_path("..", combine_path("ssl", "peer_certificate.pem"))
			, combine_path("..", combine_path("ssl", "peer_private_key.pem"))
			, combine_path("..", combine_path("ssl", "dhparams.pem"))
			, "test");
	}

	for (int i = 0; i < 15; ++i)
	{
		print_alerts(ses1, "ses1", true, true, true, &predicate);
		print_alerts(ses2, "ses2", true, true, true, &predicate);

		torrent_status st1 = tor1.status();
		torrent_status st2 = tor2.status();

		if (i % 10 == 0)
		{
			std::cerr << time_now_string() << " "
				<< "\033[32m" << int(st1.download_payload_rate / 1000.f) << "kB/s "
				<< "\033[33m" << int(st1.upload_payload_rate / 1000.f) << "kB/s "
				<< "\033[0m" << int(st1.progress * 100) << "% "
				<< st1.num_peers
				<< ": "
				<< "\033[32m" << int(st2.download_payload_rate / 1000.f) << "kB/s "
				<< "\033[31m" << int(st2.upload_payload_rate / 1000.f) << "kB/s "
				<< "\033[0m" << int(st2.progress * 100) << "% "
				<< st2.num_peers
				<< " cc: " << st2.connect_candidates
				<< std::endl;
		}

		if (peer_disconnects == 2) break;

		if (st2.is_finished) break;

		if (st2.state != torrent_status::downloading)
		{
			static char const* state_str[] =
				{"checking (q)", "checking", "dl metadata"
				, "downloading", "finished", "seeding", "allocating", "checking (r)"};
			std::cerr << "st2 state: " << state_str[st2.state] << std::endl;
		}

		TEST_CHECK(st1.state == torrent_status::seeding
			|| st1.state == torrent_status::checking_files);
		TEST_CHECK(st2.state == torrent_status::downloading);

		test_sleep(100);
	}

	TEST_CHECK(tor2.status().is_seeding == test.expected_to_complete);
}

int test_main()
{
	using namespace libtorrent;

	for (int i = 0; i < sizeof(test_config)/sizeof(test_config[0]); ++i)
		test_ssl(i);

	error_code ec;
	remove_all("tmp1_ssl", ec);
	remove_all("tmp2_ssl", ec);

	return 0;
}

<|endoftext|>


<commit_before>#include <iostream>
#include <vector>
#include <exception>

#include "Trace.h"
#include "ServerEngine.h"
#include "NodeSfc.h"
#include "NodeDCMotor.h"
#include "NodePid.h"
#include "NodePython.h"
#include "NodePass.h"
#include "NodeTimer.h"
#include "NodeServo.h"
#include "ConfigReader.h"
#include "NodeDb.h"
#include "Process.h"
#include "SocketClient.h"

using namespace Arro;
using namespace std;

//Process::Process(NodeDb& db, const string& instance):
//    RealNode{},
//    m_trace{"Process", true},
//    m_nodeDb{db},
//    m_device{nullptr},
//    m_doRunCycle{false},
//    m_name{instance},
//    m_webComponents(nullptr) {
//
//    m_trace.println("Creating sfc " + instance + "._sfc");
//
//    m_trace.println("---> Never used?? <--- ");
//
//    db.registerNode(this, instance + "._sfc");
//
//}

Process::Process(NodeDb& db, const string& url, const string& instance, StringMap params, TiXmlElement* elt):
    RealNode{},
    m_trace{"Process", true},
    m_nodeDb{db},
    m_device{nullptr},
    m_doRunCycle{false},
    m_name{instance} {

    m_trace.println("Creating instance of " + url);

    getPrimitive(url, instance, params, elt);

    std::map<std::string, std::string>::iterator iter;

    for (iter = params.begin(); iter != params.end(); ++iter) {
        m_trace.println("    parameter " + iter->first + " " + iter->second);

        auto kv = new arro::KeyValuePair();
        kv->set_key(iter->first.c_str());
        kv->set_value(iter->second.c_str());
        MessageBuf msg(new string(kv->SerializeAsString()));
        free(kv);
        m_device->handleMessage(msg, "config");
    }

    db.registerNode(this, instance);

}

Process::~Process() {
    if(m_device) delete m_device;
}

void
Process::sendParameters(StringMap& params) {
    std::map<std::string, std::string>::iterator iter;

//    auto block = new arro::ParameterBlock();
//
//    for (iter = params.begin(); iter != params.end(); ++iter) {
//        m_trace.println("    parameter " + iter->first + " " + iter->second);
//
//        auto kv = block->add_kv();
//
//        kv->set_key(iter->first.c_str());
//        kv->set_value(iter->second.c_str());
//    }
//
    auto config = new arro::_Config();

    auto map = config->value();
    for (iter = params.begin(); iter != params.end(); ++iter) {
        m_trace.println("    parameter " + iter->first + " " + iter->second);

        map[iter->first] = iter->second;
    }

    //MessageBuf msg(new string(block->SerializeAsString()));
    //free(block);
    MessageBuf msg(new string(config->SerializeAsString()));
    free(config);

    // get _config input and send a message to it.
    auto input = getInput("_config");
    input->handleMessage(msg);
}

void
Process::runCycle() {
    if(m_doRunCycle) {
        m_device->runCycle();
        m_doRunCycle = false;
    }
}

void
Process::registerInput(const string& interfName, bool enableRunCycle) {
    // only need to capture enableRunCycle
    m_nodeDb.registerNodeInput(this, interfName, [=](const MessageBuf& msg, const std::string& interfaceName) {
        if(enableRunCycle) {
            m_doRunCycle = true;
        }
        m_device->handleMessage(msg, interfaceName);
    });
}

void
Process::registerOutput(const string& interfaceName) {
    m_nodeDb.registerNodeOutput(this, interfaceName);
}

/**
 *
 * @param input
 * @return Shared pointer to message. Note: if not initialized then
 * pointer may be nullptr.
 */
MessageBuf
Process::getInputData(NodeSingleInput* input) const {
    return input->getData();
}

NodeSingleInput*
Process::getInput(const string& name) const {
    auto in = m_nodeDb.getInput(getName() + "." + name);
    if(in) {
        return in;
    } else {
        m_trace.println("no such input registered: " + getName() + "." + name);
        SendToConsole(string("Program uses unknown input: ") + getName() + "." + name);
        throw std::runtime_error("No such input registered: " + getName() + "." + name);
    }
}

NodeMultiOutput*
Process::getOutput(const string& name) const {
    auto out = m_nodeDb.getOutput(getName() + "." + name);
    if(out) {
        return out;
    } else {
        m_trace.println("no such output registered: " + getName() + "." + name);
        SendToConsole(string("Program uses unknown output: ") + getName() + "." + name);
        throw std::runtime_error("No such output registered: " + getName() + "." + name);
    }
}

void
Process::setOutputData(NodeMultiOutput* output, google::protobuf::MessageLite* value) const {
    output->submitMessage(value);
}

void
Process::getPrimitive(const string& url, const string& instance, StringMap& params, TiXmlElement* elt) {
    m_device = nullptr;
    Factory factory;

    if(url.find("Python:") == 0) {
        m_trace.println("new NodePython(" + instance + ")");
        try {
            string className = url.substr(7);
            if(ServerEngine::getFactory("Python", factory)) {
                m_device = factory(this, className, params, nullptr);
            }
        } catch(out_of_range &) {
            throw std::runtime_error("Invalid URL for Python node " + url);
        }
    } else if(url.find("UiIn:") == 0) {
        m_trace.println("new NodeUiIn(" + instance + ")");
        try {
            if(ServerEngine::getFactory("_UiUserInput", factory)) {
                m_device = factory(this, "", params, elt);
            }
        } catch(out_of_range &) {
            throw std::runtime_error("Invalid URL for SFC node " + url);
        }
    } else if(url.find("UiOut:") == 0) {
        m_trace.println("new NodeUiOut(" + instance + ")");
        try {
            if(ServerEngine::getFactory("_UiUserDisplay", factory)) {
                m_device = factory(this, "", params, elt);
            }
        } catch(out_of_range &) {
            throw std::runtime_error("Invalid URL for SFC node " + url);
        }
    } else if(url.find("Sfc:") == 0) {
        StringMap params{};
        m_trace.println("new NodeSfc(" + instance + ")");
        try {
            if(ServerEngine::getFactory("_SFC", factory)) {
                m_device = factory(this, "", params, elt);
            }
        } catch(out_of_range &) {
            throw std::runtime_error("Invalid URL for SFC node " + url);
        }
    }
    else if(url.find("Native:") == 0) {
        try {
            string className = url.substr(7);

            if(className == "pass") {
            }
            else if(ServerEngine::getFactory(className, factory)) {
                m_trace.println("new " + className + "(" + instance + ")");
                m_device = factory(this, instance, params, nullptr);
            }
            else {
                m_trace.println("unknown node" + instance );
                SendToConsole(string("unknown node ") + className);
            }
        } catch(out_of_range &) {
            m_trace.println("native node not found");
        }
    }
    if(m_device == nullptr) {
        m_trace.println("Node module not found " + url);
        throw std::runtime_error("Node module not found " + url);
    }
}

/**
 * TODO this is not the happiest function, it is for SFC only. Should be something more elegant.
 * @param sfc
 */
void
Process::registerSfc(const std::string& name, Process* sfc) {
    ((NodeSfc*)m_device)->registerSfc(name, (NodeSfc*)(sfc->m_device));
}

<commit_msg>Improve parameter passing using _Config<commit_after>#include <iostream>
#include <vector>
#include <exception>

#include "Trace.h"
#include "ServerEngine.h"
#include "NodeSfc.h"
#include "NodeDCMotor.h"
#include "NodePid.h"
#include "NodePython.h"
#include "NodePass.h"
#include "NodeTimer.h"
#include "NodeServo.h"
#include "ConfigReader.h"
#include "NodeDb.h"
#include "Process.h"
#include "SocketClient.h"

using namespace Arro;
using namespace std;

//Process::Process(NodeDb& db, const string& instance):
//    RealNode{},
//    m_trace{"Process", true},
//    m_nodeDb{db},
//    m_device{nullptr},
//    m_doRunCycle{false},
//    m_name{instance},
//    m_webComponents(nullptr) {
//
//    m_trace.println("Creating sfc " + instance + "._sfc");
//
//    m_trace.println("---> Never used?? <--- ");
//
//    db.registerNode(this, instance + "._sfc");
//
//}

Process::Process(NodeDb& db, const string& url, const string& instance, StringMap params, TiXmlElement* elt):
    RealNode{},
    m_trace{"Process", true},
    m_nodeDb{db},
    m_device{nullptr},
    m_doRunCycle{false},
    m_name{instance} {

    m_trace.println("Creating instance of " + url);

    getPrimitive(url, instance, params, elt);

    std::map<std::string, std::string>::iterator iter;

    for (iter = params.begin(); iter != params.end(); ++iter) {
        m_trace.println("    parameter " + iter->first + " " + iter->second);

        auto kv = new arro::KeyValuePair();
        kv->set_key(iter->first.c_str());
        kv->set_value(iter->second.c_str());
        MessageBuf msg(new string(kv->SerializeAsString()));
        free(kv);
        m_device->handleMessage(msg, "config");
    }

    db.registerNode(this, instance);

}

Process::~Process() {
    if(m_device) delete m_device;
}

void
Process::sendParameters(StringMap& params) {
    std::map<std::string, std::string>::iterator iter;

    auto config = new arro::_Config();

    auto map = config->value();
    for (iter = params.begin(); iter != params.end(); ++iter) {
        m_trace.println("    parameter " + iter->first + " " + iter->second);

        (*config->mutable_value())[iter->first] = iter->second;
    }

    MessageBuf msg(new string(config->SerializeAsString()));
    free(config);

    // get _config input and send a message to it.
    auto input = getInput("_config");
    input->handleMessage(msg);
}

void
Process::runCycle() {
    if(m_doRunCycle) {
        m_device->runCycle();
        m_doRunCycle = false;
    }
}

void
Process::registerInput(const string& interfName, bool enableRunCycle) {
    // only need to capture enableRunCycle
    m_nodeDb.registerNodeInput(this, interfName, [=](const MessageBuf& msg, const std::string& interfaceName) {
        if(enableRunCycle) {
            m_doRunCycle = true;
        }
        m_device->handleMessage(msg, interfaceName);
    });
}

void
Process::registerOutput(const string& interfaceName) {
    m_nodeDb.registerNodeOutput(this, interfaceName);
}

/**
 *
 * @param input
 * @return Shared pointer to message. Note: if not initialized then
 * pointer may be nullptr.
 */
MessageBuf
Process::getInputData(NodeSingleInput* input) const {
    return input->getData();
}

NodeSingleInput*
Process::getInput(const string& name) const {
    auto in = m_nodeDb.getInput(getName() + "." + name);
    if(in) {
        return in;
    } else {
        m_trace.println("no such input registered: " + getName() + "." + name);
        SendToConsole(string("Program uses unknown input: ") + getName() + "." + name);
        throw std::runtime_error("No such input registered: " + getName() + "." + name);
    }
}

NodeMultiOutput*
Process::getOutput(const string& name) const {
    auto out = m_nodeDb.getOutput(getName() + "." + name);
    if(out) {
        return out;
    } else {
        m_trace.println("no such output registered: " + getName() + "." + name);
        SendToConsole(string("Program uses unknown output: ") + getName() + "." + name);
        throw std::runtime_error("No such output registered: " + getName() + "." + name);
    }
}

void
Process::setOutputData(NodeMultiOutput* output, google::protobuf::MessageLite* value) const {
    output->submitMessage(value);
}

void
Process::getPrimitive(const string& url, const string& instance, StringMap& params, TiXmlElement* elt) {
    m_device = nullptr;
    Factory factory;

    if(url.find("Python:") == 0) {
        m_trace.println("new NodePython(" + instance + ")");
        try {
            string className = url.substr(7);
            if(ServerEngine::getFactory("Python", factory)) {
                m_device = factory(this, className, params, nullptr);
            }
        } catch(out_of_range &) {
            throw std::runtime_error("Invalid URL for Python node " + url);
        }
    } else if(url.find("UiIn:") == 0) {
        m_trace.println("new NodeUiIn(" + instance + ")");
        try {
            if(ServerEngine::getFactory("_UiUserInput", factory)) {
                m_device = factory(this, "", params, elt);
            }
        } catch(out_of_range &) {
            throw std::runtime_error("Invalid URL for SFC node " + url);
        }
    } else if(url.find("UiOut:") == 0) {
        m_trace.println("new NodeUiOut(" + instance + ")");
        try {
            if(ServerEngine::getFactory("_UiUserDisplay", factory)) {
                m_device = factory(this, "", params, elt);
            }
        } catch(out_of_range &) {
            throw std::runtime_error("Invalid URL for SFC node " + url);
        }
    } else if(url.find("Sfc:") == 0) {
        StringMap params{};
        m_trace.println("new NodeSfc(" + instance + ")");
        try {
            if(ServerEngine::getFactory("_SFC", factory)) {
                m_device = factory(this, "", params, elt);
            }
        } catch(out_of_range &) {
            throw std::runtime_error("Invalid URL for SFC node " + url);
        }
    }
    else if(url.find("Native:") == 0) {
        try {
            string className = url.substr(7);

            if(className == "pass") {
            }
            else if(ServerEngine::getFactory(className, factory)) {
                m_trace.println("new " + className + "(" + instance + ")");
                m_device = factory(this, instance, params, nullptr);
            }
            else {
                m_trace.println("unknown node" + instance );
                SendToConsole(string("unknown node ") + className);
            }
        } catch(out_of_range &) {
            m_trace.println("native node not found");
        }
    }
    if(m_device == nullptr) {
        m_trace.println("Node module not found " + url);
        throw std::runtime_error("Node module not found " + url);
    }
}

/**
 * TODO this is not the happiest function, it is for SFC only. Should be something more elegant.
 * @param sfc
 */
void
Process::registerSfc(const std::string& name, Process* sfc) {
    ((NodeSfc*)m_device)->registerSfc(name, (NodeSfc*)(sfc->m_device));
}

<|endoftext|>


<commit_before>#include <Flash.h>

bool FlashClass::erasePage(void* adr) {
    NVMADDR = KVA_TO_PA((unsigned int) adr);
    return doNvmOp(nvmopErasePage);
}

bool FlashClass::writeWord(void* adr, uint32_t val) {
    NVMADDR = KVA_TO_PA((unsigned int) adr);
    NVMDATA = val;
    return doNvmOp(nvmopWriteWord);
}

bool FlashClass::writeRow(void* adr, void *val) {
	bool blank = true;
	for (int i = 0; i < ROW_SIZE; i++) {
		if (((char *)val)[i] != 0xFF) {
			blank = false;
		}
	}
	if (blank) {
		return 0;
	}
    NVMADDR = KVA_TO_PA((unsigned int) adr);
    NVMSRCADDR = KVA_TO_PA((uint32_t)val);
    return doNvmOp(nvmopWriteRow);
}

bool FlashClass::clearNvmError() {
	return doNvmOp(nvmopNop);
}

bool FlashClass::isNvmError() {
	return (NVMCON & (_NVMCON_WRERR_MASK | _NVMCON_LVDERR_MASK)) ? true : false;
}

bool __attribute__((nomips16)) FlashClass::doNvmOp(uint32_t nvmop) {
    int         nvmSt;
    int         intSt;
    uint32_t    tm;

    // M00TODO: When DMA operations are supported in the core, need
    // to add code here to suspend DMA during the NVM operation.

    intSt = disableInterrupts();
    NVMCON = NVMCON_WREN | nvmop;

    tm = _CP0_GET_COUNT();
    while (_CP0_GET_COUNT() - tm < ((F_CPU * 6) / 2000000));

    NVMKEY      = 0xAA996655;
    NVMKEY      = 0x556699AA;
    NVMCONSET   = NVMCON_WR;

    while (NVMCON & NVMCON_WR) {
		continue;
    }

    NVMCONCLR = NVMCON_WREN;

    //M00TODO: Resume a suspended DMA operation

    restoreInterrupts(intSt);
    return(isNvmError());
}

bool FlashClass::loadPage(void *adr) {
    uint32_t *ptr = (uint32_t *)adr;

    ptr = (uint32_t *)((uint32_t)ptr & ~((PAGE_SIZE*4)-1));
    _page_address = (uint32_t)ptr;

    for (int i = 0; i < PAGE_SIZE; i++) {
        _flash_buffer[i] = *ptr;
        ptr++;
    }
    return true;
}

bool FlashClass::savePage() {
    uint32_t *ptr = (uint32_t *)_page_address;
    erasePage(ptr);
    uint32_t *p = ptr;
    for (int i = 0; i < PAGE_SIZE; i++) {
        writeWord(ptr, _flash_buffer[i]);
        ptr++;
    }
    return true;
}

bool FlashClass::writePageWord(void *adr, uint32_t val) {
    uint32_t a = (uint32_t)adr - _page_address;
    if (a > PAGE_SIZE * 4) {
        return false;
    }
    _flash_buffer[a/4] = val;
    return true;
}

bool FlashClass::verifyPage() {
    uint32_t *ptr = (uint32_t *)_page_address;
    for (int i = 0; i < PAGE_SIZE; i++) {
        if (*ptr != _flash_buffer[i]) {
            return false;
        }
        ptr++;
    }
    return true;
}

FlashClass Flash;
<commit_msg>Cleaned up compiler warnings<commit_after>#include <Flash.h>

bool FlashClass::erasePage(void* adr) {
    NVMADDR = KVA_TO_PA((unsigned int) adr);
    return doNvmOp(nvmopErasePage);
}

bool FlashClass::writeWord(void* adr, uint32_t val) {
    NVMADDR = KVA_TO_PA((unsigned int) adr);
    NVMDATA = val;
    return doNvmOp(nvmopWriteWord);
}

bool FlashClass::writeRow(void* adr, void *val) {
	bool blank = true;
	for (int i = 0; i < ROW_SIZE; i++) {
		if (((char *)val)[i] != 0xFF) {
			blank = false;
		}
	}
	if (blank) {
		return 0;
	}
    NVMADDR = KVA_TO_PA((unsigned int) adr);
    NVMSRCADDR = KVA_TO_PA((uint32_t)val);
    return doNvmOp(nvmopWriteRow);
}

bool FlashClass::clearNvmError() {
	return doNvmOp(nvmopNop);
}

bool FlashClass::isNvmError() {
	return (NVMCON & (_NVMCON_WRERR_MASK | _NVMCON_LVDERR_MASK)) ? true : false;
}

bool __attribute__((nomips16)) FlashClass::doNvmOp(uint32_t nvmop) {
    int         intSt;
    uint32_t    tm;

    // M00TODO: When DMA operations are supported in the core, need
    // to add code here to suspend DMA during the NVM operation.

    intSt = disableInterrupts();
    NVMCON = NVMCON_WREN | nvmop;

    tm = _CP0_GET_COUNT();
    while (_CP0_GET_COUNT() - tm < ((F_CPU * 6) / 2000000));

    NVMKEY      = 0xAA996655;
    NVMKEY      = 0x556699AA;
    NVMCONSET   = NVMCON_WR;

    while (NVMCON & NVMCON_WR) {
		continue;
    }

    NVMCONCLR = NVMCON_WREN;

    //M00TODO: Resume a suspended DMA operation

    restoreInterrupts(intSt);
    return(isNvmError());
}

bool FlashClass::loadPage(void *adr) {
    uint32_t *ptr = (uint32_t *)adr;

    ptr = (uint32_t *)((uint32_t)ptr & ~((PAGE_SIZE*4)-1));
    _page_address = (uint32_t)ptr;

    for (int i = 0; i < PAGE_SIZE; i++) {
        _flash_buffer[i] = *ptr;
        ptr++;
    }
    return true;
}

bool FlashClass::savePage() {
    uint32_t *ptr = (uint32_t *)_page_address;
    erasePage(ptr);
    for (int i = 0; i < PAGE_SIZE; i++) {
        writeWord(ptr, _flash_buffer[i]);
        ptr++;
    }
    return true;
}

bool FlashClass::writePageWord(void *adr, uint32_t val) {
    uint32_t a = (uint32_t)adr - _page_address;
    if (a > PAGE_SIZE * 4) {
        return false;
    }
    _flash_buffer[a/4] = val;
    return true;
}

bool FlashClass::verifyPage() {
    uint32_t *ptr = (uint32_t *)_page_address;
    for (int i = 0; i < PAGE_SIZE; i++) {
        if (*ptr != _flash_buffer[i]) {
            return false;
        }
        ptr++;
    }
    return true;
}

FlashClass Flash;
<|endoftext|>


<commit_before>#include "Mempoke.h"
#include <stdio.h>
#include <sys/mman.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <semaphore.h>
#include <pthread.h>

CoreRequest *device = 0;
DMARequest *dma = 0;
PortalAlloc *dstAlloc;
unsigned int *dstBuffer = 0;
int numWords = 16 << 3;
size_t test_sz  = numWords*sizeof(unsigned int);
size_t alloc_sz = test_sz;
sem_t conf_sem;

void dump(const char *prefix, char *buf, size_t len)
{
    fprintf(stderr, "%s ", prefix);
    for (int i = 0; i < (len > 16 ? 16 : len) ; i++)
	fprintf(stderr, "%02x", (unsigned char)buf[i]);
    fprintf(stderr, "\n");
}

class TestDMAIndication : public DMAIndication
{
  virtual void reportStateDbg(DmaDbgRec& rec){
    fprintf(stderr, "reportStateDbg: {x:%08lx y:%08lx z:%08lx w:%08lx}\n", rec.x,rec.y,rec.z,rec.w);
  }
  virtual void configResp(unsigned long channelId){
    fprintf(stderr, "configResp: %lx\n", channelId);
    sem_post(&conf_sem);
  }
  virtual void sglistResp(unsigned long channelId){
    fprintf(stderr, "sglistResp: %lx\n", channelId);
  }
  virtual void parefResp(unsigned long channelId){
    fprintf(stderr, "parefResp: %lx\n", channelId);
  }
};

class TestCoreIndication : public CoreIndication
{
  virtual void readWordResult (S0 &s){
    fprintf(stderr, "readWordResult(S0{a:%ld,b:%ld})\n", s.a, s.b);
  }
  virtual void writeWordResult (S0 &s){
    fprintf(stderr, "writeWordResult(S0{a:%ld,b:%ld})\n", s.a, s.b);
  }
};

int main(int argc, const char **argv)
{
  fprintf(stderr, "%s %s\n", __DATE__, __TIME__);
  device = CoreRequest::createCoreRequest(new TestCoreIndication);
  dma = DMARequest::createDMARequest(new TestDMAIndication);

  if(sem_init(&conf_sem, 1, 0)){
    fprintf(stderr, "failed to init conf_sem\n");
    return -1;
  }

  fprintf(stderr, "allocating memory...\n");
  dma->alloc(alloc_sz, &dstAlloc);
  dstBuffer = (unsigned int *)mmap(0, alloc_sz, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_SHARED, dstAlloc.header.fd, 0);

  pthread_t tid;
  fprintf(stderr, "creating exec thread\n");
  if(pthread_create(&tid, NULL,  portalExec, NULL)){
   fprintf(stderr, "error creating exec thread\n");
   exit(1);
  }

  unsigned int ref_dstAlloc = dma->reference(&dstAlloc);

  for (int i = 0; i < numWords; i++){
    dstBuffer[i] = i;
  }

  dma->dCacheFlushInval(&dstAlloc, dstBuffer);
  fprintf(stderr, "flush and invalidate complete\n");

  dma->configChan(1, 0, ref_dstAlloc, 2);
  sem_wait(&conf_sem);

  dma->configChan(0, 0, ref_dstAlloc, 2);
  sem_wait(&conf_sem);

  fprintf(stderr, "main about to issue requests\n");

  device->readWord(5*8);
  sleep(1);
  S0 s = {3,4};
  device->writeWord(6*8,s);
  sleep(1);
  device->readWord(6*8);

  fprintf(stderr, "main going to sleep\n");
  while(true){sleep(1);}
}
<commit_msg>fix corresponding uses to add indirection for dstAlloc<commit_after>#include "Mempoke.h"
#include <stdio.h>
#include <sys/mman.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <semaphore.h>
#include <pthread.h>

CoreRequest *device = 0;
DMARequest *dma = 0;
PortalAlloc *dstAlloc;
unsigned int *dstBuffer = 0;
int numWords = 16 << 3;
size_t test_sz  = numWords*sizeof(unsigned int);
size_t alloc_sz = test_sz;
sem_t conf_sem;

void dump(const char *prefix, char *buf, size_t len)
{
    fprintf(stderr, "%s ", prefix);
    for (int i = 0; i < (len > 16 ? 16 : len) ; i++)
	fprintf(stderr, "%02x", (unsigned char)buf[i]);
    fprintf(stderr, "\n");
}

class TestDMAIndication : public DMAIndication
{
  virtual void reportStateDbg(DmaDbgRec& rec){
    fprintf(stderr, "reportStateDbg: {x:%08lx y:%08lx z:%08lx w:%08lx}\n", rec.x,rec.y,rec.z,rec.w);
  }
  virtual void configResp(unsigned long channelId){
    fprintf(stderr, "configResp: %lx\n", channelId);
    sem_post(&conf_sem);
  }
  virtual void sglistResp(unsigned long channelId){
    fprintf(stderr, "sglistResp: %lx\n", channelId);
  }
  virtual void parefResp(unsigned long channelId){
    fprintf(stderr, "parefResp: %lx\n", channelId);
  }
};

class TestCoreIndication : public CoreIndication
{
  virtual void readWordResult (S0 &s){
    fprintf(stderr, "readWordResult(S0{a:%ld,b:%ld})\n", s.a, s.b);
  }
  virtual void writeWordResult (S0 &s){
    fprintf(stderr, "writeWordResult(S0{a:%ld,b:%ld})\n", s.a, s.b);
  }
};

int main(int argc, const char **argv)
{
  fprintf(stderr, "%s %s\n", __DATE__, __TIME__);
  device = CoreRequest::createCoreRequest(new TestCoreIndication);
  dma = DMARequest::createDMARequest(new TestDMAIndication);

  if(sem_init(&conf_sem, 1, 0)){
    fprintf(stderr, "failed to init conf_sem\n");
    return -1;
  }

  fprintf(stderr, "allocating memory...\n");
  dma->alloc(alloc_sz, &dstAlloc);
  dstBuffer = (unsigned int *)mmap(0, alloc_sz, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_SHARED, dstAlloc->header.fd, 0);

  pthread_t tid;
  fprintf(stderr, "creating exec thread\n");
  if(pthread_create(&tid, NULL,  portalExec, NULL)){
   fprintf(stderr, "error creating exec thread\n");
   exit(1);
  }

  unsigned int ref_dstAlloc = dma->reference(dstAlloc);

  for (int i = 0; i < numWords; i++){
    dstBuffer[i] = i;
  }

  dma->dCacheFlushInval(dstAlloc, dstBuffer);
  fprintf(stderr, "flush and invalidate complete\n");

  dma->configChan(1, 0, ref_dstAlloc, 2);
  sem_wait(&conf_sem);

  dma->configChan(0, 0, ref_dstAlloc, 2);
  sem_wait(&conf_sem);

  fprintf(stderr, "main about to issue requests\n");

  device->readWord(5*8);
  sleep(1);
  S0 s = {3,4};
  device->writeWord(6*8,s);
  sleep(1);
  device->readWord(6*8);

  fprintf(stderr, "main going to sleep\n");
  while(true){sleep(1);}
}
<|endoftext|>