<commit_before>/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "jsonkitspage.h"
#include "jsonwizard.h"

#include "../iprojectmanager.h"
#include "../kit.h"
#include "../project.h"
#include "../projectexplorer.h"

#include <coreplugin/featureprovider.h>
#include <coreplugin/mimedatabase.h>

#include <extensionsystem/pluginmanager.h>

#include <utils/macroexpander.h>
#include <utils/qtcassert.h>

namespace ProjectExplorer {

JsonKitsPage::JsonKitsPage(QWidget *parent) : TargetSetupPage(parent)
{ }

void JsonKitsPage::initializePage()
{
    JsonWizard *wiz = qobject_cast<JsonWizard *>(wizard());
    QTC_ASSERT(wiz, return);

    connect(wiz, &JsonWizard::filesReady, this, &JsonKitsPage::setupProjectFiles);

    const QString platform = wiz->value(QLatin1String("Platform")).toString();
    const Core::FeatureSet preferred = Core::FeatureSet::fromStringList(wiz->value(QLatin1String("PreferredFeatures")).toStringList());
    const Core::FeatureSet required = Core::FeatureSet::fromStringList(wiz->value(QLatin1String("RequiredFeatures")).toStringList());
    const QString path = wiz->expander()->expand(m_projectFilePath);

    setProjectPath(path);

    setRequiredKitMatcher(KitMatcher([required](const Kit *k) { return k->hasFeatures(required); }));
    setPreferredKitMatcher(KitMatcher([platform, preferred](const Kit *k) { return k->hasPlatform(platform) && k->hasFeatures(preferred); }));

    TargetSetupPage::initializePage();
}

void JsonKitsPage::cleanupPage()
{
    JsonWizard *wiz = qobject_cast<JsonWizard *>(wizard());
    QTC_ASSERT(wiz, return);

    disconnect(wiz, &JsonWizard::filesReady, this, 0);

    TargetSetupPage::cleanupPage();
}

void JsonKitsPage::setupProjectFiles(const JsonWizard::GeneratorFiles &files)
{
    Project *project = 0;
    QList<IProjectManager *> managerList = ExtensionSystem::PluginManager::getObjects<IProjectManager>();

    foreach (const JsonWizard::GeneratorFile &f, files) {
        if (f.file.attributes() & Core::GeneratedFile::OpenProjectAttribute) {
            QString errorMessage;
            QString path = f.file.path();
            const QFileInfo fi(path);

            if (fi.exists())
                path = fi.canonicalFilePath();

            Core::MimeType mt = Core::MimeDatabase::findByFile(fi);
            if (mt.isNull())
                continue;

            foreach (IProjectManager *manager, managerList) {
                if (manager->mimeType() == mt.type()) {
                    project = manager->openProject(path, &errorMessage);
                    break;
                }
            }

            if (project) {
                bool success = setupProject(project);
                if (success)
                    project->saveSettings();
                delete project;
            }
        }
    }
}

} // namespace ProjectExplorer
<commit_msg>JsonWizard: Code cleanup<commit_after>/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "jsonkitspage.h"
#include "jsonwizard.h"

#include "../iprojectmanager.h"
#include "../kit.h"
#include "../project.h"
#include "../projectexplorer.h"

#include <coreplugin/featureprovider.h>
#include <coreplugin/mimedatabase.h>

#include <extensionsystem/pluginmanager.h>

#include <utils/algorithm.h>
#include <utils/macroexpander.h>
#include <utils/qtcassert.h>

namespace ProjectExplorer {

JsonKitsPage::JsonKitsPage(QWidget *parent) : TargetSetupPage(parent)
{ }

void JsonKitsPage::initializePage()
{
    JsonWizard *wiz = qobject_cast<JsonWizard *>(wizard());
    QTC_ASSERT(wiz, return);

    connect(wiz, &JsonWizard::filesReady, this, &JsonKitsPage::setupProjectFiles);

    const QString platform = wiz->value(QLatin1String("Platform")).toString();
    const Core::FeatureSet preferred = Core::FeatureSet::fromStringList(wiz->value(QLatin1String("PreferredFeatures")).toStringList());
    const Core::FeatureSet required = Core::FeatureSet::fromStringList(wiz->value(QLatin1String("RequiredFeatures")).toStringList());
    const QString path = wiz->expander()->expand(m_projectFilePath);

    setProjectPath(path);

    setRequiredKitMatcher(KitMatcher([required](const Kit *k) { return k->hasFeatures(required); }));
    setPreferredKitMatcher(KitMatcher([platform, preferred](const Kit *k) { return k->hasPlatform(platform) && k->hasFeatures(preferred); }));

    TargetSetupPage::initializePage();
}

void JsonKitsPage::cleanupPage()
{
    JsonWizard *wiz = qobject_cast<JsonWizard *>(wizard());
    QTC_ASSERT(wiz, return);

    disconnect(wiz, &JsonWizard::filesReady, this, 0);

    TargetSetupPage::cleanupPage();
}

void JsonKitsPage::setupProjectFiles(const JsonWizard::GeneratorFiles &files)
{
    Project *project = 0;
    QList<IProjectManager *> managerList = ExtensionSystem::PluginManager::getObjects<IProjectManager>();

    foreach (const JsonWizard::GeneratorFile &f, files) {
        if (f.file.attributes() & Core::GeneratedFile::OpenProjectAttribute) {
            QString errorMessage;
            QString path = f.file.path();
            const QFileInfo fi(path);

            if (fi.exists())
                path = fi.canonicalFilePath();

            Core::MimeType mt = Core::MimeDatabase::findByFile(fi);
            if (mt.isNull())
                continue;

            auto manager = Utils::findOrDefault(managerList, Utils::equal(&IProjectManager::mimeType, mt.type()));
            project = manager ? manager->openProject(path, &errorMessage) : 0;
            if (project) {
                if (setupProject(project))
                    project->saveSettings();
                delete project;
                project = 0;
            }
        }
    }
}

} // namespace ProjectExplorer
<|endoftext|>


<commit_before>//
//  leaf-node-arrow.cpp
//  gepetto-viewer
//
//  Created by Pierre Fernbach in june 2015.
//  Copyright (c) 2015 LAAS-CNRS. All rights reserved.
//

#include <gepetto/viewer/leaf-node-arrow.h>

#include <osgUtil/SmoothingVisitor>
#include <osg/CullFace>
#include <hpp/util/debug.hh>

namespace graphics {

    /* Declaration of private function members */

    void LeafNodeArrow::init ()
    {

        /* Create Geode for adding ShapeDrawable */
        geode_ptr_ = new osg::Geode();

         /* create the axis : */
        float radiusCyl = getRadius();
        float lengthCyl = getSize();

        /* Create cylinder */
        ::osg::CylinderRefPtr cylinder_shape_x_ptr = new ::osg::Cylinder();
        cylinder_shape_x_ptr->set(osgVector3(lengthCyl/2.,0.,0.) , radiusCyl ,lengthCyl);
        cylinder_shape_x_ptr->setRotation(osgQuat( 0. , ::osg::X_AXIS , M_PI_2 , ::osg::Y_AXIS , 0. , ::osg::Z_AXIS ));
        /* Create cone */
        ::osg::ConeRefPtr cone_shape_x_ptr = new ::osg::Cone();
        cone_shape_x_ptr->set(osgVector3(lengthCyl+getRadius(),0.,0.) , 2. * radiusCyl , 4. * radiusCyl );
        cone_shape_x_ptr->setRotation(osgQuat( 0. , ::osg::X_AXIS , M_PI_2 , ::osg::Y_AXIS , 0. , ::osg::Z_AXIS ));

        /* create drawable and add them to geode */
        cylinder_drawable_ = new ::osg::ShapeDrawable( cylinder_shape_x_ptr );
        cone_drawable_ = new ::osg::ShapeDrawable( cone_shape_x_ptr );

        geode_ptr_->addDrawable(cylinder_drawable_);
        geode_ptr_->addDrawable(cone_drawable_);

        /* Create PositionAttitudeTransform */
        this->asQueue()->addChild(geode_ptr_);

        /* Allow transparency */
        geode_ptr_->getOrCreateStateSet()->setRenderBinDetails(10, "DepthSortedBin");
        geode_ptr_->getOrCreateStateSet()->setMode(GL_BLEND, ::osg::StateAttribute::ON);;
    }

    LeafNodeArrow::LeafNodeArrow(const std::string& name, const osgVector4& color, float radius, float size):
        Node(name)
    {

        setRadius(radius);
        setSize(size);

        init();
        setColor(color);
    }

    LeafNodeArrow::LeafNodeArrow(const LeafNodeArrow& other) :
        Node(other.getID())
    {
        init();
      //TODO
    }

    void LeafNodeArrow::initWeakPtr(LeafNodeArrowWeakPtr other_weak_ptr)
    {
        weak_ptr_ = other_weak_ptr;
    }

    /* End of declaration of private function members */

    /* Declaration of protected function members */

    LeafNodeArrowPtr_t LeafNodeArrow::create (const std::string& name , const osgVector4& color ,float radiusCenter, float size)
    {
        LeafNodeArrowPtr_t shared_ptr(new LeafNodeArrow(name, color, radiusCenter,size));

        // Add reference to itself
        shared_ptr->initWeakPtr(shared_ptr);

        return shared_ptr;
    }

    LeafNodeArrowPtr_t LeafNodeArrow::create (const std::string& name, const osgVector4& color, float radiusCenter)
    {
        //const float& size = new float;
        //*size = 0;
        LeafNodeArrowPtr_t shared_ptr(new LeafNodeArrow(name, color, radiusCenter,0));

        // Add reference to itself
        shared_ptr->initWeakPtr(shared_ptr);

        return shared_ptr;
    }

    LeafNodeArrowPtr_t LeafNodeArrow::createCopy (LeafNodeArrowPtr_t other)
    {
        LeafNodeArrowPtr_t shared_ptr(new LeafNodeArrow(*other));

        // Add reference to itself
        shared_ptr->initWeakPtr(shared_ptr);

        return shared_ptr;
    }

    /* End of declaration of protected function members */

    /* Declaration of public function members */

    LeafNodeArrowPtr_t LeafNodeArrow::clone (void) const
    {
        return LeafNodeArrow::createCopy(weak_ptr_.lock());
    }

    LeafNodeArrowPtr_t LeafNodeArrow::self (void) const
    {
        return weak_ptr_.lock();
    }

    void LeafNodeArrow::setTexture(const std::string& image_path)
    {
      osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D;
      texture->setDataVariance(osg::Object::DYNAMIC);
      osg::ref_ptr<osg::Image> image = osgDB::readImageFile(image_path);
      if (!image)
      {
        std::cout << " couldn't find texture, quiting." << std::endl;
        return;
      }
      texture->setImage(image);
      geode_ptr_->getStateSet()->setTextureAttributeAndModes(0,texture,osg::StateAttribute::ON);
    }

    void LeafNodeArrow::setRadius (const float& radius)
    {
        radius_=radius;
    }

    float LeafNodeArrow::getRadius() const
    {
        return radius_;
    }

    void LeafNodeArrow::setSize(const float& size){
        size_ = size;
    }

    float LeafNodeArrow::getSize() const
    {
        return size_;
    }

    void LeafNodeArrow::setColor (const osgVector4& color)
    {
        cylinder_drawable_->setColor(color);
        cone_drawable_->setColor(color);
        color_ = color;
    }

    void LeafNodeArrow::resize(float radius,float length){
      if(length != getSize() || radius != getRadius()){ // avoid useless resize
        osgVector4 color = cylinder_drawable_->getColor();
        geode_ptr_->removeDrawable(cylinder_drawable_);
        geode_ptr_->removeDrawable(cone_drawable_);
        setSize(length);
        setRadius(radius);

        /* Create cylinder */
        ::osg::CylinderRefPtr cylinder_shape_x_ptr = new ::osg::Cylinder();
        cylinder_shape_x_ptr->set(osgVector3(getSize()/2. + getRadius(),0.,0.) , getRadius() ,getSize());
        cylinder_shape_x_ptr->setRotation(osgQuat( 0. , ::osg::X_AXIS , M_PI_2 , ::osg::Y_AXIS , 0. , ::osg::Z_AXIS ));
        /* Create cone */
        ::osg::ConeRefPtr cone_shape_x_ptr = new ::osg::Cone();
        cone_shape_x_ptr->set(osgVector3(getSize()+getRadius(),0.,0.) , 2. * getRadius() , 4. * getRadius() );
        cone_shape_x_ptr->setRotation(osgQuat( 0. , ::osg::X_AXIS , M_PI_2 , ::osg::Y_AXIS , 0. , ::osg::Z_AXIS ));

        /* create drawable and add them to geode */
        cylinder_drawable_ = new ::osg::ShapeDrawable( cylinder_shape_x_ptr );
        cone_drawable_ = new ::osg::ShapeDrawable( cone_shape_x_ptr );

        geode_ptr_->addDrawable(cylinder_drawable_);
        geode_ptr_->addDrawable(cone_drawable_);

        }
    }

    LeafNodeArrow::~LeafNodeArrow ()
    {
        /* Proper deletion of all tree scene */

        geode_ptr_->removeDrawable(cylinder_drawable_);
        geode_ptr_->removeDrawable(cone_drawable_);

        geode_ptr_ = NULL;
        cylinder_drawable_ = NULL;
        cone_drawable_ = NULL;

        weak_ptr_.reset();
    }

    /* End of declaration of public function members */

} /* namespace graphics */

<commit_msg>correct issue with color after resize<commit_after>//
//  leaf-node-arrow.cpp
//  gepetto-viewer
//
//  Created by Pierre Fernbach in june 2015.
//  Copyright (c) 2015 LAAS-CNRS. All rights reserved.
//

#include <gepetto/viewer/leaf-node-arrow.h>

#include <osgUtil/SmoothingVisitor>
#include <osg/CullFace>
#include <hpp/util/debug.hh>

namespace graphics {

    /* Declaration of private function members */

    void LeafNodeArrow::init ()
    {

        /* Create Geode for adding ShapeDrawable */
        geode_ptr_ = new osg::Geode();

         /* create the axis : */
        float radiusCyl = getRadius();
        float lengthCyl = getSize();

        /* Create cylinder */
        ::osg::CylinderRefPtr cylinder_shape_x_ptr = new ::osg::Cylinder();
        cylinder_shape_x_ptr->set(osgVector3(lengthCyl/2.,0.,0.) , radiusCyl ,lengthCyl);
        cylinder_shape_x_ptr->setRotation(osgQuat( 0. , ::osg::X_AXIS , M_PI_2 , ::osg::Y_AXIS , 0. , ::osg::Z_AXIS ));
        /* Create cone */
        ::osg::ConeRefPtr cone_shape_x_ptr = new ::osg::Cone();
        cone_shape_x_ptr->set(osgVector3(lengthCyl+getRadius(),0.,0.) , 2. * radiusCyl , 4. * radiusCyl );
        cone_shape_x_ptr->setRotation(osgQuat( 0. , ::osg::X_AXIS , M_PI_2 , ::osg::Y_AXIS , 0. , ::osg::Z_AXIS ));

        /* create drawable and add them to geode */
        cylinder_drawable_ = new ::osg::ShapeDrawable( cylinder_shape_x_ptr );
        cone_drawable_ = new ::osg::ShapeDrawable( cone_shape_x_ptr );

        geode_ptr_->addDrawable(cylinder_drawable_);
        geode_ptr_->addDrawable(cone_drawable_);

        /* Create PositionAttitudeTransform */
        this->asQueue()->addChild(geode_ptr_);

        /* Allow transparency */
        geode_ptr_->getOrCreateStateSet()->setRenderBinDetails(10, "DepthSortedBin");
        geode_ptr_->getOrCreateStateSet()->setMode(GL_BLEND, ::osg::StateAttribute::ON);;
    }

    LeafNodeArrow::LeafNodeArrow(const std::string& name, const osgVector4& color, float radius, float size):
        Node(name)
    {

        setRadius(radius);
        setSize(size);

        init();
        setColor(color);
    }

    LeafNodeArrow::LeafNodeArrow(const LeafNodeArrow& other) :
        Node(other.getID())
    {
        init();
      //TODO
    }

    void LeafNodeArrow::initWeakPtr(LeafNodeArrowWeakPtr other_weak_ptr)
    {
        weak_ptr_ = other_weak_ptr;
    }

    /* End of declaration of private function members */

    /* Declaration of protected function members */

    LeafNodeArrowPtr_t LeafNodeArrow::create (const std::string& name , const osgVector4& color ,float radiusCenter, float size)
    {
        LeafNodeArrowPtr_t shared_ptr(new LeafNodeArrow(name, color, radiusCenter,size));

        // Add reference to itself
        shared_ptr->initWeakPtr(shared_ptr);

        return shared_ptr;
    }

    LeafNodeArrowPtr_t LeafNodeArrow::create (const std::string& name, const osgVector4& color, float radiusCenter)
    {
        //const float& size = new float;
        //*size = 0;
        LeafNodeArrowPtr_t shared_ptr(new LeafNodeArrow(name, color, radiusCenter,0));

        // Add reference to itself
        shared_ptr->initWeakPtr(shared_ptr);

        return shared_ptr;
    }

    LeafNodeArrowPtr_t LeafNodeArrow::createCopy (LeafNodeArrowPtr_t other)
    {
        LeafNodeArrowPtr_t shared_ptr(new LeafNodeArrow(*other));

        // Add reference to itself
        shared_ptr->initWeakPtr(shared_ptr);

        return shared_ptr;
    }

    /* End of declaration of protected function members */

    /* Declaration of public function members */

    LeafNodeArrowPtr_t LeafNodeArrow::clone (void) const
    {
        return LeafNodeArrow::createCopy(weak_ptr_.lock());
    }

    LeafNodeArrowPtr_t LeafNodeArrow::self (void) const
    {
        return weak_ptr_.lock();
    }

    void LeafNodeArrow::setTexture(const std::string& image_path)
    {
      osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D;
      texture->setDataVariance(osg::Object::DYNAMIC);
      osg::ref_ptr<osg::Image> image = osgDB::readImageFile(image_path);
      if (!image)
      {
        std::cout << " couldn't find texture, quiting." << std::endl;
        return;
      }
      texture->setImage(image);
      geode_ptr_->getStateSet()->setTextureAttributeAndModes(0,texture,osg::StateAttribute::ON);
    }

    void LeafNodeArrow::setRadius (const float& radius)
    {
        radius_=radius;
    }

    float LeafNodeArrow::getRadius() const
    {
        return radius_;
    }

    void LeafNodeArrow::setSize(const float& size){
        size_ = size;
    }

    float LeafNodeArrow::getSize() const
    {
        return size_;
    }

    void LeafNodeArrow::setColor (const osgVector4& color)
    {
        cylinder_drawable_->setColor(color);
        cone_drawable_->setColor(color);
        color_ = color;
    }

    void LeafNodeArrow::resize(float radius,float length){
      if(length != getSize() || radius != getRadius()){ // avoid useless resize
        osgVector4 color = cylinder_drawable_->getColor();
        geode_ptr_->removeDrawable(cylinder_drawable_);
        geode_ptr_->removeDrawable(cone_drawable_);
        setSize(length);
        setRadius(radius);

        /* Create cylinder */
        ::osg::CylinderRefPtr cylinder_shape_x_ptr = new ::osg::Cylinder();
        cylinder_shape_x_ptr->set(osgVector3(getSize()/2. + getRadius(),0.,0.) , getRadius() ,getSize());
        cylinder_shape_x_ptr->setRotation(osgQuat( 0. , ::osg::X_AXIS , M_PI_2 , ::osg::Y_AXIS , 0. , ::osg::Z_AXIS ));
        /* Create cone */
        ::osg::ConeRefPtr cone_shape_x_ptr = new ::osg::Cone();
        cone_shape_x_ptr->set(osgVector3(getSize()+getRadius(),0.,0.) , 2. * getRadius() , 4. * getRadius() );
        cone_shape_x_ptr->setRotation(osgQuat( 0. , ::osg::X_AXIS , M_PI_2 , ::osg::Y_AXIS , 0. , ::osg::Z_AXIS ));

        /* create drawable and add them to geode */
        cylinder_drawable_ = new ::osg::ShapeDrawable( cylinder_shape_x_ptr );
        cone_drawable_ = new ::osg::ShapeDrawable( cone_shape_x_ptr );
        cylinder_drawable_->setColor(color);
        cone_drawable_->setColor(color);

        geode_ptr_->addDrawable(cylinder_drawable_);
        geode_ptr_->addDrawable(cone_drawable_);

        }
    }

    LeafNodeArrow::~LeafNodeArrow ()
    {
        /* Proper deletion of all tree scene */

        geode_ptr_->removeDrawable(cylinder_drawable_);
        geode_ptr_->removeDrawable(cone_drawable_);

        geode_ptr_ = NULL;
        cylinder_drawable_ = NULL;
        cone_drawable_ = NULL;

        weak_ptr_.reset();
    }

    /* End of declaration of public function members */

} /* namespace graphics */

<|endoftext|>


<commit_before>// Copyright 2019 Open Source Robotics Foundation, Inc.
// Copyright 2016-2018 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef RMW_FASTRTPS_SHARED_CPP__QOS_HPP_
#define RMW_FASTRTPS_SHARED_CPP__QOS_HPP_

#include <fastdds/dds/core/policy/QosPolicies.hpp>
#include <fastdds/dds/publisher/qos/DataWriterQos.hpp>
#include <fastdds/dds/subscriber/qos/DataReaderQos.hpp>
#include <fastdds/dds/topic/qos/TopicQos.hpp>

#include <fastrtps/qos/QosPolicies.h>

#include "rmw/rmw.h"

#include "rmw_fastrtps_shared_cpp/visibility_control.h"

RMW_FASTRTPS_SHARED_CPP_PUBLIC
bool
is_valid_qos(const rmw_qos_profile_t & qos_policies);

RMW_FASTRTPS_SHARED_CPP_PUBLIC
bool
get_datareader_qos(
  const rmw_qos_profile_t & qos_policies,
  eprosima::fastdds::dds::DataReaderQos & reader_qos);

RMW_FASTRTPS_SHARED_CPP_PUBLIC
bool
get_datawriter_qos(
  const rmw_qos_profile_t & qos_policies,
  eprosima::fastdds::dds::DataWriterQos & writer_qos);

RMW_FASTRTPS_SHARED_CPP_PUBLIC
bool
get_topic_qos(
  const rmw_qos_profile_t & qos_policies,
  eprosima::fastdds::dds::TopicQos & topic_qos);

RMW_FASTRTPS_SHARED_CPP_PUBLIC
rmw_time_t
dds_duration_to_rmw(const eprosima::fastrtps::Duration_t & duration);

/*
 * Converts the DDS QOS Policy; of type DataWriterQos or DataReaderQos into rmw_qos_profile_t.
 *
 * \param[in] dds_qos of type DataWriterQos or DataReaderQos
 * \param[out] qos the equivalent of the data in dds_qos as a rmw_qos_profile_t
 */
template<typename DDSQoSPolicyT>
void
dds_qos_to_rmw_qos(
  const DDSQoSPolicyT & dds_qos,
  rmw_qos_profile_t * qos)
{
  switch (dds_qos.reliability().kind) {
    case eprosima::fastdds::dds::BEST_EFFORT_RELIABILITY_QOS:
      qos->reliability = RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT;
      break;
    case eprosima::fastdds::dds::RELIABLE_RELIABILITY_QOS:
      qos->reliability = RMW_QOS_POLICY_RELIABILITY_RELIABLE;
      break;
    default:
      qos->reliability = RMW_QOS_POLICY_RELIABILITY_UNKNOWN;
      break;
  }

  switch (dds_qos.durability().kind) {
    case eprosima::fastdds::dds::TRANSIENT_LOCAL_DURABILITY_QOS:
      qos->durability = RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL;
      break;
    case eprosima::fastdds::dds::VOLATILE_DURABILITY_QOS:
      qos->durability = RMW_QOS_POLICY_DURABILITY_VOLATILE;
      break;
    default:
      qos->durability = RMW_QOS_POLICY_DURABILITY_UNKNOWN;
      break;
  }

  qos->deadline = dds_duration_to_rmw(dds_qos.deadline().period);
  qos->lifespan = dds_duration_to_rmw(dds_qos.lifespan().duration);

  switch (dds_qos.liveliness().kind) {
    case eprosima::fastdds::dds::AUTOMATIC_LIVELINESS_QOS:
      qos->liveliness = RMW_QOS_POLICY_LIVELINESS_AUTOMATIC;
      break;
    case eprosima::fastdds::dds::MANUAL_BY_TOPIC_LIVELINESS_QOS:
      qos->liveliness = RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_TOPIC;
      break;
    default:
      qos->liveliness = RMW_QOS_POLICY_LIVELINESS_UNKNOWN;
      break;
  }

  qos->liveliness_lease_duration = dds_duration_to_rmw(dds_qos.liveliness().lease_duration);

  switch (dds_qos.history().kind) {
    case eprosima::fastdds::dds::KEEP_LAST_HISTORY_QOS:
      qos->history = RMW_QOS_POLICY_HISTORY_KEEP_LAST;
      break;
    case eprosima::fastdds::dds::KEEP_ALL_HISTORY_QOS:
      qos->history = RMW_QOS_POLICY_HISTORY_KEEP_ALL;
      break;
    default:
      qos->history = RMW_QOS_POLICY_HISTORY_UNKNOWN;
      break;
  }
  qos->depth = static_cast<size_t>(dds_qos.history().depth);
}

/*
 * Converts the RTPS QOS Policy; of type WriterQos or ReaderQos into rmw_qos_profile_t.
 * Since WriterQos or ReaderQos do not have information about history and depth,
 * these values are not set by this function.
 *
 * \param[in] rtps_qos of type WriterQos or ReaderQos
 * \param[out] qos the equivalent of the data in rtps_qos as a rmw_qos_profile_t
 */
template<typename RTPSQoSPolicyT>
void
rtps_qos_to_rmw_qos(
  const RTPSQoSPolicyT & rtps_qos,
  rmw_qos_profile_t * qos)
{
  switch (rtps_qos.m_reliability.kind) {
    case eprosima::fastrtps::BEST_EFFORT_RELIABILITY_QOS:
      qos->reliability = RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT;
      break;
    case eprosima::fastrtps::RELIABLE_RELIABILITY_QOS:
      qos->reliability = RMW_QOS_POLICY_RELIABILITY_RELIABLE;
      break;
    default:
      qos->reliability = RMW_QOS_POLICY_RELIABILITY_UNKNOWN;
      break;
  }

  switch (rtps_qos.m_durability.kind) {
    case eprosima::fastrtps::TRANSIENT_LOCAL_DURABILITY_QOS:
      qos->durability = RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL;
      break;
    case eprosima::fastrtps::VOLATILE_DURABILITY_QOS:
      qos->durability = RMW_QOS_POLICY_DURABILITY_VOLATILE;
      break;
    default:
      qos->durability = RMW_QOS_POLICY_DURABILITY_UNKNOWN;
      break;
  }

  qos->deadline = dds_duration_to_rmw(rtps_qos.m_deadline.period);
  qos->lifespan = dds_duration_to_rmw(rtps_qos.m_lifespan.duration);

  switch (rtps_qos.m_liveliness.kind) {
    case eprosima::fastrtps::AUTOMATIC_LIVELINESS_QOS:
      qos->liveliness = RMW_QOS_POLICY_LIVELINESS_AUTOMATIC;
      break;
    case eprosima::fastrtps::MANUAL_BY_TOPIC_LIVELINESS_QOS:
      qos->liveliness = RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_TOPIC;
      break;
    default:
      qos->liveliness = RMW_QOS_POLICY_LIVELINESS_UNKNOWN;
      break;
  }
  qos->liveliness_lease_duration = dds_duration_to_rmw(rtps_qos.m_liveliness.lease_duration);
}

extern template RMW_FASTRTPS_SHARED_CPP_PUBLIC
void dds_qos_to_rmw_qos<eprosima::fastdds::dds::DataWriterQos>(
  const eprosima::fastdds::dds::DataWriterQos & dds_qos,
  rmw_qos_profile_t * qos);

extern template RMW_FASTRTPS_SHARED_CPP_PUBLIC
void dds_qos_to_rmw_qos<eprosima::fastdds::dds::DataReaderQos>(
  const eprosima::fastdds::dds::DataReaderQos & dds_qos,
  rmw_qos_profile_t * qos);

template<typename AttributeT>
void
dds_attributes_to_rmw_qos(
  const AttributeT & dds_qos,
  rmw_qos_profile_t * qos);

extern template RMW_FASTRTPS_SHARED_CPP_PUBLIC
void
dds_attributes_to_rmw_qos<eprosima::fastrtps::PublisherAttributes>(
  const eprosima::fastrtps::PublisherAttributes & dds_qos,
  rmw_qos_profile_t * qos);

extern template RMW_FASTRTPS_SHARED_CPP_PUBLIC
void
dds_attributes_to_rmw_qos<eprosima::fastrtps::SubscriberAttributes>(
  const eprosima::fastrtps::SubscriberAttributes & dds_qos,
  rmw_qos_profile_t * qos);

#endif  // RMW_FASTRTPS_SHARED_CPP__QOS_HPP_
<commit_msg>Fix cpplint error (#574)<commit_after>// Copyright 2019 Open Source Robotics Foundation, Inc.
// Copyright 2016-2018 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef RMW_FASTRTPS_SHARED_CPP__QOS_HPP_
#define RMW_FASTRTPS_SHARED_CPP__QOS_HPP_

#include <fastdds/dds/core/policy/QosPolicies.hpp>
#include <fastdds/dds/publisher/qos/DataWriterQos.hpp>
#include <fastdds/dds/subscriber/qos/DataReaderQos.hpp>
#include <fastdds/dds/topic/qos/TopicQos.hpp>

#include "fastrtps/qos/QosPolicies.h"

#include "rmw/rmw.h"

#include "rmw_fastrtps_shared_cpp/visibility_control.h"

RMW_FASTRTPS_SHARED_CPP_PUBLIC
bool
is_valid_qos(const rmw_qos_profile_t & qos_policies);

RMW_FASTRTPS_SHARED_CPP_PUBLIC
bool
get_datareader_qos(
  const rmw_qos_profile_t & qos_policies,
  eprosima::fastdds::dds::DataReaderQos & reader_qos);

RMW_FASTRTPS_SHARED_CPP_PUBLIC
bool
get_datawriter_qos(
  const rmw_qos_profile_t & qos_policies,
  eprosima::fastdds::dds::DataWriterQos & writer_qos);

RMW_FASTRTPS_SHARED_CPP_PUBLIC
bool
get_topic_qos(
  const rmw_qos_profile_t & qos_policies,
  eprosima::fastdds::dds::TopicQos & topic_qos);

RMW_FASTRTPS_SHARED_CPP_PUBLIC
rmw_time_t
dds_duration_to_rmw(const eprosima::fastrtps::Duration_t & duration);

/*
 * Converts the DDS QOS Policy; of type DataWriterQos or DataReaderQos into rmw_qos_profile_t.
 *
 * \param[in] dds_qos of type DataWriterQos or DataReaderQos
 * \param[out] qos the equivalent of the data in dds_qos as a rmw_qos_profile_t
 */
template<typename DDSQoSPolicyT>
void
dds_qos_to_rmw_qos(
  const DDSQoSPolicyT & dds_qos,
  rmw_qos_profile_t * qos)
{
  switch (dds_qos.reliability().kind) {
    case eprosima::fastdds::dds::BEST_EFFORT_RELIABILITY_QOS:
      qos->reliability = RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT;
      break;
    case eprosima::fastdds::dds::RELIABLE_RELIABILITY_QOS:
      qos->reliability = RMW_QOS_POLICY_RELIABILITY_RELIABLE;
      break;
    default:
      qos->reliability = RMW_QOS_POLICY_RELIABILITY_UNKNOWN;
      break;
  }

  switch (dds_qos.durability().kind) {
    case eprosima::fastdds::dds::TRANSIENT_LOCAL_DURABILITY_QOS:
      qos->durability = RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL;
      break;
    case eprosima::fastdds::dds::VOLATILE_DURABILITY_QOS:
      qos->durability = RMW_QOS_POLICY_DURABILITY_VOLATILE;
      break;
    default:
      qos->durability = RMW_QOS_POLICY_DURABILITY_UNKNOWN;
      break;
  }

  qos->deadline = dds_duration_to_rmw(dds_qos.deadline().period);
  qos->lifespan = dds_duration_to_rmw(dds_qos.lifespan().duration);

  switch (dds_qos.liveliness().kind) {
    case eprosima::fastdds::dds::AUTOMATIC_LIVELINESS_QOS:
      qos->liveliness = RMW_QOS_POLICY_LIVELINESS_AUTOMATIC;
      break;
    case eprosima::fastdds::dds::MANUAL_BY_TOPIC_LIVELINESS_QOS:
      qos->liveliness = RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_TOPIC;
      break;
    default:
      qos->liveliness = RMW_QOS_POLICY_LIVELINESS_UNKNOWN;
      break;
  }

  qos->liveliness_lease_duration = dds_duration_to_rmw(dds_qos.liveliness().lease_duration);

  switch (dds_qos.history().kind) {
    case eprosima::fastdds::dds::KEEP_LAST_HISTORY_QOS:
      qos->history = RMW_QOS_POLICY_HISTORY_KEEP_LAST;
      break;
    case eprosima::fastdds::dds::KEEP_ALL_HISTORY_QOS:
      qos->history = RMW_QOS_POLICY_HISTORY_KEEP_ALL;
      break;
    default:
      qos->history = RMW_QOS_POLICY_HISTORY_UNKNOWN;
      break;
  }
  qos->depth = static_cast<size_t>(dds_qos.history().depth);
}

/*
 * Converts the RTPS QOS Policy; of type WriterQos or ReaderQos into rmw_qos_profile_t.
 * Since WriterQos or ReaderQos do not have information about history and depth,
 * these values are not set by this function.
 *
 * \param[in] rtps_qos of type WriterQos or ReaderQos
 * \param[out] qos the equivalent of the data in rtps_qos as a rmw_qos_profile_t
 */
template<typename RTPSQoSPolicyT>
void
rtps_qos_to_rmw_qos(
  const RTPSQoSPolicyT & rtps_qos,
  rmw_qos_profile_t * qos)
{
  switch (rtps_qos.m_reliability.kind) {
    case eprosima::fastrtps::BEST_EFFORT_RELIABILITY_QOS:
      qos->reliability = RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT;
      break;
    case eprosima::fastrtps::RELIABLE_RELIABILITY_QOS:
      qos->reliability = RMW_QOS_POLICY_RELIABILITY_RELIABLE;
      break;
    default:
      qos->reliability = RMW_QOS_POLICY_RELIABILITY_UNKNOWN;
      break;
  }

  switch (rtps_qos.m_durability.kind) {
    case eprosima::fastrtps::TRANSIENT_LOCAL_DURABILITY_QOS:
      qos->durability = RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL;
      break;
    case eprosima::fastrtps::VOLATILE_DURABILITY_QOS:
      qos->durability = RMW_QOS_POLICY_DURABILITY_VOLATILE;
      break;
    default:
      qos->durability = RMW_QOS_POLICY_DURABILITY_UNKNOWN;
      break;
  }

  qos->deadline = dds_duration_to_rmw(rtps_qos.m_deadline.period);
  qos->lifespan = dds_duration_to_rmw(rtps_qos.m_lifespan.duration);

  switch (rtps_qos.m_liveliness.kind) {
    case eprosima::fastrtps::AUTOMATIC_LIVELINESS_QOS:
      qos->liveliness = RMW_QOS_POLICY_LIVELINESS_AUTOMATIC;
      break;
    case eprosima::fastrtps::MANUAL_BY_TOPIC_LIVELINESS_QOS:
      qos->liveliness = RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_TOPIC;
      break;
    default:
      qos->liveliness = RMW_QOS_POLICY_LIVELINESS_UNKNOWN;
      break;
  }
  qos->liveliness_lease_duration = dds_duration_to_rmw(rtps_qos.m_liveliness.lease_duration);
}

extern template RMW_FASTRTPS_SHARED_CPP_PUBLIC
void dds_qos_to_rmw_qos<eprosima::fastdds::dds::DataWriterQos>(
  const eprosima::fastdds::dds::DataWriterQos & dds_qos,
  rmw_qos_profile_t * qos);

extern template RMW_FASTRTPS_SHARED_CPP_PUBLIC
void dds_qos_to_rmw_qos<eprosima::fastdds::dds::DataReaderQos>(
  const eprosima::fastdds::dds::DataReaderQos & dds_qos,
  rmw_qos_profile_t * qos);

template<typename AttributeT>
void
dds_attributes_to_rmw_qos(
  const AttributeT & dds_qos,
  rmw_qos_profile_t * qos);

extern template RMW_FASTRTPS_SHARED_CPP_PUBLIC
void
dds_attributes_to_rmw_qos<eprosima::fastrtps::PublisherAttributes>(
  const eprosima::fastrtps::PublisherAttributes & dds_qos,
  rmw_qos_profile_t * qos);

extern template RMW_FASTRTPS_SHARED_CPP_PUBLIC
void
dds_attributes_to_rmw_qos<eprosima::fastrtps::SubscriberAttributes>(
  const eprosima::fastrtps::SubscriberAttributes & dds_qos,
  rmw_qos_profile_t * qos);

#endif  // RMW_FASTRTPS_SHARED_CPP__QOS_HPP_
<|endoftext|>


<commit_before>#include "APSEthernet.h"

#ifdef _WIN32
#include "iphlpapi.h"
#else
#include <ifaddrs.h>
#endif

APSEthernet::APSEthernet() : socket_(ios_, udp::endpoint(udp::v4(), APS_PROTO)) {
    FILE_LOG(logDEBUG) << "Creating ethernet interface";
    //enable broadcasting for enumerating
    socket_.set_option(asio::socket_base::broadcast(true));

    //io_service will return immediately so post receive task before .run()
    setup_receive();

    //Setup the asio service to run on a background thread
    receiveThread_ = std::thread([this](){ ios_.run(); });
};

APSEthernet::~APSEthernet() {
    FILE_LOG(logDEBUG) << "Cleaning up ethernet interface";
    ios_.stop();
    receiveThread_.join();
}

void APSEthernet::setup_receive(){
    socket_.async_receive_from(
        asio::buffer(receivedData_, 2048), senderEndpoint_,
        [this](std::error_code ec, std::size_t bytesReceived)
        {
            //If there is anything to look at hand it off to the sorter
            if (!ec && bytesReceived > 0)
            {
                vector<uint8_t> packetData(receivedData_, receivedData_ + bytesReceived);
                sort_packet(packetData, senderEndpoint_);
            }

            //Start the receiver again
            setup_receive();
    });
}

void APSEthernet::sort_packet(const vector<uint8_t> & packetData, const udp::endpoint & sender){
    //If we have the endpoint address then add it to the queue
    string senderIP = sender.address().to_string();
    if (msgQueues_.find(senderIP) == msgQueues_.end()) {
        //If it isn't in our list of APSs then perhaps we are seeing an enumerate status response
        //If so add the device info to the set
        if (packetData.size() == 84) {
            devInfo_[senderIP].endpoint = sender;
            //Turn the byte array into a packet to extract the MAC address and firmware version
            //MAC not strictly necessary as we could just use the broadcast MAC address
            APSEthernetPacket packet = APSEthernetPacket(packetData);
            devInfo_[senderIP].macAddr = packet.header.src;
            APSStatusBank_t statusRegs;
            std::copy(packet.payload.begin(), packet.payload.end(), statusRegs.array);
            FILE_LOG(logDEBUG1) << "Added device with IP " << senderIP <<
                " ; MAC addresss " << devInfo_[senderIP].macAddr.to_string() <<
                " ; firmware version " << hexn<4> << statusRegs.userFirmwareVersion;
        }
    }
    else {
        //Turn the byte array into an APSEthernetPacket
        APSEthernetPacket packet = APSEthernetPacket(packetData);
        //Grab a lock and push the packet into the message queue
        mLock_.lock();
        msgQueues_[senderIP].emplace(packet);
        mLock_.unlock();
    }
}

/* PUBLIC methods */

void APSEthernet::init() {
    reset_maps();
}

vector<string> APSEthernet::get_local_IPs(){
    vector<string> IPs;

    #ifdef _WIN32

    DWORD dwRetVal = 0;
    ULONG family = AF_INET; // we only care about IPv4 for now
    LONG flags = GAA_FLAG_INCLUDE_PREFIX; // not sure what the address prefix is
    PIP_ADAPTER_ADDRESSES pAddresses = nullptr;
    PIP_ADAPTER_ADDRESSES pCurAddresses = nullptr;
    PIP_ADAPTER_UNICAST_ADDRESS pUnicast = nullptr;

    ULONG outBufLen = 15000; //MSDN recommends preallocating 15KB
    pAddresses = (IP_ADAPTER_ADDRESSES *) malloc(outBufLen);
    dwRetVal = GetAdaptersAddresses(family, flags, nullptr, pAddresses, &outBufLen);

    if (dwRetVal == NO_ERROR) {
      for(pCurAddresses = pAddresses; pCurAddresses != nullptr; pCurAddresses = pCurAddresses->Next){
        FILE_LOG(logDEBUG1) << "Found IPv4 interface.";
        FILE_LOG(logDEBUG3) << "IfIndex (IPv4 interface): " << pCurAddresses->IfIndex;
        FILE_LOG(logDEBUG2) << "Adapter name: " << pCurAddresses->AdapterName;
        FILE_LOG(logDEBUG2) << "Friendly adapter name: " << pCurAddresses->FriendlyName; //TODO figure out unicode printing

        //Not yet supported in mingw64
        FILE_LOG(logDEBUG2) << "Transmit link speed: " << pCurAddresses->TransmitLinkSpeed;
        FILE_LOG(logDEBUG2) << "Receive link speed: " << pCurAddresses->ReceiveLinkSpeed;

        for(pUnicast = pCurAddresses->FirstUnicastAddress; pUnicast != nullptr; pUnicast = pUnicast->Next){
            char IPV4Addr[16]; //should be LPTSTR
            DWORD addrSize;
            WSAAddressToString(pUnicast->Address.lpSockaddr, pUnicast->Address.iSockaddrLength, nullptr, IPV4Addr, &addrSize);
            IPs.push_back(string(IPV4Addr));
            FILE_LOG(logDEBUG1) << "IPv4 address: " << IPs.back();
            FILE_LOG(logDEBUG1) << "Prefix length: " << pUnicast->OnLinkPrefixLength; //doesn't seem to work with mingw64
        }
      }
      free(pAddresses);
      pAddresses = nullptr;
    }
    else{
      FILE_LOG(logERROR) << "Call to GetAdaptersAddresses failed.";
      free(pAddresses);
      pAddresses = nullptr;
    }

    #else

    struct ifaddrs *ifap, *ifa;

    getifaddrs(&ifap);
    for (ifa = ifap; ifa != nullptr; ifa = ifa->ifa_next) {
        //We only care about IPv4 addresses
        if (ifa->ifa_addr->sa_family == AF_INET) {
            struct sockaddr_in* sa = (struct sockaddr_in *) ifa->ifa_addr;
            char* addr = inet_ntoa(sa->sin_addr);
            IPs.push_back(string(addr));
            FILE_LOG(logDEBUG1) << "Interface: " << ifa->ifa_name << "Address: " << IPs.back();
        }
    }
    freeifaddrs(ifap);
    #endif //_WIN32

    return IPs;
}

set<string> APSEthernet::enumerate() {
	/*
	 * Look for all APS units that respond to the broadcast packet
	 */

	FILE_LOG(logDEBUG1) << "APSEthernet::enumerate";

    reset_maps();

    vector<string> localIPs = get_local_IPs();

    for(auto IP : localIPs){
        //Put together the broadcast status request
        APSEthernetPacket broadcastPacket = APSEthernetPacket::create_broadcast_packet();
        typedef asio::ip::address_v4 addrv4;
        addrv4 broadcastAddr = addrv4::broadcast(addrv4::from_string(IP), addrv4::from_string("255.255.255.0"));
        FILE_LOG(logDEBUG2) << "Sending enumerate broadcast out on: " << broadcastAddr.to_string();
        udp::endpoint broadCastEndPoint(broadcastAddr, APS_PROTO);
        socket_.send_to(asio::buffer(broadcastPacket.serialize()), broadCastEndPoint);
    }

    std::this_thread::sleep_for(std::chrono::milliseconds(100));

    set<string> deviceSerials;
    for (auto kv : devInfo_) {
        FILE_LOG(logINFO) << "Found device: " << kv.first;
        deviceSerials.insert(kv.first);
    }
    return deviceSerials;
}

void APSEthernet::reset_maps() {
    devInfo_.clear();
    msgQueues_.clear();
}

void APSEthernet::connect(string serial) {

    mLock_.lock();
	msgQueues_[serial] = queue<APSEthernetPacket>();
    mLock_.unlock();
    if (devInfo_.find(serial) == devInfo_.end()) {
        devInfo_[serial].endpoint = udp::endpoint(asio::ip::address_v4::from_string(serial), APS_PROTO);
        devInfo_[serial].macAddr = MACAddr("FF:FF:FF:FF:FF:FF");
    }
}

void APSEthernet::disconnect(string serial) {
    mLock_.lock();
	msgQueues_.erase(serial);
    mLock_.unlock();
}

int APSEthernet::send(string serial, APSEthernetPacket msg, bool checkResponse) {
    msg.header.dest = devInfo_[serial].macAddr;
    return send_chunk(serial, vector<APSEthernetPacket>(1, msg), !checkResponse);
}

int APSEthernet::send(string serial, vector<APSEthernetPacket> msg, unsigned ackEvery /* see header for default */) {
    //Fill out the destination  MAC address
    FILE_LOG(logDEBUG3) << "Sending " << msg.size() << " packets to " << serial;
    auto iter = msg.begin();
    bool noACK = false;
    if (ackEvery == 0) {
        noACK = true;
        ackEvery = 1;
    }
    // it's nice to have extra status on slow EPROM writes
    bool verbose = (msg[0].header.command.cmd == static_cast<uint32_t>(APS_COMMANDS::EPROMIO));

    vector<APSEthernetPacket> buffer(ackEvery);

    while (iter != msg.end()){

        //Copy the next chunk into a buffer
        auto endPoint = iter + ackEvery;
        if (endPoint > msg.end()) {
            endPoint = msg.end();
        }
        auto chunkSize = std::distance(iter, endPoint);
        buffer.resize(chunkSize);
        std::copy(iter, endPoint, buffer.begin());

        for (auto & packet : buffer ){
            // insert the target MAC address - not really necessary anymore because UDP does filtering
            packet.header.dest = devInfo_[serial].macAddr;
            //NOACK sets the top bit of the command nibble of the command word
            packet.header.command.cmd |= (1 << 3);
        }

        //Apply acknowledge flag to last element of chunk
        if (!noACK){
            buffer.back().header.command.cmd &= ~(1 << 3);
        }

        auto result = send_chunk(serial, buffer, noACK);
        if (result != 0){
            return result;
        }
        std::advance(iter, chunkSize);

        if (verbose && (std::distance(msg.begin(), iter) % 1000 == 0)) {
            FILE_LOG(logDEBUG) << "Write " << 100*std::distance(msg.begin(), iter)/msg.size() << "% complete";
        }
    }
    return 0;
}

int APSEthernet::send_chunk(string serial, vector<APSEthernetPacket> chunk, bool noACK){

    unsigned seqNum, retryct = 0;

    while (retryct++ < 3) {
        seqNum = 0;
        for (auto packet : chunk){
            packet.header.seqNum = seqNum;
            seqNum++;
            FILE_LOG(logDEBUG4) << "Packet command: " << print_APSCommand(packet.header.command);
            socket_.send_to(asio::buffer(packet.serialize()), devInfo_[serial].endpoint);
            std::this_thread::sleep_for(std::chrono::microseconds(100));
        }

        if(noACK) break;
        //Wait for acknowledge
        //TODO: how to check response mode/stat for success?
        try{
            auto response = receive(serial)[0];
            break;
        }
        catch (std::exception& e) {
            FILE_LOG(logDEBUG) << "No acknowledge received, retrying ...";
        }
    }

    if (retryct == 3) {
        return -1;
    }
    return 0;
}

vector<APSEthernetPacket> APSEthernet::receive(string serial, size_t numPackets, size_t timeoutMS) {
    //Read the packets coming back in up to the timeout
    //Defaults: receive(string serial, size_t numPackets = 1, size_t timeoutMS = 1000);
    std::chrono::time_point<std::chrono::steady_clock> start, end;

    start = std::chrono::steady_clock::now();
    size_t elapsedTime = 0;

    vector<APSEthernetPacket> outVec;

    while (elapsedTime < timeoutMS){
        if (!msgQueues_[serial].empty()){
            mLock_.lock();
            outVec.push_back(msgQueues_[serial].front());
            msgQueues_[serial].pop();
            mLock_.unlock();
            FILE_LOG(logDEBUG4) << "Received packet command: " << print_APSCommand(outVec.back().header.command);
            if (outVec.size() == numPackets){
                FILE_LOG(logDEBUG3) << "Received " << numPackets << " packets from " << serial;
                return outVec;
            }
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
        end = std::chrono::steady_clock::now();
        elapsedTime =  std::chrono::duration_cast<std::chrono::milliseconds>(end-start).count();
    }

    throw runtime_error("Timed out on receive");
}
<commit_msg>Undo packet throttling commit<commit_after>#include "APSEthernet.h"

#ifdef _WIN32
#include "iphlpapi.h"
#else
#include <ifaddrs.h>
#endif

APSEthernet::APSEthernet() : socket_(ios_, udp::endpoint(udp::v4(), APS_PROTO)) {
    FILE_LOG(logDEBUG) << "Creating ethernet interface";
    //enable broadcasting for enumerating
    socket_.set_option(asio::socket_base::broadcast(true));

    //io_service will return immediately so post receive task before .run()
    setup_receive();

    //Setup the asio service to run on a background thread
    receiveThread_ = std::thread([this](){ ios_.run(); });
};

APSEthernet::~APSEthernet() {
    FILE_LOG(logDEBUG) << "Cleaning up ethernet interface";
    ios_.stop();
    receiveThread_.join();
}

void APSEthernet::setup_receive(){
    socket_.async_receive_from(
        asio::buffer(receivedData_, 2048), senderEndpoint_,
        [this](std::error_code ec, std::size_t bytesReceived)
        {
            //If there is anything to look at hand it off to the sorter
            if (!ec && bytesReceived > 0)
            {
                vector<uint8_t> packetData(receivedData_, receivedData_ + bytesReceived);
                sort_packet(packetData, senderEndpoint_);
            }

            //Start the receiver again
            setup_receive();
    });
}

void APSEthernet::sort_packet(const vector<uint8_t> & packetData, const udp::endpoint & sender){
    //If we have the endpoint address then add it to the queue
    string senderIP = sender.address().to_string();
    if (msgQueues_.find(senderIP) == msgQueues_.end()) {
        //If it isn't in our list of APSs then perhaps we are seeing an enumerate status response
        //If so add the device info to the set
        if (packetData.size() == 84) {
            devInfo_[senderIP].endpoint = sender;
            //Turn the byte array into a packet to extract the MAC address and firmware version
            //MAC not strictly necessary as we could just use the broadcast MAC address
            APSEthernetPacket packet = APSEthernetPacket(packetData);
            devInfo_[senderIP].macAddr = packet.header.src;
            APSStatusBank_t statusRegs;
            std::copy(packet.payload.begin(), packet.payload.end(), statusRegs.array);
            FILE_LOG(logDEBUG1) << "Added device with IP " << senderIP <<
                " ; MAC addresss " << devInfo_[senderIP].macAddr.to_string() <<
                " ; firmware version " << hexn<4> << statusRegs.userFirmwareVersion;
        }
    }
    else {
        //Turn the byte array into an APSEthernetPacket
        APSEthernetPacket packet = APSEthernetPacket(packetData);
        //Grab a lock and push the packet into the message queue
        mLock_.lock();
        msgQueues_[senderIP].emplace(packet);
        mLock_.unlock();
    }
}

/* PUBLIC methods */

void APSEthernet::init() {
    reset_maps();
}

vector<string> APSEthernet::get_local_IPs(){
    vector<string> IPs;

    #ifdef _WIN32

    DWORD dwRetVal = 0;
    ULONG family = AF_INET; // we only care about IPv4 for now
    LONG flags = GAA_FLAG_INCLUDE_PREFIX; // not sure what the address prefix is
    PIP_ADAPTER_ADDRESSES pAddresses = nullptr;
    PIP_ADAPTER_ADDRESSES pCurAddresses = nullptr;
    PIP_ADAPTER_UNICAST_ADDRESS pUnicast = nullptr;

    ULONG outBufLen = 15000; //MSDN recommends preallocating 15KB
    pAddresses = (IP_ADAPTER_ADDRESSES *) malloc(outBufLen);
    dwRetVal = GetAdaptersAddresses(family, flags, nullptr, pAddresses, &outBufLen);

    if (dwRetVal == NO_ERROR) {
      for(pCurAddresses = pAddresses; pCurAddresses != nullptr; pCurAddresses = pCurAddresses->Next){
        FILE_LOG(logDEBUG1) << "Found IPv4 interface.";
        FILE_LOG(logDEBUG3) << "IfIndex (IPv4 interface): " << pCurAddresses->IfIndex;
        FILE_LOG(logDEBUG2) << "Adapter name: " << pCurAddresses->AdapterName;
        FILE_LOG(logDEBUG2) << "Friendly adapter name: " << pCurAddresses->FriendlyName; //TODO figure out unicode printing

        //Not yet supported in mingw64
        FILE_LOG(logDEBUG2) << "Transmit link speed: " << pCurAddresses->TransmitLinkSpeed;
        FILE_LOG(logDEBUG2) << "Receive link speed: " << pCurAddresses->ReceiveLinkSpeed;

        for(pUnicast = pCurAddresses->FirstUnicastAddress; pUnicast != nullptr; pUnicast = pUnicast->Next){
            char IPV4Addr[16]; //should be LPTSTR
            DWORD addrSize;
            WSAAddressToString(pUnicast->Address.lpSockaddr, pUnicast->Address.iSockaddrLength, nullptr, IPV4Addr, &addrSize);
            IPs.push_back(string(IPV4Addr));
            FILE_LOG(logDEBUG1) << "IPv4 address: " << IPs.back();
            FILE_LOG(logDEBUG1) << "Prefix length: " << pUnicast->OnLinkPrefixLength; //doesn't seem to work with mingw64
        }
      }
      free(pAddresses);
      pAddresses = nullptr;
    }
    else{
      FILE_LOG(logERROR) << "Call to GetAdaptersAddresses failed.";
      free(pAddresses);
      pAddresses = nullptr;
    }

    #else

    struct ifaddrs *ifap, *ifa;

    getifaddrs(&ifap);
    for (ifa = ifap; ifa != nullptr; ifa = ifa->ifa_next) {
        //We only care about IPv4 addresses
        if (ifa->ifa_addr->sa_family == AF_INET) {
            struct sockaddr_in* sa = (struct sockaddr_in *) ifa->ifa_addr;
            char* addr = inet_ntoa(sa->sin_addr);
            IPs.push_back(string(addr));
            FILE_LOG(logDEBUG1) << "Interface: " << ifa->ifa_name << "Address: " << IPs.back();
        }
    }
    freeifaddrs(ifap);
    #endif //_WIN32

    return IPs;
}

set<string> APSEthernet::enumerate() {
	/*
	 * Look for all APS units that respond to the broadcast packet
	 */

	FILE_LOG(logDEBUG1) << "APSEthernet::enumerate";

    reset_maps();

    vector<string> localIPs = get_local_IPs();

    for(auto IP : localIPs){
        //Put together the broadcast status request
        APSEthernetPacket broadcastPacket = APSEthernetPacket::create_broadcast_packet();
        typedef asio::ip::address_v4 addrv4;
        addrv4 broadcastAddr = addrv4::broadcast(addrv4::from_string(IP), addrv4::from_string("255.255.255.0"));
        FILE_LOG(logDEBUG2) << "Sending enumerate broadcast out on: " << broadcastAddr.to_string();
        udp::endpoint broadCastEndPoint(broadcastAddr, APS_PROTO);
        socket_.send_to(asio::buffer(broadcastPacket.serialize()), broadCastEndPoint);
    }

    std::this_thread::sleep_for(std::chrono::milliseconds(100));

    set<string> deviceSerials;
    for (auto kv : devInfo_) {
        FILE_LOG(logINFO) << "Found device: " << kv.first;
        deviceSerials.insert(kv.first);
    }
    return deviceSerials;
}

void APSEthernet::reset_maps() {
    devInfo_.clear();
    msgQueues_.clear();
}

void APSEthernet::connect(string serial) {

    mLock_.lock();
	msgQueues_[serial] = queue<APSEthernetPacket>();
    mLock_.unlock();
    if (devInfo_.find(serial) == devInfo_.end()) {
        devInfo_[serial].endpoint = udp::endpoint(asio::ip::address_v4::from_string(serial), APS_PROTO);
        devInfo_[serial].macAddr = MACAddr("FF:FF:FF:FF:FF:FF");
    }
}

void APSEthernet::disconnect(string serial) {
    mLock_.lock();
	msgQueues_.erase(serial);
    mLock_.unlock();
}

int APSEthernet::send(string serial, APSEthernetPacket msg, bool checkResponse) {
    msg.header.dest = devInfo_[serial].macAddr;
    return send_chunk(serial, vector<APSEthernetPacket>(1, msg), !checkResponse);
}

int APSEthernet::send(string serial, vector<APSEthernetPacket> msg, unsigned ackEvery /* see header for default */) {
    //Fill out the destination  MAC address
    FILE_LOG(logDEBUG3) << "Sending " << msg.size() << " packets to " << serial;
    auto iter = msg.begin();
    bool noACK = false;
    if (ackEvery == 0) {
        noACK = true;
        ackEvery = 1;
    }
    // it's nice to have extra status on slow EPROM writes
    bool verbose = (msg[0].header.command.cmd == static_cast<uint32_t>(APS_COMMANDS::EPROMIO));

    vector<APSEthernetPacket> buffer(ackEvery);

    while (iter != msg.end()){

        //Copy the next chunk into a buffer
        auto endPoint = iter + ackEvery;
        if (endPoint > msg.end()) {
            endPoint = msg.end();
        }
        auto chunkSize = std::distance(iter, endPoint);
        buffer.resize(chunkSize);
        std::copy(iter, endPoint, buffer.begin());

        for (auto & packet : buffer ){
            // insert the target MAC address - not really necessary anymore because UDP does filtering
            packet.header.dest = devInfo_[serial].macAddr;
            //NOACK sets the top bit of the command nibble of the command word
            packet.header.command.cmd |= (1 << 3);
        }

        //Apply acknowledge flag to last element of chunk
        if (!noACK){
            buffer.back().header.command.cmd &= ~(1 << 3);
        }

        auto result = send_chunk(serial, buffer, noACK);
        if (result != 0){
            return result;
        }
        std::advance(iter, chunkSize);

        if (verbose && (std::distance(msg.begin(), iter) % 1000 == 0)) {
            FILE_LOG(logDEBUG) << "Write " << 100*std::distance(msg.begin(), iter)/msg.size() << "% complete";
        }
    }
    return 0;
}

int APSEthernet::send_chunk(string serial, vector<APSEthernetPacket> chunk, bool noACK){

    unsigned seqNum, retryct = 0;

    while (retryct++ < 3) {
        seqNum = 0;
        for (auto packet : chunk){
            packet.header.seqNum = seqNum;
            seqNum++;
            FILE_LOG(logDEBUG4) << "Packet command: " << print_APSCommand(packet.header.command);
            socket_.send_to(asio::buffer(packet.serialize()), devInfo_[serial].endpoint);
            // std::this_thread::sleep_for(std::chrono::microseconds(100));
        }

        if(noACK) break;
        //Wait for acknowledge
        //TODO: how to check response mode/stat for success?
        try{
            auto response = receive(serial)[0];
            break;
        }
        catch (std::exception& e) {
            FILE_LOG(logDEBUG) << "No acknowledge received, retrying ...";
        }
    }

    if (retryct == 3) {
        return -1;
    }
    return 0;
}

vector<APSEthernetPacket> APSEthernet::receive(string serial, size_t numPackets, size_t timeoutMS) {
    //Read the packets coming back in up to the timeout
    //Defaults: receive(string serial, size_t numPackets = 1, size_t timeoutMS = 1000);
    std::chrono::time_point<std::chrono::steady_clock> start, end;

    start = std::chrono::steady_clock::now();
    size_t elapsedTime = 0;

    vector<APSEthernetPacket> outVec;

    while (elapsedTime < timeoutMS){
        if (!msgQueues_[serial].empty()){
            mLock_.lock();
            outVec.push_back(msgQueues_[serial].front());
            msgQueues_[serial].pop();
            mLock_.unlock();
            FILE_LOG(logDEBUG4) << "Received packet command: " << print_APSCommand(outVec.back().header.command);
            if (outVec.size() == numPackets){
                FILE_LOG(logDEBUG3) << "Received " << numPackets << " packets from " << serial;
                return outVec;
            }
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
        end = std::chrono::steady_clock::now();
        elapsedTime =  std::chrono::duration_cast<std::chrono::milliseconds>(end-start).count();
    }

    throw runtime_error("Timed out on receive");
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtDeclarative module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qmlpixmapcache_p.h"

#include "qfxperf_p_p.h"

#include <qmlengine.h>
#include <private/qmlglobal_p.h>

#include <QCoreApplication>
#include <QImageReader>
#include <QHash>
#include <QNetworkReply>
#include <QPixmapCache>
#include <QFile>
#include <QThread>
#include <QMutex>
#include <QWaitCondition>
#include <QtCore/qdebug.h>
#include <private/qobject_p.h>

QT_BEGIN_NAMESPACE

#if (QT_VERSION < QT_VERSION_CHECK(4, 6, 2))
static uint qHash(const QUrl &u)
{
    return qHash(u.toString());
}
#endif

class QmlImageReader : public QThread
{
    Q_OBJECT
public:
    QmlImageReader(QObject *parent=0);
    ~QmlImageReader();

    void read(QmlPixmapReply *rep);
    void cancel(QmlPixmapReply *rep);

protected:
    void run();

private:
    struct Job {
        Job() : reply(0), error(false) {}
        QmlPixmapReply *reply;
        QImage img;
        bool error;
    };

    void loadImage(Job &job);

    QList<Job> jobs;
    QMutex mutex;
    QWaitCondition haveJob;
    bool quit;
};

class QmlImageDecodeEvent : public QEvent
{
public:
    QmlImageDecodeEvent(bool err, QImage &img) : QEvent(QEvent::User), error(err), image(img) {}

    bool error;
    QImage image;
};

Q_GLOBAL_STATIC(QmlImageReader, qmlImageReader)

QmlImageReader::QmlImageReader(QObject *parent) : QThread(parent), quit(false)
{
    start(QThread::LowPriority);
}

QmlImageReader::~QmlImageReader()
{
    quit = true;
    haveJob.wakeOne();
}

void QmlImageReader::read(QmlPixmapReply *reply)
{
    mutex.lock();
    Job job;
    job.reply = reply;
    jobs.append(job);
    if (jobs.count() == 1)
        haveJob.wakeOne();
    mutex.unlock();
}

void QmlImageReader::cancel(QmlPixmapReply *reply)
{
    mutex.lock();
    QList<Job>::iterator it = jobs.begin();
    while (it != jobs.end()) {
        if ((*it).reply == reply) {
            jobs.erase(it);
            break;
        }
        ++it;
    }
    mutex.unlock();
}

void QmlImageReader::loadImage(Job &job)
{
    QImageReader imgio(job.reply->device());
    if (imgio.read(&job.img)) {
        job.error = false;
    } else {
        job.error = true;
        qWarning() << imgio.errorString();
    }
}

void QmlImageReader::run()
{
    while (1) {
        mutex.lock();
        if (!jobs.count())
            haveJob.wait(&mutex);
        if (quit)
            break;
        Job runningJob = jobs.takeFirst();
        runningJob.reply->addRef();
        mutex.unlock();

        loadImage(runningJob);
        QCoreApplication::postEvent(runningJob.reply, new QmlImageDecodeEvent(runningJob.error, runningJob.img));
    }
}

static bool readImage(QIODevice *dev, QPixmap *pixmap)
{
    QImageReader imgio(dev);

//#define QT_TEST_SCALED_SIZE
#ifdef QT_TEST_SCALED_SIZE
    /*
    Some mechanism is needed for loading images at a limited size, especially
    for remote images. Loading only thumbnails of remote progressive JPEG
    images can be efficient. (Qt jpeg handler does not do so currently)
    */

    QSize limit(60,60);
    QSize sz = imgio.size();
    if (sz.width() > limit.width() || sz.height() > limit.height()) {
        sz.scale(limit,Qt::KeepAspectRatio);
        imgio.setScaledSize(sz);
    }
#endif

    QImage img;
    if (imgio.read(&img)) {
#ifdef QT_TEST_SCALED_SIZE
        if (!sz.isValid())
            img = img.scaled(limit,Qt::KeepAspectRatio);
#endif
        *pixmap = QPixmap::fromImage(img);
        return true;
    } else {
        qWarning() << imgio.errorString();
        return false;
    }
}

/*!
    \internal
    \class QmlPixmapCache
    \brief Enacapsultes a pixmap for QmlGraphics items.

    This class is NOT reentrant.
 */

static QString toLocalFileOrQrc(const QUrl& url)
{
    QString r = url.toLocalFile();
    if (r.isEmpty() && url.scheme() == QLatin1String("qrc"))
        r = QLatin1Char(':') + url.path();
    return r;
}

inline uint qHash(const QUrl &uri)
{
    return qHash(uri.toEncoded(QUrl::FormattingOption(0x100)));
}

typedef QHash<QUrl, QmlPixmapReply *> QmlPixmapReplyHash;
Q_GLOBAL_STATIC(QmlPixmapReplyHash, qmlActivePixmapReplies);

class QmlPixmapReplyPrivate : public QObjectPrivate
{
    Q_DECLARE_PUBLIC(QmlPixmapReply)

public:
    QmlPixmapReplyPrivate(const QUrl &u, QNetworkReply *r)
        : QObjectPrivate(), refCount(1), url(u), reply(r), status(QmlPixmapReply::Loading) {
    }

    int refCount;
    QUrl url;
    QNetworkReply *reply;
    QPixmap pixmap; // ensure reference to pixmap so QPixmapCache does not discard
    QImage image;
    QmlPixmapReply::Status status;
};

QmlPixmapReply::QmlPixmapReply(const QUrl &url, QNetworkReply *reply)
  : QObject(*new QmlPixmapReplyPrivate(url, reply), 0)
{
    Q_D(QmlPixmapReply);

    static int replyDownloadProgress = -1;
    static int replyFinished = -1;
    static int thisDownloadProgress = -1;
    static int thisNetworkRequestDone = -1;

    if (replyDownloadProgress == -1) {
        replyDownloadProgress = QNetworkReply::staticMetaObject.indexOfSignal("downloadProgress(qint64,qint64)");
        replyFinished = QNetworkReply::staticMetaObject.indexOfSignal("finished()");
        thisDownloadProgress = QmlPixmapReply::staticMetaObject.indexOfSignal("downloadProgress(qint64,qint64)");
        thisNetworkRequestDone = QmlPixmapReply::staticMetaObject.indexOfSlot("networkRequestDone()");
    }

    QMetaObject::connect(d->reply, replyDownloadProgress, this, thisDownloadProgress, Qt::DirectConnection);
    QMetaObject::connect(d->reply, replyFinished, this, thisNetworkRequestDone);
}

QmlPixmapReply::~QmlPixmapReply()
{
    Q_D(QmlPixmapReply);
    if (d->status == Decoding)
        qmlImageReader()->cancel(this);
    delete d->reply;
}

const QUrl &QmlPixmapReply::url() const
{
    Q_D(const QmlPixmapReply);
    return d->url;
}

void QmlPixmapReply::networkRequestDone()
{
    Q_D(QmlPixmapReply);
    if (d->reply->error()) {
        d->pixmap = QPixmap();
        d->status = Error;
        QByteArray key = d->url.toEncoded(QUrl::FormattingOption(0x100));
        QString strKey = QString::fromLatin1(key.constData(), key.count());
        QPixmapCache::insert(strKey, d->pixmap);
        qWarning() << "Network error loading" << d->url << d->reply->errorString();
        emit finished();
    } else {
        qmlImageReader()->read(this);
        d->status = Decoding;
    }
}

bool QmlPixmapReply::event(QEvent *event)
{
    Q_D(QmlPixmapReply);
    if (event->type() == QEvent::User) {
        if (!release(true)) {
            QmlImageDecodeEvent *de = static_cast<QmlImageDecodeEvent*>(event);
            d->status = de->error ? Error : Ready;
            if (d->status == Ready) {
                d->pixmap = QPixmap::fromImage(de->image);
                d->image = QImage();
            } else {
                qWarning() << "Error decoding" << d->url;
            }
            QByteArray key = d->url.toEncoded(QUrl::FormattingOption(0x100));
            QString strKey = QString::fromLatin1(key.constData(), key.count());
            QPixmapCache::insert(strKey, d->pixmap);
            emit finished();
        }
        return true;
    }

    return QObject::event(event);
}

QmlPixmapReply::Status QmlPixmapReply::status() const
{
    Q_D(const QmlPixmapReply);
    return d->status;
}

QIODevice *QmlPixmapReply::device()
{
    Q_D(QmlPixmapReply);
    return d->reply;
}

void QmlPixmapReply::addRef()
{
    Q_D(QmlPixmapReply);
    ++d->refCount;
}

bool QmlPixmapReply::release(bool defer)
{
    Q_D(QmlPixmapReply);
    Q_ASSERT(d->refCount > 0);
    --d->refCount;
    if (d->refCount == 0) {
        qmlActivePixmapReplies()->remove(d->url);
        if (defer)
            deleteLater();
        else
            delete this;
        return true;
    }

    return false;
}

/*!
    Finds the cached pixmap corresponding to \a url.
    If the image is a network resource and has not yet
    been retrieved and cached, request() must be called.

    Returns Ready, or Error if the image has been retrieved,
    otherwise the current retrieval status.
*/
QmlPixmapReply::Status QmlPixmapCache::get(const QUrl& url, QPixmap *pixmap)
{
    QmlPixmapReply::Status status = QmlPixmapReply::Unrequested;

#ifndef QT_NO_LOCALFILE_OPTIMIZED_QML
    QString lf = toLocalFileOrQrc(url);
    if (!lf.isEmpty()) {
        status = QmlPixmapReply::Ready;
        if (!QPixmapCache::find(lf,pixmap)) {
            QFile f(lf);
            if (f.open(QIODevice::ReadOnly)) {
                if (!readImage(&f, pixmap)) {
                    qWarning() << "Format error loading" << url;
                    *pixmap = QPixmap();
                    status = QmlPixmapReply::Error;
                }
            } else {
                qWarning() << "Cannot open" << url;
                *pixmap = QPixmap();
                status = QmlPixmapReply::Error;
            }
            if (status == QmlPixmapReply::Ready)
                QPixmapCache::insert(lf, *pixmap);
        }
        return status;
    }
#endif

    QByteArray key = url.toEncoded(QUrl::FormattingOption(0x100));
    QString strKey = QString::fromLatin1(key.constData(), key.count());
    QmlPixmapReplyHash::Iterator iter = qmlActivePixmapReplies()->find(url);
    if (QPixmapCache::find(strKey, pixmap)) {
        if (iter != qmlActivePixmapReplies()->end()) {
            status = (*iter)->status();
            (*iter)->release();
        } else {
            status = pixmap->isNull() ? QmlPixmapReply::Error : QmlPixmapReply::Ready;
        }
    } else if (iter != qmlActivePixmapReplies()->end()) {
        status = QmlPixmapReply::Loading;
    }

    return status;
}

/*!
    Starts a network request to load \a url.

    Returns a QmlPixmapReply.  Caller should connect to QmlPixmapReply::finished()
    and call get() when the image is available.

    The returned QmlPixmapReply will be deleted when all request() calls are
    matched by a corresponding get() call.
*/
QmlPixmapReply *QmlPixmapCache::request(QmlEngine *engine, const QUrl &url)
{
    QmlPixmapReplyHash::Iterator iter = qmlActivePixmapReplies()->find(url);
    if (iter == qmlActivePixmapReplies()->end()) {
        QNetworkRequest req(url);
        req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
        QmlPixmapReply *item = new QmlPixmapReply(url, engine->networkAccessManager()->get(req));
        iter = qmlActivePixmapReplies()->insert(url, item);
    } else {
        (*iter)->addRef();
    }

    return (*iter);
}

/*!
    Cancels a previous call to request().

    May also cancel loading (eg. if no other pending request).

    Any connections from the QmlPixmapReply returned by request() to \a obj will be
    disconnected.
*/
void QmlPixmapCache::cancel(const QUrl& url, QObject *obj)
{
    QmlPixmapReplyHash::Iterator iter = qmlActivePixmapReplies()->find(url);
    if (iter == qmlActivePixmapReplies()->end())
        return;

    QmlPixmapReply *reply = *iter;
    if (obj)
        QObject::disconnect(reply, 0, obj, 0);
    reply->release();
}

/*!
    This function is mainly for test verification. It returns the number of
    requests that are still unfinished.
*/
int QmlPixmapCache::pendingRequests()
{
    return qmlActivePixmapReplies()->count();
}

#include <qmlpixmapcache.moc>

QT_END_NAMESPACE
<commit_msg>Remove qHash(QUrl) duplicate<commit_after>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtDeclarative module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qmlpixmapcache_p.h"

#include "qfxperf_p_p.h"

#include <qmlengine.h>
#include <private/qmlglobal_p.h>

#include <QCoreApplication>
#include <QImageReader>
#include <QHash>
#include <QNetworkReply>
#include <QPixmapCache>
#include <QFile>
#include <QThread>
#include <QMutex>
#include <QWaitCondition>
#include <QtCore/qdebug.h>
#include <private/qobject_p.h>

QT_BEGIN_NAMESPACE

inline uint qHash(const QUrl &uri)
{
    return qHash(uri.toEncoded(QUrl::FormattingOption(0x100)));
}

class QmlImageReader : public QThread
{
    Q_OBJECT
public:
    QmlImageReader(QObject *parent=0);
    ~QmlImageReader();

    void read(QmlPixmapReply *rep);
    void cancel(QmlPixmapReply *rep);

protected:
    void run();

private:
    struct Job {
        Job() : reply(0), error(false) {}
        QmlPixmapReply *reply;
        QImage img;
        bool error;
    };

    void loadImage(Job &job);

    QList<Job> jobs;
    QMutex mutex;
    QWaitCondition haveJob;
    bool quit;
};

class QmlImageDecodeEvent : public QEvent
{
public:
    QmlImageDecodeEvent(bool err, QImage &img) : QEvent(QEvent::User), error(err), image(img) {}

    bool error;
    QImage image;
};

Q_GLOBAL_STATIC(QmlImageReader, qmlImageReader)

QmlImageReader::QmlImageReader(QObject *parent) : QThread(parent), quit(false)
{
    start(QThread::LowPriority);
}

QmlImageReader::~QmlImageReader()
{
    quit = true;
    haveJob.wakeOne();
}

void QmlImageReader::read(QmlPixmapReply *reply)
{
    mutex.lock();
    Job job;
    job.reply = reply;
    jobs.append(job);
    if (jobs.count() == 1)
        haveJob.wakeOne();
    mutex.unlock();
}

void QmlImageReader::cancel(QmlPixmapReply *reply)
{
    mutex.lock();
    QList<Job>::iterator it = jobs.begin();
    while (it != jobs.end()) {
        if ((*it).reply == reply) {
            jobs.erase(it);
            break;
        }
        ++it;
    }
    mutex.unlock();
}

void QmlImageReader::loadImage(Job &job)
{
    QImageReader imgio(job.reply->device());
    if (imgio.read(&job.img)) {
        job.error = false;
    } else {
        job.error = true;
        qWarning() << imgio.errorString();
    }
}

void QmlImageReader::run()
{
    while (1) {
        mutex.lock();
        if (!jobs.count())
            haveJob.wait(&mutex);
        if (quit)
            break;
        Job runningJob = jobs.takeFirst();
        runningJob.reply->addRef();
        mutex.unlock();

        loadImage(runningJob);
        QCoreApplication::postEvent(runningJob.reply, new QmlImageDecodeEvent(runningJob.error, runningJob.img));
    }
}

static bool readImage(QIODevice *dev, QPixmap *pixmap)
{
    QImageReader imgio(dev);

//#define QT_TEST_SCALED_SIZE
#ifdef QT_TEST_SCALED_SIZE
    /*
    Some mechanism is needed for loading images at a limited size, especially
    for remote images. Loading only thumbnails of remote progressive JPEG
    images can be efficient. (Qt jpeg handler does not do so currently)
    */

    QSize limit(60,60);
    QSize sz = imgio.size();
    if (sz.width() > limit.width() || sz.height() > limit.height()) {
        sz.scale(limit,Qt::KeepAspectRatio);
        imgio.setScaledSize(sz);
    }
#endif

    QImage img;
    if (imgio.read(&img)) {
#ifdef QT_TEST_SCALED_SIZE
        if (!sz.isValid())
            img = img.scaled(limit,Qt::KeepAspectRatio);
#endif
        *pixmap = QPixmap::fromImage(img);
        return true;
    } else {
        qWarning() << imgio.errorString();
        return false;
    }
}

/*!
    \internal
    \class QmlPixmapCache
    \brief Enacapsultes a pixmap for QmlGraphics items.

    This class is NOT reentrant.
 */

static QString toLocalFileOrQrc(const QUrl& url)
{
    QString r = url.toLocalFile();
    if (r.isEmpty() && url.scheme() == QLatin1String("qrc"))
        r = QLatin1Char(':') + url.path();
    return r;
}

typedef QHash<QUrl, QmlPixmapReply *> QmlPixmapReplyHash;
Q_GLOBAL_STATIC(QmlPixmapReplyHash, qmlActivePixmapReplies);

class QmlPixmapReplyPrivate : public QObjectPrivate
{
    Q_DECLARE_PUBLIC(QmlPixmapReply)

public:
    QmlPixmapReplyPrivate(const QUrl &u, QNetworkReply *r)
        : QObjectPrivate(), refCount(1), url(u), reply(r), status(QmlPixmapReply::Loading) {
    }

    int refCount;
    QUrl url;
    QNetworkReply *reply;
    QPixmap pixmap; // ensure reference to pixmap so QPixmapCache does not discard
    QImage image;
    QmlPixmapReply::Status status;
};

QmlPixmapReply::QmlPixmapReply(const QUrl &url, QNetworkReply *reply)
  : QObject(*new QmlPixmapReplyPrivate(url, reply), 0)
{
    Q_D(QmlPixmapReply);

    static int replyDownloadProgress = -1;
    static int replyFinished = -1;
    static int thisDownloadProgress = -1;
    static int thisNetworkRequestDone = -1;

    if (replyDownloadProgress == -1) {
        replyDownloadProgress = QNetworkReply::staticMetaObject.indexOfSignal("downloadProgress(qint64,qint64)");
        replyFinished = QNetworkReply::staticMetaObject.indexOfSignal("finished()");
        thisDownloadProgress = QmlPixmapReply::staticMetaObject.indexOfSignal("downloadProgress(qint64,qint64)");
        thisNetworkRequestDone = QmlPixmapReply::staticMetaObject.indexOfSlot("networkRequestDone()");
    }

    QMetaObject::connect(d->reply, replyDownloadProgress, this, thisDownloadProgress, Qt::DirectConnection);
    QMetaObject::connect(d->reply, replyFinished, this, thisNetworkRequestDone);
}

QmlPixmapReply::~QmlPixmapReply()
{
    Q_D(QmlPixmapReply);
    if (d->status == Decoding)
        qmlImageReader()->cancel(this);
    delete d->reply;
}

const QUrl &QmlPixmapReply::url() const
{
    Q_D(const QmlPixmapReply);
    return d->url;
}

void QmlPixmapReply::networkRequestDone()
{
    Q_D(QmlPixmapReply);
    if (d->reply->error()) {
        d->pixmap = QPixmap();
        d->status = Error;
        QByteArray key = d->url.toEncoded(QUrl::FormattingOption(0x100));
        QString strKey = QString::fromLatin1(key.constData(), key.count());
        QPixmapCache::insert(strKey, d->pixmap);
        qWarning() << "Network error loading" << d->url << d->reply->errorString();
        emit finished();
    } else {
        qmlImageReader()->read(this);
        d->status = Decoding;
    }
}

bool QmlPixmapReply::event(QEvent *event)
{
    Q_D(QmlPixmapReply);
    if (event->type() == QEvent::User) {
        if (!release(true)) {
            QmlImageDecodeEvent *de = static_cast<QmlImageDecodeEvent*>(event);
            d->status = de->error ? Error : Ready;
            if (d->status == Ready) {
                d->pixmap = QPixmap::fromImage(de->image);
                d->image = QImage();
            } else {
                qWarning() << "Error decoding" << d->url;
            }
            QByteArray key = d->url.toEncoded(QUrl::FormattingOption(0x100));
            QString strKey = QString::fromLatin1(key.constData(), key.count());
            QPixmapCache::insert(strKey, d->pixmap);
            emit finished();
        }
        return true;
    }

    return QObject::event(event);
}

QmlPixmapReply::Status QmlPixmapReply::status() const
{
    Q_D(const QmlPixmapReply);
    return d->status;
}

QIODevice *QmlPixmapReply::device()
{
    Q_D(QmlPixmapReply);
    return d->reply;
}

void QmlPixmapReply::addRef()
{
    Q_D(QmlPixmapReply);
    ++d->refCount;
}

bool QmlPixmapReply::release(bool defer)
{
    Q_D(QmlPixmapReply);
    Q_ASSERT(d->refCount > 0);
    --d->refCount;
    if (d->refCount == 0) {
        qmlActivePixmapReplies()->remove(d->url);
        if (defer)
            deleteLater();
        else
            delete this;
        return true;
    }

    return false;
}

/*!
    Finds the cached pixmap corresponding to \a url.
    If the image is a network resource and has not yet
    been retrieved and cached, request() must be called.

    Returns Ready, or Error if the image has been retrieved,
    otherwise the current retrieval status.
*/
QmlPixmapReply::Status QmlPixmapCache::get(const QUrl& url, QPixmap *pixmap)
{
    QmlPixmapReply::Status status = QmlPixmapReply::Unrequested;

#ifndef QT_NO_LOCALFILE_OPTIMIZED_QML
    QString lf = toLocalFileOrQrc(url);
    if (!lf.isEmpty()) {
        status = QmlPixmapReply::Ready;
        if (!QPixmapCache::find(lf,pixmap)) {
            QFile f(lf);
            if (f.open(QIODevice::ReadOnly)) {
                if (!readImage(&f, pixmap)) {
                    qWarning() << "Format error loading" << url;
                    *pixmap = QPixmap();
                    status = QmlPixmapReply::Error;
                }
            } else {
                qWarning() << "Cannot open" << url;
                *pixmap = QPixmap();
                status = QmlPixmapReply::Error;
            }
            if (status == QmlPixmapReply::Ready)
                QPixmapCache::insert(lf, *pixmap);
        }
        return status;
    }
#endif

    QByteArray key = url.toEncoded(QUrl::FormattingOption(0x100));
    QString strKey = QString::fromLatin1(key.constData(), key.count());
    QmlPixmapReplyHash::Iterator iter = qmlActivePixmapReplies()->find(url);
    if (QPixmapCache::find(strKey, pixmap)) {
        if (iter != qmlActivePixmapReplies()->end()) {
            status = (*iter)->status();
            (*iter)->release();
        } else {
            status = pixmap->isNull() ? QmlPixmapReply::Error : QmlPixmapReply::Ready;
        }
    } else if (iter != qmlActivePixmapReplies()->end()) {
        status = QmlPixmapReply::Loading;
    }

    return status;
}

/*!
    Starts a network request to load \a url.

    Returns a QmlPixmapReply.  Caller should connect to QmlPixmapReply::finished()
    and call get() when the image is available.

    The returned QmlPixmapReply will be deleted when all request() calls are
    matched by a corresponding get() call.
*/
QmlPixmapReply *QmlPixmapCache::request(QmlEngine *engine, const QUrl &url)
{
    QmlPixmapReplyHash::Iterator iter = qmlActivePixmapReplies()->find(url);
    if (iter == qmlActivePixmapReplies()->end()) {
        QNetworkRequest req(url);
        req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
        QmlPixmapReply *item = new QmlPixmapReply(url, engine->networkAccessManager()->get(req));
        iter = qmlActivePixmapReplies()->insert(url, item);
    } else {
        (*iter)->addRef();
    }

    return (*iter);
}

/*!
    Cancels a previous call to request().

    May also cancel loading (eg. if no other pending request).

    Any connections from the QmlPixmapReply returned by request() to \a obj will be
    disconnected.
*/
void QmlPixmapCache::cancel(const QUrl& url, QObject *obj)
{
    QmlPixmapReplyHash::Iterator iter = qmlActivePixmapReplies()->find(url);
    if (iter == qmlActivePixmapReplies()->end())
        return;

    QmlPixmapReply *reply = *iter;
    if (obj)
        QObject::disconnect(reply, 0, obj, 0);
    reply->release();
}

/*!
    This function is mainly for test verification. It returns the number of
    requests that are still unfinished.
*/
int QmlPixmapCache::pendingRequests()
{
    return qmlActivePixmapReplies()->count();
}

#include <qmlpixmapcache.moc>

QT_END_NAMESPACE
<|endoftext|>


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

#ifndef _BGFX_POLYGON_B2DPOLYPOLYGONFILLRULE_HXX
#define _BGFX_POLYGON_B2DPOLYPOLYGONFILLRULE_HXX

#ifndef _SAL_TYPES_H_
#include <sal/types.h>
#endif

//////////////////////////////////////////////////////////////////////////////

namespace basegfx
{
    /** Fill rule to use for poly-polygon filling.

        The fill rule determines which areas are inside, and which are
        outside the poly-polygon.
     */
    enum FillRule
    {
        /** Areas, for which a scanline has crossed an odd number of
            vertices, are regarded 'inside', the remainder 'outside'
            of the poly-polygon.
         */
        FillRule_EVEN_ODD,

        /** For each edge a scanline crosses, a current winding number
            is updated. Downward edges count +1, upward edges count
            -1. If the total accumulated winding number for one area
            is not zero, this area is regarded 'inside', otherwise,
            'outside'.
         */
        FillRule_NONZERO_WINDING_NUMBER
    };
}

#endif /* _BGFX_POLYGON_B2DPOLYPOLYGONFILLRULE_HXX */
<commit_msg>INTEGRATION: CWS changefileheader (1.3.88); FILE MERGED 2008/04/01 15:01:08 thb 1.3.88.2: #i85898# Stripping all external header guards 2008/03/28 16:05:41 rt 1.3.88.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: b2dpolypolygonfillrule.hxx,v $
 * $Revision: 1.4 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef _BGFX_POLYGON_B2DPOLYPOLYGONFILLRULE_HXX
#define _BGFX_POLYGON_B2DPOLYPOLYGONFILLRULE_HXX

#include <sal/types.h>

//////////////////////////////////////////////////////////////////////////////

namespace basegfx
{
    /** Fill rule to use for poly-polygon filling.

        The fill rule determines which areas are inside, and which are
        outside the poly-polygon.
     */
    enum FillRule
    {
        /** Areas, for which a scanline has crossed an odd number of
            vertices, are regarded 'inside', the remainder 'outside'
            of the poly-polygon.
         */
        FillRule_EVEN_ODD,

        /** For each edge a scanline crosses, a current winding number
            is updated. Downward edges count +1, upward edges count
            -1. If the total accumulated winding number for one area
            is not zero, this area is regarded 'inside', otherwise,
            'outside'.
         */
        FillRule_NONZERO_WINDING_NUMBER
    };
}

#endif /* _BGFX_POLYGON_B2DPOLYPOLYGONFILLRULE_HXX */
<|endoftext|>