<commit_before>/*
 * Copyright (C) 2009 Nokia Corporation.
 *
 * Contact: Marius Vollmer <marius.vollmer@nokia.com>
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 *
 */

#include <QtTest/QtTest>
#include <QtCore>
#include "nanoxml.h"
#include "fileutils.h"
#include "contexttypeinfo.h"
#include "contexttyperegistryinfo.h"

ContextTypeRegistryInfo* ContextTypeRegistryInfo::registryInstance = new ContextTypeRegistryInfo();

/* Mocked ContextTypeRegistryInfo */

ContextTypeRegistryInfo::ContextTypeRegistryInfo()
{
}

ContextTypeRegistryInfo* ContextTypeRegistryInfo::instance()
{
    return registryInstance;
}

NanoTree ContextTypeRegistryInfo::typeDefinitionForName(QString name)
{
    if (name == "double") {
        QVariantList tree;
        QVariantList doc;
        QVariantList name;
        name << QVariant("name");
        name << QVariant("double");
        doc << QVariant("doc");
        doc << QVariant("double doc");
        tree << QVariant("type");
        tree << QVariant(name);
        tree << QVariant(doc);
        return ContextTypeInfo(QVariant(tree));
    } else if (name == "complex") {
        QVariantList tree;
        QVariantList doc;
        QVariantList base;
        QVariantList name;
        name << QVariant("name");
        name << QVariant("complex");
        doc << QVariant("doc");
        doc << QVariant("complex doc");
        base << QVariant("base");
        base << QVariant("double");
        tree << QVariant("type");
        tree << QVariant(name);
        tree << QVariant(doc);
        tree << QVariant(base);
        return ContextTypeInfo(QVariant(tree));
    } else
        return ContextTypeInfo();
}

class ContextTypeInfoUnitTest : public QObject
{
    Q_OBJECT

private slots:
    void name();
    void doc();
    void base();
    void definition();
    void parseDoubleType();
    void parseCustomDoubleType();
    void parseUniformList();
    void parseMap();
};

void ContextTypeInfoUnitTest::name()
{
    QCOMPARE(ContextTypeInfo(QString("bool")).name(), QString("bool"));
    QCOMPARE(ContextTypeInfo(QString("string")).name(), QString("string"));

    QVariantList lst;
    lst << QVariant("int32");
    QCOMPARE(ContextTypeInfo(QVariant(lst)).name(), QString("int32"));
}

void ContextTypeInfoUnitTest::doc()
{
    QCOMPARE(ContextTypeInfo(QString("double")).doc(), QString("double doc"));
}

void ContextTypeInfoUnitTest::definition()
{
    NanoTree def = ContextTypeInfo(QString("double")).definition();
    QCOMPARE(def.keyValue("name").toString(), QString("double"));
    QCOMPARE(def.keyValue("doc").toString(), QString("double doc"));
}

void ContextTypeInfoUnitTest::base()
{
    ContextTypeInfo base = ContextTypeInfo(QString("complex")).base();
    QCOMPARE(base.name(), QString("double"));
    QCOMPARE(base.doc(), QString("double doc"));
}

void ContextTypeInfoUnitTest::parseDoubleType()
{
    /*
    NanoXml parser(LOCAL_FILE("double.xml"));
    QCOMPARE(parser.didFail(), false);

    ContextTypeInfo typeInfo(parser.result());
    QCOMPARE(typeInfo.name(), QString("double"));
    QCOMPARE(typeInfo.parameterDoc("min"), QString("Minimum value"));
    QCOMPARE(typeInfo.parameterDoc("max"), QString("Maximum value"));
    QCOMPARE(typeInfo.doc(), QString("A double value within the given limits."));
    */

    //QStringList params = typeInfo.parameters();
    //QCOMPARE(params.size(), 2);
    //QVERIFY(params.contains(QString("min")));
    //QVERIFY(params.contains(QString("max")));
}

void ContextTypeInfoUnitTest::parseCustomDoubleType()
{
    /*
    NanoXml parser(LOCAL_FILE("custom-double.xml"));
    QCOMPARE(parser.didFail(), false);

    ContextTypeInfo typeInfo(parser.result());
    QCOMPARE(typeInfo.name(), QString("custom-double"));
    QCOMPARE(typeInfo.parameterValue("min"), QString("1"));
    QCOMPARE(typeInfo.parameterValue("max"), QString("666"));
    QCOMPARE(typeInfo.parameterDoc("min"), QString("Minimum value"));
    QCOMPARE(typeInfo.parameterDoc("max"), QString("Maximum value"));
    QCOMPARE(typeInfo.doc(), QString("A double value that represents the level of hell in you."));
    */
}

void ContextTypeInfoUnitTest::parseUniformList()
{
    /*
    NanoXml parser(LOCAL_FILE("uniform-list.xml"));
    QCOMPARE(parser.didFail(), false);

    ContextUniformListTypeInfo listInfo(parser.result());
    QCOMPARE(listInfo.base().name(), QString("list"));
    QCOMPARE(listInfo.name(), QString("uniform-list"));
    ContextTypeInfo elementTypeInfo = listInfo.elementType();
    QCOMPARE(elementTypeInfo.name(), QString("double"));
    */
}

void ContextTypeInfoUnitTest::parseMap()
{
    /*
    NanoXml parser(LOCAL_FILE("person.xml"));
    QCOMPARE(parser.didFail(), false);

    ContextMapTypeInfo personInfo(parser.result());
    QCOMPARE(personInfo.name(), QString("person"));
    QCOMPARE(personInfo.base().name(), QString("map"));
    QCOMPARE(personInfo.keyDoc("name"), QString("Name of the person"));
    QCOMPARE(personInfo.keyDoc("surname"), QString("Surname of the person"));
    QCOMPARE(personInfo.keyDoc("age"), QString("Age of the person"));

    QCOMPARE(personInfo.keyType("name").name(), QString("string"));
    QCOMPARE(personInfo.keyType("surname").name(), QString("string"));
    QCOMPARE(personInfo.keyType("age").name(), QString("int32"));
    */
}

#include "contexttypeinfounittest.moc"
QTEST_MAIN(ContextTypeInfoUnitTest);
<commit_msg>Test ContextTypeInfo::parameterDoc.<commit_after>/*
 * Copyright (C) 2009 Nokia Corporation.
 *
 * Contact: Marius Vollmer <marius.vollmer@nokia.com>
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 *
 */

#include <QtTest/QtTest>
#include <QtCore>
#include "nanoxml.h"
#include "fileutils.h"
#include "contexttypeinfo.h"
#include "contexttyperegistryinfo.h"

ContextTypeRegistryInfo* ContextTypeRegistryInfo::registryInstance = new ContextTypeRegistryInfo();

/* Mocked ContextTypeRegistryInfo */

ContextTypeRegistryInfo::ContextTypeRegistryInfo()
{
}

ContextTypeRegistryInfo* ContextTypeRegistryInfo::instance()
{
    return registryInstance;
}

NanoTree ContextTypeRegistryInfo::typeDefinitionForName(QString name)
{
    if (name == "double") {
        QVariantList tree;
        QVariantList doc;
        QVariantList name;
        name << QVariant("name");
        name << QVariant("double");
        doc << QVariant("doc");
        doc << QVariant("double doc");
        tree << QVariant("type");
        tree << QVariant(name);
        tree << QVariant(doc);
        return ContextTypeInfo(QVariant(tree));
    } else if (name == "complex") {
        QVariantList tree;
        QVariantList doc;
        QVariantList base;
        QVariantList name;
        QVariantList params;
        QVariantList p1;
        QVariantList p1Doc;

        name << QVariant("name");
        name << QVariant("complex");

        doc << QVariant("doc");
        doc << QVariant("complex doc");

        base << QVariant("base");
        base << QVariant("double");

        p1 << QVariant("p1");
        p1Doc << QVariant("doc");
        p1Doc << QVariant("p1 doc");
        p1 << QVariant(p1Doc);
        params << QVariant("params");
        params << QVariant(p1);

        tree << QVariant("type");
        tree << QVariant(name);
        tree << QVariant(params);
        tree << QVariant(doc);
        tree << QVariant(base);
        return ContextTypeInfo(QVariant(tree));
    } else
        return ContextTypeInfo();
}

class ContextTypeInfoUnitTest : public QObject
{
    Q_OBJECT

private slots:
    void name();
    void doc();
    void base();
    void definition();
    void parameterDoc();
    void parseDoubleType();
    void parseCustomDoubleType();
    void parseUniformList();
    void parseMap();
};

void ContextTypeInfoUnitTest::name()
{
    QCOMPARE(ContextTypeInfo(QString("bool")).name(), QString("bool"));
    QCOMPARE(ContextTypeInfo(QString("string")).name(), QString("string"));

    QVariantList lst;
    lst << QVariant("int32");
    QCOMPARE(ContextTypeInfo(QVariant(lst)).name(), QString("int32"));
}

void ContextTypeInfoUnitTest::doc()
{
    QCOMPARE(ContextTypeInfo(QString("double")).doc(), QString("double doc"));
}

void ContextTypeInfoUnitTest::definition()
{
    NanoTree def = ContextTypeInfo(QString("double")).definition();
    QCOMPARE(def.keyValue("name").toString(), QString("double"));
    QCOMPARE(def.keyValue("doc").toString(), QString("double doc"));
}

void ContextTypeInfoUnitTest::base()
{
    ContextTypeInfo base = ContextTypeInfo(QString("complex")).base();
    QCOMPARE(base.name(), QString("double"));
    QCOMPARE(base.doc(), QString("double doc"));
}

void ContextTypeInfoUnitTest::parameterDoc()
{
    ContextTypeInfo typeInfo = ContextTypeInfo(QString("complex"));
    QCOMPARE(typeInfo.parameterDoc("p1"), QString("p1 doc"));

}

void ContextTypeInfoUnitTest::parseDoubleType()
{
    /*
    NanoXml parser(LOCAL_FILE("double.xml"));
    QCOMPARE(parser.didFail(), false);

    ContextTypeInfo typeInfo(parser.result());
    QCOMPARE(typeInfo.name(), QString("double"));
    QCOMPARE(typeInfo.parameterDoc("min"), QString("Minimum value"));
    QCOMPARE(typeInfo.parameterDoc("max"), QString("Maximum value"));
    QCOMPARE(typeInfo.doc(), QString("A double value within the given limits."));
    */

    //QStringList params = typeInfo.parameters();
    //QCOMPARE(params.size(), 2);
    //QVERIFY(params.contains(QString("min")));
    //QVERIFY(params.contains(QString("max")));
}

void ContextTypeInfoUnitTest::parseCustomDoubleType()
{
    /*
    NanoXml parser(LOCAL_FILE("custom-double.xml"));
    QCOMPARE(parser.didFail(), false);

    ContextTypeInfo typeInfo(parser.result());
    QCOMPARE(typeInfo.name(), QString("custom-double"));
    QCOMPARE(typeInfo.parameterValue("min"), QString("1"));
    QCOMPARE(typeInfo.parameterValue("max"), QString("666"));
    QCOMPARE(typeInfo.parameterDoc("min"), QString("Minimum value"));
    QCOMPARE(typeInfo.parameterDoc("max"), QString("Maximum value"));
    QCOMPARE(typeInfo.doc(), QString("A double value that represents the level of hell in you."));
    */
}

void ContextTypeInfoUnitTest::parseUniformList()
{
    /*
    NanoXml parser(LOCAL_FILE("uniform-list.xml"));
    QCOMPARE(parser.didFail(), false);

    ContextUniformListTypeInfo listInfo(parser.result());
    QCOMPARE(listInfo.base().name(), QString("list"));
    QCOMPARE(listInfo.name(), QString("uniform-list"));
    ContextTypeInfo elementTypeInfo = listInfo.elementType();
    QCOMPARE(elementTypeInfo.name(), QString("double"));
    */
}

void ContextTypeInfoUnitTest::parseMap()
{
    /*
    NanoXml parser(LOCAL_FILE("person.xml"));
    QCOMPARE(parser.didFail(), false);

    ContextMapTypeInfo personInfo(parser.result());
    QCOMPARE(personInfo.name(), QString("person"));
    QCOMPARE(personInfo.base().name(), QString("map"));
    QCOMPARE(personInfo.keyDoc("name"), QString("Name of the person"));
    QCOMPARE(personInfo.keyDoc("surname"), QString("Surname of the person"));
    QCOMPARE(personInfo.keyDoc("age"), QString("Age of the person"));

    QCOMPARE(personInfo.keyType("name").name(), QString("string"));
    QCOMPARE(personInfo.keyType("surname").name(), QString("string"));
    QCOMPARE(personInfo.keyType("age").name(), QString("int32"));
    */
}

#include "contexttypeinfounittest.moc"
QTEST_MAIN(ContextTypeInfoUnitTest);
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    Mesh2.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 2002 Insight Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

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

//  Software Guide : BeginLatex
//
//  A Mesh can contain a variety of cells types. Typical cells are the
//  LineCell, TriangleCell, QuadrilateralCell and TetrahedronCell. A large
//  flexibility is provided for managing cells at the price of a bit more of
//  complexity than in the case of point management.
//
//  The following code creates a polygonal line in order to illustrate the
//  simplest case of cell management in a Mesh. The only cell type used here is
//  the \code{itk::LineCell}. The header file of this class has to be included.
//
//  \index{itk::LineCell!Header}
//
//  Software Guide : EndLatex

#include "itkMesh.h"

// Software Guide : BeginCodeSnippet
#include "itkLineCell.h"
// Software Guide : EndCodeSnippet

int main()
{

  typedef float                             PixelType;
  typedef itk::Mesh< PixelType, 3 >         MeshType;

  //  Software Guide : BeginLatex
  //
  //  In order to be consitent with the Mesh, cell types have to be configured
  //  with a number of custom types taken from the mesh traits. The set of
  //  traits relevant to cells are packaged by the Mesh class into the
  //  \code{CellType} trait. This trait needs to be passed to the actual cell
  //  types at the moment of their instantiation. The following line shows how
  //  to extract the Cell traits from the Mesh type.
  //
  //  \index{itk::Mesh!CellType}
  //  \index{itk::Mesh!traits}
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  typedef MeshType::CellType                CellType;
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  The \code{itk::LineCell} type can now be instantiated using the traits
  //  taken from the Mesh.  \index{itk::LineCell!Instantiation}
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  typedef itk::LineCell< CellType >         LineType;
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  The main difference in the way cells and points are managed by the Mesh
  //  is that points are stored by copy on the PointsContainer while cells are
  //  stored in the CellsContainer using pointers. The reason for using
  //  pointers is that cells use C++ polymorphism on the mesh. This means that
  //  the mesh is only aware of having pointers to a generic cell which is the
  //  base class of all the specific cell types. This architecture makes
  //  possible to combine different cell types in the same mesh. Points, on the
  //  other hand, are of a single type and have a small memory footprint, which
  //  facilitates to copy them directly inside the container.
  //
  //  \index{itk::Cell!CellAutoPointer}
  //  \index{itk::Mesh!CellAutoPointer}
  //  \index{CellAutoPointer}
  //  \index{itk::AutoPointer}
  //
  //  Managing cells by pointers add another level of complexity to the Mesh
  //  since it is now necessary to stablish a protocol to make clear who is
  //  responsible for allocating and releasing the cells' memory. This protocol
  //  is implemented in the form of a specific type of pointer called the
  //  \code{CellAutoPointer}. This pointer differ in many senses from the
  //  SmartPointer. The CellAutoPointer has a internal pointer to the actual
  //  object and a boolean flag that indicates if the CellAutoPointer is
  //  responsible for releasing the cell memory whenever the time comes for its
  //  own destruction. It is said that a \code{CellAutoPointer} \emph{owns} the
  //  cell when it is responsible for its destruction. Many CellAutoPointer can
  //  point to the same cell but at any given time, only \textbf{one}
  //  CellAutoPointer can own the cell.
  //
  //  The \code{CellAutoPointer} trait is defined in the MeshType and can be
  //  extracted as illustrated in the following line.
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  typedef CellType::CellAutoPointer         CellAutoPointer;
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  Note that the CellAutoPointer is pointing to a generic cell type. It is
  //  not aware of the actual type of the cell, which can be for example
  //  LineCell, TriangleCell or TetrahedronCell. This fact will influence the
  //  way in which we access cells later on.
  //
  //  At this point we can actually create a mesh and insert some points on it.
  //
  //  \index{itk::Mesh!New()}
  //  \index{itk::Mesh!SetPoint()}
  //  \index{itk::Mesh!PointType}
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  MeshType::Pointer  mesh = MeshType::New();

  MeshType::PointType p0;
  MeshType::PointType p1;
  MeshType::PointType p2;

  p0[0] = -1.0; p0[1] = 0.0; p0[2] = 0.0;
  p1[0] =  1.0; p1[1] = 0.0; p1[2] = 0.0;
  p2[0] =  1.0; p2[1] = 1.0; p2[2] = 0.0;

  mesh->SetPoint( 0, p0 );
  mesh->SetPoint( 1, p1 );
  mesh->SetPoint( 2, p2 );
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  The following code creates two CellAutoPointers and initialize them with
  //  newly created cell objects. The actual cell type created in this case is
  //  \code{itk::LineCell}. Note that cells are created with the normal
  //  \code{new} C++ operator. The CellAutoPointer takes ownership of the
  //  received pointer by using the method \code{TakeOwnership()}. Even though
  //  this may seem verbose on the code, it results to be necessary to make
  //  more explicity from the code that the responsibility of memory release is
  //  assumed by the AutoPointer.
  //
  //  \index{itk::AutoPointer!TakeOwnership()}
  //  \index{CellAutoPointer!TakeOwnership()}
  //  \index{CellType!creation}
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  CellAutoPointer line0;
  CellAutoPointer line1;

  line0.TakeOwnership(  new LineType  );
  line1.TakeOwnership(  new LineType  );
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  The LineCells should now be associated with points in the mesh. This is
  //  done using the identifiers assigned to points when they were inserted in
  //  the mesh. Every cell type has a specific number of points to be
  //  associated with. For example a \code{LineCell} requires two points, a
  //  \code{TriangleCell} requires three and a \code{TetrahedronCell} requires
  //  four. Cells use an internal numbering system for points. It is simple an
  //  index in the range $\{0,NumberOfPoints-1\}$. The association of points
  //  and cells is done by the \code{SetPointId()} method which requires the
  //  user to provide the internal index of the point in the cell and the
  //  corresponding pointIdentifier in the Mesh. The internal cell index is the
  //  first parameter of \code{SetPointId()} while the mesh point-identifier is
  //  the second.
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  line0->SetPointId( 0, 0 ); // line between points 0 and 1
  line0->SetPointId( 1, 1 );

  line1->SetPointId( 0, 1 ); // line between points 1 and 2
  line1->SetPointId( 1, 2 );
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  Cells are inserted in the mesh using the \code{SetCell()} method. It
  //  requires an identifier and the AutoPointer to the cell. The Mesh will
  //  take ownership of the cell to which the AutoPointer is pointing. This is
  //  done internally by the \code{SetCell()} method. In this way, the
  //  destruction of the CellAutoPointer will not induce the destruction of the
  //  associated cell.
  //
  //  \index{itk::Mesh!SetCell()}
  //  \index{SetCell()!itk::Mesh}
  //  \index{itk::Mesh!Inserting cells}
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  mesh->SetCell( 0, line0 );
  mesh->SetCell( 1, line1 );
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  After being argument of a \code{SetCell()} method, a CellAutoPointer no
  //  longer holds ownership of the cells. It is important not to use this same
  //  CellAutoPointer again as argument to \code{SetCell()} without first
  //  securing ownership of another cell.
  //
  //  Software Guide : EndLatex

  std::cout << "Points = " << mesh->GetNumberOfPoints() << std::endl;

  //  Software Guide : BeginLatex
  //
  //  The number of Cells currently inserted in the mesh can be queried with
  //  the \code{GetNumberOfCells()} method.
  //
  //  \index{itk::Mesh!GetNumberOfCells()}
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  std::cout << "Cells  = " << mesh->GetNumberOfCells()  << std::endl;
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  In a way analogous to points, cells can be accessed using Iterators to
  //  the CellsContainer in the mesh. The trait for the cell iterator can be
  //  extracted from the mesh and used to define a local type.
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  typedef MeshType::CellsContainer::Iterator  CellIterator;
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  Then the iterators to the first and past-end cell in the mesh can be
  //  obtained respectively with the \code{Begin()} and \code{End()} methods of
  //  the CellsContainer. The CellsContainer of the mesh is returned by the
  //  \code{GetCells()} method.
  //
  //  \index{itk::Mesh!Iterating cells}
  //  \index{itk::Mesh!GetCells()}
  //  \index{CellsContainer!Begin()}
  //  \index{CellsContainer!End()}
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  CellIterator  cellIterator = mesh->GetCells()->Begin();
  CellIterator  end          = mesh->GetCells()->End();
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  Finally a standard loop is used to iterate over all the cells. Note the
  //  use of the \code{Value()} method used to get the actual pointer to the
  //  cell from the CellIterator. Note also that the values returned are
  //  pointers to the generic CellType. These pointers have to be down-casted
  //  in order to be used as actual LineCell types. Safe down-casting is
  //  performed with the \code{dynamic\_cast} operator which will throw an
  //  exception if the convertion cannot be safely performed.
  //
  //  \index{down casting}
  //  \index{CellIterator!Value()}
  //  \index{CellIterator!increment}
  //  \index{itk::Mesh!CellType casting}
  //  \index{Print()}
  //  \index{CellType!Print()}
  //  \index{CellType!GetNumberOfPoints()}
  //  \index{LineCell!Print()}
  //  \index{LineCell!GetNumberOfPoints()}
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  while( cellIterator != end ) {
    MeshType::CellType * cellptr = cellIterator->Value();
    LineType * line = dynamic_cast<LineType *>( cellptr );
    std::cout << line->GetNumberOfPoints() << std::cout;
    ++cellIterator;
    }
  // Software Guide : EndCodeSnippet

  return 0;

}

<commit_msg>FIX: Value() called with ->.  and typo in cout.<commit_after>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    Mesh2.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 2002 Insight Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

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

//  Software Guide : BeginLatex
//
//  A Mesh can contain a variety of cells types. Typical cells are the
//  LineCell, TriangleCell, QuadrilateralCell and TetrahedronCell. A large
//  flexibility is provided for managing cells at the price of a bit more of
//  complexity than in the case of point management.
//
//  The following code creates a polygonal line in order to illustrate the
//  simplest case of cell management in a Mesh. The only cell type used here is
//  the \code{itk::LineCell}. The header file of this class has to be included.
//
//  \index{itk::LineCell!Header}
//
//  Software Guide : EndLatex

#include "itkMesh.h"

// Software Guide : BeginCodeSnippet
#include "itkLineCell.h"
// Software Guide : EndCodeSnippet

int main()
{

  typedef float                             PixelType;
  typedef itk::Mesh< PixelType, 3 >         MeshType;

  //  Software Guide : BeginLatex
  //
  //  In order to be consitent with the Mesh, cell types have to be configured
  //  with a number of custom types taken from the mesh traits. The set of
  //  traits relevant to cells are packaged by the Mesh class into the
  //  \code{CellType} trait. This trait needs to be passed to the actual cell
  //  types at the moment of their instantiation. The following line shows how
  //  to extract the Cell traits from the Mesh type.
  //
  //  \index{itk::Mesh!CellType}
  //  \index{itk::Mesh!traits}
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  typedef MeshType::CellType                CellType;
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  The \code{itk::LineCell} type can now be instantiated using the traits
  //  taken from the Mesh.  \index{itk::LineCell!Instantiation}
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  typedef itk::LineCell< CellType >         LineType;
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  The main difference in the way cells and points are managed by the Mesh
  //  is that points are stored by copy on the PointsContainer while cells are
  //  stored in the CellsContainer using pointers. The reason for using
  //  pointers is that cells use C++ polymorphism on the mesh. This means that
  //  the mesh is only aware of having pointers to a generic cell which is the
  //  base class of all the specific cell types. This architecture makes
  //  possible to combine different cell types in the same mesh. Points, on the
  //  other hand, are of a single type and have a small memory footprint, which
  //  facilitates to copy them directly inside the container.
  //
  //  \index{itk::Cell!CellAutoPointer}
  //  \index{itk::Mesh!CellAutoPointer}
  //  \index{CellAutoPointer}
  //  \index{itk::AutoPointer}
  //
  //  Managing cells by pointers add another level of complexity to the Mesh
  //  since it is now necessary to stablish a protocol to make clear who is
  //  responsible for allocating and releasing the cells' memory. This protocol
  //  is implemented in the form of a specific type of pointer called the
  //  \code{CellAutoPointer}. This pointer differ in many senses from the
  //  SmartPointer. The CellAutoPointer has a internal pointer to the actual
  //  object and a boolean flag that indicates if the CellAutoPointer is
  //  responsible for releasing the cell memory whenever the time comes for its
  //  own destruction. It is said that a \code{CellAutoPointer} \emph{owns} the
  //  cell when it is responsible for its destruction. Many CellAutoPointer can
  //  point to the same cell but at any given time, only \textbf{one}
  //  CellAutoPointer can own the cell.
  //
  //  The \code{CellAutoPointer} trait is defined in the MeshType and can be
  //  extracted as illustrated in the following line.
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  typedef CellType::CellAutoPointer         CellAutoPointer;
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  Note that the CellAutoPointer is pointing to a generic cell type. It is
  //  not aware of the actual type of the cell, which can be for example
  //  LineCell, TriangleCell or TetrahedronCell. This fact will influence the
  //  way in which we access cells later on.
  //
  //  At this point we can actually create a mesh and insert some points on it.
  //
  //  \index{itk::Mesh!New()}
  //  \index{itk::Mesh!SetPoint()}
  //  \index{itk::Mesh!PointType}
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  MeshType::Pointer  mesh = MeshType::New();

  MeshType::PointType p0;
  MeshType::PointType p1;
  MeshType::PointType p2;

  p0[0] = -1.0; p0[1] = 0.0; p0[2] = 0.0;
  p1[0] =  1.0; p1[1] = 0.0; p1[2] = 0.0;
  p2[0] =  1.0; p2[1] = 1.0; p2[2] = 0.0;

  mesh->SetPoint( 0, p0 );
  mesh->SetPoint( 1, p1 );
  mesh->SetPoint( 2, p2 );
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  The following code creates two CellAutoPointers and initialize them with
  //  newly created cell objects. The actual cell type created in this case is
  //  \code{itk::LineCell}. Note that cells are created with the normal
  //  \code{new} C++ operator. The CellAutoPointer takes ownership of the
  //  received pointer by using the method \code{TakeOwnership()}. Even though
  //  this may seem verbose on the code, it results to be necessary to make
  //  more explicity from the code that the responsibility of memory release is
  //  assumed by the AutoPointer.
  //
  //  \index{itk::AutoPointer!TakeOwnership()}
  //  \index{CellAutoPointer!TakeOwnership()}
  //  \index{CellType!creation}
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  CellAutoPointer line0;
  CellAutoPointer line1;

  line0.TakeOwnership(  new LineType  );
  line1.TakeOwnership(  new LineType  );
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  The LineCells should now be associated with points in the mesh. This is
  //  done using the identifiers assigned to points when they were inserted in
  //  the mesh. Every cell type has a specific number of points to be
  //  associated with. For example a \code{LineCell} requires two points, a
  //  \code{TriangleCell} requires three and a \code{TetrahedronCell} requires
  //  four. Cells use an internal numbering system for points. It is simple an
  //  index in the range $\{0,NumberOfPoints-1\}$. The association of points
  //  and cells is done by the \code{SetPointId()} method which requires the
  //  user to provide the internal index of the point in the cell and the
  //  corresponding pointIdentifier in the Mesh. The internal cell index is the
  //  first parameter of \code{SetPointId()} while the mesh point-identifier is
  //  the second.
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  line0->SetPointId( 0, 0 ); // line between points 0 and 1
  line0->SetPointId( 1, 1 );

  line1->SetPointId( 0, 1 ); // line between points 1 and 2
  line1->SetPointId( 1, 2 );
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  Cells are inserted in the mesh using the \code{SetCell()} method. It
  //  requires an identifier and the AutoPointer to the cell. The Mesh will
  //  take ownership of the cell to which the AutoPointer is pointing. This is
  //  done internally by the \code{SetCell()} method. In this way, the
  //  destruction of the CellAutoPointer will not induce the destruction of the
  //  associated cell.
  //
  //  \index{itk::Mesh!SetCell()}
  //  \index{SetCell()!itk::Mesh}
  //  \index{itk::Mesh!Inserting cells}
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  mesh->SetCell( 0, line0 );
  mesh->SetCell( 1, line1 );
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  After being argument of a \code{SetCell()} method, a CellAutoPointer no
  //  longer holds ownership of the cells. It is important not to use this same
  //  CellAutoPointer again as argument to \code{SetCell()} without first
  //  securing ownership of another cell.
  //
  //  Software Guide : EndLatex

  std::cout << "Points = " << mesh->GetNumberOfPoints() << std::endl;

  //  Software Guide : BeginLatex
  //
  //  The number of Cells currently inserted in the mesh can be queried with
  //  the \code{GetNumberOfCells()} method.
  //
  //  \index{itk::Mesh!GetNumberOfCells()}
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  std::cout << "Cells  = " << mesh->GetNumberOfCells()  << std::endl;
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  In a way analogous to points, cells can be accessed using Iterators to
  //  the CellsContainer in the mesh. The trait for the cell iterator can be
  //  extracted from the mesh and used to define a local type.
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  typedef MeshType::CellsContainer::Iterator  CellIterator;
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  Then the iterators to the first and past-end cell in the mesh can be
  //  obtained respectively with the \code{Begin()} and \code{End()} methods of
  //  the CellsContainer. The CellsContainer of the mesh is returned by the
  //  \code{GetCells()} method.
  //
  //  \index{itk::Mesh!Iterating cells}
  //  \index{itk::Mesh!GetCells()}
  //  \index{CellsContainer!Begin()}
  //  \index{CellsContainer!End()}
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  CellIterator  cellIterator = mesh->GetCells()->Begin();
  CellIterator  end          = mesh->GetCells()->End();
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  Finally a standard loop is used to iterate over all the cells. Note the
  //  use of the \code{Value()} method used to get the actual pointer to the
  //  cell from the CellIterator. Note also that the values returned are
  //  pointers to the generic CellType. These pointers have to be down-casted
  //  in order to be used as actual LineCell types. Safe down-casting is
  //  performed with the \code{dynamic\_cast} operator which will throw an
  //  exception if the convertion cannot be safely performed.
  //
  //  \index{down casting}
  //  \index{CellIterator!Value()}
  //  \index{CellIterator!increment}
  //  \index{itk::Mesh!CellType casting}
  //  \index{Print()}
  //  \index{CellType!Print()}
  //  \index{CellType!GetNumberOfPoints()}
  //  \index{LineCell!Print()}
  //  \index{LineCell!GetNumberOfPoints()}
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  while( cellIterator != end ) {
    MeshType::CellType * cellptr = cellIterator.Value();
    LineType * line = dynamic_cast<LineType *>( cellptr );
    std::cout << line->GetNumberOfPoints() << std::endl;
    ++cellIterator;
    }
  // Software Guide : EndCodeSnippet

  return 0;

}

<|endoftext|>


<commit_before>//******************************************************************************
// FILE : function_variable_value_specific.cpp
//
// LAST MODIFIED : 15 July 2004
//
// DESCRIPTION :
//==============================================================================

// global classes
// ==============

// template class Function_variable_value_specific
// ===============================================

EXPORT template<typename Value_type>
Function_variable_value_specific<Value_type>::
	Function_variable_value_specific<Value_type>(
	bool (*set_function)(Value_type&,const Function_variable_handle)):
	set_function(set_function){};

EXPORT template<typename Value_type>
Function_variable_value_specific<Value_type>::
	~Function_variable_value_specific<Value_type>(){}

EXPORT template<typename Value_type>
const std::string Function_variable_value_specific<Value_type>::type()
{
	return (type_string);
}

EXPORT template<typename Value_type>
bool Function_variable_value_specific<Value_type>::set(Value_type& value,
	const Function_variable_handle variable)
{
	bool result;

	result=false;
	if (set_function)
	{
		result=(*set_function)(value,variable);
	}

	return (result);
}
<commit_msg>Sorting out templates<commit_after>//******************************************************************************
// FILE : function_variable_value_specific.cpp
//
// LAST MODIFIED : 15 July 2004
//
// DESCRIPTION :
//==============================================================================

// global classes
// ==============

// template class Function_variable_value_specific
// ===============================================

EXPORT template<typename Value_type>
Function_variable_value_specific<Value_type>::
	Function_variable_value_specific(
	bool (*set_function)(Value_type&,const Function_variable_handle)):
	set_function(set_function){};

EXPORT template<typename Value_type>
Function_variable_value_specific<Value_type>::
	~Function_variable_value_specific<Value_type>(){}

EXPORT template<typename Value_type>
const std::string Function_variable_value_specific<Value_type>::type()
{
	return (type_string);
}

EXPORT template<typename Value_type>
bool Function_variable_value_specific<Value_type>::set(Value_type& value,
	const Function_variable_handle variable)
{
	bool result;

	result=false;
	if (set_function)
	{
		result=(*set_function)(value,variable);
	}

	return (result);
}
<|endoftext|>


<commit_before><commit_msg>Fixed bug preventing gallery apps from being autoupdated/synced.<commit_after><|endoftext|>


<commit_before>// tag::C++11check[]
#define STRING2(x) #x
#define STRING(x) STRING2(x)

#if __cplusplus < 201103L
  #pragma message("WARNING: the compiler may not be C++11 compliant. __cplusplus version is : " STRING(__cplusplus))
#endif
// end::C++11check[]

// tag::includes[]
#include <iostream>
#include <vector>
#include <algorithm>

#include <GL/glew.h>
#include <SDL.h>
// end::includes[]

// tag::namespace[]
using namespace std;
// end::namespace[]

// tag::globalVariables[]
std::string exeName;
SDL_Window *win; //pointer to the SDL_Window
SDL_GLContext context; //the SDL_GLContext
int frameCount = 0;
std::string frameLine = "";
// end::globalVariables[]

// tag::vertexShader[]
//string holding the **source** of our vertex shader, to save loading from a file
const std::string strVertexShader = R"(
	#version 330
	in vec2 position;
	uniform vec2 offset;
	void main()
	{
	   vec2 tmpPosition = position + offset;
     gl_Position = vec4(tmpPosition, 0.0, 1.0);
	}
)";
// end::vertexShader[]

// tag::fragmentShader[]
//string holding the **source** of our fragment shader, to save loading from a file
const std::string strFragmentShader = R"(
	#version 330
	out vec4 outputColor;
	void main()
	{
	   outputColor = vec4(1.0f, 1.0f, 1.0f, 1.0f);
	}
)";
// end::fragmentShader[]

//our variables
bool done = false;

//the data about our geometry
const GLfloat vertexData[] = {
	 0.000f,  0.500f,
	-0.433f, -0.250f,
	 0.433f, -0.250f,
};

//the offset we'll pass to the GLSL
GLfloat offset[] = { -0.5, -0.5 }; //using different values from CPU and static GLSL examples, to make it clear this is working
GLfloat offsetVelocity[] = { 0.2, 0.2 }; //rate of change of offset in units per second

//our GL and GLSL variables

GLuint theProgram; //GLuint that we'll fill in to refer to the GLSL program (only have 1 at this point)
GLint positionLocation; //GLuint that we'll fill in with the location of the `offset` variable in the GLSL
GLint offsetLocation; //GLuint that we'll fill in with the location of the `offset` variable in the GLSL

GLuint vertexDataBufferObject;
GLuint vertexArrayObject;

// end Global Variables
/////////////////////////

void initialise()
{
	if (SDL_Init(SDL_INIT_EVERYTHING) != 0){
		cout << "SDL_Init Error: " << SDL_GetError() << std::endl;
		exit(1);
	}
	cout << "SDL initialised OK!\n";
}

void createWindow()
{
	//get executable name, and use as window title
	int beginIdxWindows = exeName.rfind("\\"); //find last occurrence of a backslash
	int beginIdxLinux = exeName.rfind("/"); //find last occurrence of a forward slash
	int beginIdx = max(beginIdxWindows, beginIdxLinux);
	std::string exeNameEnd = exeName.substr(beginIdx + 1);
	const char *exeNameCStr = exeNameEnd.c_str();

	//create window
	win = SDL_CreateWindow(exeNameCStr, 100, 100, 600, 600, SDL_WINDOW_OPENGL); //same height and width makes the window square ...

	//error handling
	if (win == nullptr)
	{
		std::cout << "SDL_CreateWindow Error: " << SDL_GetError() << std::endl;
		SDL_Quit();
		exit(1);
	}
	cout << "SDL CreatedWindow OK!\n";
}

void setGLAttributes()
{
  int major = 3;
	int minor = 3;
	cout << "Built for OpenGL Version " << major << "." << minor << endl; //ahttps://en.wikipedia.org/wiki/OpenGL_Shading_Language#Versions
	// set the opengl context version
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, major);
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, minor);
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); //core profile
	cout << "Set OpenGL context to versicreate remote branchon " << major << "." << minor << " OK!\n";
}

void createContext()
{
	setGLAttributes();

	context = SDL_GL_CreateContext(win);
	if (context == nullptr){
		SDL_DestroyWindow(win);
		std::cout << "SDL_GL_CreateContext Error: " << SDL_GetError() << std::endl;
		SDL_Quit();
		exit(1);
	}
	cout << "Created OpenGL context OK!\n";
}

void initGlew()
{
	GLenum rev;
	glewExperimental = GL_TRUE; //GLEW isn't perfect - see https://www.opengl.org/wiki/OpenGL_Loading_Library#GLEW
	rev = glewInit();
	if (GLEW_OK != rev){
		std::cout << "GLEW Error: " << glewGetErrorString(rev) << std::endl;
		SDL_Quit();
		exit(1);
	}
	else {
		cout << "GLEW Init OK!\n";
	}
}

GLuint createShader(GLenum eShaderType, const std::string &strShaderFile)
{
	GLuint shader = glCreateShader(eShaderType);
	//error check
	const char *strFileData = strShaderFile.c_str();
	glShaderSource(shader, 1, &strFileData, NULL);

	glCompileShader(shader);

	GLint status;
	glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
	if (status == GL_FALSE)
	{
		GLint infoLogLength;
		glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);

		GLchar *strInfoLog = new GLchar[infoLogLength + 1];
		glGetShaderInfoLog(shader, infoLogLength, NULL, strInfoLog);

		const char *strShaderType = NULL;
		switch (eShaderType)
		{
		case GL_VERTEX_SHADER: strShaderType = "vertex"; break;
		case GL_GEOMETRY_SHADER: strShaderType = "geometry"; break;
		case GL_FRAGMENT_SHADER: strShaderType = "fragment"; break;
		}

		fprintf(stderr, "Compile failure in %s shader:\n%s\n", strShaderType, strInfoLog);
		delete[] strInfoLog;
	}

	return shader;
}

GLuint createProgram(const std::vector<GLuint> &shaderList)
{
	GLuint program = glCreateProgram();

	for (size_t iLoop = 0; iLoop < shaderList.size(); iLoop++)
		glAttachShader(program, shaderList[iLoop]);

	glLinkProgram(program);

	GLint status;
	glGetProgramiv(program, GL_LINK_STATUS, &status);
	if (status == GL_FALSE)
	{
		GLint infoLogLength;
		glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLength);

		GLchar *strInfoLog = new GLchar[infoLogLength + 1];
		glGetProgramInfoLog(program, infoLogLength, NULL, strInfoLog);
		fprintf(stderr, "Linker failure: %s\n", strInfoLog);
		delete[] strInfoLog;
	}

	for (size_t iLoop = 0; iLoop < shaderList.size(); iLoop++)
		glDetachShader(program, shaderList[iLoop]);

	return program;
}

void initializeProgram()
{
	std::vector<GLuint> shaderList;

	shaderList.push_back(createShader(GL_VERTEX_SHADER, strVertexShader));
	shaderList.push_back(createShader(GL_FRAGMENT_SHADER, strFragmentShader));

	theProgram = createProgram(shaderList);
	if (theProgram == 0)
	{
		cout << "GLSL program creation error." << std::endl;
		SDL_Quit();
		exit(1);
	}
	else {
		cout << "GLSL program creation OK! GLUint is: " << theProgram << std::endl;
	}

	positionLocation = glGetAttribLocation(theProgram, "position");
	offsetLocation = glGetUniformLocation(theProgram, "offset");
	//clean up shaders (we don't need them anymore as they are no in theProgram
	for_each(shaderList.begin(), shaderList.end(), glDeleteShader);
}

void initializeVertexBuffer()
{
	glGenBuffers(1, &vertexDataBufferObject);

	glBindBuffer(GL_ARRAY_BUFFER, vertexDataBufferObject);
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW);
	glBindBuffer(GL_ARRAY_BUFFER, 0);
	cout << "vertexDataBufferObject created OK! GLUint is: " << vertexDataBufferObject << std::endl;
}

void loadAssets()
{
	initializeProgram(); //create GLSL Shaders, link into a GLSL program, and get IDs of attributes and variables

	initializeVertexBuffer(); //load data into a vertex buffer

	cout << "Loaded Assets OK!\n";
}

void setupvertexArrayObject()
{
	glGenVertexArrays(1, &vertexArrayObject); //create a Vertex Array Object
	cout << "Vertex Array Object created OK! GLUint is: " << vertexArrayObject << std::endl;

	glBindVertexArray(vertexArrayObject); //make the just created vertexArrayObject the active one

		glBindBuffer(GL_ARRAY_BUFFER, vertexDataBufferObject); //bind vertexDataBufferObject

		glEnableVertexAttribArray(positionLocation); //enable attribute at index positionLocation

		glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, 0, 0); //specify that position data contains four floats per vertex, and goes into attribute index positionLocation

	glBindVertexArray(0); //unbind the vertexArrayObject so we can't change it

	//cleanup
	glDisableVertexAttribArray(positionLocation); //disable vertex attribute at index positionLocation
	glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind array buffer

}

void handleInput()
{
	//Event-based input handling
	//The underlying OS is event-based, so **each** key-up or key-down (for example)
	//generates an event.
	//  - https://wiki.libsdl.org/SDL_PollEvent
	//In some scenarios we want to catch **ALL** the events, not just to present state
	//  - for instance, if taking keyboard input the user might key-down two keys during a frame
	//    - we want to catch based, and know the order
	//  - or the user might key-down and key-up the same within a frame, and we still want something to happen (e.g. jump)
	//  - the alternative is to Poll the current state with SDL_GetKeyboardState

	SDL_Event event; //somewhere to store an event

	//NOTE: there may be multiple events per frame
	while (SDL_PollEvent(&event)) //loop until SDL_PollEvent returns 0 (meaning no more events)
	{
		switch (event.type)
		{
		case SDL_QUIT:
			done = true; //set donecreate remote branch flag if SDL wants to quit (i.e. if the OS has triggered a close event,
							//  - such as window close, or SIGINT
			break;

			//keydown handling - we should to the opposite on key-up for direction controls (generally)
		case SDL_KEYDOWN:
			//Keydown can fire repeatable if key-repeat is on.
			//  - the repeat flag is set on the keyboard event, if this is a repeat event
			//  - in our case, we're going to ignore repeat events
			//  - https://wiki.libsdl.org/SDL_KeyboardEvent
			if (!event.key.repeat)
				switch (event.key.keysym.sym)
				{
					//hit escape to exit
					case SDLK_ESCAPE: done = true;
				}
			break;
		}
	}
}

void updateSimulation(double simLength) //update simulation with an amount of time to simulate for (in seconds)
{
  //CHANGE ME
}

void preRender()
{
	glViewport(0, 0, 600, 600); //set viewpoint
	glClearColor(1.0f, 0.0f, 0.0f, 1.0f); //set clear colour
	glClear(GL_COLOR_BUFFER_BIT); //clear the window (technical the scissor box bounds)
}

void render()
{
	glUseProgram(theProgram); //installs the program object specified by program as part of current rendering state

	//load data to GLSL that **may** have changed
	glUniform2f(offsetLocation, offset[0], offset[1]);
		//alternatively, use glUnivform2fv
		//glUniform2fv(offsetLocation, 1, offset); //Note: the count is 1, because we are setting a single uniform vec2 - https://www.opengl.org/wiki/GLSL_:_common_mistakes#How_to_use_glUniform

	glBindVertexArray(vertexArrayObject);

	glDrawArrays(GL_TRIANGLES, 0, 3); //Draw something, using Triangles, and 3 vertices - i.e. one lonely triangle

	glBindVertexArray(0);

	glUseProgram(0); //clean up

}

void postRender()
{
	SDL_GL_SwapWindow(win);; //present the frame buffer to the display (swapBuffers)
  frameLine += "Frame: " + std::to_string(frameCount++);
  cout << "\r" << frameLine << std::flush;
  frameLine = "";
}

void cleanUp()
{
	SDL_GL_DeleteContext(context);
	SDL_DestroyWindow(win);
	cout << "Cleaning up OK!\n";
}

int main( int argc, char* args[] )
{
	exeName = args[0];
	//setup
	//- do just once
	initialise();
	createWindow();

	createContext();

	initGlew();

	glViewport(0,0,600,600); //should check what the actual window res is?

  SDL_GL_SwapWindow(win); //force a swap, to make the trace clearer

	//do stuff that only needs to happen once
	//- create shaders
	//- load vertex data
	loadAssets();

	//setup a GL object (a VertexArrayObject) that stores how to access data and from where
	setupvertexArrayObject();

	while (!done) //loop until done flag is set)
	{
		handleInput();

		updateSimulation(0.02); //call update simulation with an amount of time to simulate for (in seconds)
		  //WARNING - we are always updating by a constant amount of time. This should be tied to how long has elapsed
		    // see, for example, http://headerphile.blogspot.co.uk/2014/07/part-9-no-more-delays.html

		preRender();

		render(); //RENDER HERE - PLACEHOLDER

		postRender();

	}

	//cleanup and exit
	cleanUp();
	SDL_Quit();

	return 0;
}
<commit_msg>include string - needed on windows<commit_after>// tag::C++11check[]
#define STRING2(x) #x
#define STRING(x) STRING2(x)

#if __cplusplus < 201103L
  #pragma message("WARNING: the compiler may not be C++11 compliant. __cplusplus version is : " STRING(__cplusplus))
#endif
// end::C++11check[]

// tag::includes[]
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>

#include <GL/glew.h>
#include <SDL.h>
// end::includes[]

// tag::namespace[]
using namespace std;
// end::namespace[]

// tag::globalVariables[]
std::string exeName;
SDL_Window *win; //pointer to the SDL_Window
SDL_GLContext context; //the SDL_GLContext
int frameCount = 0;
std::string frameLine = "";
// end::globalVariables[]

// tag::vertexShader[]
//string holding the **source** of our vertex shader, to save loading from a file
const std::string strVertexShader = R"(
	#version 330
	in vec2 position;
	uniform vec2 offset;
	void main()
	{
	   vec2 tmpPosition = position + offset;
     gl_Position = vec4(tmpPosition, 0.0, 1.0);
	}
)";
// end::vertexShader[]

// tag::fragmentShader[]
//string holding the **source** of our fragment shader, to save loading from a file
const std::string strFragmentShader = R"(
	#version 330
	out vec4 outputColor;
	void main()
	{
	   outputColor = vec4(1.0f, 1.0f, 1.0f, 1.0f);
	}
)";
// end::fragmentShader[]

//our variables
bool done = false;

//the data about our geometry
const GLfloat vertexData[] = {
	 0.000f,  0.500f,
	-0.433f, -0.250f,
	 0.433f, -0.250f,
};

//the offset we'll pass to the GLSL
GLfloat offset[] = { -0.5, -0.5 }; //using different values from CPU and static GLSL examples, to make it clear this is working
GLfloat offsetVelocity[] = { 0.2, 0.2 }; //rate of change of offset in units per second

//our GL and GLSL variables

GLuint theProgram; //GLuint that we'll fill in to refer to the GLSL program (only have 1 at this point)
GLint positionLocation; //GLuint that we'll fill in with the location of the `offset` variable in the GLSL
GLint offsetLocation; //GLuint that we'll fill in with the location of the `offset` variable in the GLSL

GLuint vertexDataBufferObject;
GLuint vertexArrayObject;

// end Global Variables
/////////////////////////

void initialise()
{
	if (SDL_Init(SDL_INIT_EVERYTHING) != 0){
		cout << "SDL_Init Error: " << SDL_GetError() << std::endl;
		exit(1);
	}
	cout << "SDL initialised OK!\n";
}

void createWindow()
{
	//get executable name, and use as window title
	int beginIdxWindows = exeName.rfind("\\"); //find last occurrence of a backslash
	int beginIdxLinux = exeName.rfind("/"); //find last occurrence of a forward slash
	int beginIdx = max(beginIdxWindows, beginIdxLinux);
	std::string exeNameEnd = exeName.substr(beginIdx + 1);
	const char *exeNameCStr = exeNameEnd.c_str();

	//create window
	win = SDL_CreateWindow(exeNameCStr, 100, 100, 600, 600, SDL_WINDOW_OPENGL); //same height and width makes the window square ...

	//error handling
	if (win == nullptr)
	{
		std::cout << "SDL_CreateWindow Error: " << SDL_GetError() << std::endl;
		SDL_Quit();
		exit(1);
	}
	cout << "SDL CreatedWindow OK!\n";
}

void setGLAttributes()
{
  int major = 3;
	int minor = 3;
	cout << "Built for OpenGL Version " << major << "." << minor << endl; //ahttps://en.wikipedia.org/wiki/OpenGL_Shading_Language#Versions
	// set the opengl context version
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, major);
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, minor);
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); //core profile
	cout << "Set OpenGL context to versicreate remote branchon " << major << "." << minor << " OK!\n";
}

void createContext()
{
	setGLAttributes();

	context = SDL_GL_CreateContext(win);
	if (context == nullptr){
		SDL_DestroyWindow(win);
		std::cout << "SDL_GL_CreateContext Error: " << SDL_GetError() << std::endl;
		SDL_Quit();
		exit(1);
	}
	cout << "Created OpenGL context OK!\n";
}

void initGlew()
{
	GLenum rev;
	glewExperimental = GL_TRUE; //GLEW isn't perfect - see https://www.opengl.org/wiki/OpenGL_Loading_Library#GLEW
	rev = glewInit();
	if (GLEW_OK != rev){
		std::cout << "GLEW Error: " << glewGetErrorString(rev) << std::endl;
		SDL_Quit();
		exit(1);
	}
	else {
		cout << "GLEW Init OK!\n";
	}
}

GLuint createShader(GLenum eShaderType, const std::string &strShaderFile)
{
	GLuint shader = glCreateShader(eShaderType);
	//error check
	const char *strFileData = strShaderFile.c_str();
	glShaderSource(shader, 1, &strFileData, NULL);

	glCompileShader(shader);

	GLint status;
	glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
	if (status == GL_FALSE)
	{
		GLint infoLogLength;
		glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);

		GLchar *strInfoLog = new GLchar[infoLogLength + 1];
		glGetShaderInfoLog(shader, infoLogLength, NULL, strInfoLog);

		const char *strShaderType = NULL;
		switch (eShaderType)
		{
		case GL_VERTEX_SHADER: strShaderType = "vertex"; break;
		case GL_GEOMETRY_SHADER: strShaderType = "geometry"; break;
		case GL_FRAGMENT_SHADER: strShaderType = "fragment"; break;
		}

		fprintf(stderr, "Compile failure in %s shader:\n%s\n", strShaderType, strInfoLog);
		delete[] strInfoLog;
	}

	return shader;
}

GLuint createProgram(const std::vector<GLuint> &shaderList)
{
	GLuint program = glCreateProgram();

	for (size_t iLoop = 0; iLoop < shaderList.size(); iLoop++)
		glAttachShader(program, shaderList[iLoop]);

	glLinkProgram(program);

	GLint status;
	glGetProgramiv(program, GL_LINK_STATUS, &status);
	if (status == GL_FALSE)
	{
		GLint infoLogLength;
		glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLength);

		GLchar *strInfoLog = new GLchar[infoLogLength + 1];
		glGetProgramInfoLog(program, infoLogLength, NULL, strInfoLog);
		fprintf(stderr, "Linker failure: %s\n", strInfoLog);
		delete[] strInfoLog;
	}

	for (size_t iLoop = 0; iLoop < shaderList.size(); iLoop++)
		glDetachShader(program, shaderList[iLoop]);

	return program;
}

void initializeProgram()
{
	std::vector<GLuint> shaderList;

	shaderList.push_back(createShader(GL_VERTEX_SHADER, strVertexShader));
	shaderList.push_back(createShader(GL_FRAGMENT_SHADER, strFragmentShader));

	theProgram = createProgram(shaderList);
	if (theProgram == 0)
	{
		cout << "GLSL program creation error." << std::endl;
		SDL_Quit();
		exit(1);
	}
	else {
		cout << "GLSL program creation OK! GLUint is: " << theProgram << std::endl;
	}

	positionLocation = glGetAttribLocation(theProgram, "position");
	offsetLocation = glGetUniformLocation(theProgram, "offset");
	//clean up shaders (we don't need them anymore as they are no in theProgram
	for_each(shaderList.begin(), shaderList.end(), glDeleteShader);
}

void initializeVertexBuffer()
{
	glGenBuffers(1, &vertexDataBufferObject);

	glBindBuffer(GL_ARRAY_BUFFER, vertexDataBufferObject);
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW);
	glBindBuffer(GL_ARRAY_BUFFER, 0);
	cout << "vertexDataBufferObject created OK! GLUint is: " << vertexDataBufferObject << std::endl;
}

void loadAssets()
{
	initializeProgram(); //create GLSL Shaders, link into a GLSL program, and get IDs of attributes and variables

	initializeVertexBuffer(); //load data into a vertex buffer

	cout << "Loaded Assets OK!\n";
}

void setupvertexArrayObject()
{
	glGenVertexArrays(1, &vertexArrayObject); //create a Vertex Array Object
	cout << "Vertex Array Object created OK! GLUint is: " << vertexArrayObject << std::endl;

	glBindVertexArray(vertexArrayObject); //make the just created vertexArrayObject the active one

		glBindBuffer(GL_ARRAY_BUFFER, vertexDataBufferObject); //bind vertexDataBufferObject

		glEnableVertexAttribArray(positionLocation); //enable attribute at index positionLocation

		glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, 0, 0); //specify that position data contains four floats per vertex, and goes into attribute index positionLocation

	glBindVertexArray(0); //unbind the vertexArrayObject so we can't change it

	//cleanup
	glDisableVertexAttribArray(positionLocation); //disable vertex attribute at index positionLocation
	glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind array buffer

}

void handleInput()
{
	//Event-based input handling
	//The underlying OS is event-based, so **each** key-up or key-down (for example)
	//generates an event.
	//  - https://wiki.libsdl.org/SDL_PollEvent
	//In some scenarios we want to catch **ALL** the events, not just to present state
	//  - for instance, if taking keyboard input the user might key-down two keys during a frame
	//    - we want to catch based, and know the order
	//  - or the user might key-down and key-up the same within a frame, and we still want something to happen (e.g. jump)
	//  - the alternative is to Poll the current state with SDL_GetKeyboardState

	SDL_Event event; //somewhere to store an event

	//NOTE: there may be multiple events per frame
	while (SDL_PollEvent(&event)) //loop until SDL_PollEvent returns 0 (meaning no more events)
	{
		switch (event.type)
		{
		case SDL_QUIT:
			done = true; //set donecreate remote branch flag if SDL wants to quit (i.e. if the OS has triggered a close event,
							//  - such as window close, or SIGINT
			break;

			//keydown handling - we should to the opposite on key-up for direction controls (generally)
		case SDL_KEYDOWN:
			//Keydown can fire repeatable if key-repeat is on.
			//  - the repeat flag is set on the keyboard event, if this is a repeat event
			//  - in our case, we're going to ignore repeat events
			//  - https://wiki.libsdl.org/SDL_KeyboardEvent
			if (!event.key.repeat)
				switch (event.key.keysym.sym)
				{
					//hit escape to exit
					case SDLK_ESCAPE: done = true;
				}
			break;
		}
	}
}

void updateSimulation(double simLength) //update simulation with an amount of time to simulate for (in seconds)
{
  //CHANGE ME
}

void preRender()
{
	glViewport(0, 0, 600, 600); //set viewpoint
	glClearColor(1.0f, 0.0f, 0.0f, 1.0f); //set clear colour
	glClear(GL_COLOR_BUFFER_BIT); //clear the window (technical the scissor box bounds)
}

void render()
{
	glUseProgram(theProgram); //installs the program object specified by program as part of current rendering state

	//load data to GLSL that **may** have changed
	glUniform2f(offsetLocation, offset[0], offset[1]);
		//alternatively, use glUnivform2fv
		//glUniform2fv(offsetLocation, 1, offset); //Note: the count is 1, because we are setting a single uniform vec2 - https://www.opengl.org/wiki/GLSL_:_common_mistakes#How_to_use_glUniform

	glBindVertexArray(vertexArrayObject);

	glDrawArrays(GL_TRIANGLES, 0, 3); //Draw something, using Triangles, and 3 vertices - i.e. one lonely triangle

	glBindVertexArray(0);

	glUseProgram(0); //clean up

}

void postRender()
{
	SDL_GL_SwapWindow(win);; //present the frame buffer to the display (swapBuffers)
  frameLine += "Frame: " + std::to_string(frameCount++);
  cout << "\r" << frameLine << std::flush;
  frameLine = "";
}

void cleanUp()
{
	SDL_GL_DeleteContext(context);
	SDL_DestroyWindow(win);
	cout << "Cleaning up OK!\n";
}

int main( int argc, char* args[] )
{
	exeName = args[0];
	//setup
	//- do just once
	initialise();
	createWindow();

	createContext();

	initGlew();

	glViewport(0,0,600,600); //should check what the actual window res is?

  SDL_GL_SwapWindow(win); //force a swap, to make the trace clearer

	//do stuff that only needs to happen once
	//- create shaders
	//- load vertex data
	loadAssets();

	//setup a GL object (a VertexArrayObject) that stores how to access data and from where
	setupvertexArrayObject();

	while (!done) //loop until done flag is set)
	{
		handleInput();

		updateSimulation(0.02); //call update simulation with an amount of time to simulate for (in seconds)
		  //WARNING - we are always updating by a constant amount of time. This should be tied to how long has elapsed
		    // see, for example, http://headerphile.blogspot.co.uk/2014/07/part-9-no-more-delays.html

		preRender();

		render(); //RENDER HERE - PLACEHOLDER

		postRender();

	}

	//cleanup and exit
	cleanUp();
	SDL_Quit();

	return 0;
}
<|endoftext|>


<commit_before>//---------------------------------------------------------------------------
//
//             kPPP: A pppd front end for the KDE project
//
//---------------------------------------------------------------------------
//
// (c) 1997-1998 Bernd Johannes Wuebben <wuebben@kde.org>
// (c) 1997-1999 Mario Weilguni <mweilguni@kde.org>
// (c) 1998-1999 Harri Porten <porten@kde.org>
//
// derived from Jay Painters "ezppp"
//
//---------------------------------------------------------------------------
//
//  $Id$
//
//---------------------------------------------------------------------------
//
//  This program 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 program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Library General Public License for more details.
//
//  You should have received a copy of the GNU Library General Public
//  License along with this program; if not, write to the Free
//  Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//
//---------------------------------------------------------------------------

#include <qcombobox.h>
#include <qlabel.h>
#include <kurllabel.h>
#include <qlayout.h>
#include <qlistview.h>
#include <qdir.h>
#include <qregexp.h>
#include <qwmatrix.h>
#include <qcheckbox.h>
#include <kdialog.h>
#include <kstandarddirs.h>
#include <klocale.h>
#include <kiconloader.h>
#include <krun.h>

#include "acctselect.h"
#include "pppdata.h"

AccountingSelector::AccountingSelector(QWidget *parent, bool _isnewaccount, const char *name)
  :  QWidget(parent, name),
    isnewaccount(_isnewaccount)
{
  QVBoxLayout *l1 = new QVBoxLayout(parent, 0, KDialog::spacingHint());

  enable_accounting = new QCheckBox(i18n("&Enable accounting"), parent);
  l1->addWidget(enable_accounting, 1);
  connect(enable_accounting, SIGNAL(toggled(bool)), this, SLOT(enableItems(bool)));

  // insert the tree widget
  tl = new QListView(parent, "treewidget");

  connect(tl, SIGNAL(selectionChanged(QListViewItem*)), this,
          SLOT(slotSelectionChanged(QListViewItem*)));
  tl->setMinimumSize(220, 200);
  l1->addWidget(tl, 1);

  KURLLabel *up = new KURLLabel(parent);
  up->setText(i18n("Check for rule updates"));
  up->setURL("http://devel-home.kde.org/~kppp/rules.html");
  connect(up, SIGNAL(leftClickedURL(const QString&)), SLOT(openURL(const QString&)));

  l1->addWidget(up, 1);

  // label to display the currently selected ruleset
  QHBoxLayout *l11 = new QHBoxLayout;
  l1->addSpacing(10);
  l1->addLayout(l11);
  QLabel *lsel = new QLabel(i18n("Selected:"), parent);
  selected = new QLabel(parent);
  selected->setFrameStyle(QFrame::Sunken | QFrame::WinPanel);
  selected->setLineWidth(1);
  selected->setFixedHeight(selected->sizeHint().height() + 16);
  l11->addWidget(lsel, 0);
  l11->addSpacing(10);
  l11->addWidget(selected, 1);

  // volume accounting
  l1->addStretch(1);
  QHBoxLayout *l12 = new QHBoxLayout;
  l1->addLayout(l12);
  QLabel *usevol_l = new QLabel(i18n("Volume accounting:"), parent);
  use_vol = new QComboBox(parent);
  use_vol->insertItem(i18n("No Accounting"), 0);
  use_vol->insertItem(i18n("Bytes In"), 1);
  use_vol->insertItem(i18n("Bytes Out"), 2);
  use_vol->insertItem(i18n("Bytes In & Out"), 3);
  use_vol->setCurrentItem(gpppdata.VolAcctEnabled());
  l12->addWidget(usevol_l);
  l12->addWidget(use_vol);

  // load the pmfolder pixmap from KDEdir
  pmfolder = UserIcon("folder");

  // scale the pixmap
  if(pmfolder.width() > 0) {
    QWMatrix wm;
    wm.scale(16.0/pmfolder.width(), 16.0/pmfolder.width());
    pmfolder = pmfolder.xForm(wm);
  }

  // load the pmfolder pixmap from KDEdir
  pmfile = UserIcon("phone");

  // scale the pixmap
  if(pmfile.width() > 0) {
    QWMatrix wm;
    wm.scale(16.0/pmfile.width(), 16.0/pmfile.width());
    pmfile = pmfile.xForm(wm);
  }

  enable_accounting->setChecked(gpppdata.AcctEnabled());

  setupTreeWidget();

  l1->activate();
}

QString AccountingSelector::fileNameToName(QString s) {

  s.replace('_', " ");
  return KURL::decode_string(s);

}

QString AccountingSelector::nameToFileName(QString s) {

  s.replace(' ', "_");
  return s;

}

QListViewItem *AccountingSelector::findByName(QString name)
{
  QListViewItem *ch = tl->firstChild();
  while(ch) {
    if(ch->text(0) == name)
      return ch;
    ch = ch->nextSibling();
  }
  return 0;
}

void AccountingSelector::insertDir(QDir d, QListViewItem *root) {

  QListViewItem* tli = 0;

  // sanity check
  if(!d.exists() || !d.isReadable())
    return;

  // set up filter
  d.setNameFilter("*.rst");
  d.setFilter(QDir::Files);
  d.setSorting(QDir::Name);

  // read the list of files
  const QFileInfoList *list = d.entryInfoList();
  QFileInfoListIterator it( *list );
  QFileInfo *fi;

  // traverse the list and insert into the widget
  while((fi = it.current())) {
    ++it;

    QString samename = fi->fileName();

    QListViewItem *i = findByName(samename);

    // skip this file if already in tree
    if(i)
      continue;

    // check if this is the file we should mark
    QString name = fileNameToName(fi->baseName(true));
    if(root)
      tli = new QListViewItem(root, name);
    else
      tli = new QListViewItem(tl, name);

    tli->setPixmap(0, pmfile);

    // check if this is the item we are searching for
    // (only in "Edit"-mode, not in "New"-mode
    if(!isnewaccount && !edit_s.isEmpty() &&
       (edit_s == QString(fi->filePath()).right(edit_s.length()))) {
      edit_item = tli;
    }
  }

  // set up a filter for the directories
  d.setFilter(QDir::Dirs);
  d.setNameFilter("*");
  const QFileInfoList *dlist = d.entryInfoList();
  QFileInfoListIterator dit(*dlist);

  while((fi = dit.current())) {
    // skip "." and ".." directories
    if(fi->fileName().left(1) != ".") {
      // convert to human-readable name
      QString name = fileNameToName(fi->fileName());

      // if the tree already has an item with this name,
      // skip creation and use this one, otherwise
      // create a new entry
      QListViewItem *i = findByName(name);
      if(!i) {
        QListViewItem* item;

        if(root)
          item = new QListViewItem(root, name);
        else
          item = new QListViewItem(tl, name);

        item->setPixmap(0, pmfolder);

	insertDir(QDir(fi->filePath()), item);
      } else
	insertDir(QDir(fi->filePath()), i);
    }
    ++dit;
  }
}

void AccountingSelector::setupTreeWidget() {
  // search the item
  edit_item = 0;
  if(!isnewaccount) {
    edit_s = gpppdata.accountingFile();
  }
  else
    edit_s = "";

  tl->addColumn( i18n("Available Rules") );
  tl->setColumnWidth(0, 205);
  tl->setRootIsDecorated(true);

  // look in ~/.kde/share/apps/kppp/Rules and $KDEDIR/share/apps/kppp/Rules
  QStringList dirs = KGlobal::dirs()->resourceDirs("appdata");
  for (QStringList::ConstIterator it = dirs.begin();
       it != dirs.end(); it++) {
    insertDir(QDir((*it) + "Rules"), 0);
  }

  // when mode is "Edit", then hightlight the
  // appropriate item
  if(!isnewaccount && edit_item) {
    tl->setSelected(edit_item, true);
    tl->setOpen(edit_item->parent(), true);
    tl->ensureItemVisible(edit_item);
  }

  enableItems(enable_accounting->isChecked());
}

void AccountingSelector::enableItems(bool enabled) {

  tl->setEnabled(enabled);

  if(!enabled || (!tl->currentItem()))
    selected->setText(i18n("(none)"));
  else {
    QListViewItem* i = tl->currentItem();
    QString s;
    while(i) {
      s = "/" + i->text(0) + s;
      i = i->parent();
    }
    selected->setText(s.mid(1));

    s += ".rst";
    edit_s = nameToFileName(s);
  }
}

void AccountingSelector::slotSelectionChanged(QListViewItem* i) {

  if(!i || i->childCount())
    return;

  if(!enable_accounting->isChecked())
    return;

  enableItems(true);
}

bool AccountingSelector::save() {

  if(enable_accounting->isChecked()) {
    gpppdata.setAccountingFile(edit_s);
    gpppdata.setAcctEnabled(true);
  } else {
    gpppdata.setAccountingFile("");
    gpppdata.setAcctEnabled(false);
  }

  gpppdata.setVolAcctEnabled(use_vol->currentItem());

  return true;
}

void AccountingSelector::openURL(const QString &url) {
  new KRun( url );
}

#include "acctselect.moc"

<commit_msg>KURL(const QString&) fixes<commit_after>//---------------------------------------------------------------------------
//
//             kPPP: A pppd front end for the KDE project
//
//---------------------------------------------------------------------------
//
// (c) 1997-1998 Bernd Johannes Wuebben <wuebben@kde.org>
// (c) 1997-1999 Mario Weilguni <mweilguni@kde.org>
// (c) 1998-1999 Harri Porten <porten@kde.org>
//
// derived from Jay Painters "ezppp"
//
//---------------------------------------------------------------------------
//
//  $Id$
//
//---------------------------------------------------------------------------
//
//  This program 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 program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Library General Public License for more details.
//
//  You should have received a copy of the GNU Library General Public
//  License along with this program; if not, write to the Free
//  Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//
//---------------------------------------------------------------------------

#include <qcombobox.h>
#include <qlabel.h>
#include <kurllabel.h>
#include <qlayout.h>
#include <qlistview.h>
#include <qdir.h>
#include <qregexp.h>
#include <qwmatrix.h>
#include <qcheckbox.h>
#include <kdialog.h>
#include <kstandarddirs.h>
#include <klocale.h>
#include <kiconloader.h>
#include <krun.h>

#include "acctselect.h"
#include "pppdata.h"

AccountingSelector::AccountingSelector(QWidget *parent, bool _isnewaccount, const char *name)
  :  QWidget(parent, name),
    isnewaccount(_isnewaccount)
{
  QVBoxLayout *l1 = new QVBoxLayout(parent, 0, KDialog::spacingHint());

  enable_accounting = new QCheckBox(i18n("&Enable accounting"), parent);
  l1->addWidget(enable_accounting, 1);
  connect(enable_accounting, SIGNAL(toggled(bool)), this, SLOT(enableItems(bool)));

  // insert the tree widget
  tl = new QListView(parent, "treewidget");

  connect(tl, SIGNAL(selectionChanged(QListViewItem*)), this,
          SLOT(slotSelectionChanged(QListViewItem*)));
  tl->setMinimumSize(220, 200);
  l1->addWidget(tl, 1);

  KURLLabel *up = new KURLLabel(parent);
  up->setText(i18n("Check for rule updates"));
  up->setURL("http://devel-home.kde.org/~kppp/rules.html");
  connect(up, SIGNAL(leftClickedURL(const QString&)), SLOT(openURL(const QString&)));

  l1->addWidget(up, 1);

  // label to display the currently selected ruleset
  QHBoxLayout *l11 = new QHBoxLayout;
  l1->addSpacing(10);
  l1->addLayout(l11);
  QLabel *lsel = new QLabel(i18n("Selected:"), parent);
  selected = new QLabel(parent);
  selected->setFrameStyle(QFrame::Sunken | QFrame::WinPanel);
  selected->setLineWidth(1);
  selected->setFixedHeight(selected->sizeHint().height() + 16);
  l11->addWidget(lsel, 0);
  l11->addSpacing(10);
  l11->addWidget(selected, 1);

  // volume accounting
  l1->addStretch(1);
  QHBoxLayout *l12 = new QHBoxLayout;
  l1->addLayout(l12);
  QLabel *usevol_l = new QLabel(i18n("Volume accounting:"), parent);
  use_vol = new QComboBox(parent);
  use_vol->insertItem(i18n("No Accounting"), 0);
  use_vol->insertItem(i18n("Bytes In"), 1);
  use_vol->insertItem(i18n("Bytes Out"), 2);
  use_vol->insertItem(i18n("Bytes In & Out"), 3);
  use_vol->setCurrentItem(gpppdata.VolAcctEnabled());
  l12->addWidget(usevol_l);
  l12->addWidget(use_vol);

  // load the pmfolder pixmap from KDEdir
  pmfolder = UserIcon("folder");

  // scale the pixmap
  if(pmfolder.width() > 0) {
    QWMatrix wm;
    wm.scale(16.0/pmfolder.width(), 16.0/pmfolder.width());
    pmfolder = pmfolder.xForm(wm);
  }

  // load the pmfolder pixmap from KDEdir
  pmfile = UserIcon("phone");

  // scale the pixmap
  if(pmfile.width() > 0) {
    QWMatrix wm;
    wm.scale(16.0/pmfile.width(), 16.0/pmfile.width());
    pmfile = pmfile.xForm(wm);
  }

  enable_accounting->setChecked(gpppdata.AcctEnabled());

  setupTreeWidget();

  l1->activate();
}

QString AccountingSelector::fileNameToName(QString s) {

  s.replace('_', " ");
  return KURL::decode_string(s);

}

QString AccountingSelector::nameToFileName(QString s) {

  s.replace(' ', "_");
  return s;

}

QListViewItem *AccountingSelector::findByName(QString name)
{
  QListViewItem *ch = tl->firstChild();
  while(ch) {
    if(ch->text(0) == name)
      return ch;
    ch = ch->nextSibling();
  }
  return 0;
}

void AccountingSelector::insertDir(QDir d, QListViewItem *root) {

  QListViewItem* tli = 0;

  // sanity check
  if(!d.exists() || !d.isReadable())
    return;

  // set up filter
  d.setNameFilter("*.rst");
  d.setFilter(QDir::Files);
  d.setSorting(QDir::Name);

  // read the list of files
  const QFileInfoList *list = d.entryInfoList();
  QFileInfoListIterator it( *list );
  QFileInfo *fi;

  // traverse the list and insert into the widget
  while((fi = it.current())) {
    ++it;

    QString samename = fi->fileName();

    QListViewItem *i = findByName(samename);

    // skip this file if already in tree
    if(i)
      continue;

    // check if this is the file we should mark
    QString name = fileNameToName(fi->baseName(true));
    if(root)
      tli = new QListViewItem(root, name);
    else
      tli = new QListViewItem(tl, name);

    tli->setPixmap(0, pmfile);

    // check if this is the item we are searching for
    // (only in "Edit"-mode, not in "New"-mode
    if(!isnewaccount && !edit_s.isEmpty() &&
       (edit_s == QString(fi->filePath()).right(edit_s.length()))) {
      edit_item = tli;
    }
  }

  // set up a filter for the directories
  d.setFilter(QDir::Dirs);
  d.setNameFilter("*");
  const QFileInfoList *dlist = d.entryInfoList();
  QFileInfoListIterator dit(*dlist);

  while((fi = dit.current())) {
    // skip "." and ".." directories
    if(fi->fileName().left(1) != ".") {
      // convert to human-readable name
      QString name = fileNameToName(fi->fileName());

      // if the tree already has an item with this name,
      // skip creation and use this one, otherwise
      // create a new entry
      QListViewItem *i = findByName(name);
      if(!i) {
        QListViewItem* item;

        if(root)
          item = new QListViewItem(root, name);
        else
          item = new QListViewItem(tl, name);

        item->setPixmap(0, pmfolder);

	insertDir(QDir(fi->filePath()), item);
      } else
	insertDir(QDir(fi->filePath()), i);
    }
    ++dit;
  }
}

void AccountingSelector::setupTreeWidget() {
  // search the item
  edit_item = 0;
  if(!isnewaccount) {
    edit_s = gpppdata.accountingFile();
  }
  else
    edit_s = "";

  tl->addColumn( i18n("Available Rules") );
  tl->setColumnWidth(0, 205);
  tl->setRootIsDecorated(true);

  // look in ~/.kde/share/apps/kppp/Rules and $KDEDIR/share/apps/kppp/Rules
  QStringList dirs = KGlobal::dirs()->resourceDirs("appdata");
  for (QStringList::ConstIterator it = dirs.begin();
       it != dirs.end(); it++) {
    insertDir(QDir((*it) + "Rules"), 0);
  }

  // when mode is "Edit", then hightlight the
  // appropriate item
  if(!isnewaccount && edit_item) {
    tl->setSelected(edit_item, true);
    tl->setOpen(edit_item->parent(), true);
    tl->ensureItemVisible(edit_item);
  }

  enableItems(enable_accounting->isChecked());
}

void AccountingSelector::enableItems(bool enabled) {

  tl->setEnabled(enabled);

  if(!enabled || (!tl->currentItem()))
    selected->setText(i18n("(none)"));
  else {
    QListViewItem* i = tl->currentItem();
    QString s;
    while(i) {
      s = "/" + i->text(0) + s;
      i = i->parent();
    }
    selected->setText(s.mid(1));

    s += ".rst";
    edit_s = nameToFileName(s);
  }
}

void AccountingSelector::slotSelectionChanged(QListViewItem* i) {

  if(!i || i->childCount())
    return;

  if(!enable_accounting->isChecked())
    return;

  enableItems(true);
}

bool AccountingSelector::save() {

  if(enable_accounting->isChecked()) {
    gpppdata.setAccountingFile(edit_s);
    gpppdata.setAcctEnabled(true);
  } else {
    gpppdata.setAccountingFile("");
    gpppdata.setAcctEnabled(false);
  }

  gpppdata.setVolAcctEnabled(use_vol->currentItem());

  return true;
}

void AccountingSelector::openURL(const QString &url) {
  new KRun( KURL( url ) );
}

#include "acctselect.moc"

<|endoftext|>


<commit_before>#include <CompositeTransformation.h>
#include <EventTypeHelpers.h>
#include <MetaEvent.h>
#include <IO.h>

#include <boost/graph/depth_first_search.hpp>
#include <boost/graph/copy.hpp>
#include <boost/graph/transpose_graph.hpp>
#include <boost/graph/graphviz.hpp>

#include <algorithm>
#include <iterator>

using namespace std;

using namespace boost;

struct CompositeTransformer : public Transformer {
    using TransPtr = Transformation::TransPtr;
    using Graph = adjacency_list<vecS, vecS, bidirectionalS, TransPtr>;
    using Vertex= Graph::vertex_descriptor;
    using Edge= Graph::edge_descriptor;

    Graph graph;
    /** \brief Generate CompositeTransformer from CompositeTransformation
     *  \param out output EventType of the created MetaEvents
     *  \param in input EventTypes of the consumed MetaEvents
     *  \param g CompositeTransformation graph to generate Transformers from
     **/
    CompositeTransformer(const EventType& out, const EventTypes& in, const CompositeTransformation::Graph& g)
      : Transformer(Transformation::invalid, out, in) {
      auto vertexCopy = [&g, this](CompositeTransformation::Vertex in, Vertex out) {
        graph[out] = g[in].create();
      };
      auto edgeCopy = [&g, this](CompositeTransformation::Graph::edge_descriptor in, Edge out) {};
      Graph temp;
      transpose_graph(g, graph, boost::vertex_copy(vertexCopy).edge_copy(edgeCopy));
    }

    /** \brief check for applicability  of Transformer
     *  \param  events input events to check
     *  \return true if transformer can be applied, false otherwise
     *  \todo implement **/
    bool check(const Events& events) const {
      return false;
    }

    /** \brief execute transformer on input events
     *  \param events input events
     *  \return result of the transformer graph
     *  \todo implement
     **/
    MetaEvent operator()(const Events& events) {
      return MetaEvent();
    }

    /** \brief print composite transformer
     *  \param o output stream to print to
     **/
    void print(std::ostream& o) const {
      auto writeVertex = [this](ostream& o, Vertex v){
        TransPtr t = graph[v];
        if(t)
          o << " [label=\"" << *t << "\"]";
        else
          o << " [label=\"nullptr\"]";
      };
      write_graphviz(o, graph, writeVertex);
    }
};

using Graph        = CompositeTransformation::Graph;
using Vertex       = CompositeTransformation::Vertex;
using VertexResult = CompositeTransformation::VertexResult;
using VertexList   = CompositeTransformation::VertexList;
using Edge         = Graph::edge_descriptor;
using EventTypes   = CompositeTransformation::EventTypes;
using EventIDs     = CompositeTransformation::EventIDs;
using TransPtr     = CompositeTransformation::TransPtr;
using TransList    = CompositeTransformation::TransList;

struct InputEventTypeExtractor : public boost::default_dfs_visitor {
  Vertex temp;
  EventTypes& in;

  InputEventTypeExtractor(EventTypes& in)
    : in(in)
  {}

  void discover_vertex(Vertex v, const Graph& g) {
    temp = v;
  }

  void finish_vertex(Vertex v, const Graph& g) {
    if(temp == v) {
      const EventTypes& tempIn = g[v].in();
      copy(tempIn.begin(), tempIn.end(), back_inserter(in));
    }
  }
};

struct FindEventType : public boost::default_dfs_visitor {
  VertexList& result;
  const EventType& eT;

  FindEventType(const EventType& eT, VertexList& result)
    : result(result), eT(eT)
  {}

  void discover_vertex(Vertex v, const Graph& g) {
    if(count(g[v].in().begin(), g[v].in().end(), eT))
      result.push_back(v);
  }
};
;

CompositeTransformation::CompositeTransformation(TransformationPtr tPtr, const EventType& goal,
                                                 const EventType& provided) {
  VertexResult res = addRootTransformation(tPtr, goal, provided);
  if(res.second)
    mRoot = res.first;
}

TransPtr CompositeTransformation::create() const {
  if(boost::num_vertices(mGraph)==1) {
    return mGraph[mRoot].create();
  }
  return TransPtr(new CompositeTransformer(mOut, mIn, mGraph));
}

bool CompositeTransformation::check() const {
  return boost::num_vertices(mGraph);
}

VertexResult CompositeTransformation::addRootTransformation(TransformationPtr tPtr, const EventType& tempGoal,
                                                            const EventType& provided) {
  if(num_vertices(mGraph)==0) {
    Vertex root = boost::add_vertex(mGraph);
    ConfiguredTransformation& cT = mGraph[root];
    cT.trans(tPtr);
    cT.out(tempGoal);
    if(provided==EventType())
      cT.in(tPtr->in(tempGoal));
    else
      cT.in(tPtr->in(tempGoal, provided));
    in(cT.in());
    out(cT.out());
    return make_pair(root, true);
  }else
    return make_pair(Vertex(), false);
}

VertexResult CompositeTransformation::addTransformation(TransformationPtr tPtr, Vertex v,
                                                        const EventType& intermediate,
                                                        const EventType& provided) {
  const EventTypes& tempIn = mGraph[v].in();
  if(!count(tempIn.begin(), tempIn.end(), intermediate))
    return make_pair(Vertex(), false);

  Vertex newV = boost::add_vertex(mGraph);
  ConfiguredTransformation& cT = mGraph[newV];
  cT.trans(tPtr);
  cT.out(intermediate);
  if(provided==EventType())
    cT.in(tPtr->in(intermediate));
  else
    cT.in(tPtr->in(intermediate, provided));
  auto e = boost::add_edge(v, newV, mGraph);
  mGraph[e.first]=cT.out();
  mIn.clear();
  boost::depth_first_search(mGraph, boost::visitor(InputEventTypeExtractor(mIn)));
  //sort(mIn.begin(), mIn.end());
  //mIn.erase(unique(mIn.begin(). mIn.end()), mIn.end());
  return make_pair(newV, true);
}

EventIDs CompositeTransformation::inIDs() const {
  EventIDs ids(mIn.size());
  copy(mIn.begin(), mIn.end(), ids.begin());
  return ids;
}

TransList CompositeTransformation::path(Vertex v) const {
  TransList result;
  bool done=false;
  do {
    result.push_back(mGraph[v].trans());
    auto in=in_edges(v, mGraph);
    if(in.first!=in.second)
      v=source(*in.first, mGraph);
    else
      done=true;
  }while(!done);
  return result;
}

VertexResult CompositeTransformation::find(TransformationPtr tPtr) const {
  auto  pred = [this, tPtr](Vertex v){ return mGraph[v].trans()==tPtr; };
  auto it = find_if(vertices(mGraph).first, vertices(mGraph).second, pred);
  if(it==vertices(mGraph).second)
    return make_pair(Vertex(), false);
  else
    return make_pair(*it, true);
}

VertexList CompositeTransformation::find(const EventType& eT) const {
  VertexList result;
  boost::depth_first_search(mGraph, boost::visitor(FindEventType(eT, result)));
  return result;
}

/** \todo implement **/
ostream& operator<<(ostream& o, const CompositeTransformation& t) {
  const Graph& g=t.graph();
  auto writeVertex = [&g](ostream& o, Vertex v){
      if(g[v].trans())
        o << " [label=\"" << *g[v].trans() << "\"]";
      else
        o << " [label=\"nullptr\"]";
  };
  auto writeEdge = [&g](ostream& o, Edge e){
    o << " [label=\"" << g[e] << "\"]";
  };
  write_graphviz(o, g, writeVertex, writeEdge);
  return o;
}
<commit_msg>CompositeTransformer: implement execution<commit_after>#include <CompositeTransformation.h>
#include <EventTypeHelpers.h>
#include <MetaEvent.h>
#include <IO.h>

#include <boost/graph/depth_first_search.hpp>
#include <boost/graph/breadth_first_search.hpp>
#include <boost/graph/copy.hpp>
#include <boost/graph/transpose_graph.hpp>
#include <boost/graph/graphviz.hpp>

#include <algorithm>
#include <iterator>

#include <iostream>

using namespace std;

using namespace boost;

struct CompositeTransformer : public Transformer {
    using TransPtr = Transformation::TransPtr;
    using Graph = adjacency_list<vecS, vecS, bidirectionalS, TransPtr, EventType>;
    using Vertex= Graph::vertex_descriptor;
    using Edge= Graph::edge_descriptor;

    struct CallVisitor : public default_dfs_visitor {

      MetaEvent& e;
      map<Vertex, MetaEvent> buffer;

      const Events& input;
      CallVisitor(MetaEvent& e, const Events& input) : e(e), input(input) {}
      void finish_vertex(Vertex v, const Graph& g) {
        Events localIn;
        TransPtr currTrans = g[v];
        auto edges = out_edges(v, g);
        for(const EventType& eT : currTrans->in()) {
          bool found = false;
          for(auto it=edges.first; it!=edges.second; it++)
            if(g[*it]==eT) {
              localIn.push_back(&buffer[target(*it, g)]);
              found=true;
              break;
            }
          if(!found)
            for(const MetaEvent* eIn : input)
              if(eT == (EventType)*eIn) {
                localIn.push_back(eIn);
                break;
              }
        }
        buffer[v] = (*g[v])(localIn);
        e=buffer[v];
      }
    };

    Graph graph;
    Vertex root;
    /** \brief Generate CompositeTransformer from CompositeTransformation
     *  \param out output EventType of the created MetaEvents
     *  \param in input EventTypes of the consumed MetaEvents
     *  \param g CompositeTransformation graph to generate Transformers from
     **/
    CompositeTransformer(const EventType& out, const EventTypes& in, const CompositeTransformation::Graph& g)
      : Transformer(Transformation::invalid, out, in) {
      auto vertexCopy = [&g, this](CompositeTransformation::Vertex in, Vertex out) {
        graph[out] = g[in].create();
      };
      Graph temp;
      copy_graph(g, graph, boost::vertex_copy(vertexCopy));
      auto it = find_if(vertices(graph).first, vertices(graph).second,
                        [this](Vertex v){ return !in_degree(v, graph);});
      root = *it;
    }

    /** \brief check for applicability  of Transformer
     *  \param  events input events to check
     *  \return true if transformer can be applied, false otherwise
     **/
    bool check(const Events& events) const {
      for(const EventType& eT : in())
        if(!any_of(events.begin(), events.end(), [&eT](const MetaEvent* e){ return EventType(*e)<=eT; }))
          return false;
      return true;
    }

    /** \brief execute transformer on input events
     *  \param events input events
     *  \return result of the transformer graph
     **/
    MetaEvent operator()(const Events& events) {
      MetaEvent e;
      vector<default_color_type> colors(num_vertices(graph));
      depth_first_visit(graph, root, CallVisitor(e, events),
                        make_iterator_property_map(colors.begin(), get(vertex_index, graph)));
      return e;
    }

    /** \brief print composite transformer
     *  \param o output stream to print to
     **/
    void print(std::ostream& o) const {
      auto writeVertex = [this](ostream& o, Vertex v){
        TransPtr t = graph[v];
        if(t)
          o << " [label=\"" << *t << "\"]";
        else
          o << " [label=\"nullptr\"]";
      };
      auto writeEdge = [this](ostream& o, Edge e) {
        o << " [label=\"" << graph[e] << "\"]";
      };
      write_graphviz(o, graph, writeVertex, writeEdge);
    }
};

using Graph        = CompositeTransformation::Graph;
using Vertex       = CompositeTransformation::Vertex;
using VertexResult = CompositeTransformation::VertexResult;
using VertexList   = CompositeTransformation::VertexList;
using Edge         = Graph::edge_descriptor;
using EventTypes   = CompositeTransformation::EventTypes;
using EventIDs     = CompositeTransformation::EventIDs;
using TransPtr     = CompositeTransformation::TransPtr;
using TransList    = CompositeTransformation::TransList;

struct InputEventTypeExtractor : public boost::default_dfs_visitor {
  Vertex temp;
  EventTypes& in;

  InputEventTypeExtractor(EventTypes& in)
    : in(in)
  {}

  void discover_vertex(Vertex v, const Graph& g) {
    temp = v;
  }

  void finish_vertex(Vertex v, const Graph& g) {
    if(temp == v) {
      const EventTypes& tempIn = g[v].in();
      copy(tempIn.begin(), tempIn.end(), back_inserter(in));
    }
  }
};

struct FindEventType : public boost::default_dfs_visitor {
  VertexList& result;
  const EventType& eT;

  FindEventType(const EventType& eT, VertexList& result)
    : result(result), eT(eT)
  {}

  void discover_vertex(Vertex v, const Graph& g) {
    if(count(g[v].in().begin(), g[v].in().end(), eT))
      result.push_back(v);
  }
};
;

CompositeTransformation::CompositeTransformation(TransformationPtr tPtr, const EventType& goal,
                                                 const EventType& provided) {
  VertexResult res = addRootTransformation(tPtr, goal, provided);
  if(res.second)
    mRoot = res.first;
}

TransPtr CompositeTransformation::create() const {
  if(boost::num_vertices(mGraph)==1) {
    return mGraph[mRoot].create();
  }
  return TransPtr(new CompositeTransformer(mOut, mIn, mGraph));
}

bool CompositeTransformation::check() const {
  return boost::num_vertices(mGraph);
}

VertexResult CompositeTransformation::addRootTransformation(TransformationPtr tPtr, const EventType& tempGoal,
                                                            const EventType& provided) {
  if(num_vertices(mGraph)==0) {
    Vertex root = boost::add_vertex(mGraph);
    ConfiguredTransformation& cT = mGraph[root];
    cT.trans(tPtr);
    cT.out(tempGoal);
    if(provided==EventType())
      cT.in(tPtr->in(tempGoal));
    else
      cT.in(tPtr->in(tempGoal, provided));
    in(cT.in());
    out(cT.out());
    return make_pair(root, true);
  }else
    return make_pair(Vertex(), false);
}

VertexResult CompositeTransformation::addTransformation(TransformationPtr tPtr, Vertex v,
                                                        const EventType& intermediate,
                                                        const EventType& provided) {
  const EventTypes& tempIn = mGraph[v].in();
  if(!count(tempIn.begin(), tempIn.end(), intermediate))
    return make_pair(Vertex(), false);

  Vertex newV = boost::add_vertex(mGraph);
  ConfiguredTransformation& cT = mGraph[newV];
  cT.trans(tPtr);
  cT.out(intermediate);
  if(provided==EventType())
    cT.in(tPtr->in(intermediate));
  else
    cT.in(tPtr->in(intermediate, provided));
  auto e = boost::add_edge(v, newV, mGraph);
  mGraph[e.first]=cT.out();
  mIn.clear();
  boost::depth_first_search(mGraph, boost::visitor(InputEventTypeExtractor(mIn)));
  return make_pair(newV, true);
}

EventIDs CompositeTransformation::inIDs() const {
  EventIDs ids(mIn.size());
  copy(mIn.begin(), mIn.end(), ids.begin());
  return ids;
}

TransList CompositeTransformation::path(Vertex v) const {
  TransList result;
  bool done=false;
  do {
    result.push_back(mGraph[v].trans());
    auto in=in_edges(v, mGraph);
    if(in.first!=in.second)
      v=source(*in.first, mGraph);
    else
      done=true;
  }while(!done);
  return result;
}

VertexResult CompositeTransformation::find(TransformationPtr tPtr) const {
  auto  pred = [this, tPtr](Vertex v){ return mGraph[v].trans()==tPtr; };
  auto it = find_if(vertices(mGraph).first, vertices(mGraph).second, pred);
  if(it==vertices(mGraph).second)
    return make_pair(Vertex(), false);
  else
    return make_pair(*it, true);
}

VertexList CompositeTransformation::find(const EventType& eT) const {
  VertexList result;
  boost::depth_first_search(mGraph, boost::visitor(FindEventType(eT, result)));
  return result;
}

/** \todo implement **/
ostream& operator<<(ostream& o, const CompositeTransformation& t) {
  const Graph& g=t.graph();
  auto writeVertex = [&g](ostream& o, Vertex v){
      if(g[v].trans())
        o << " [label=\"" << *g[v].trans() << "\"]";
      else
        o << " [label=\"nullptr\"]";
  };
  auto writeEdge = [&g](ostream& o, Edge e){
    o << " [label=\"" << g[e] << "\"]";
  };
  write_graphviz(o, g, writeVertex, writeEdge);
  return o;
}
<|endoftext|>