Go back to Richel Bilderbeek's homepage.

Go back to Richel Bilderbeek's C++ page.

 

 

 

 

 

(C++) ConceptMap

 

STLQt CreatorLubuntuWindows

 

ConceptMap is a class for a concept map.

 

ConceptMap is used in, among others, the tool TestConceptMap and the project Brainweaver.

Technical facts

 

 

 

 

 

 

./CppConceptMap/CppConceptMap.pri

 

INCLUDEPATH += \
    ../../Classes/CppConceptMap


OTHER_FILES += \
    ../../Classes/CppConceptMap/Licence.txt

HEADERS += \
    ../../Classes/CppConceptMap/conceptmapfwd.h \
    ../../Classes/CppConceptMap/conceptmapcenternode.h \
    ../../Classes/CppConceptMap/conceptmapcenternodefactory.h \
    ../../Classes/CppConceptMap/conceptmapcompetency.h \
    ../../Classes/CppConceptMap/conceptmapconcept.h \
    ../../Classes/CppConceptMap/conceptmapconceptfactory.h \
    ../../Classes/CppConceptMap/conceptmap.h \
    ../../Classes/CppConceptMap/conceptmapfactory.h \
    ../../Classes/CppConceptMap/conceptmapedgefactory.h \
    ../../Classes/CppConceptMap/conceptmapexample.h \
    ../../Classes/CppConceptMap/conceptmapexamplefactory.h \
    ../../Classes/CppConceptMap/conceptmapexamples.h \
    ../../Classes/CppConceptMap/conceptmapexamplesfactory.h \
    ../../Classes/CppConceptMap/conceptmapnode.h \
    ../../Classes/CppConceptMap/conceptmapnodefactory.h \
    ../../Classes/CppConceptMap/conceptmaphelper.h \
    ../../Classes/CppConceptMap/conceptmapedge.h \
    ../../Classes/CppConceptMap/conceptmapwidget.h \
    ../../Classes/CppConceptMap/conceptmapcommand.h \
    ../../Classes/CppConceptMap/conceptmapelement.h \
    ../../Classes/CppConceptMap/conceptmapcommandfactory.h \
    ../../Classes/CppConceptMap/conceptmapwidgetfactory.h \
    ../../Classes/CppConceptMap/conceptmapcommandcreatenewconceptmap.h \
    ../../Classes/CppConceptMap/conceptmapcommandcreatenewnode.h \
    ../../Classes/CppConceptMap/conceptmapcommanddeleteconceptmap.h \
    ../../Classes/CppConceptMap/conceptmapcommandlosefocus.h \
    ../../Classes/CppConceptMap/conceptmapcommandsetfocusrandom.h \
    ../../Classes/CppConceptMap/conceptmapcommanddeletenode.h \
    ../../Classes/CppConceptMap/conceptmapcommanddeletefocusnode.h \
    ../../Classes/CppConceptMap/conceptmapcommandcreatenewedge.h \
    ../../Classes/CppConceptMap/conceptmapcommandaddfocusrandom.h \
    ../../Classes/CppConceptMap/conceptmapcommandaddselectedrandom.h \
    ../../Classes/CppConceptMap/conceptmapcommandunselectrandom.h \
    ../../Classes/CppConceptMap/conceptmapcompetencies.h \
    ../../Classes/CppConceptMap/conceptmapregex.h \
    ../../Classes/CppConceptMap/conceptmapcommandsetselectedwithcoordinat.h

SOURCES += \
    ../../Classes/CppConceptMap/conceptmapcenternode.cpp \
    ../../Classes/CppConceptMap/conceptmapcenternodefactory.cpp \
    ../../Classes/CppConceptMap/conceptmapcompetency.cpp \
    ../../Classes/CppConceptMap/conceptmapconcept.cpp \
    ../../Classes/CppConceptMap/conceptmapconceptfactory.cpp \
    ../../Classes/CppConceptMap/conceptmap.cpp \
    ../../Classes/CppConceptMap/conceptmapfactory.cpp \
    ../../Classes/CppConceptMap/conceptmapedge.cpp \
    ../../Classes/CppConceptMap/conceptmapedgefactory.cpp \
    ../../Classes/CppConceptMap/conceptmapexample.cpp \
    ../../Classes/CppConceptMap/conceptmapexamplefactory.cpp \
    ../../Classes/CppConceptMap/conceptmapexamples.cpp \
    ../../Classes/CppConceptMap/conceptmapexamplesfactory.cpp \
    ../../Classes/CppConceptMap/conceptmapnode.cpp \
    ../../Classes/CppConceptMap/conceptmapnodefactory.cpp \
    ../../Classes/CppConceptMap/conceptmaphelper.cpp \
    ../../Classes/CppConceptMap/conceptmapwidget.cpp \
    ../../Classes/CppConceptMap/conceptmapcommand.cpp \
    ../../Classes/CppConceptMap/conceptmapelement.cpp \
    ../../Classes/CppConceptMap/conceptmapcommandfactory.cpp \
    ../../Classes/CppConceptMap/conceptmapwidgetfactory.cpp \
    ../../Classes/CppConceptMap/conceptmapcommandcreatenewconceptmap.cpp \
    ../../Classes/CppConceptMap/conceptmapcommandcreatenewnode.cpp \
    ../../Classes/CppConceptMap/conceptmapcommanddeleteconceptmap.cpp \
    ../../Classes/CppConceptMap/conceptmapcommandlosefocus.cpp \
    ../../Classes/CppConceptMap/conceptmapcommandsetfocusrandom.cpp \
    ../../Classes/CppConceptMap/conceptmapcommanddeletenode.cpp \
    ../../Classes/CppConceptMap/conceptmapcommanddeletefocusnode.cpp \
    ../../Classes/CppConceptMap/conceptmapcommandcreatenewedge.cpp \
    ../../Classes/CppConceptMap/conceptmapcommandaddfocusrandom.cpp \
    ../../Classes/CppConceptMap/conceptmapcommandaddselectedrandom.cpp \
    ../../Classes/CppConceptMap/conceptmapcommandunselectrandom.cpp \
    ../../Classes/CppConceptMap/conceptmapcompetencies.cpp \
    ../../Classes/CppConceptMap/conceptmapregex.cpp \
    ../../Classes/CppConceptMap/conceptmapconcept_test.cpp \
    ../../Classes/CppConceptMap/conceptmap_test.cpp \
    ../../Classes/CppConceptMap/conceptmapcommandsetselectedwithcoordinat.cpp

 

 

 

 

 

./CppConceptMap/conceptmap.h

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#ifndef CONCEPTMAPCONCEPTMAP_H
#define CONCEPTMAPCONCEPTMAP_H

#include <string>
#include <vector>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#include <boost/shared_ptr.hpp>
#include "conceptmapfwd.h"
#pragma GCC diagnostic pop

namespace ribi {
namespace cmap {

struct ConceptMapFactory;

///A concept map
///Its interface is based on nodes and edges
///Use ConceptMapWidget to work with commands
struct ConceptMap
{
  typedef boost::shared_ptr<ConceptMap> ConceptMapPtr;
  typedef boost::shared_ptr<const ConceptMap> ReadOnlyConceptMapPtr;
  typedef boost::shared_ptr<Edge> EdgePtr;
  typedef boost::shared_ptr<const Edge> ReadOnlyEdgePtr;
  typedef boost::shared_ptr<Node> NodePtr;
  typedef boost::shared_ptr<const Node> ReadOnlyNodePtr;
  typedef boost::shared_ptr<CenterNode> CenterNodePtr;
  typedef boost::shared_ptr<const CenterNode> ReadOnlyCenterNodePtr;
  typedef std::vector<ConceptMapPtr> ConceptMaps;
  typedef std::vector<EdgePtr> Edges;
  typedef std::vector<ReadOnlyEdgePtr> ReadOnlyEdges;
  typedef std::vector<NodePtr> Nodes;
  typedef std::vector<ReadOnlyNodePtr> ReadOnlyNodes;
  typedef ConceptMaps SubConceptMaps; //Just to let the code speak more for itself

  ConceptMap(const ConceptMap&) = delete;
  ConceptMap& operator=(const ConceptMap&) = delete;

  //Add an Edge, assumes that the nodes it points to are in the concept map
  void AddEdge(const EdgePtr& edge) noexcept;

  //Add a node, always works
  void AddNode(const NodePtr& node) noexcept;

  ///Test if this ConceptMap can be constructed successfully
  static bool CanConstruct(
    const Nodes& nodes,
    const Edges& edges
  ) noexcept;

  ///Prepend the question as a first node, before adding the supplied nodes
  static std::vector<NodePtr> CreateNodes(
    const std::string& question,
    const Nodes& nodes
  ) noexcept;

  ///Create all sub-conceptmaps
  ///Note that CreateSubs()[0] is the concept map around the focal question
  SubConceptMaps CreateSubs() const noexcept;

  ///Delete an edge
  void DeleteEdge(const EdgePtr& edge) noexcept;

  ///Delete a node and all the edges connected to it
  void DeleteNode(const ReadOnlyNodePtr& node) noexcept;
  void DeleteNode(const NodePtr& node) noexcept;

  ///Check if the ConceptMap is empty, that is: it has no nodes and (thus) no edges
  bool Empty() const noexcept;

  ///Find the CenterNode, if any
  ReadOnlyCenterNodePtr FindCenterNode() const noexcept;
  CenterNodePtr FindCenterNode() noexcept;

  ReadOnlyEdges GetEdges() const noexcept;
  Edges& GetEdges() noexcept { return m_edges; }

  ///Get the focal node (always at index zero)
  ReadOnlyNodePtr GetFocalNode() const noexcept;
  NodePtr GetFocalNode() noexcept;

  ReadOnlyNodes GetNodes() const noexcept;
  Nodes& GetNodes() noexcept { return m_nodes; }

  //Use this instead:
  //  assert(FindCenterNode());
  //  assert(FindCenterNode()->GetConcept());
  //  return FindCenterNode()->GetConcept()->GetName();
  //
  //std::string GetQuestion() const noexcept

  static std::string GetVersion() noexcept;
  static std::vector<std::string> GetVersionHistory() noexcept;

  bool HasNode(const ReadOnlyNodePtr& node) const noexcept;
  //const std::vector<boost::shared_ptr<      Node>>& GetNodes() { return m_nodes; }

  ///Similar to operator==, except that the GUI member variables aren't checked for equality
  static bool HasSameContent(const ConceptMap& lhs, const ConceptMap& rhs) noexcept;

  #ifndef NDEBUG
  ///Check if there are no nulls in the edges and nodes
  bool IsValid() const noexcept;
  #endif

  ///Convert a ConceptMap from an XML std::string
  static std::string ToXml(const ReadOnlyConceptMapPtr& c) noexcept;

private:

  ///The edges
  Edges m_edges;

  ///The nodes
  Nodes m_nodes;

  #ifndef NDEBUG
  static void Test() noexcept;
  #endif

  ///Block constructor, except for the friend ConceptMapFactory
  ConceptMap(const std::string& question) noexcept;
  //Nodes[0] must be the focal question
  explicit ConceptMap(
    const Nodes& nodes = {},
    const Edges& edges = {}
  ) noexcept;
  ///Create a concept map from a cluster
  #ifdef TO_ADD_TO_PROJECTBRAINWEAVER
  ConceptMap(
    const std::string& question,
    const boost::shared_ptr<cmap::Cluster>& cluster);
  #endif

  ///To make the compiler use the const version
  ReadOnlyCenterNodePtr FindCenterNodeConst() const noexcept { return FindCenterNode(); }
  ///To make the compiler use the const version
  ReadOnlyNodePtr GetFocalNodeConst() const noexcept { return GetFocalNode(); }

  friend ConceptMapFactory;
  ///Block destructor, except for the friend boost::checked_delete
  ~ConceptMap() noexcept;
  friend void boost::checked_delete<>(ConceptMap* x);
  friend void boost::checked_delete<>(const ConceptMap* x);
};

///Count the number of CenterNodes
///- regular concept map: 1, the focus
///- sub-concept map: 0 or 1, if the focus is connected to the sub's focus node
int CountCenterNodes(const boost::shared_ptr<const ConceptMap>& conceptmap) noexcept;

///Count the number of Edges connected to a CenterNodes
int CountCenterNodeEdges(const boost::shared_ptr<const ConceptMap>& conceptmap) noexcept;

bool operator==(const ConceptMap& lhs, const ConceptMap& rhs) noexcept;
bool operator!=(const ConceptMap& lhs, const ConceptMap& rhs) noexcept;

} //~namespace cmap
} //~namespace ribi

#endif // CONCEPTMAPCONCEPTMAP_H

 

 

 

 

 

./CppConceptMap/conceptmap.cpp

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#include "conceptmap.h"

#include <set>
#include <sstream>
#include <functional>
#include "conceptmapcenternodefactory.h"
#include "conceptmapcenternode.h"
#include "conceptmapconceptfactory.h"
#include "conceptmapconcept.h"
#include "conceptmapedgefactory.h"
#include "conceptmapedge.h"
#include "conceptmapexamplesfactory.h"
#include "conceptmaphelper.h"
#include "conceptmapnodefactory.h"
#include "conceptmapnode.h"
#include "testtimer.h"
#include "trace.h"
//#include "conceptmapcluster.h"
#pragma GCC diagnostic pop

ribi::cmap::ConceptMap::ConceptMap(const std::string& question) noexcept
  : m_edges( {} ),
    m_nodes(CreateNodes(question, {} ))
{
  #ifndef NDEBUG
  Test();
  assert(ConceptMap::CanConstruct(m_nodes,m_edges));
  assert(FindCenterNode()
    && "Assume a CenterNode at the center of ConceptMap");
  assert(IsCenterNode(FindCenterNode())
    && "The CenterNode found must really be a CenterNode");
  assert(FindCenterNode()->GetConcept()
    && "The CenterNode must have an initialized Concept to display the focus");
  assert(FindCenterNode()->GetConcept()->GetName() == question
    && "The CenterNode must display the focus");
  #endif
}

ribi::cmap::ConceptMap::ConceptMap(
    const Nodes& nodes,
    const Edges& edges
)  noexcept
  : m_edges(edges),
    m_nodes(nodes)
{
  #ifndef NDEBUG
  Test();
  if (!ConceptMap::CanConstruct(nodes,edges))
  {
    TRACE("ERROR");
    const std::size_t n_nodes = nodes.size();
    for (std::size_t i=0; i!=n_nodes; ++i)
    {
      std::cout << i << ": " << nodes[i]->ToXml() << '\n';
    }

    const std::size_t n_edges = edges.size();
    for (std::size_t i=0; i!=n_edges; ++i)
    {
      const auto edge = edges[i];
      const auto const_nodes = AddConst(nodes);
      const auto from_iter = std::find(nodes.begin(),nodes.end(),edge->GetFrom());
      const auto to_iter = std::find(nodes.begin(),nodes.end(),edge->GetTo());
      assert(from_iter != nodes.end());
      assert(to_iter != nodes.end());
      std::cout
        << i << ": "
        << Edge::ToXml(boost::const_pointer_cast<const Edge>(edge),const_nodes)
        << '\n';
    }
  }
  assert(ConceptMap::CanConstruct(nodes,edges));
  #endif
}

#ifdef TO_ADD_TO_PROJECTBRAINWEAVER
ribi::cmap::ConceptMap::ConceptMap(
  const std::string& question,
  const boost::shared_ptr<cmap::Cluster>& cluster)
  : m_edges{},
    m_nodes(CreateNodes(question, {} ))
{
  #ifndef NDEBUG
  Test();
  #endif

  const std::vector<boost::shared_ptr<ribi::cmap::Concept>>& v = cluster->Get();
  const int n = boost::numeric_cast<int>(v.size());
  for (int i=0; i!=n; ++i)
  {
    const int x = 0;
    const int y = 0;
    const boost::shared_ptr<Node> node = NodeFactory().Create(v[i],x,y);
    assert(node);
    m_nodes.push_back(node);
  }
  assert(v.size() + 1 == m_nodes.size()
    && "Assume the ConceptMap has as much nodes as the cluster has concepts + one focal question");
}
#endif //TO_ADD_TO_PROJECTBRAINWEAVER

ribi::cmap::ConceptMap::~ConceptMap() noexcept
{
  //OK
}

void ribi::cmap::ConceptMap::AddEdge(const EdgePtr& edge) noexcept
{
  assert(edge);
  #define TODO_RICHEL
  #ifdef  TODO_RICHEL
  if (std::count(m_nodes.begin(),m_nodes.end(),edge->GetFrom()) == 0)
  {
    TRACE("ERROR");
  }
  assert(HasNode(edge->GetFrom()));
  assert(HasNode(edge->GetTo()));
  assert(std::count(m_nodes.begin(),m_nodes.end(),edge->GetFrom()) == 1
    && "First enter the node this edge originates from"); //TODO RJCB
  assert(std::count(m_nodes.begin(),m_nodes.end(),edge->GetTo()) == 1
    && "First enter the node this edge targets to");
  #endif
  m_edges.push_back(edge);
}

void ribi::cmap::ConceptMap::AddNode(const NodePtr& node) noexcept
{
  assert(node);
  m_nodes.push_back(node);
  assert(std::count(m_nodes.begin(),m_nodes.end(),node) == 1
    && "Every node must be unique");
  //Do not let concept map signal that a new node has been added:
  //keep it as stupid as possible. Let ConceptMapWidget
  //have this behavior
}


bool ribi::cmap::ConceptMap::CanConstruct(
  const Nodes& /* nodes */,
  const Edges& edges) noexcept
{
  const bool trace_verbose = false;

  //Test if there are 'two-way' edges, that is, one edge going from A to B
  //and another edge going from B to A
  {
    const int n_edges = edges.size();
    for (int i=0; i!=n_edges; ++i)
    {
      const boost::shared_ptr<ribi::cmap::Edge> & a = edges[i];
      const auto a_from = a->GetFrom();
      const auto a_to   = a->GetTo();
      for (int j=i+1; j!=n_edges; ++j)
      {
        assert(i != j);
        assert(j < n_edges);
        const boost::shared_ptr<Edge> & b = edges[j];
        assert(a.get() != b.get() && "Assume different pointers");
        const auto b_from = b->GetFrom();
        const auto b_to   = b->GetTo();
        if (a_from.get() == b_from.get() && a_to.get() == b_to.get())
        {
          if (trace_verbose)
          {
            TRACE("Cannot have two edges from the same node to the same node");
          }
          return false;
        }
        if (a_from.get() == b_to.get() && a_to.get() == b_from.get())
        {
          if (trace_verbose)
          {
            TRACE("Cannot have two edges from the same node to the same node");
          }
          return false;
        }
      }
    }
  }
  return true;
}

ribi::cmap::ConceptMap::Nodes ribi::cmap::ConceptMap::CreateNodes(
  const std::string& question,
  const Nodes& nodes) noexcept
{
  Nodes v;
  const boost::shared_ptr<Concept> concept(
    ConceptFactory().Create(
      question,
      ExamplesFactory().Create(), //No examples
      false, //Is not complex
      -1, //No rated complexity
      -1, //No rated concreteness
      -1  //No rated specificity
    )
  );
  const boost::shared_ptr<CenterNode> center_node {
    CenterNodeFactory().Create(concept,0.0,0.0)
  };
  assert(center_node);
  v.push_back(center_node);
  std::copy(nodes.begin(),nodes.end(),std::back_inserter(v));
  assert(v.size() == nodes.size() + 1);
  return v;
}

ribi::cmap::ConceptMap::SubConceptMaps ribi::cmap::ConceptMap::CreateSubs() const noexcept
{
  SubConceptMaps v;
  for (const boost::shared_ptr<Node>& focal_node: m_nodes)
  {
    assert(focal_node);

    //Collect all edges connected top the focal node (which is m_nodes[i])
    Nodes nodes{};
    Edges edges{};

    nodes.push_back(focal_node);

    for (const boost::shared_ptr<Edge>& focal_edge: m_edges)
    {
     if (focal_edge->GetFrom() == focal_node)
      {
        edges.push_back(focal_edge);
        assert(focal_edge->GetTo() != focal_node);
        nodes.push_back(focal_edge->GetTo());
      }
      else if (focal_edge->GetTo() == focal_node)
      {
        edges.push_back(focal_edge);
        assert(focal_edge->GetFrom() != focal_node);
        nodes.push_back(focal_edge->GetFrom());
      }
    }
    assert(!nodes.empty());
    //Put CenterNode in front
    const auto iter = std::find_if(nodes.begin(),nodes.end(),[](const boost::shared_ptr<Node> node) { return IsCenterNode(node); } );
    if (iter != nodes.end()) { std::swap(*nodes.begin(),*iter); }
    assert(ConceptMap::CanConstruct(nodes,edges) && "Only construct valid concept maps");
    const boost::shared_ptr<ConceptMap> concept_map(new ConceptMap(nodes,edges));
    assert(concept_map->IsValid());
    v.push_back(concept_map);
  }
  return v;
}

void ribi::cmap::ConceptMap::DeleteEdge(const EdgePtr& edge) noexcept
{
  #ifndef NDEBUG
  assert(edge);
  //One cannot be sure if the edges are already deleted or not
  if(std::count(m_edges.begin(),m_edges.end(),edge) == 0) return;
  assert(std::count(m_edges.begin(),m_edges.end(),edge) != 0
    && "The edge must exist");
  assert(std::count(m_edges.begin(),m_edges.end(),edge) == 1
    && "Every edge is unique");
  const std::size_t n_edges_before = m_edges.size();
  #endif

  m_edges.erase(std::remove(m_edges.begin(),m_edges.end(),edge),m_edges.end());

  #ifndef NDEBUG
  const std::size_t n_edges_after = m_edges.size();
  assert(n_edges_before - 1 == n_edges_after);
  #endif
}

void ribi::cmap::ConceptMap::DeleteNode(const NodePtr& node) noexcept
{
  DeleteNode(boost::dynamic_pointer_cast<const Node>(node));
}

void ribi::cmap::ConceptMap::DeleteNode(const ReadOnlyNodePtr& node) noexcept
{
  #ifndef NDEBUG
  assert(node);
  if (std::count(m_nodes.begin(),m_nodes.end(),node) == 0)
  {
    //There are multiple ways to delete a node:
    // - QtConceptMap: delete the QtNode, which deletes the Node
    // - ConceptMapWidget: deletes the Node, which signals its observers of this event
    //Because the sequence
    return;
  }
  assert(std::count(m_nodes.begin(),m_nodes.end(),node) > 0
    && "Can only delete an existing node");
  assert(std::count(m_nodes.begin(),m_nodes.end(),node) == 1
    && "Every node is unique");
  const std::size_t n_nodes_before = m_nodes.size();
  #endif

  //Delete all edges going to this node
  std::vector<boost::shared_ptr<ribi::cmap::Edge>> to_be_deleted;
  std::copy_if(m_edges.begin(),m_edges.end(),std::back_inserter(to_be_deleted),
    [node](boost::shared_ptr<Edge> edge)
    {
      return edge->GetFrom() == node || edge->GetTo() == node;
    }
  );
  for (boost::shared_ptr<Edge> edge: to_be_deleted)
  {
    DeleteEdge(edge);
  }

  //Delete the node itself
  //Copied from http://www.richelbilderbeek.nl/CppVector.htm
  m_nodes.erase(std::remove(m_nodes.begin(),m_nodes.end(),node),m_nodes.end());

  #ifndef NDEBUG
  const std::size_t n_nodes_after = m_nodes.size();
  assert(n_nodes_before - 1 == n_nodes_after);
  #endif
}


bool ribi::cmap::ConceptMap::Empty() const noexcept
{
  assert(!(m_nodes.empty() && !m_edges.empty())
    && "If there are no nodes, there cannot be edges");
  return m_nodes.empty(); // && m_edges.empty();
}

ribi::cmap::ConceptMap::ReadOnlyCenterNodePtr ribi::cmap::ConceptMap::FindCenterNode() const noexcept
{
  const auto iter = std::find_if(m_nodes.begin(),m_nodes.end(),
    [](const boost::shared_ptr<const Node> node)
    {
      return IsCenterNode(node);
    }
  );
  boost::shared_ptr<const CenterNode> center_node;
  if (iter == m_nodes.end())
  {
    assert(!center_node);
  }
  else
  {
    center_node = boost::dynamic_pointer_cast<const CenterNode>(*iter);
    assert(center_node);
  }
  return center_node;
}

ribi::cmap::ConceptMap::CenterNodePtr ribi::cmap::ConceptMap::FindCenterNode() noexcept
{
  //Calls the const version of this member function
  //To avoid duplication in const and non-const member functions [1]
  //[1] Scott Meyers. Effective C++ (3rd edition). ISBN: 0-321-33487-6.
  //    Item 3, paragraph 'Avoid duplication in const and non-const member functions'
  const ReadOnlyCenterNodePtr center_node {
    dynamic_cast<const ConceptMap*>(this)->FindCenterNodeConst() //Add const because compiler cannt find the right version
  };
  return boost::const_pointer_cast<CenterNode>(
    center_node
  );
}


ribi::cmap::ConceptMap::ReadOnlyEdges ribi::cmap::ConceptMap::GetEdges() const noexcept
{
  return AddConst(m_edges);
}

ribi::cmap::ConceptMap::ReadOnlyNodePtr ribi::cmap::ConceptMap::GetFocalNode() const noexcept
{
  if (m_nodes.empty()) return boost::shared_ptr<const Node>();
  return m_nodes[0];
}

ribi::cmap::ConceptMap::NodePtr ribi::cmap::ConceptMap::GetFocalNode() noexcept
{
  //Calls the const version of this member function
  //To avoid duplication in const and non-const member functions [1]
  //[1] Scott Meyers. Effective C++ (3rd edition). ISBN: 0-321-33487-6.
  //    Item 3, paragraph 'Avoid duplication in const and non-const member functions'
  boost::shared_ptr<const Node> focal_node {
    dynamic_cast<const ConceptMap*>(this)->GetFocalNodeConst() //Compiler cannot distinguish member functions by type
  };
  return boost::const_pointer_cast<Node>(
    focal_node
  );
}


ribi::cmap::ConceptMap::ReadOnlyNodes ribi::cmap::ConceptMap::GetNodes() const noexcept
{
  return AddConst(m_nodes);
}

/*
std::string ribi::cmap::ConceptMap::GetQuestion() const noexcept
{
  const boost::shared_ptr<const CenterNode> center_node(FindCenterNode());
  if (center_node)
  {
    assert(center_node->GetConcept());
    return center_node->GetConcept()->GetName();
  }
  else return "";
}
*/

std::string ribi::cmap::ConceptMap::GetVersion() noexcept
{
  return "1.2";
}

std::vector<std::string> ribi::cmap::ConceptMap::GetVersionHistory() noexcept
{
  return {
    "2013-xx-xx: Version 1.0: initial version",
    "2013-12-23: Version 1.1: started versioning",
    "2014-02-08: Version 1.2: support an empty concept map"
  };
}

bool ribi::cmap::ConceptMap::HasNode(const boost::shared_ptr<const Node>& node) const noexcept
{
  return std::count(m_nodes.begin(),m_nodes.end(),node);
}

bool ribi::cmap::ConceptMap::HasSameContent(
  const ribi::cmap::ConceptMap& lhs,
  const ribi::cmap::ConceptMap& rhs
) noexcept
{
  const bool trace_verbose{false};

  if (lhs.GetEdges().size() != rhs.GetEdges().size())
  {
    if (trace_verbose) { TRACE("Number of edges differ"); }
    return false;
  }
  if (lhs.GetNodes().size() != rhs.GetNodes().size())
  {
    if (trace_verbose)
    {
      TRACE("Number of nodes differ");
      TRACE(lhs.GetNodes().size());
      TRACE(rhs.GetNodes().size());
    }
    return false;
  }
  //Function to compare Node smart pointers
  //typedef boost::shared_ptr<const Node> ConstNodePtr;
  //const std::function<bool(const boost::shared_ptr<const Node>& lhs,
  //  const boost::shared_ptr<const Node>& rhs)> node_cmp
  //  = [](const boost::shared_ptr<const Node>& lhs,
  //       const boost::shared_ptr<const Node>& rhs)
  //    {
  //      return *lhs < *rhs;
  //    };
  //Function to compare Concept smart pointers
  typedef boost::shared_ptr<const ribi::cmap::Concept> ConstConceptPtr;
  const std::function<bool(const boost::shared_ptr<const ribi::cmap::Concept>& lhs,
    const boost::shared_ptr<const ribi::cmap::Concept>& rhs)> concept_cmp
    = [](const boost::shared_ptr<const ribi::cmap::Concept>& lhs,
         const boost::shared_ptr<const ribi::cmap::Concept>& rhs)
      {
        return *lhs < *rhs;
      };


  //Same Concepts
  {
    const std::vector<boost::shared_ptr<const Node>> nodes_lhs = lhs.GetNodes();
    std::multiset<ConstConceptPtr,decltype(concept_cmp)> concepts_lhs(concept_cmp);
    std::transform(nodes_lhs.begin(),nodes_lhs.end(),
      std::inserter(concepts_lhs,concepts_lhs.begin()),
      [](boost::shared_ptr<const Node> node)
      {
        assert(node);
        assert(node->GetConcept());
        ConstConceptPtr concept = node->GetConcept();
        return concept;
      }
    );

    const std::vector<boost::shared_ptr<const Node>> nodes_rhs = rhs.GetNodes();
    std::multiset<ConstConceptPtr,decltype(concept_cmp)> concepts_rhs(concept_cmp);

    std::transform(nodes_rhs.begin(),nodes_rhs.end(),
      std::inserter(concepts_rhs,concepts_rhs.begin()),
      [](const boost::shared_ptr<const Node>& node)
      {
        return node->GetConcept();
      }
    );
    if (std::mismatch(concepts_lhs.begin(),concepts_lhs.end(),concepts_rhs.begin(),
      [](const ConstConceptPtr& a,
         const ConstConceptPtr& b)
        {
          return *a == *b;
        }
      )
      != std::make_pair(concepts_lhs.end(),concepts_rhs.end()))
    {
      if (trace_verbose) { TRACE("Node concepts differ"); }
      return false;
    }
  }
  //Same Edges
  {
    const std::vector<boost::shared_ptr<const Edge>> edges_lhs = lhs.GetEdges();
    std::multiset<ConstConceptPtr,decltype(concept_cmp)> concepts_lhs(concept_cmp);
    std::transform(edges_lhs.begin(),edges_lhs.end(),
      std::inserter(concepts_lhs,concepts_lhs.begin()),
      [](const boost::shared_ptr<const Edge>& edge)
      {
        assert(edge);
        assert(edge->GetNode());
        assert(edge->GetNode()->GetConcept());
        return edge->GetNode()->GetConcept();
      }
    );

    const std::vector<boost::shared_ptr<const Edge>> edges_rhs = rhs.GetEdges();

    std::multiset<ConstConceptPtr,decltype(concept_cmp)> concepts_rhs(concept_cmp);
    std::transform(edges_rhs.begin(),edges_rhs.end(),
      std::inserter(concepts_rhs,concepts_rhs.begin()),
      [](const boost::shared_ptr<const cmap::Edge>& edge)
      {
        assert(edge);
        assert(edge->GetNode());
        assert(edge->GetNode()->GetConcept());
        return edge->GetNode()->GetConcept();
      }
    );
    if (std::mismatch(concepts_lhs.begin(),concepts_lhs.end(),concepts_rhs.begin(),
      [](const ConstConceptPtr& a,const ConstConceptPtr& b)
        {
          return *a == *b;
        }
      )
      != std::make_pair(concepts_lhs.end(),concepts_rhs.end()))
    {
      if (trace_verbose) { TRACE("Edge concepts differ"); }
      return false;
    }
  }
  //Check if for each edge a same 'from' and 'to' concept can be found
  {
    typedef std::tuple<std::string,std::string,std::string> FakeEdge;
    typedef std::vector<FakeEdge> FakeEdges;

    assert(lhs.GetEdges().size() == rhs.GetEdges().size());

    FakeEdges v;
    const int sz = lhs.GetEdges().size();
    for (int i=0; i!=sz; ++i)
    {
      const auto from_node = lhs.GetEdges()[i]->GetFrom();
      const std::string str_from = from_node->GetConcept()->GetName();
      const std::string str_mid = lhs.GetEdges()[i]->GetNode()->GetConcept()->GetName();
      const auto to_node = lhs.GetEdges()[i]->GetTo();
      const std::string str_to = to_node->GetConcept()->GetName();
      //Only if arrow is reversed, reverse the fake edge
      if (
           lhs.GetEdges()[i]->HasTailArrow() == true
        && lhs.GetEdges()[i]->HasHeadArrow() == false)
      {
        v.push_back(std::make_tuple(str_to,str_mid,str_from));
      }
      else if (lhs.GetEdges()[i]->HasTailArrow() == lhs.GetEdges()[i]->HasHeadArrow())
      {
        //Two-way or zero-way arrow, add it in both directions
        v.push_back(std::make_tuple(str_to,str_mid,str_from));
        v.push_back(std::make_tuple(str_from,str_mid,str_to));
      }
      else
      {
        //Normal arrow
        v.push_back(std::make_tuple(str_from,str_mid,str_to));
      }
    }
    assert(boost::numeric_cast<int>(v.size()) >= sz);

    FakeEdges w;
    for (int i=0; i!=sz; ++i)
    {
      const auto from_node = rhs.GetEdges()[i]->GetFrom();
      const std::string str_from = from_node->GetConcept()->GetName();
      const std::string str_mid = rhs.GetEdges()[i]->GetNode()->GetConcept()->GetName();
      const auto to_node = rhs.GetEdges()[i]->GetTo();
      const std::string str_to = to_node->GetConcept()->GetName();
      //w.push_back(std::make_tuple(str_from,str_mid,str_to));
      //Only if arrow is reversed, reverse the fake edge
      if (
           rhs.GetEdges()[i]->HasTailArrow() == true
        && rhs.GetEdges()[i]->HasHeadArrow() == false)
      {
        w.push_back(std::make_tuple(str_to,str_mid,str_from));
      }
      else if (rhs.GetEdges()[i]->HasTailArrow() == rhs.GetEdges()[i]->HasHeadArrow())
      {
        //Two-way or zero-way arrow, add it in both directions
        w.push_back(std::make_tuple(str_to,str_mid,str_from));
        w.push_back(std::make_tuple(str_from,str_mid,str_to));
      }
      else
      {
        //Normal arrow
        w.push_back(std::make_tuple(str_from,str_mid,str_to));
      }
    }
    assert(static_cast<int>(w.size()) >= sz);
    if (v.size() != w.size()) return false;

    std::sort(v.begin(),v.end());
    std::sort(w.begin(),w.end());
    if (v != w)
    {
      //#define REALLY_SHOW_ME_THIS_7364894385876473475934758934753
      #ifdef REALLY_SHOW_ME_THIS_7364894385876473475934758934753
      #ifndef NDEBUG
      for (int i=0; i!=sz; ++i)
      {
        std::stringstream s;
        s << "[" << (i+1) << "/" << sz << "]: ("
          << std::get<0>(v[i]) << "," << std::get<1>(v[i]) << "," << std::get<2>(v[i])
          << ") , ("
          << std::get<0>(w[i]) << "," << std::get<1>(w[i]) << "," << std::get<2>(w[i])
          << ")";
        TRACE(s);
      }
      #endif
      #endif
      return false;
    }
  }
  return true;
}

#ifndef NDEBUG
bool ribi::cmap::ConceptMap::IsValid() const noexcept
{
  for (const boost::shared_ptr<Node>& node: m_nodes)
  {
    if (!node)
    {
      TRACE("Node is nullptr");
      return false;
    }
  }
  for (const boost::shared_ptr<Edge>& edge: m_edges)
  {
    if (!edge)
    {
      TRACE("Edge is nullptr");
      return false;
    }
    if (!edge->GetTo())
    {
      TRACE("edge->GetTo() is nullptr");
      return false;
    }
    if (!edge->GetFrom())
    {
      TRACE("edge->GetFrom() is nullptr");
      return false;
    }
    if (std::count(
      m_nodes.begin(),
      m_nodes.end(),
      edge->GetTo()) != 1)
    {
      TRACE("edge->GetTo() points to node not in the concept map");
      return false;
    }
    if(std::count(
      m_nodes.begin(),
      m_nodes.end(),
      edge->GetFrom()) != 1)
    {
      TRACE("edge->GetFrom() points to node not in the concept map");
      return false;
    }
  }
  return true;
}
#endif

std::string ribi::cmap::ConceptMap::ToXml(const ReadOnlyConceptMapPtr& map) noexcept
{
  std::stringstream s;
  s << "<concept_map>";
  s << "<nodes>";
  const std::vector<boost::shared_ptr<const Node>>& nodes = map->GetNodes();
  for (const boost::shared_ptr<const Node> node: nodes)
  {
    s << node->ToXml();
  }
  s << "</nodes>";
  s << "<edges>";
  const std::vector<boost::shared_ptr<const cmap::Edge>>& edges = map->GetEdges();
  for (const boost::shared_ptr<const cmap::Edge> edge: edges)
  {
    s << Edge::ToXml(edge,nodes);
  }
  s << "</edges>";
  s << "</concept_map>";

  const std::string r = s.str();
  assert(r.size() >= 27);
  assert(r.substr(0,13) == "<concept_map>");
  assert(r.substr(r.size() - 14,14) == "</concept_map>");

  return r;
}

int ribi::cmap::CountCenterNodes(
  const ribi::cmap::ConceptMap::ReadOnlyConceptMapPtr& conceptmap
) noexcept
{
  const auto v = conceptmap->GetNodes();
  const int cnt = std::count_if(v.begin(),v.end(),
    [](const boost::shared_ptr<const Node> node)
    {
      return IsCenterNode(node);
    }
  );
  assert(cnt < 2 && "A concept map can have one or zero (a sub-conceptmap) center nodes");
  return cnt;
}

int ribi::cmap::CountCenterNodeEdges(
  const ribi::cmap::ConceptMap::ReadOnlyConceptMapPtr& conceptmap
) noexcept
{
  const int n_center_nodes{CountCenterNodes(conceptmap)};
  assert(n_center_nodes < 2 && "A concept map can have one or zero (a sub-conceptmap) center nodes");
  if (n_center_nodes == 0) return 0;
  const auto v = conceptmap->GetEdges();
  const int cnt{
    std::count_if(v.begin(),v.end(),
      [](const boost::shared_ptr<const Edge> edge)
      {
        return IsConnectedToCenterNode(edge);
      }
    )
  };
  return cnt;
}

bool ribi::cmap::operator==(const ribi::cmap::ConceptMap& lhs, const ribi::cmap::ConceptMap& rhs) noexcept
{
  //Compare nodes
  {
    const std::vector<boost::shared_ptr<const Node>> lhs_nodes = lhs.GetNodes();
    const std::vector<boost::shared_ptr<const Node>> rhs_nodes = rhs.GetNodes();
    if (lhs_nodes.size() != rhs_nodes.size()) return false;
    if (!
      std::equal(
        std::begin(lhs_nodes),
        std::end(  lhs_nodes),
        std::begin(rhs_nodes),
        [](const boost::shared_ptr<const Node> lhs_node,
           const boost::shared_ptr<const Node> rhs_node)
        {
          return *lhs_node == *rhs_node;
        }
      )
    )
    {
      return false;
    }
  }
  //Compare edges
  {
    const std::vector<boost::shared_ptr<const cmap::Edge>> lhs_edges = lhs.GetEdges();
    const std::vector<boost::shared_ptr<const cmap::Edge>> rhs_edges = rhs.GetEdges();
    if (lhs_edges.size() != rhs_edges.size()) return false;
    if (!
      std::equal(
        std::begin(lhs_edges),
        std::end(  lhs_edges),
        std::begin(rhs_edges),
        [](const boost::shared_ptr<const cmap::Edge> lhs_edge,
           const boost::shared_ptr<const cmap::Edge> rhs_edge)
        {
          return *lhs_edge == *rhs_edge;
        }
      )
    )
    {
      return false;
    }
  }
  return true;

}

bool ribi::cmap::operator!=(const ribi::cmap::ConceptMap& lhs, const ribi::cmap::ConceptMap& rhs) noexcept
{
  return !(lhs == rhs);
}

 

 

 

 

 

./CppConceptMap/conceptmap_test.cpp

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#include "conceptmap.h"

#include <sstream>
#include <set>
#include <iterator>

#include <boost/lexical_cast.hpp>

#include <QRegExp>

#include "conceptmapcenternode.h"
#include "conceptmapcenternodefactory.h"
#include "conceptmapcompetency.h"
#include "conceptmapconcept.h"
#include "conceptmapconceptfactory.h"
#include "conceptmapedge.h"
#include "conceptmapedgefactory.h"
#include "conceptmapexamplefactory.h"
#include "conceptmapexamplesfactory.h"
#include "conceptmapfactory.h"
#include "conceptmaphelper.h"
#include "conceptmaphelper.h"
#include "conceptmapnode.h"
#include "conceptmapnodefactory.h"
#include "testtimer.h"
#include "trace.h"
#include "xml.h"
#pragma GCC diagnostic pop

#ifndef NDEBUG
void ribi::cmap::ConceptMap::Test() noexcept
{
  {
    static bool is_tested{false};
    if (is_tested) return;
    is_tested = true;
  }
  CenterNodeFactory();
  ConceptFactory();
  ExamplesFactory();
  NodeFactory();
  EdgeFactory();
  TestHelperFunctions();
  const TestTimer test_timer(__func__,__FILE__,1.0);
  const bool trace_verbose{false};
  typedef std::vector<boost::shared_ptr<Node>> Nodes;

  if (trace_verbose) { TRACE("Create tests"); }
  {
    //const TestTimer test_timer(boost::lexical_cast<std::string>(__LINE__),__FILE__,0.1);
    const std::vector<boost::shared_ptr<const ConceptMap>> v{AddConst(ConceptMapFactory().GetAllTests())};
    assert(!v.empty());
  }
  if (trace_verbose) { TRACE("DeepCopy must result in two identical concept maps"); }
  {
    //const TestTimer test_timer(boost::lexical_cast<std::string>(__LINE__),__FILE__,0.1);
    const boost::shared_ptr<const ConceptMap> m{ConceptMapFactory().GetHeteromorphousTestConceptMap(19)};
    const boost::shared_ptr<ConceptMap> c{ConceptMapFactory().DeepCopy(m)};
    assert(*c == *m);
  }
  if (trace_verbose) { TRACE("ConceptMap->XML->ConceptMap must result in two identical concept maps"); }
  {
    //const TestTimer test_timer(boost::lexical_cast<std::string>(__LINE__),__FILE__,0.2);
    const boost::shared_ptr<const ConceptMap> m{ConceptMapFactory().GetHeteromorphousTestConceptMap(19)};
    const std::string s{ToXml(m)};
    const boost::shared_ptr<ConceptMap> d = ConceptMapFactory().FromXml(s);
    assert(*m == *d);
  }
  if (trace_verbose) { TRACE("CanConstruct"); }
  {
    //const TestTimer test_timer(boost::lexical_cast<std::string>(__LINE__),__FILE__,0.1);
    assert(CanConstruct( {}, {} ) && "Assume empty concept map can be constructed");
  }
  {
    //const TestTimer test_timer(boost::lexical_cast<std::string>(__LINE__),__FILE__,0.1);
    const boost::shared_ptr<Concept> concept(ConceptFactory().Create("FOCAL QUESTION"));
    const boost::shared_ptr<Node> node = NodeFactory().Create(concept,123,234);
    assert(CanConstruct( { node }, {} ) && "Assume focal question without examples can be constructed");
  }
  {
    //const TestTimer test_timer(boost::lexical_cast<std::string>(__LINE__),__FILE__,0.1);
    const boost::shared_ptr<Concept> concept(ConceptFactory().Create("FOCAL QUESTION", { {"No",Competency::misc},{"examples",Competency::misc},{"allowed",Competency::misc} } ));
    const boost::shared_ptr<Node> node = NodeFactory().Create(concept,123,234);
    assert(CanConstruct( { node }, {} )
      && "Assume focal question with examples can be constructed"
      && "for example, when creating a sub-concept map");
  }
  if (trace_verbose) { TRACE("HasSameContent"); }
  {
    if (trace_verbose) { TRACE("HasSameContent 1"); }
    {
      //const TestTimer test_timer(boost::lexical_cast<std::string>(__LINE__),__FILE__,0.1);
      assert(NodeFactory().GetTests().size() >= 3);
      const boost::shared_ptr<CenterNode> node_a(CenterNodeFactory().CreateFromStrings("FOCAL QUESTION"));
      assert(node_a);
      const boost::shared_ptr<Node> node_b(NodeFactory().GetTests().at(1));
      assert(node_b);
      const boost::shared_ptr<Node> node_c(NodeFactory().GetTests().at(2));
      assert(node_c);
      const boost::shared_ptr<ConceptMap> map_a(
        ConceptMapFactory().Create(
          {
            CenterNodeFactory().CreateFromStrings("FOCAL QUESTION"),
            NodeFactory().GetTests().at(1),
            NodeFactory().GetTests().at(2)
          }
        )
      );
      assert(map_a);
      assert(map_a->GetNodes().size() == 3);
      const boost::shared_ptr<ConceptMap> map_b(
        ConceptMapFactory().Create(
          {
            CenterNodeFactory().CreateFromStrings("FOCAL QUESTION"),
            NodeFactory().GetTests().at(1),
            NodeFactory().GetTests().at(2)
          }
        )
      );
      assert(map_b);
      assert(map_b->GetNodes().size() == 3);
      assert(HasSameContent(*map_a,*map_b));
      assert(map_a != map_b);

      const boost::shared_ptr<ConceptMap> map_c(
        ConceptMapFactory().Create(
          {
            CenterNodeFactory().CreateFromStrings("FOCAL QUESTION"),
            NodeFactory().GetTests().at(1),
            NodeFactory().GetTests().at(2),
            NodeFactory().GetTests().at(2)
          }
        )
      );
      assert(!HasSameContent(*map_a,*map_c));
      assert(!HasSameContent(*map_b,*map_c));

    }
    if (trace_verbose) { TRACE("HasSameContent 2"); }
    {
      //const TestTimer test_timer(boost::lexical_cast<std::string>(__LINE__),__FILE__,0.1);
      const boost::shared_ptr<Concept> concept_b(ConceptFactory().Create("1", { {"2",Competency::misc},{"3",Competency::misc} } ));
      const boost::shared_ptr<Concept> concept_f(ConceptFactory().Create("1", { {"2",Competency::misc},{"3",Competency::misc} } ));
      const boost::shared_ptr<Node> node_b(NodeFactory().Create(concept_b,321,432));
      const boost::shared_ptr<ConceptMap> map_a(
        ConceptMapFactory().Create(
          {
            CenterNodeFactory().CreateFromStrings("FOCAL QUESTION"),
            NodeFactory().GetTests().at(1),
            NodeFactory().CreateFromStrings("4", { {"5",Competency::misc},{"6",Competency::misc} },345,456)
          }
        )
      );
      const boost::shared_ptr<ConceptMap> map_b(
        ConceptMapFactory().Create(
          {
            CenterNodeFactory().CreateFromStrings("FOCAL QUESTION"),
            NodeFactory().GetTests().at(1),
            NodeFactory().CreateFromStrings("4", { {"5",Competency::misc},{"6",Competency::misc} },901,012)
          }
        )
      );
      assert(HasSameContent(*map_a,*map_b));
      assert(map_a != map_b);

      const boost::shared_ptr<Node> node_g = NodeFactory().Create(concept_f,901,012);
      const boost::shared_ptr<ConceptMap> map_c(
        ConceptMapFactory().Create(
          {
            CenterNodeFactory().CreateFromStrings("FOCAL QUESTION"), node_b, node_g
          }
        )
      );
      assert(map_a != map_c);
      assert(map_b != map_c);
      assert(!HasSameContent(*map_a,*map_c));
      assert(!HasSameContent(*map_b,*map_c));
    }
    if (trace_verbose) { TRACE("HasSameContent 3"); }
    {
      //const TestTimer test_timer(boost::lexical_cast<std::string>(__LINE__),__FILE__,0.1);
      const boost::shared_ptr<Concept> concept_a(ConceptFactory().Create("FOCAL QUESTION"));
      const boost::shared_ptr<Concept> concept_b(ConceptFactory().Create("1",{{"2",Competency::misc},{"3",Competency::misc}}));
      const boost::shared_ptr<Concept> concept_c(ConceptFactory().Create("4",{{"5",Competency::misc},{"6",Competency::misc}}));
      const boost::shared_ptr<Concept> concept_d(ConceptFactory().Create("FOCAL QUESTION"));
      const boost::shared_ptr<Concept> concept_e(ConceptFactory().Create("4",{{"5",Competency::misc},{"6",Competency::misc} } ));
      const boost::shared_ptr<Concept> concept_f(ConceptFactory().Create("1",{{"2",Competency::misc},{"3",Competency::misc} } ));
      const boost::shared_ptr<Node> node_a(CenterNodeFactory().Create(concept_a,123,234));
      const boost::shared_ptr<Node> node_b(NodeFactory().Create(concept_b,123,234));
      const boost::shared_ptr<Node> node_c(NodeFactory().Create(concept_c,345,456));
      const boost::shared_ptr<Node> node_d(CenterNodeFactory().Create(concept_d,567,678));
      const boost::shared_ptr<Node> node_e(NodeFactory().Create(concept_e,789,890));
      const boost::shared_ptr<Node> node_f(NodeFactory().Create(concept_f,901,012));
      const boost::shared_ptr<ConceptMap> map_a(ConceptMapFactory().Create( { node_a, node_b, node_c } ));
      const boost::shared_ptr<ConceptMap> map_b(ConceptMapFactory().Create( { node_d, node_f, node_e } )); //Swap e and f
      assert(HasSameContent(*map_a,*map_b));
      assert(map_a != map_b);
      const boost::shared_ptr<ConceptMap> map_c(ConceptMapFactory().Create( { node_d, node_c, node_e } ));
      assert(!HasSameContent(*map_a,*map_c));
      assert(!HasSameContent(*map_b,*map_c));
      assert(map_a != map_c);
      assert(map_b != map_c);
    }
    if (trace_verbose) { TRACE("HasSameContent 4"); }
    {
      //const TestTimer test_timer(boost::lexical_cast<std::string>(__LINE__),__FILE__,0.1);
      const boost::shared_ptr<Concept> concept_n11(ConceptFactory().Create("1"));
      const boost::shared_ptr<Concept> concept_n12(ConceptFactory().Create("2"));
      const boost::shared_ptr<Concept> concept_n13(ConceptFactory().Create("3"));
      const boost::shared_ptr<Concept> concept_n21(ConceptFactory().Create("1"));
      const boost::shared_ptr<Concept> concept_n22(ConceptFactory().Create("2"));
      const boost::shared_ptr<Concept> concept_n23(ConceptFactory().Create("3"));

      const boost::shared_ptr<Node> node_11(CenterNodeFactory().Create(concept_n11,123,234));
      const boost::shared_ptr<Node> node_12(NodeFactory().Create(concept_n12,321,432));
      const boost::shared_ptr<Node> node_13(NodeFactory().Create(concept_n13,345,456));
      const boost::shared_ptr<Node> node_21(CenterNodeFactory().Create(concept_n21,567,678));
      const boost::shared_ptr<Node> node_22(NodeFactory().Create(concept_n22,789,890));
      const boost::shared_ptr<Node> node_23(NodeFactory().Create(concept_n23,901,012));

      const boost::shared_ptr<Concept> concept_e11(ConceptFactory().Create("9"));
      const boost::shared_ptr<Concept> concept_e12(ConceptFactory().Create("8"));
      const boost::shared_ptr<Concept> concept_e13(ConceptFactory().Create("7"));
      const boost::shared_ptr<Concept> concept_e21(ConceptFactory().Create("9"));
      const boost::shared_ptr<Concept> concept_e22(ConceptFactory().Create("8"));
      const boost::shared_ptr<Concept> concept_e23(ConceptFactory().Create("7"));

      const Nodes nodes_1 = { node_11, node_12, node_13 };
      const Nodes nodes_2 = { node_21, node_22, node_23 };

      const boost::shared_ptr<Edge> edge_11(EdgeFactory().Create(NodeFactory().Create(concept_e11,1.2,3.4),nodes_1.at(0),false,nodes_1.at(1),true));
      const boost::shared_ptr<Edge> edge_12(EdgeFactory().Create(NodeFactory().Create(concept_e12,2.3,4.5),nodes_1.at(0),false,nodes_1.at(2),true));
      const boost::shared_ptr<Edge> edge_13(EdgeFactory().Create(NodeFactory().Create(concept_e13,3.4,5.6),nodes_1.at(1),false,nodes_1.at(2),true));

      const boost::shared_ptr<Edge> edge_21(EdgeFactory().Create(NodeFactory().Create(concept_e21,4.5,6.7),nodes_2.at(0),false,nodes_2.at(1),true));
      const boost::shared_ptr<Edge> edge_22(EdgeFactory().Create(NodeFactory().Create(concept_e22,5.6,7.8),nodes_2.at(0),false,nodes_2.at(2),true));
      const boost::shared_ptr<Edge> edge_23(EdgeFactory().Create(NodeFactory().Create(concept_e23,6.7,8.9),nodes_2.at(1),false,nodes_2.at(2),true));

      const boost::shared_ptr<ConceptMap> map_a(ConceptMapFactory().Create(
        { node_11, node_12, node_13 },
        { edge_11, edge_12, edge_13 }
        )
      );
      const boost::shared_ptr<ConceptMap> map_b(ConceptMapFactory().Create(
        { node_21, node_22, node_23 },
        { edge_21, edge_22, edge_23 }
        )
      );
      assert(HasSameContent(*map_a,*map_b));
      assert(map_a != map_b);

      const boost::shared_ptr<ConceptMap> map_c(ConceptMapFactory().Create(
        { node_21, node_22, node_23 },
        { edge_21, edge_22 }
        )
      );
      assert(!HasSameContent(*map_a,*map_c));
      assert(!HasSameContent(*map_b,*map_c));
      assert(map_a != map_c);
      assert(map_b != map_c);
    }
    if (trace_verbose) { TRACE("HasSameContent 5"); }
    {
      //const TestTimer test_timer(boost::lexical_cast<std::string>(__LINE__),__FILE__,0.1);
      const boost::shared_ptr<Concept> concept_n11(ConceptFactory().Create("1"));
      const boost::shared_ptr<Concept> concept_n12(ConceptFactory().Create("2"));
      const boost::shared_ptr<Concept> concept_n13(ConceptFactory().Create("3"));

      const boost::shared_ptr<Node> node_11(CenterNodeFactory().Create(concept_n11,123,234));
      const boost::shared_ptr<Node> node_12(NodeFactory().Create(concept_n12,321,432));
      const boost::shared_ptr<Node> node_13(NodeFactory().Create(concept_n13,345,456));

      const boost::shared_ptr<Concept> concept_e11(ConceptFactory().Create("1->2"));
      const boost::shared_ptr<Concept> concept_e12(ConceptFactory().Create("1->3"));
      const boost::shared_ptr<Concept> concept_e13(ConceptFactory().Create("2->3"));

      const boost::shared_ptr<Concept> concept_n21(ConceptFactory().Create("1"));
      const boost::shared_ptr<Concept> concept_n22(ConceptFactory().Create("3"));
      const boost::shared_ptr<Concept> concept_n23(ConceptFactory().Create("2"));

      const boost::shared_ptr<Node> node_21(CenterNodeFactory().Create(concept_n21,123,234));
      const boost::shared_ptr<Node> node_22(NodeFactory().Create(concept_n22,321,432));
      const boost::shared_ptr<Node> node_23(NodeFactory().Create(concept_n23,345,456));

      const boost::shared_ptr<Concept> concept_e21(ConceptFactory().Create("2->3"));
      const boost::shared_ptr<Concept> concept_e22(ConceptFactory().Create("1->2"));
      const boost::shared_ptr<Concept> concept_e23(ConceptFactory().Create("1->3"));

      const Nodes nodes_1 = { node_11, node_12, node_13 };
      const Nodes nodes_2 = { node_21, node_22, node_23 };

      const boost::shared_ptr<Edge> edge_21(EdgeFactory().Create(NodeFactory().Create(concept_e21,1.2,3.4),nodes_2.at(2),false,nodes_2.at(1),true));
      const boost::shared_ptr<Edge> edge_22(EdgeFactory().Create(NodeFactory().Create(concept_e22,2.3,4.5),nodes_2.at(0),false,nodes_2.at(2),true));
      const boost::shared_ptr<Edge> edge_23(EdgeFactory().Create(NodeFactory().Create(concept_e23,3.4,4.5),nodes_2.at(0),false,nodes_2.at(1),true));

      const boost::shared_ptr<Edge> edge_11(EdgeFactory().Create(NodeFactory().Create(concept_e11,1.2,3.4),nodes_1.at(0),false,nodes_1.at(1),true));
      const boost::shared_ptr<Edge> edge_12(EdgeFactory().Create(NodeFactory().Create(concept_e12,2.3,4.5),nodes_1.at(0),false,nodes_1.at(2),true));
      const boost::shared_ptr<Edge> edge_13(EdgeFactory().Create(NodeFactory().Create(concept_e13,3.4,5.6),nodes_1.at(1),false,nodes_1.at(2),true));

      const boost::shared_ptr<ConceptMap> map_a(ConceptMapFactory().Create(
        { node_11, node_12, node_13 },
        { edge_11, edge_12, edge_13 }
        )
      );
      const boost::shared_ptr<ConceptMap> map_b(ConceptMapFactory().Create(
        { node_21, node_22, node_23 },
        { edge_21, edge_22, edge_23 }
        )
      );
      assert(HasSameContent(*map_a,*map_b));
      assert(map_a != map_b);
    }
    if (trace_verbose) { TRACE("HasSameContent 6"); }
    {
      //const TestTimer test_timer(boost::lexical_cast<std::string>(__LINE__),__FILE__,0.1);
      const boost::shared_ptr<const ConceptMap> a{ConceptMapFactory().GetHeteromorphousTestConceptMap(19)};
      const boost::shared_ptr<const ConceptMap> b{ConceptMapFactory().GetHeteromorphousTestConceptMap(19)};
      assert(ConceptMap::HasSameContent(*a,*b));
    }
    if (trace_verbose) { TRACE("HasSameContent 7"); }
    {
      //const TestTimer test_timer(boost::lexical_cast<std::string>(__LINE__),__FILE__,0.1);
      const boost::shared_ptr<const ConceptMap> a{ConceptMapFactory().GetHeteromorphousTestConceptMap(18)};
      const boost::shared_ptr<const ConceptMap> b{ConceptMapFactory().GetHeteromorphousTestConceptMap(19)};
      assert(!ConceptMap::HasSameContent(*a,*b));
    }
    if (trace_verbose) { TRACE("Test simple homomorphous maps"); }
    {
      //const TestTimer test_timer(boost::lexical_cast<std::string>(__LINE__),__FILE__,0.1);
      const auto v = AddConst(ConceptMapFactory().GetSimpleHomomorphousTestConceptMaps());
      const int sz = v.size();
      for (int i = 0; i!=sz; ++i)
      {
        for (int j = i; j!=sz; ++j)
        {
          const boost::shared_ptr<const ConceptMap> a(ConceptMapFactory().DeepCopy(v[i]));
          assert(a);
          assert( a !=  v[i]);
          assert(*a == *v[i]);
          const boost::shared_ptr<const ConceptMap> b(ConceptMapFactory().DeepCopy(v[j]));
          assert(b);
          assert( b !=  v[j]);
          assert(*b == *v[j]);
          assert(a != b);
          if (i == j)
          {
            assert(ConceptMap::HasSameContent(*a,*b));
          }
          else
          {
            if (!ConceptMap::HasSameContent(*a,*b))
            {
              std::stringstream s;
              s << "Testing simple concept maps #" << i << " and #" << j << " must be homomorphous";
              TRACE(s.str());
            }
            assert(ConceptMap::HasSameContent(*a,*b));
          }
        }
      }
      //TRACE("ConceptMap::Test: simple homomorphous testing concept maps are successfully identified as being different, yet homomorphous");
    }
    if (trace_verbose) { TRACE("Test complex homomorphous maps"); }
    {
      //const TestTimer test_timer(boost::lexical_cast<std::string>(__LINE__),__FILE__,0.1);
      const int sz = ConceptMapFactory().GetNumberOfComplexHomomorphousTestConceptMaps();
      for (int i = 1; i!=sz; ++i)
      {
        const int j = i - 1;
        const boost::shared_ptr<const ConceptMap> a{ConceptMapFactory().GetComplexHomomorphousTestConceptMap(i)};
        const boost::shared_ptr<const ConceptMap> b{ConceptMapFactory().GetComplexHomomorphousTestConceptMap(j)};
        assert(ConceptMap::HasSameContent(*a,*b));
      }
      //TRACE("ConceptMap::Test: complex homomorphous testing concept maps are successfully identified as being different, yet homomorphous");
    }


    //OLD NOTE: There is no perfect check for shuffled, yet homomorphous concept maps
    //LATER NOTE: Yet, I cannot think of an example that wouldn't get caught
    //  so perhaps the check _is_ perfect?
  }

  #ifdef TO_ADD_TO_PROJECTBRAINWEAVER
  //Conversion from Cluster
  {
    const std::vector<boost::shared_ptr<Cluster> > clusters = ClusterFactory::GetTests();
    std::for_each(clusters.begin(),clusters.end(),
      [](const boost::shared_ptr<Cluster> & cluster)
      {
        if (cluster)
        {
          const boost::shared_ptr<ConceptMap> m(ConceptMapFactory().CreateFromCluster("Focal question",cluster));
          assert(m);
          const std::string s = ConceptMap::ToXml(m);
          const boost::shared_ptr<ConceptMap> n = ConceptMapFactory().FromXml(s);
          assert(n);
          assert(IsEqual(*m,*n));
        }
      }
    );
  }
  #endif
  if (trace_verbose) { TRACE("CreateSubs"); }
  {
    //const TestTimer test_timer(boost::lexical_cast<std::string>(__LINE__),__FILE__,0.1);
    //Count the number of expected sub concept maps
    {
      const std::vector<boost::shared_ptr<ConceptMap> > maps
        = ConceptMapFactory().GetHeteromorphousTestConceptMaps();
      const int n_heteromorphous_concept_maps = 20;
      assert(n_heteromorphous_concept_maps == static_cast<int>(maps.size())
        && "To warn you if you change the number of testing concept maps");
      const std::vector<int> n_subs_expected = { 0,2,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5 } ;
      assert(n_heteromorphous_concept_maps == static_cast<int>(n_subs_expected.size()));
      assert(n_subs_expected[ 0] == 0);
      assert(n_subs_expected[ 1] == 2);
      assert(n_subs_expected[ 2] == 3);
      assert(n_subs_expected[ 6] == 3);
      assert(n_subs_expected[ 7] == 4);
      assert(n_subs_expected[14] == 4);
      assert(n_subs_expected[15] == 5);
      //assert(n_subs_expected[16] == 5);

      assert(maps.size() == n_subs_expected.size());
      const int sz = static_cast<int>(n_subs_expected.size());
      for (int i=0; i!=sz; ++i)
      {
        if (!maps[i]) continue;
        const boost::shared_ptr<ConceptMap>& map = maps[i];

        const std::vector<boost::shared_ptr<ConceptMap> > subs = map->CreateSubs();
        #ifndef NDEBUG
        if (static_cast<int>(subs.size()) != n_subs_expected[i])
        {
          TRACE(i);
          TRACE(subs.size());
          TRACE(n_subs_expected[i]);
        }
        #endif
        assert(static_cast<int>(subs.size()) == n_subs_expected[i]);
      }
    }
  }
  if (trace_verbose) { TRACE("CountCenterNodes"); }
  //Count the number of CenterNode objects
  {
    //const TestTimer test_timer(boost::lexical_cast<std::string>(__LINE__),__FILE__,0.1);
    for (const boost::shared_ptr<const ConceptMap> map: ConceptMapFactory().GetHeteromorphousTestConceptMaps())
    {
      if (CountCenterNodes(map) == 0) continue;

      //Count the edges connected to CenterNode
      const int n_edges_connected_to_center { CountCenterNodeEdges(map) };
      const int n_center_nodes_expected
        = n_edges_connected_to_center + 1; //+1, because with no edges, you expect the center node only

      //Count the number of sub concept maps with a center node
      const std::vector<boost::shared_ptr<ConceptMap> > subs = map->CreateSubs();
      const int n_center_nodes_here {
        static_cast<int>(
          std::count_if(subs.begin(),subs.end(),
            [](const boost::shared_ptr<const ConceptMap> sub)
            {
              return CountCenterNodes(sub) > 0;
            }
          )
        )
      };
      const int n_center_nodes_found = n_center_nodes_here;
      if (n_center_nodes_expected != n_center_nodes_found)
      {
        TRACE("ERROR");
        TRACE("Original map next:");
        for (const std::string s: xml::XmlToPretty(ToXml(map))) { TRACE(s); }
        TRACE(n_center_nodes_expected);
        TRACE(n_center_nodes_found);
        TRACE(subs.size());
      }
      assert(n_center_nodes_expected == n_center_nodes_found);

    }
  }
  if (trace_verbose) { TRACE("IsValid"); }
  {
    //const TestTimer test_timer(boost::lexical_cast<std::string>(__LINE__),__FILE__,0.1);

    boost::shared_ptr<Node> node_a = CenterNodeFactory().CreateFromStrings("...");

    boost::shared_ptr<ConceptMap> concept_map = ConceptMapFactory().Create(
      { node_a } );
    assert(concept_map);
    assert(concept_map->IsValid());
    const boost::shared_ptr<Node> node = NodeFactory().CreateFromStrings("...");
    concept_map->AddNode(node);
    assert(concept_map->IsValid());
  }
  if (trace_verbose) { TRACE("Add nodes and edges"); }
  {
    //const TestTimer test_timer(boost::lexical_cast<std::string>(__LINE__),__FILE__,0.1);
    const auto concept_map = ConceptMapFactory().GetHeteromorphousTestConceptMap(19);
    assert(concept_map);
    const int n_nodes_before = concept_map->GetNodes().size();
    const int n_edges_before = concept_map->GetEdges().size();
    const auto node_a = NodeFactory().GetTests().at(0);
    const auto node_b = NodeFactory().GetTests().at(1);
    const int index = 0;
    assert(index < static_cast<int>(ConceptFactory().GetTests().size()));
    const auto concept = ConceptFactory().GetTests().at(index);
    const auto edge = EdgeFactory().Create(
      NodeFactory().Create(concept,123.456,456.789),node_a,true,node_b,true);
    concept_map->AddNode(node_a);
    concept_map->AddNode(node_b);
    concept_map->AddEdge(edge);
    const int n_nodes_after = concept_map->GetNodes().size();
    const int n_edges_after = concept_map->GetEdges().size();
    assert(n_nodes_after == n_nodes_before + 2);
    assert(n_edges_after == n_edges_before + 1);
  }
  if (trace_verbose) { TRACE("Deletion of nodes"); }
  {
    //const TestTimer test_timer(boost::lexical_cast<std::string>(__LINE__),__FILE__,0.1);
    const int test_index{19};
    const std::size_t n_nodes = ConceptMapFactory().GetHeteromorphousTestConceptMap(test_index)->GetNodes().size();
    for (std::size_t j=0; j!=n_nodes; ++j)
    {
      const boost::shared_ptr<ConceptMap> concept_map = ConceptMapFactory().GetHeteromorphousTestConceptMap(test_index);
      assert(concept_map);
      assert(concept_map->GetNodes().size() == n_nodes);
      assert(j < concept_map->GetNodes().size());
      const boost::shared_ptr<Node> node = concept_map->GetNodes()[j];
      concept_map->DeleteNode(node);
      assert(concept_map->GetNodes().size() == n_nodes - 1
        && "Node must really be gone");
    }
  }
  if (trace_verbose) { TRACE("Deletion of edges"); }
  {
    //const TestTimer test_timer(boost::lexical_cast<std::string>(__LINE__),__FILE__,0.1);
    const int test_index{19};
    const std::size_t n_edges = ConceptMapFactory().GetHeteromorphousTestConceptMap(test_index)->GetEdges().size();
    for (std::size_t j=0; j!=n_edges; ++j)
    {
      const boost::shared_ptr<ConceptMap> concept_map = ConceptMapFactory().GetHeteromorphousTestConceptMap(test_index);
      assert(concept_map);
      assert(concept_map->GetEdges().size() == n_edges);
      assert(j < concept_map->GetEdges().size());
      const boost::shared_ptr<Edge> edge = concept_map->GetEdges()[j];
      concept_map->DeleteEdge(edge);
      assert(concept_map->GetEdges().size() == n_edges - 1
        && "Edge must really be gone");
    }
  }
  if (trace_verbose) { TRACE("Is GetNode()[0] a CenterNode?"); }
  {
    ////const TestTimer test_timer(boost::lexical_cast<std::string>(__LINE__),__FILE__,0.1);
    const auto concept_maps = ConceptMapFactory().GetHeteromorphousTestConceptMaps();
    for (const auto& concept_map: concept_maps)
    {
      if (concept_map->GetNodes().empty()) continue;
      assert(concept_map->FindCenterNode() && "Assume a CenterNode at the center of ConceptMap");
    }
  }
}
#endif

 

 

 

 

 

./CppConceptMap/conceptmapcenternode.h

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#ifndef CONCEPTMAPCENTERNODE_H
#define CONCEPTMAPCENTERNODE_H

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#include "conceptmapnode.h"
#include "conceptmapfwd.h"
#pragma GCC diagnostic pop

namespace ribi {
namespace cmap {

///The focal question of a ConceptMap
///- Every ConceptMap usually has one CenterNode
///- Every sub concept-map has none or one CenterNode
///  (a sub concet-map has a focal node instead)
struct CenterNode : public Node
{
  ///Block destructor, except for the friend boost::checked_delete
  ~CenterNode() noexcept {}
  friend void boost::checked_delete<>(CenterNode* x);

  ///Block construction, except for NodeFactory
  friend struct CenterNodeFactory;
  CenterNode() = delete;

  //lock to enforce use of CenterNodeFactory
  explicit CenterNode(
    const boost::shared_ptr<Concept>& concept,
    const double x,
    const double y,
    const CenterNodeFactory& lock
  );

  std::string ToXml() const noexcept;
};

///Returns true if Node is of derived class type CenterNode
///Returns true if Node is Node
bool IsCenterNode(const boost::shared_ptr<const Node> node) noexcept;

} //~namespace cmap

} //~namespace ribi

#endif // CONCEPTMAPCENTERNODE_H

 

 

 

 

 

./CppConceptMap/conceptmapcenternode.cpp

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#include "conceptmapcenternode.h"

#include <cassert>
#include <sstream>

#include "conceptmapconcept.h"
#include "conceptmapnodefactory.h"
#include "testtimer.h"

ribi::cmap::CenterNode::CenterNode(
  const boost::shared_ptr<Concept>& concept,
  const double x,
  const double y,
  const CenterNodeFactory&
)
  : Node(concept,x,y,NodeFactory())
{

}

bool ribi::cmap::IsCenterNode(const boost::shared_ptr<const ribi::cmap::Node> node) noexcept
{
  assert(node);
  return boost::dynamic_pointer_cast<const CenterNode>(node).get();
}

std::string ribi::cmap::CenterNode::ToXml() const noexcept
{
  std::stringstream s;
  s << "<center_node>";
  s << GetConcept()->ToXml();
  s << "<x>" << GetX() << "</x>";
  s << "<y>" << GetY() << "</y>";
  s << "</center_node>";

  const std::string r = s.str();
  assert(r.size() >= 13);
  assert(r.substr(0,13) == "<center_node>");
  assert(r.substr(r.size() - 14,14) == "</center_node>");

  return r;
}

 

 

 

 

 

./CppConceptMap/conceptmapcenternodefactory.h

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#ifndef CONCEPTMAPCENTERNODEFACTORY_H
#define CONCEPTMAPCENTERNODEFACTORY_H

#include <string>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#include <boost/shared_ptr.hpp>
#include "conceptmapfwd.h"
#include "conceptmapcompetency.h"
#pragma GCC diagnostic pop

namespace ribi {
namespace cmap {

struct  CenterNodeFactory
{
  CenterNodeFactory();

  const boost::shared_ptr<CenterNode> Create(
    const boost::shared_ptr<Concept>& concept,
    const double x = 0.0,
    const double y = 0.0
  ) const noexcept;

  const boost::shared_ptr<CenterNode> CreateFromStrings(
    const std::string& name,
    const std::vector<std::pair<std::string,Competency> >& examples = {},
    const double x = 0.0,
    const double y = 0.0
  ) const noexcept;

  #ifndef NDEBUG
  const boost::shared_ptr<CenterNode> DeepCopy(
    const boost::shared_ptr<const CenterNode>& node
  ) const noexcept;
  #endif

  ///Obtain a CenterNode from an XML std::string
  const boost::shared_ptr<CenterNode> FromXml(const std::string& s) const noexcept;

  #ifndef NDEBUG
  static void Test() noexcept;
  #endif
};

} //~namespace cmap
} //~namespace ribi

#endif // CONCEPTMAPCENTERNODEFACTORY_H

 

 

 

 

 

./CppConceptMap/conceptmapcenternodefactory.cpp

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#include "conceptmapcenternodefactory.h"

#include <cassert>

#include <boost/lexical_cast.hpp>

#include "conceptmapcenternode.h"
#include "conceptmapconcept.h"
#include "conceptmapconceptfactory.h"
#include "conceptmapexamplefactory.h"
#include "conceptmapexamplesfactory.h"
#include "conceptmaphelper.h"
#include "conceptmapnodefactory.h"
#include "conceptmapregex.h"
#include "counter.h"
#include "ribi_regex.h"
#include "testtimer.h"
#include "trace.h"
#include "xml.h"
#pragma GCC diagnostic pop

ribi::cmap::CenterNodeFactory::CenterNodeFactory()
{
  #ifndef NDEBUG
  Test();
  #endif
}

const boost::shared_ptr<ribi::cmap::CenterNode> ribi::cmap::CenterNodeFactory::Create(
  const boost::shared_ptr<ribi::cmap::Concept>& concept,
  const double x,
  const double y) const noexcept
{
  assert(concept);
  boost::shared_ptr<CenterNode> node(
    new cmap::CenterNode(
      concept,x,y,*this
    )
  );
  assert(node);
  assert(*concept == *node->GetConcept());
  assert(node->GetX() == x);
  assert(node->GetY() == y);
  return node;
}

const boost::shared_ptr<ribi::cmap::CenterNode> ribi::cmap::CenterNodeFactory::CreateFromStrings(
  const std::string& name,
  const std::vector<std::pair<std::string,Competency> >& examples,
  const double x,
  const double y
) const noexcept
{
  boost::shared_ptr<CenterNode> node(
    new CenterNode(
      ConceptFactory().Create(name,examples),
      x,
      y,
      *this
    )
  );
  assert(node);
  assert(node->GetConcept());
  assert(node->GetX() == x);
  assert(node->GetY() == y);
  return node;
}

#ifndef NDEBUG
const boost::shared_ptr<ribi::cmap::CenterNode> ribi::cmap::CenterNodeFactory::DeepCopy(
  const boost::shared_ptr<const cmap::CenterNode>& node
) const noexcept
{
  assert(node);
  assert(node->GetConcept());
  const boost::shared_ptr<Concept> new_concept {
    ConceptFactory().DeepCopy(node->GetConcept())
  };
  assert(new_concept);
  assert(*node->GetConcept() == *new_concept);
  const boost::shared_ptr<CenterNode> new_node
    = Create(new_concept,
      node->GetX(),
      node->GetY()
    );
  assert(new_node);
  assert(new_node->GetConcept());
  assert(*node == *new_node);
  return new_node;
}
#endif

const boost::shared_ptr<ribi::cmap::CenterNode> ribi::cmap::CenterNodeFactory::FromXml(
  const std::string& s
) const noexcept
{
  if (s.size() < 27)
  {
    return boost::shared_ptr<CenterNode>();
  }
  if (s.substr(0,13) != "<center_node>")
  {
    return boost::shared_ptr<CenterNode>();
  }
  if (s.substr(s.size() - 14,14) != "</center_node>")
  {
    return boost::shared_ptr<CenterNode>();
  }

  //m_concept
  boost::shared_ptr<Concept> concept;
  {
    const auto v = Regex().GetRegexMatches(s,Regex().GetRegexConcept());
    assert(v.size() == 1);
    concept = ConceptFactory().FromXml(v[0]);
  }
  //m_x
  double x = 0.0;
  {
    const std::vector<std::string> v = Regex().GetRegexMatches(s,Regex().GetRegexX());
    assert(v.size() == 1);
    x = boost::lexical_cast<double>(ribi::xml::StripXmlTag(v[0]));
  }
  //m_x
  double y = 0.0;
  {
    const auto v = Regex().GetRegexMatches(s,Regex().GetRegexY());
    assert(v.size() == 1);
    y = boost::lexical_cast<double>(ribi::xml::StripXmlTag(v[0]));
  }
  assert(concept);
  const boost::shared_ptr<CenterNode> node(new CenterNode(concept,x,y,*this));
  assert(node);
  assert(node->ToXml() == s);
  return node;
}

#ifndef NDEBUG
void ribi::cmap::CenterNodeFactory::Test() noexcept
{
  {
    static bool is_tested{false};
    if (is_tested) return;
    is_tested = true;
  }
  NodeFactory();
  ConceptFactory();
  Counter();
  ExampleFactory();
  ExamplesFactory();
  ::ribi::Regex();
  ::ribi::cmap::TestHelperFunctions();
  ::ribi::cmap::Regex();

  const TestTimer test_timer{__func__,__FILE__,0.1};

  const auto concept = ConceptFactory().GetTest(0);
  const double x{0.1};
  const double y{2.3};
  const auto node = CenterNodeFactory().Create(concept,x,y);
  assert(node);
  assert(concept == node->GetConcept());
  assert(node->GetX() == x);
  assert(node->GetY() == y);
}
#endif

 

 

 

 

 

./CppConceptMap/conceptmapcommand.h

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#ifndef CONCEPTMAPCOMMAND_H
#define CONCEPTMAPCOMMAND_H

#include <string>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#include <boost/shared_ptr.hpp>
#include <boost/signals2.hpp>

#include "conceptmapfwd.h"
#pragma GCC diagnostic pop

namespace ribi {
namespace cmap {

///Command can be used to do and undo commands to a concept map Widget
///Command must use a Widget* because a Widget will call a Command with this:
///
///  some_command->CanDo(this);
///
struct Command
{
  Command() noexcept;
  virtual ~Command() noexcept {}
  bool CanDoCommand(const Widget * const widget) const noexcept;
  bool CanDoCommand(const boost::shared_ptr<const Widget> widget) const noexcept { return CanDoCommand(widget.get()); }
  void DoCommand(Widget * const widget) noexcept;
  void DoCommand(const boost::shared_ptr<Widget> widget) noexcept { DoCommand(widget.get()); }

  virtual std::string ToStr() const noexcept = 0;
  void Undo() noexcept;

  boost::signals2::signal<void(const Command*)> m_signal_undo;

  private:
  ///Hook, should be private in derived classes as well, use the general form
  virtual bool CanDoCommandSpecific(const Widget * const widget) const noexcept = 0;

  ///Hook, should be private in derived classes as well, use the general form
  virtual void DoCommandSpecific(Widget * const widget) noexcept = 0;

  ///Hook, should be private in derived classes as well, use the general form
  virtual void UndoSpecific() noexcept = 0;

};

} //~namespace cmap
} //~namespace ribi


#endif // CONCEPTMAPCOMMAND_H

 

 

 

 

 

./CppConceptMap/conceptmapcommand.cpp

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#include "conceptmapcommand.h"

#include <cassert>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#pragma GCC diagnostic pop

//Don't include ConceptMap, use Widget its mostly-private-except-for-Command interface only
#include "conceptmapwidget.h"
#include "trace.h"

ribi::cmap::Command::Command() noexcept
  : m_signal_undo{}
{

}

bool ribi::cmap::Command::CanDoCommand(const Widget * const widget) const noexcept
{
  assert(widget);
  return CanDoCommandSpecific(widget);
}

void ribi::cmap::Command::DoCommand(Widget * const widget) noexcept
{
  assert(widget);
  assert(CanDoCommand(widget));
  DoCommandSpecific(widget);
  /*
  #ifndef NDEBUG
  for (int i=0; i!=2; ++i)
  {
    Undo();
    DoCommandSpecific(widget);
  }
  #endif
  */
}

void ribi::cmap::Command::Undo() noexcept
{
  UndoSpecific();
  m_signal_undo(this);
}

 

 

 

 

 

./CppConceptMap/conceptmapcommandaddfocusrandom.h

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#ifndef CONCEPTMAPCOMMANDADDFOCUSRANDOM_H
#define CONCEPTMAPCOMMANDADDFOCUSRANDOM_H

#error Please do not use a nonsense class

#ifdef SUPPORT_NONSENSE
//Do not forget: only one item can have focus
//What you probably meant is to add a selected item
#endif //#ifdef SUPPORT_NONSENSE

#endif // CONCEPTMAPCOMMANDADDFOCUSRANDOM_H

 

 

 

 

 

./CppConceptMap/conceptmapcommandaddfocusrandom.cpp

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#ifdef SUPPORT_NONSENSE


#endif //#ifdef SUPPORT_NONSENSE

 

 

 

 

 

./CppConceptMap/conceptmapcommandaddselectedrandom.h

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#ifndef CONCEPTMAPCOMMANDADDSELECTEDRANDOM_H
#define CONCEPTMAPCOMMANDADDSELECTEDRANDOM_H

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#include "conceptmapcommand.h"
#pragma GCC diagnostic pop

namespace ribi {
namespace cmap {

///Add another item to the selected pool
struct CommandAddSelectedRandom : public Command
{
  using ConstEdges = std::vector<boost::shared_ptr<const Edge>>;
  using ConstNodes = std::vector<boost::shared_ptr<const Node>>;
  using Edges = std::vector<boost::shared_ptr<Edge>>;
  using Nodes = std::vector<boost::shared_ptr<Node>>;
  using EdgesAndNodes = std::pair<Edges,Nodes>;
  using ConstEdgesAndNodes = std::pair<ConstEdges,ConstNodes>;

  CommandAddSelectedRandom() : m_old_selected{}, m_widget{} {}
  CommandAddSelectedRandom(const CommandAddSelectedRandom&) = delete;
  CommandAddSelectedRandom& operator=(const CommandAddSelectedRandom&) = delete;
  ~CommandAddSelectedRandom() noexcept {}

  std::string ToStr() const noexcept final { return "add selected random"; }
  void Undo() noexcept;

  private:
  ConstEdgesAndNodes m_old_selected;
  Widget * m_widget;

  bool CanDoCommandSpecific(const Widget * const widget) const noexcept final;
  void DoCommandSpecific(Widget * const widget) noexcept final;
  void UndoSpecific() noexcept final;
};

} //~namespace cmap
} //~namespace ribi


#endif // CONCEPTMAPCOMMANDADDSELECTEDRANDOM_H

 

 

 

 

 

./CppConceptMap/conceptmapcommandaddselectedrandom.cpp

 

#include "conceptmapcommandaddselectedrandom.h"

#include "conceptmapcommandsetfocusrandom.h"

#include <cassert>

#include "conceptmap.h"
#include "conceptmapwidget.h"
#include "conceptmaphelper.h"
#include "trace.h"

bool ribi::cmap::CommandAddSelectedRandom::CanDoCommandSpecific(const Widget * const widget) const noexcept
{
  assert(widget);
  assert(widget->GetConceptMap() || !widget->GetConceptMap());
  const bool verbose{false};
  if (!widget->GetConceptMap())
  {
    if (verbose) TRACE("AddSelected needs a concept map");
    return false;
  }
  if (widget->GetConceptMap()->GetNodes().empty())
  {
    if (verbose) TRACE("AddSelected needs nodes to focus on");
    return false;
  }
  if (const_cast<Widget*>(widget)->GetRandomNodes(AddConst(widget->GetSelectedNodes())).empty())
  {
    if (verbose)
    {
      TRACE("AddSelected needs non-focused nodes to focus on");
      TRACE(widget->GetSelectedNodes().size());
      TRACE(widget->GetConceptMap()->GetNodes().size());
    }
    return false;
  }
  return true;
}

void ribi::cmap::CommandAddSelectedRandom::DoCommandSpecific(Widget * const widget) noexcept
{
  assert(widget);

  //Transfer focus to this Node
  m_widget = widget;
  m_old_selected = const_cast<const Widget*>(widget)->GetSelected();
  const auto selected_edges(widget->GetRandomEdges(AddConst(m_old_selected.first)));
  const auto selected_nodes(widget->GetRandomNodes(AddConst(m_old_selected.second)));
  m_widget->AddSelected(selected_edges,selected_nodes);
  //m_widget->m_signal_set_focus_node();
  //m_widget->m_signal_concept_map_changed();

  assert(m_widget);
  assert(widget);
}

void ribi::cmap::CommandAddSelectedRandom::UndoSpecific() noexcept
{
  assert(m_widget);

  //Lose focus to this Node
  m_widget->SetSelected(m_old_selected);
}

 

 

 

 

 

./CppConceptMap/conceptmapcommandcreatenewconceptmap.h

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#ifndef CONCEPTMAPCOMMANDCREATENEWCONCEPTMAP_H
#define CONCEPTMAPCOMMANDCREATENEWCONCEPTMAP_H

/*

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#include "conceptmapcommand.h"
#pragma GCC diagnostic pop

namespace ribi {
namespace cmap {

///Start a new concept map
///-Can be used only when there is no existing concept map
struct CommandCreateNewConceptMap : public Command
{
  CommandCreateNewConceptMap() : m_widget{} {}
  CommandCreateNewConceptMap(const CommandCreateNewConceptMap&) = delete;
  CommandCreateNewConceptMap& operator=(const CommandCreateNewConceptMap&) = delete;
  ~CommandCreateNewConceptMap() noexcept {}

  std::string ToStr() const noexcept { return "create new concept map"; }
  void Undo() noexcept;

  private:
  Widget * m_widget;

  bool CanDoCommandSpecific(const Widget * const widget) const noexcept;
  void DoCommandSpecific(Widget * const widget) noexcept;
};

} //~namespace cmap
} //~namespace ribi

*/
#endif // CONCEPTMAPCOMMANDCREATENEWCONCEPTMAP_H

 

 

 

 

 

./CppConceptMap/conceptmapcommandcreatenewconceptmap.cpp

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#include "conceptmapcommandcreatenewconceptmap.h"

/*

#include <cassert>

#include "conceptmapwidget.h"

bool ribi::cmap::CommandCreateNewConceptMap::CanDoCommandSpecific(const Widget * const widget) const noexcept
{
  assert(widget);
  return !widget->GetConceptMap();
}

void ribi::cmap::CommandCreateNewConceptMap::DoCommandSpecific(Widget * const widget) noexcept
{
  assert(!m_widget);

  assert(widget);
  assert(!widget->GetConceptMap().get());

  m_widget = widget;

  const boost::shared_ptr<ConceptMap> new_map {
    ConceptMapFactory().Create("...")
  };
  assert(new_map);
  m_widget->SetConceptMap(new_map);

  m_widget->m_signal_concept_map_changed();

  assert(m_widget);
  assert(m_widget->GetConceptMap().get());
}

void ribi::cmap::CommandCreateNewConceptMap::Undo() noexcept
{
  assert(m_widget);
  assert(m_widget->GetConceptMap().get());

  boost::shared_ptr<ConceptMap> empty_map;
  m_widget->SetConceptMap(empty_map);

  m_widget->m_signal_concept_map_changed();

  m_widget = nullptr;

}

*/

 

 

 

 

 

./CppConceptMap/conceptmapcommandcreatenewedge.h

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#ifndef CONCEPTMAPCOMMANDCREATENEWEDGE_H
#define CONCEPTMAPCOMMANDCREATENEWEDGE_H

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#include "conceptmapcommand.h"
#pragma GCC diagnostic pop

namespace ribi {
namespace cmap {

///Start a new node
///-Can be used only when there is an existing concept map
struct CommandCreateNewEdge : public Command
{
  CommandCreateNewEdge() : m_edge{}, m_nodes{}, m_widget{} {}
  CommandCreateNewEdge(const CommandCreateNewEdge&) = delete;
  CommandCreateNewEdge& operator=(const CommandCreateNewEdge&) = delete;
  ~CommandCreateNewEdge() noexcept {}

  std::string ToStr() const noexcept final { return "create new edge"; }

  private:
  boost::shared_ptr<Edge> m_edge;
  std::vector<boost::shared_ptr<Node>> m_nodes;

  std::vector<boost::shared_ptr<ribi::cmap::Node>> m_prev_selected; //Selected before Edge was added

  Widget * m_widget;

  bool CanDoCommandSpecific(const Widget * const widget) const noexcept final;
  void DoCommandSpecific(Widget * const widget) noexcept final;
  void UndoSpecific() noexcept final;
};

} //~namespace cmap
} //~namespace ribi

#endif // CONCEPTMAPCOMMANDCREATENEWEDGE_H

 

 

 

 

 

./CppConceptMap/conceptmapcommandcreatenewedge.cpp

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#include "conceptmapcommandcreatenewedge.h"

#include <cassert>

#include "conceptmap.h"
#include "conceptmapwidget.h"
#include "conceptmapedgefactory.h"

bool ribi::cmap::CommandCreateNewEdge::CanDoCommandSpecific(const Widget * const widget) const noexcept
{
  assert(widget);
  return widget->GetConceptMap() && widget->GetSelectedNodes().size() == 2;
}

void ribi::cmap::CommandCreateNewEdge::DoCommandSpecific(Widget * const widget) noexcept
{
  assert(!m_widget);
  assert(widget);
  assert(widget->GetConceptMap().get());
  assert(CanDoCommand(widget));

  m_widget = widget;
  m_nodes.push_back(m_widget->GetSelectedNodes()[0]);
  m_nodes.push_back(m_widget->GetSelectedNodes()[1]);

  assert(m_nodes.size() == 2);
  assert(m_nodes[0]);
  assert(m_nodes[1]);
  assert(m_nodes[0] != m_nodes[1]
    && "An edge must be created from two different nodes");
  assert(m_widget->GetConceptMap()->HasNode(m_nodes[0])
    && "An edge must be created from two existing nodes");
  assert(m_widget->GetConceptMap()->HasNode(m_nodes[1])
    && "An edge must be created from two existing nodes");

  m_prev_selected = m_widget->GetSelectedNodes();

  m_edge = m_widget->CreateNewEdge();

  m_widget->SetSelected( ribi::cmap::Widget::ConstEdges({m_edge}), {});

  assert(m_widget);
  assert(m_edge);
}

void ribi::cmap::CommandCreateNewEdge::UndoSpecific() noexcept
{
  assert(m_widget);
  assert(m_widget->GetConceptMap().get());


  m_widget->DeleteEdge(m_edge);

  m_widget->SetSelected(m_prev_selected);


  m_widget = nullptr;
  m_nodes.clear();
  m_edge = boost::shared_ptr<Edge>();

}

 

 

 

 

 

./CppConceptMap/conceptmapcommandcreatenewnode.h

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#ifndef CONCEPTMAPCOMMANDCREATENEWNODE_H
#define CONCEPTMAPCOMMANDCREATENEWNODE_H

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#include "conceptmapcommand.h"
#pragma GCC diagnostic pop

namespace ribi {
namespace cmap {

///Start a new node
///-Can be used only when there is an existing concept map
struct CommandCreateNewNode : public Command
{
  CommandCreateNewNode() : m_node{}, m_widget{} {}
  CommandCreateNewNode(const CommandCreateNewNode&) = delete;
  CommandCreateNewNode& operator=(const CommandCreateNewNode&) = delete;
  ~CommandCreateNewNode() noexcept {}

  std::string ToStr() const noexcept final { return "create new node"; }

  private:
  boost::shared_ptr<Node> m_node;
  Widget * m_widget;

  bool CanDoCommandSpecific(const Widget * const widget) const noexcept final;
  void DoCommandSpecific(Widget * const widget) noexcept final;
  void UndoSpecific() noexcept final;
};

} //~namespace cmap
} //~namespace ribi

#endif // CONCEPTMAPCOMMANDCREATENEWNODE_H

 

 

 

 

 

./CppConceptMap/conceptmapcommandcreatenewnode.cpp

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#include "conceptmapcommandcreatenewnode.h"

#include <cassert>

#include "conceptmapwidget.h"
#include "conceptmapnode.h"

bool ribi::cmap::CommandCreateNewNode::CanDoCommandSpecific(const Widget * const widget) const noexcept
{
  assert(widget);
  return widget->GetConceptMap().get();
}

void ribi::cmap::CommandCreateNewNode::DoCommandSpecific(Widget * const widget) noexcept
{
  assert(!m_widget && "Cannot do a command twice");
  assert(!m_node);
  assert(widget);
  assert(widget->GetConceptMap().get());

  m_widget = widget;
  m_node = m_widget->CreateNewNode();

  assert(m_widget);
  assert(m_node);
}

void ribi::cmap::CommandCreateNewNode::UndoSpecific() noexcept
{
  assert(m_widget);
  assert(m_widget->GetConceptMap().get());

  m_widget->DeleteNode(m_node);

  m_widget = nullptr;
  m_node = boost::shared_ptr<Node>();

}

 

 

 

 

 

./CppConceptMap/conceptmapcommanddeleteconceptmap.h

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#ifndef CONCEPTMAPCOMMANDDELETECONCEPTMAP_H
#define CONCEPTMAPCOMMANDDELETECONCEPTMAP_H

/*

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#include "conceptmapcommand.h"
#pragma GCC diagnostic pop

namespace ribi {
namespace cmap {

///Delete a concept map
///-Can be used only when there is an existing concept map
struct CommandDeleteConceptMap : public Command
{
  CommandDeleteConceptMap() : m_deleted_concept_map{}, m_widget{} {}
  CommandDeleteConceptMap(const CommandDeleteConceptMap&) = delete;
  CommandDeleteConceptMap& operator=(const CommandDeleteConceptMap&) = delete;
  ~CommandDeleteConceptMap() noexcept {}
  std::string ToStr() const noexcept { return "delete concept map"; }

  private:
  boost::shared_ptr<ConceptMap> m_deleted_concept_map;
  Widget * m_widget;
  bool CanDoCommandSpecific(const Widget * const widget) const noexcept final;
  void DoCommandSpecific(Widget * const widget) noexcept final;
  void UndoSpecific() noexcept final;
};

} //~namespace cmap
} //~namespace ribi

*/

#endif // CONCEPTMAPCOMMANDDELETECONCEPTMAP_H

 

 

 

 

 

./CppConceptMap/conceptmapcommanddeleteconceptmap.cpp

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#include "conceptmapcommanddeleteconceptmap.h"
/*

#include <cassert>

#include "conceptmapwidget.h"

bool ribi::cmap::CommandDeleteConceptMap::CanDoCommandSpecific(const Widget * const widget) const noexcept
{
  assert(widget);
  assert(static_cast<bool>(m_widget) == static_cast<bool>(m_deleted_concept_map));
  //Cannot delete a concept map, when
  // - the command already has deleted one, so its internals are non-nullptr
  // - the offered widget has no concept map
  return !m_widget && widget->GetConceptMap().get();
}

void ribi::cmap::CommandDeleteConceptMap::DoCommandSpecific(Widget * const widget) noexcept
{
  assert(widget);
  assert(CanDoCommandSpecific(widget));
  assert(widget->GetConceptMap().get());
  //Correct pre state
  //Before executing the command,
  //CommandDeleteConceptMap its internals (m_widget and m_conceptmap)
  //should both be nullptr
  assert(!m_widget && "Before deleting a Widget its ConceptMap,"
    "CommandDeleteConceptMap::m_widget must be nullptr");
  assert(!m_deleted_concept_map);

  m_widget = widget;
  m_deleted_concept_map = widget->GetConceptMap();
  const boost::shared_ptr<ConceptMap> m;
  widget->SetConceptMap(m);

  m_widget->m_signal_concept_map_changed();

  //Correct post state
  assert(m_widget);
  assert(m_deleted_concept_map);
  assert(!widget->GetConceptMap().get());
  assert(!m_widget->GetConceptMap().get());
}

void ribi::cmap::CommandDeleteConceptMap::Undo() noexcept
{
  //Correct pre state
  assert(m_widget);
  assert(m_deleted_concept_map);
  assert(!m_widget->GetConceptMap().get());

  m_widget->SetConceptMap(m_deleted_concept_map);
  boost::shared_ptr<ConceptMap> empty_map;
  m_deleted_concept_map = empty_map;
  m_widget->m_signal_concept_map_changed();
  m_widget = nullptr;

  //Correct post state
  assert(!m_widget);
  assert(!m_deleted_concept_map);
}

*/

 

 

 

 

 

./CppConceptMap/conceptmapcommanddeletefocusnode.h

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#ifndef CONCEPTMAPCOMMANDDELETEFOCUSNODE_H
#define CONCEPTMAPCOMMANDDELETEFOCUSNODE_H

#ifdef USE_FOCUS_COMMANDS_201506712

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#include "conceptmapcommand.h"
#pragma GCC diagnostic pop

namespace ribi {
namespace cmap {

///Delete a node the concept map has in focus
///-Can be used only when there is an existing concept map
/// and a Node in focus
struct CommandDeleteFocusNode : public Command
{
  CommandDeleteFocusNode() : m_old_focus{}, m_widget{} {}
  CommandDeleteFocusNode(const CommandDeleteFocusNode&) = delete;
  CommandDeleteFocusNode& operator=(const CommandDeleteFocusNode&) = delete;
  ~CommandDeleteFocusNode() noexcept {}

  std::string ToStr() const noexcept final { return "delete node in focus"; }

  private:
  boost::shared_ptr<Node> m_old_focus;
  Widget * m_widget;

  bool CanDoCommandSpecific(const Widget * const widget) const noexcept final;
  void DoCommandSpecific(Widget * const widget) noexcept final;
  void UndoSpecific() noexcept final;
};

} //~namespace cmap
} //~namespace ribi

#endif // USE_FOCUS_COMMANDS_201506712

#endif // CONCEPTMAPCOMMANDDELETEFOCUSNODE_H

 

 

 

 

 

./CppConceptMap/conceptmapcommanddeletefocusnode.cpp

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#ifdef USE_FOCUS_COMMANDS_201506712

#include "conceptmapcommanddeletefocusnode.h"

#include <cassert>

#include "conceptmapwidget.h"

bool ribi::cmap::CommandDeleteFocusNode::CanDoCommandSpecific(const Widget * const widget) const noexcept
{
  assert(widget);
  return widget->GetConceptMap().get() && widget->GetFocus();
}

void ribi::cmap::CommandDeleteFocusNode::DoCommandSpecific(Widget * const widget) noexcept
{
  assert(!m_widget);
  assert(widget);
  assert(widget->GetConceptMap().get());
  assert(CanDoCommand(widget));

  m_widget = widget;
  m_old_focus = m_widget->GetFocus();
  assert(m_old_focus);
  m_widget->DeleteNode(m_old_focus);
  assert(m_widget);
}

void ribi::cmap::CommandDeleteFocusNode::UndoSpecific() noexcept
{
  assert(m_widget);
  assert(m_widget->GetConceptMap().get());

  m_widget->AddNode(m_old_focus);

  m_widget = nullptr;
  m_old_focus = boost::shared_ptr<Node>();

}

#endif // USE_FOCUS_COMMANDS_201506712

 

 

 

 

 

./CppConceptMap/conceptmapcommanddeletenode.h

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#ifndef CONCEPTMAPCOMMANDDELETENODE_H
#define CONCEPTMAPCOMMANDDELETENODE_H

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#include "conceptmapcommand.h"
#pragma GCC diagnostic pop

namespace ribi {
namespace cmap {

///Delete an existing node
struct CommandDeleteNode : public Command
{
  CommandDeleteNode(const boost::shared_ptr<Node> node);
  CommandDeleteNode(const CommandDeleteNode&) = delete;
  CommandDeleteNode& operator=(const CommandDeleteNode&) = delete;
  ~CommandDeleteNode() noexcept {}

  std::string ToStr() const noexcept final { return "delete node"; }

  private:
  boost::shared_ptr<Node> m_node;
  Widget * m_widget;

  bool CanDoCommandSpecific(const Widget * const widget) const noexcept final;
  void DoCommandSpecific(Widget * const widget) noexcept final;
  void UndoSpecific() noexcept final;
};

} //~namespace cmap
} //~namespace ribi

#endif // CONCEPTMAPCOMMANDDELETENODE_H

 

 

 

 

 

./CppConceptMap/conceptmapcommanddeletenode.cpp

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#include "conceptmapcommanddeletenode.h"

#include <cassert>

#include "conceptmapwidget.h"

ribi::cmap::CommandDeleteNode::CommandDeleteNode(const boost::shared_ptr<Node> node)
  : m_node{node}, m_widget{}
{
  assert(m_node);
}

bool ribi::cmap::CommandDeleteNode::CanDoCommandSpecific(const Widget * const widget) const noexcept
{
  assert(widget);
  return widget->GetConceptMap().get();
}

void ribi::cmap::CommandDeleteNode::DoCommandSpecific(Widget * const widget) noexcept
{
  assert(!m_widget);
  assert(m_node);
  assert(widget);
  assert(widget->GetConceptMap().get());

  m_widget = widget;
  m_widget->DeleteNode(m_node);

  assert(m_widget);
  assert(m_node);
}

void ribi::cmap::CommandDeleteNode::UndoSpecific() noexcept
{
  assert(m_widget);
  assert(m_widget->GetConceptMap().get());

  m_widget->AddNode(m_node);

  m_widget = nullptr;
}

 

 

 

 

 

./CppConceptMap/conceptmapcommandfactory.h

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#ifndef CONCEPTMAPCOMMANDFACTORY_H
#define CONCEPTMAPCOMMANDFACTORY_H

#include <vector>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#include <boost/shared_ptr.hpp>
#include "conceptmapfwd.h"
#pragma GCC diagnostic pop

namespace ribi {
namespace cmap {

///CommandFactory creates Commands
struct CommandFactory
{
  static std::vector<boost::shared_ptr<Command> > CreateTestCommands() noexcept;
};

} //~namespace cmap
} //~namespace ribi


#endif // CONCEPTMAPCOMMANDFACTORY_H

 

 

 

 

 

./CppConceptMap/conceptmapcommandfactory.cpp

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#include "conceptmapcommandfactory.h"

#include <cassert>

#include "conceptmapcommandaddselectedrandom.h"
#include "conceptmapcommandcreatenewconceptmap.h"
#include "conceptmapcommandcreatenewedge.h"
#include "conceptmapcommandcreatenewnode.h"
#include "conceptmapcommanddeleteconceptmap.h"
#include "conceptmapcommand.h"
#include "conceptmapcommandlosefocus.h"
#include "conceptmapcommanddeletefocusnode.h"
#include "conceptmapcommandsetfocusrandom.h"
#include "conceptmapcommandsetselectedwithcoordinat.h"

std::vector<boost::shared_ptr<ribi::cmap::Command> > ribi::cmap::CommandFactory::CreateTestCommands() noexcept
{
  std::vector<boost::shared_ptr<Command> > v;

  {
    const boost::shared_ptr<Command> p {
      new CommandAddSelectedRandom
    };
    assert(p);
    v.push_back(p);
  }
  /*
  {
    const boost::shared_ptr<Command> p {
      new CommandCreateNewConceptMap
    };
    assert(p);
    v.push_back(p);
  }
  */
  {
    const boost::shared_ptr<Command> p {
      new CommandCreateNewEdge
    };
    assert(p);
    v.push_back(p);
  }
  {
    const boost::shared_ptr<Command> p {
      new CommandCreateNewNode
    };
    assert(p);
    v.push_back(p);
  }
  /*
  {
    const boost::shared_ptr<Command> p {
      new CommandDeleteConceptMap
    };
    assert(p);
    v.push_back(p);
  }
  */
  #ifdef USE_FOCUS_COMMANDS_201506712
  {
    const boost::shared_ptr<Command> p {
      new CommandLoseFocus
    };
    assert(p);
    v.push_back(p);
  }
  {
    const boost::shared_ptr<Command> p {
      new CommandSetFocusRandom
    };
    assert(p);
    v.push_back(p);
  }
  {
    const boost::shared_ptr<Command> p {
      new CommandSetFocusWithCoordinat(0,0)
    };
    assert(p);
    v.push_back(p);
  }
  {
    const boost::shared_ptr<Command> p {
      new CommandDeleteFocusNode
    };
    assert(p);
    v.push_back(p);
  }
  #endif // USE_FOCUS_COMMANDS_201506712
  return v;
}

 

 

 

 

 

./CppConceptMap/conceptmapcommandlosefocus.h

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#ifndef CONCEPTMAPCOMMANDLOSEFOCUS_H
#define CONCEPTMAPCOMMANDLOSEFOCUS_H

#ifdef USE_FOCUS_COMMANDS_201506712

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#include <boost/shared_ptr.hpp>

#include "conceptmapcommand.h"
#pragma GCC diagnostic pop

namespace ribi {
namespace cmap {

///Lose focus of top node
///- opposite of AddFocus
struct CommandLoseFocus : public Command
{
  CommandLoseFocus() : m_old_focus{}, m_widget{} {}
  CommandLoseFocus(const CommandLoseFocus&) = delete;
  CommandLoseFocus& operator=(const CommandLoseFocus&) = delete;
  ~CommandLoseFocus() noexcept {}

  std::string ToStr() const noexcept final { return "lose focus"; }

  private:
  boost::shared_ptr<Node> m_old_focus;
  Widget * m_widget;

  bool CanDoCommandSpecific(const Widget * const widget) const noexcept final;
  void DoCommandSpecific(Widget * const widget) noexcept final;
  void UndoSpecific() noexcept final;
};

} //~namespace cmap
} //~namespace ribi

#endif // USE_FOCUS_COMMANDS_201506712

#endif // CONCEPTMAPCOMMANDLOSEFOCUS_H

 

 

 

 

 

./CppConceptMap/conceptmapcommandlosefocus.cpp

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#ifdef USE_FOCUS_COMMANDS_201506712

#include "conceptmapcommandlosefocus.h"

#include <cassert>

#include "conceptmapwidget.h"

bool ribi::cmap::CommandLoseFocus::CanDoCommandSpecific(const Widget * const widget) const noexcept
{
  assert(widget);
  return widget->GetFocus().get();
}

void ribi::cmap::CommandLoseFocus::DoCommandSpecific(Widget * const widget) noexcept
{
  assert(widget);
  assert(CanDoCommand(widget));
  assert(!m_widget);
  assert(!m_old_focus);

  //Transfer focus to this command
  m_widget = widget;

  assert(widget->m_focus);

  std::swap(m_old_focus,widget->m_focus);
  m_widget->m_signal_lose_focus(m_old_focus);

  assert( m_widget);
  assert( m_old_focus);
  assert(!widget->m_focus);
}

void ribi::cmap::CommandLoseFocus::UndoSpecific() noexcept
{
  assert( m_widget);
  assert( m_old_focus);
  assert(!m_widget->m_focus);

  //Transfer focus to this command
  std::swap(m_old_focus,m_widget->m_focus);
  m_widget->m_signal_concept_map_changed();

  assert(!m_old_focus);
  assert( m_widget->m_focus);

  m_widget = nullptr;

  assert(!m_widget);
  assert(!m_old_focus);
}

#endif // USE_FOCUS_COMMANDS_201506712

 

 

 

 

 

./CppConceptMap/conceptmapcommandsetfocusrandom.h

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#ifndef CONCEPTMAPCOMMANDSETFOCUSRANDOM_H
#define CONCEPTMAPCOMMANDSETFOCUSRANDOM_H

#ifdef USE_FOCUS_COMMANDS_201506712


#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#include "conceptmapcommand.h"
#pragma GCC diagnostic pop

namespace ribi {
namespace cmap {

///Set focus with a coordinat
///- opposite of LoseFocus
///- SetFocus does not care if there currently is something in focus
struct CommandSetFocusRandom : public Command
{
  CommandSetFocusRandom() : m_old_focus{}, m_widget{} {}
  CommandSetFocusRandom(const CommandSetFocusRandom&) = delete;
  CommandSetFocusRandom& operator=(const CommandSetFocusRandom&) = delete;
  ~CommandSetFocusRandom() noexcept {}

  std::string ToStr() const noexcept final { return "set focus random"; }

  private:
  boost::shared_ptr<Node> m_old_focus;
  Widget * m_widget;

  bool CanDoCommandSpecific(const Widget * const widget) const noexcept final;
  void DoCommandSpecific(Widget * const widget) noexcept final;
  void UndoSpecific() noexcept final;
};

} //~namespace cmap
} //~namespace ribi

#endif // USE_FOCUS_COMMANDS_201506712

#endif // CONCEPTMAPCOMMANDSETFOCUSRANDOM_H

 

 

 

 

 

./CppConceptMap/conceptmapcommandsetfocusrandom.cpp

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#ifdef USE_FOCUS_COMMANDS_201506712

#include "conceptmapcommandsetfocusrandom.h"

#include <cassert>

#include "conceptmap.h"
#include "conceptmapwidget.h"

bool ribi::cmap::CommandSetFocusRandom::CanDoCommandSpecific(const Widget * const widget) const noexcept
{
  assert(widget);
  assert(widget->GetConceptMap() || !widget->GetConceptMap());
  std::vector<boost::shared_ptr<const Node>> nodes_to_exclude;
  if (widget->GetFocus()) { nodes_to_exclude.push_back(widget->GetFocus()); }
  //The concept map must contain at least one node
  return
        widget->GetConceptMap()
    && !widget->GetConceptMap()->GetNodes().empty()
    && !const_cast<Widget*>(widget)->GetRandomNodes(nodes_to_exclude).empty()
  ;
}

void ribi::cmap::CommandSetFocusRandom::DoCommandSpecific(Widget * const widget) noexcept
{
  assert( widget);
  assert(!m_widget);

  //Transfer focus to this Node
  m_widget = widget;
  m_old_focus = widget->GetFocus();

  std::vector<boost::shared_ptr<const Node>> nodes_to_exclude;
  if (widget->GetFocus()) { nodes_to_exclude.push_back(widget->GetFocus()); }

  const auto new_focus(widget->GetRandomNode(nodes_to_exclude));
  m_widget->SetFocus(new_focus);
  m_widget->m_signal_set_focus(new_focus);
  //m_widget->m_signal_concept_map_changed();

  assert(m_widget);
  assert(  widget);
}

void ribi::cmap::CommandSetFocusRandom::UndoSpecific() noexcept
{
  assert(m_widget);
  //Put back the old focus, or lose the focus
  if (m_old_focus)
  {
    m_widget->SetFocus(m_old_focus);
  }
  else
  {
    m_widget->LoseFocus();
  }
  m_widget->m_signal_set_focus(m_widget->m_focus);
  m_old_focus = boost::shared_ptr<Node>();
  m_widget = nullptr;
  assert(!m_widget);
}

#endif // USE_FOCUS_COMMANDS_201506712

 

 

 

 

 

./CppConceptMap/conceptmapcommandsetselectedwithcoordinat.h

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#ifndef CONCEPTMAPCOMMANDSETSELECTEDWITHCOORDINAT_H
#define CONCEPTMAPCOMMANDSETSELECTEDWITHCOORDINAT_H

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#include <vector>

#include "conceptmapcommand.h"
#pragma GCC diagnostic pop

namespace ribi {
namespace cmap {

///Set selected with a coordinat
///- opposite of LoseSelected
///- SetSelected does not care if there currently something else is selected
struct CommandSetSelectedWithCoordinat : public Command
{
  using ConstEdges = std::vector<boost::shared_ptr<const Edge>>;
  using ConstNodes = std::vector<boost::shared_ptr<const Node>>;
  using Edges = std::vector<boost::shared_ptr<Edge>>;
  using Nodes = std::vector<boost::shared_ptr<Node>>;
  using EdgesAndNodes = std::pair<Edges,Nodes>;
  using ConstEdgesAndNodes = std::pair<ConstEdges,ConstNodes>;

  CommandSetSelectedWithCoordinat(const int x, const int y)
    : m_old_focus{}, m_widget{}, m_x(x), m_y(y) {}
  CommandSetSelectedWithCoordinat(const CommandSetSelectedWithCoordinat&) = delete;
  CommandSetSelectedWithCoordinat& operator=(const CommandSetSelectedWithCoordinat&) = delete;
  ~CommandSetSelectedWithCoordinat() noexcept {}

  std::string ToStr() const noexcept final { return "set focus with coordinat"; }

  private:
  ConstEdgesAndNodes m_old_focus;
  Widget * m_widget;

  const int m_x;
  const int m_y;

  bool CanDoCommandSpecific(const Widget * const widget) const noexcept final;
  void DoCommandSpecific(Widget * const widget) noexcept final;
  void UndoSpecific() noexcept final;
};

} //~namespace cmap
} //~namespace ribi


#endif // CONCEPTMAPCOMMANDSETSELECTEDWITHCOORDINAT_H

 

 

 

 

 

./CppConceptMap/conceptmapcommandsetselectedwithcoordinat.cpp

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#include "conceptmapcommandsetselectedwithcoordinat.h"

#include <cassert>

#include "conceptmapwidget.h"
#include "conceptmapnode.h"

bool ribi::cmap::CommandSetSelectedWithCoordinat::CanDoCommandSpecific(const Widget * const widget) const noexcept
{
  assert(widget);
  return
    widget->FindNodeAt(m_x,m_y).get();
}

void ribi::cmap::CommandSetSelectedWithCoordinat::DoCommandSpecific(Widget * const widget) noexcept
{
  assert(CanDoCommandSpecific(widget));
  assert(widget);

  m_old_focus = const_cast<const Widget*>(widget)->GetSelected();
  m_widget = widget;

  const boost::shared_ptr<Node> node {
    widget->FindNodeAt(m_x,m_y)
  };

  widget->m_focus = node;
  //widget->m_signal_set_focus(node);

  assert(m_widget);
  assert(widget);
}

void ribi::cmap::CommandSetSelectedWithCoordinat::UndoSpecific() noexcept
{
  assert(m_widget);
  assert(m_widget->m_focus);

  //Give back previous selection
  m_widget->SetSelected(m_old_focus);

  m_widget->m_signal_concept_map_changed();

  assert(m_widget);
}

 

 

 

 

 

./CppConceptMap/conceptmapcommandunselectrandom.h

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#ifndef CONCEPTMAPCOMMANDUNSELECTRANDOM_H
#define CONCEPTMAPCOMMANDUNSELECTRANDOM_H

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#include "conceptmapcommand.h"
#pragma GCC diagnostic pop

namespace ribi {
namespace cmap {

///Add another item to the selected pool
struct CommandUnselectRandom : public Command
{
  using ConstEdges = std::vector<boost::shared_ptr<const Edge>>;
  using ConstNodes = std::vector<boost::shared_ptr<const Node>>;
  using Edges = std::vector<boost::shared_ptr<Edge>>;
  using Nodes = std::vector<boost::shared_ptr<Node>>;
  using EdgesAndNodes = std::pair<Edges,Nodes>;
  using ConstEdgesAndNodes = std::pair<ConstEdges,ConstNodes>;

  CommandUnselectRandom() : m_old_selected{}, m_widget{} {}
  CommandUnselectRandom(const CommandUnselectRandom&) = delete;
  CommandUnselectRandom& operator=(const CommandUnselectRandom&) = delete;
  ~CommandUnselectRandom() noexcept {}

  std::string ToStr() const noexcept final { return "unselect random"; }
  void Undo() noexcept;

  private:
  ConstEdgesAndNodes m_old_selected;
  Widget * m_widget;

  bool CanDoCommandSpecific(const Widget * const widget) const noexcept final;
  void DoCommandSpecific(Widget * const widget) noexcept final;
  void UndoSpecific() noexcept final;
};

} //~namespace cmap
} //~namespace ribi

#endif // CONCEPTMAPCOMMANDUNSELECTRANDOM_H

 

 

 

 

 

./CppConceptMap/conceptmapcommandunselectrandom.cpp

 

#include "conceptmapcommandunselectrandom.h"

#include "conceptmapcommandsetfocusrandom.h"

#include <cassert>

#include "conceptmap.h"
#include "conceptmapwidget.h"
#include "conceptmaphelper.h"
#include "trace.h"

bool ribi::cmap::CommandUnselectRandom::CanDoCommandSpecific(const Widget * const widget) const noexcept
{
  assert(widget);
  assert(widget->GetConceptMap() || !widget->GetConceptMap());
  const bool verbose{false};
  if (!widget->GetConceptMap())
  {
    if (verbose) TRACE("Unselect needs a concept map");
    return false;
  }
  if (widget->GetSelectedEdges().empty() && widget->GetSelectedNodes().empty())
  {
    if (verbose) TRACE("Unselect needs nodes to unselect on");
    return false;
  }
  return true;
}

void ribi::cmap::CommandUnselectRandom::DoCommandSpecific(Widget * const widget) noexcept
{
  assert(widget);

  m_widget = widget;
  m_old_selected = const_cast<const Widget*>(widget)->GetSelected();

  //Get a random selected edge or node
  auto all_selected = const_cast<const Widget*>(widget)->GetSelected();
  const int n_edges{static_cast<int>(all_selected.first.size())};
  const int n_nodes{static_cast<int>(all_selected.second.size())};
  assert(n_edges + n_nodes > 0);
  const int i{std::rand() % (n_edges + n_nodes)};
  if (i < n_edges)
  {
    //Unselect edge
    std::swap(all_selected.first[i],all_selected.first.back());
    all_selected.first.pop_back();
  }
  else
  {
    //Unselect node
    std::swap(all_selected.second[i - n_edges],all_selected.second.back());
    all_selected.second.pop_back();
  }
  m_widget->SetSelected(all_selected);

  //m_widget->m_signal_set_focus_node();
  //m_widget->m_signal_concept_map_changed();

  assert(m_widget);
  assert(widget);
}

void ribi::cmap::CommandUnselectRandom::UndoSpecific() noexcept
{
  assert(m_widget);

  //Re-select the previously selected Node
  m_widget->SetSelected(m_old_selected);

}

 

 

 

 

 

./CppConceptMap/conceptmapcompetencies.h

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#ifndef CONCEPTMAPCOMPETENCIES_H
#define CONCEPTMAPCOMPETENCIES_H

#include <string>
#include <vector>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#include <boost/bimap.hpp>

#include "conceptmapcompetency.h"
#pragma GCC diagnostic pop

namespace ribi {
namespace cmap {

///Functions to work on with the Competency enumeration
struct Competencies
{
  Competencies();
  std::vector<Competency> GetAllCompetencies() const noexcept;
  int ToIndex(const Competency competency) const noexcept;
  std::string ToStrDutch(const Competency competency) const noexcept;
  std::string ToStr(const Competency competency) const noexcept;
  Competency ToTypeFromDutch(const std::string& dutch_string) const noexcept;
  Competency ToType(const std::string& s) const noexcept;

  private:
  static boost::bimap<Competency,std::string> m_map_dutch;
  static boost::bimap<Competency,std::string> m_map_english;
  static boost::bimap<Competency,std::string> CreateMapDutch() noexcept;
  static boost::bimap<Competency,std::string> CreateMapEnglish() noexcept;

  #ifndef NDEBUG
  static void Test() noexcept;
  #endif
};

} //~namespace cmap
} //~namespace ribi


#endif // CONCEPTMAPCOMPETENCIES_H

 

 

 

 

 

./CppConceptMap/conceptmapcompetencies.cpp

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#include "conceptmapcompetencies.h"

#include <cassert>
#include <stdexcept>

boost::bimap<ribi::cmap::Competency,std::string> ribi::cmap::Competencies::m_map_english;
boost::bimap<ribi::cmap::Competency,std::string> ribi::cmap::Competencies::m_map_dutch;

ribi::cmap::Competencies::Competencies()
{
  #ifndef NDEBUG
  Test();
  #endif
}

boost::bimap<ribi::cmap::Competency,std::string> ribi::cmap::Competencies::CreateMapEnglish() noexcept
{
  #ifndef NDEBUG
  Test();
  #endif

  boost::bimap<Competency,std::string> m;
  m.insert(boost::bimap<Competency,std::string>::value_type(
    Competency::uninitialized,"uninitialized"));
  m.insert(boost::bimap<Competency,std::string>::value_type(
    Competency::profession,"profession"));
  m.insert(boost::bimap<Competency,std::string>::value_type(
    Competency::organisations,"organisations"));
  m.insert(boost::bimap<Competency,std::string>::value_type(
    Competency::social_surroundings,"social_surroundings"));
  m.insert(boost::bimap<Competency,std::string>::value_type(
    Competency::target_audience,"target_audience"));
  m.insert(boost::bimap<Competency,std::string>::value_type(
    Competency::ti_knowledge,"ti_knowledge"));
  m.insert(boost::bimap<Competency,std::string>::value_type(
    Competency::prof_growth,"prof_growth"));
  m.insert(boost::bimap<Competency,std::string>::value_type(
    Competency::misc,"misc"));
  assert(m.left.size() == static_cast<int>(Competency::n_competencies));
  return m;
}

boost::bimap<ribi::cmap::Competency,std::string> ribi::cmap::Competencies::CreateMapDutch() noexcept
{
  #ifndef NDEBUG
  Test();
  #endif

  boost::bimap<Competency,std::string> m;
  m.insert(boost::bimap<Competency,std::string>::value_type(
    Competency::uninitialized,"[Ongeinitialiseerd]"));
  m.insert(boost::bimap<Competency,std::string>::value_type(
    Competency::profession,"Kennis van het beroepsdomein"));
  m.insert(boost::bimap<Competency,std::string>::value_type(
    Competency::organisations,"Kennis van de organisatie"));
  m.insert(boost::bimap<Competency,std::string>::value_type(
    Competency::social_surroundings,"Kennis van de sociale omgeving"));
  m.insert(boost::bimap<Competency,std::string>::value_type(
    Competency::target_audience,"Kennis van de doelgroep"));
  m.insert(boost::bimap<Competency,std::string>::value_type(
    Competency::ti_knowledge,"Technisch instrumentele kennis"));
  m.insert(boost::bimap<Competency,std::string>::value_type(
    Competency::prof_growth,"Kennis van de eigen persoon"));
  m.insert(boost::bimap<Competency,std::string>::value_type(
    Competency::misc,"Overige"));
  assert(m.left.size() == static_cast<int>(Competency::n_competencies));
  return m;
}

std::vector<ribi::cmap::Competency> ribi::cmap::Competencies::GetAllCompetencies() const noexcept
{
  const std::vector<Competency> v {
    ribi::cmap::Competency::uninitialized,
    ribi::cmap::Competency::profession,
    ribi::cmap::Competency::organisations,
    ribi::cmap::Competency::social_surroundings,
    ribi::cmap::Competency::target_audience,
    ribi::cmap::Competency::ti_knowledge,
    ribi::cmap::Competency::prof_growth,
    ribi::cmap::Competency::misc
  };
  assert(static_cast<int>(v.size()) == static_cast<int>(Competency::n_competencies));
  return v;
}

#ifndef NDEBUG
void ribi::cmap::Competencies::Test() noexcept
{
  {
    static bool is_tested{false};
    if (is_tested) return;
    is_tested = true;
  }
  static_assert(static_cast<int>(Competency::uninitialized) == 0,
    "Start the uninitialized value at zero, so that GetAllCompetencies can check against n_competencies"
  );
  Competencies c;
  {
    const std::vector<Competency> v = c.GetAllCompetencies();
    const std::size_t sz = v.size();
    for (std::size_t i=0; i!=sz; ++i)
    {
      assert(i < v.size());
      const Competency t = v[i];
      const std::string s = c.ToStr(t);
      assert(!s.empty());
      const Competency u = c.ToType(s);
      assert(u == t);
    }
    for (std::size_t i=0; i!=sz; ++i)
    {
      assert(i < v.size());
      const Competency t = v[i];
      const std::string s = c.ToStrDutch(t);
      assert(!s.empty());
      const Competency u = c.ToTypeFromDutch(s);
      assert(u == t);
    }
  }
  //ToIndex
  {
    assert(c.ToIndex(Competency::uninitialized) == 0);
  }
}
#endif

int ribi::cmap::Competencies::ToIndex(const Competency competency) const noexcept
{
  return static_cast<int>(competency);
}

std::string ribi::cmap::Competencies::ToStr(const Competency type) const noexcept
{
  if (m_map_english.left.empty()) m_map_english = CreateMapEnglish();
  assert(!m_map_english.left.empty());
  assert(m_map_english.left.count(type) == 1);
  const std::string s = m_map_english.left.find(type)->second;
  return s;
}

std::string ribi::cmap::Competencies::ToStrDutch(const Competency type) const noexcept
{
  if (m_map_dutch.left.empty()) m_map_dutch = CreateMapDutch();
  assert(!m_map_dutch.left.empty());
  assert(m_map_dutch.left.count(type) == 1);
  const std::string s = m_map_dutch.left.find(type)->second;
  return s;
}

ribi::cmap::Competency ribi::cmap::Competencies::ToType(const std::string& s) const noexcept
{
  if (m_map_english.right.empty()) m_map_english = CreateMapEnglish();
  assert(!m_map_english.right.empty());
  assert(m_map_english.right.count(s) == 1);
  const Competency t = m_map_english.right.find(s)->second;
  return t;
}

ribi::cmap::Competency ribi::cmap::Competencies::ToTypeFromDutch(const std::string& s) const noexcept
{
  if (m_map_dutch.right.empty()) m_map_dutch = CreateMapDutch();
  assert(!m_map_dutch.right.empty());
  assert(m_map_dutch.right.count(s) == 1);
  const Competency t = m_map_dutch.right.find(s)->second;
  return t;
}

 

 

 

 

 

./CppConceptMap/conceptmapcompetency.h

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#ifndef CONCEPTMAPCOMPETENCY_H
#define CONCEPTMAPCOMPETENCY_H


namespace ribi {
namespace cmap {

enum class Competency
{
  uninitialized,       //Not yet set, must equal zero
  profession,          //NL: 'Beroepsdomein'
  organisations,       //NL: 'Organisaties'
  social_surroundings, //NL: 'Sociale omgeving'
  target_audience,     //NL 'Doelgroep'
  ti_knowledge,        //'Technical Instrumental', NL: 'Technische instrumentele kennis'
  prof_growth,         //Professionele groei
  misc,                //NL: 'Overig'
  n_competencies       //Used for debugging only
};


} //~namespace cmap
} //~namespace ribi

#endif // CONCEPTMAPCOMPETENCY_H

 

 

 

 

 

./CppConceptMap/conceptmapcompetency.cpp

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#include "conceptmapcompetency.h"

 

 

 

 

 

./CppConceptMap/conceptmapconcept.h

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#ifndef CONCEPTMAPCONCEPT_H
#define CONCEPTMAPCONCEPT_H

#include <string>
#include <vector>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#include <boost/shared_ptr.hpp>
#include <boost/signals2.hpp>
#include <QRegExp>
#include "conceptmapfwd.h"
#pragma GCC diagnostic pop

namespace ribi {
namespace cmap {

struct ConceptFactory;

///A Concept is a class that has a name and examples
///A Concept is a Node without coordinats
///A Concept is an Edge without coordinats, source and target
///A Concept is the GUI independent part of a concept. It is displayed as:
/// - QtConceptDialog (as a QDialog, to be used in a QDialog)
/// - (as part of QtNode)
/// - (as part of QtEdge)
struct Concept
{
  ///Block copying, as signals cannot be copied
  Concept(const Concept& other) = delete;
  Concept& operator=(const Concept& other) = delete;

  ///Get the examples of the concept, e.g. 'Plato', 'Aristotle'
  boost::shared_ptr<const Examples> GetExamples() const noexcept;
  boost::shared_ptr<Examples>& GetExamples() noexcept { return m_examples; }

  ///Has an assessor rated the name of this concept as being an addition to the complexity?
  ///This is something different than m_rating_complexity:
  ///m_is_complex can be used to help the assessor determine a m_rating_complexity,
  ///but m_rating_complexity is the final and complete rating
  bool GetIsComplex() const noexcept { return m_is_complex; }

  ///Get the name of the concept, e.g. 'Philosphy'
  const std::string& GetName() const noexcept { return m_name; }

  ///Get the rating of this Concept for complexity
  ///-1: not rated, 0: lowest, 2: highest
  int GetRatingComplexity() const noexcept { return m_rating_complexity; }

  ///Get the rating of this Concept for concreteness
  ///-1: not rated, 0: lowest, 2: highest
  int GetRatingConcreteness() const noexcept { return m_rating_concreteness; }

  ///Get the rating of this Concept for specificity
  ///-1: not rated, 0: lowest, 2: highest
  int GetRatingSpecificity() const noexcept { return m_rating_specificity; }

  ///Set the examples
  void SetExamples(const boost::shared_ptr<Examples>& examples) noexcept;

  ///Has an assessor rated the name of this concept as being an addition to the complexity?
  ///This is something different than m_rating_complexity:
  ///m_is_complex can be used to help the assessor determine a m_rating_complexity,
  ///but m_rating_complexity is the final and complete rating
  void SetIsComplex(const bool is_complex) noexcept;

  ///Set the name
  void SetName(const std::string& name) noexcept;

  ///Set the rating of this Concept for complexity
  ///-1: not rated, 0: lowest, 2: highest
  void SetRatingComplexity(const int rating_complexity) noexcept;

  ///Set the rating of this Concept for concreteness
  ///-1: not rated, 0: lowest, 2: highest
  void SetRatingConcreteness(const int rating_concreteness) noexcept;

  ///Set the rating of this Concept for specificity
  ///-1: not rated, 0: lowest, 2: highest
  void SetRatingSpecificity(const int rating_specificity) noexcept;

  ///Convert Concept to a short std::string
  std::string ToStr() const noexcept;

  ///Convert Concept to a std::string to write to file
  std::string ToXml() const noexcept;

  ///Emitted when the examples are changed
  mutable boost::signals2::signal<void(Concept*)> m_signal_examples_changed;

  ///Emitted when IsComplex
  mutable boost::signals2::signal<void(Concept*)> m_signal_is_complex_changed;

  ///Emitted when the name is changed
  mutable boost::signals2::signal<void(Concept*)> m_signal_name_changed;

  ///Emitted when the rating of the complexity is changed
  mutable boost::signals2::signal<void(Concept*)> m_signal_rating_complexity_changed;

  ///Emitted when the rating of the complexity is changed
  mutable boost::signals2::signal<void(Concept*)> m_signal_rating_concreteness_changed;

  ///Emitted when the rating of the specificity is changed
  mutable boost::signals2::signal<void(Concept*)> m_signal_rating_specificity_changed;

  private:

  ///Examples of the concept, e.g. 'Plato', 'Aristotle'
  boost::shared_ptr<Examples> m_examples;

  ///Has an assessor rated the name of this concept as being an addition to the complexity?
  ///This is something different than m_rating_complexity:
  ///m_is_complex can be used to help the assessor determine a m_rating_complexity,
  ///but m_rating_complexity is the final and complete rating
  bool m_is_complex;

  ///The name of the concept, e.g. 'Philosphy'
  std::string m_name;

  ///The rating of this Concept for complexity
  ///-1: not rated, 0: lowest, 2: highest
  int m_rating_complexity;

  ///The rating of this Concept for concreteness
  ///-1: not rated, 0: lowest, 2: highest
  int m_rating_concreteness;

  ///The rating of this Concept for specificity
  ///-1: not rated, 0: lowest, 2: highest
  int m_rating_specificity;

  #ifndef NDEBUG
  ///Test this class
  static void Test() noexcept;
  #endif

  ///Use checked_delete for destructor
  ~Concept() {}
  friend void boost::checked_delete<>(Concept* x);

  ///Let only ConceptFactory construct Concepts
  explicit Concept(
    const std::string& name,
    const boost::shared_ptr<Examples>& examples,
    const bool is_complex,
    const int rating_complexity,
    const int rating_concreteness,
    const int rating_specificity);
  friend class ConceptFactory;
};

std::ostream& operator<<(std::ostream& os, const Concept& concept) noexcept;

bool operator==(const Concept& lhs, const Concept& rhs);
bool operator!=(const Concept& lhs, const Concept& rhs);

///Two Concept instances are ordered as follows:
///(1) Alphabetically on the name
///(2) (if the names are equal) On their Examples
bool operator<(const Concept& lhs, const Concept& rhs);

bool operator<(
  const boost::shared_ptr<Concept>& lhs,
  const boost::shared_ptr<Concept>& rhs) = delete;
bool operator<(
  const boost::shared_ptr<const Concept>& lhs,
  const boost::shared_ptr<      Concept>& rhs) = delete;
bool operator<(
  const boost::shared_ptr<      Concept>& lhs,
  const boost::shared_ptr<const Concept>& rhs) = delete;
bool operator<(
  const boost::shared_ptr<const Concept>& lhs,
  const boost::shared_ptr<const Concept>& rhs) = delete;

} //~namespace cmap
} //~namespace ribi

#endif // CONCEPTMAPCONCEPT_H

 

 

 

 

 

./CppConceptMap/conceptmapconcept.cpp

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#include "conceptmapconcept.h"

#include <boost/lexical_cast.hpp>

#include "conceptmapconceptfactory.h"
#include "conceptmaphelper.h"
#include "conceptmapcompetency.h"
#include "conceptmapexample.h"
#include "conceptmapexamples.h"
#include "conceptmapexamplesfactory.h"
#include "trace.h"
#include "xml.h"
#pragma GCC diagnostic pop

ribi::cmap::Concept::Concept(
  const std::string& name,
  const boost::shared_ptr<ribi::cmap::Examples>& examples,
  const bool is_complex,
  const int rating_complexity,
  const int rating_concreteness,
  const int rating_specificity)
  : m_signal_examples_changed{},
    m_signal_is_complex_changed{},
    m_signal_name_changed{},
    m_signal_rating_complexity_changed{},
    m_signal_rating_concreteness_changed{},
    m_signal_rating_specificity_changed{},
    m_examples{examples},
    m_is_complex{is_complex},
    m_name{name},
    m_rating_complexity{rating_complexity},
    m_rating_concreteness{rating_concreteness},
    m_rating_specificity{rating_specificity}

{
  #ifndef NDEBUG
  Test();
  assert(m_examples);
  assert(m_rating_complexity   >= -1);
  assert(m_rating_complexity   <=  2);
  assert(m_rating_concreteness >= -1);
  assert(m_rating_concreteness <=  2);
  assert(m_rating_specificity  >= -1);
  assert(m_rating_specificity  <=  2);
  #endif
}


boost::shared_ptr<const ribi::cmap::Examples> ribi::cmap::Concept::GetExamples() const noexcept
{
  assert(m_examples);
  const boost::shared_ptr<const Examples> p(m_examples);
  assert(p);
  return p;
}

void ribi::cmap::Concept::SetExamples(const boost::shared_ptr<ribi::cmap::Examples>& examples) noexcept
{
  if (examples != m_examples)
  {
    m_examples = examples;
    m_signal_examples_changed(this);
  }
}

void ribi::cmap::Concept::SetIsComplex(const bool is_complex) noexcept
{
  if (is_complex != m_is_complex)
  {
    m_is_complex = is_complex;
    m_signal_is_complex_changed(this);
  }
}


void ribi::cmap::Concept::SetName(const std::string& name) noexcept
{
  if (name != m_name)
  {
    m_name = name;
    m_signal_name_changed(this);
  }
}

void ribi::cmap::Concept::SetRatingComplexity(const int rating_complexity) noexcept
{
  assert(rating_complexity >= -1);
  assert(rating_complexity <=  2);

  if (m_rating_complexity != rating_complexity)
  {
    m_rating_complexity = rating_complexity;
    assert(m_rating_complexity >= -1);
    assert(m_rating_complexity <=  2);
    m_signal_rating_complexity_changed(this);
  }
}

void ribi::cmap::Concept::SetRatingConcreteness(const int rating_concreteness) noexcept
{
  if (m_rating_concreteness != rating_concreteness)
  {
    m_rating_concreteness = rating_concreteness;
    assert(m_rating_concreteness >= -1);
    assert(m_rating_concreteness <=  2);
    m_signal_rating_concreteness_changed(this);
  }
}

void ribi::cmap::Concept::SetRatingSpecificity(const int rating_specificity) noexcept
{
  if (m_rating_specificity != rating_specificity)
  {
    m_rating_specificity = rating_specificity;
    assert(m_rating_specificity >= -1);
    assert(m_rating_specificity <=  2);
    m_signal_rating_specificity_changed(this);
  }
}

std::string ribi::cmap::Concept::ToStr() const noexcept
{
  std::stringstream s;
  s
    << GetName() << " "
    << GetExamples()->ToStr() << " "
    << GetIsComplex() << " "
    << GetRatingComplexity() << " "
    << GetRatingConcreteness() << " "
    << GetRatingSpecificity()
  ;
  return s.str();
}

std::string ribi::cmap::Concept::ToXml() const noexcept
{
  std::stringstream s;
  s
    << "<concept>"
    <<   "<name>"
    <<     GetName()
    <<   "</name>"
    <<   GetExamples()->ToXml()
    <<   "<concept_is_complex>"
    <<     GetIsComplex()
    <<   "</concept_is_complex>"
    <<   "<complexity>"
    <<     GetRatingComplexity()
    <<   "</complexity>"
    <<   "<concreteness>"
    <<     GetRatingConcreteness()
    <<   "</concreteness>"
    <<   "<specificity>"
    <<     GetRatingSpecificity()
    <<   "</specificity>"
    << "</concept>"
  ;
  const std::string r = s.str();

  assert(r.size() >= 19);
  assert(r.substr(0,9) == "<concept>");
  assert(r.substr(r.size() - 10,10) == "</concept>");
  return r;
}

std::ostream& ribi::cmap::operator<<(std::ostream& os, const Concept& concept) noexcept
{
  os << concept.ToStr();
  return os;
}

bool ribi::cmap::operator==(const ribi::cmap::Concept& lhs, const ribi::cmap::Concept& rhs)
{
  const bool verbose{false};
  if (lhs.GetIsComplex() != rhs.GetIsComplex())
  {
    if (verbose) { TRACE("Concept::IsComplex differs"); }
    return false;
  }
  if (lhs.GetName() != rhs.GetName())
  {
    if (verbose) { TRACE("Concept::Name differs"); }
    return false;
  }
  if (lhs.GetRatingComplexity() != rhs.GetRatingComplexity())
  {
    if (verbose) { TRACE("Concept::RatingComplexity differs"); }
    return false;
  }
  if (lhs.GetRatingConcreteness() != rhs.GetRatingConcreteness())
  {
    if (verbose) { TRACE("Concept::RatingConcreteness differs"); }
    return false;
  }
  if (lhs.GetRatingSpecificity() != rhs.GetRatingSpecificity())
  {
    if (verbose) { TRACE("Concept::RatingSpecificity differs"); }
    return false;
  }
  const auto lhs_examples = lhs.GetExamples();
  const auto rhs_examples = rhs.GetExamples();
  if (lhs_examples == nullptr)
  {
    if (rhs_examples == nullptr)
    {
      return true;
    }
    if (verbose) { TRACE("Concept::Examples differs: lhs is nullptr"); }
    return false;
  }
  if (rhs_examples == nullptr)
  {
    if (verbose) { TRACE("Concept::Examples differs: rhs is nullptr"); }
    return false;
  }
  assert(rhs_examples);
  if (lhs_examples == rhs_examples) return true;
  if (*lhs_examples == *rhs_examples)
  {
    return true;
  }
  else
  {
    if (verbose) { TRACE("Concept::Examples differs: content is different"); }
    return false;
  }
}

bool ribi::cmap::operator!=(const ribi::cmap::Concept& lhs, const ribi::cmap::Concept& rhs)
{
  return !(lhs == rhs);
}

bool ribi::cmap::operator<(const ribi::cmap::Concept& lhs, const ribi::cmap::Concept& rhs)
{
  if (lhs.GetName() < rhs.GetName()) return true;
  if (lhs.GetName() > rhs.GetName()) return false;
  if (*lhs.GetExamples() < *rhs.GetExamples()) return true;
  if (*lhs.GetExamples() != *rhs.GetExamples()) return false;
  assert(*lhs.GetExamples() == *rhs.GetExamples());
  if (lhs.GetRatingComplexity() < rhs.GetRatingComplexity()) return true;
  if (lhs.GetRatingComplexity() > rhs.GetRatingComplexity()) return false;
  if (lhs.GetRatingConcreteness() < rhs.GetRatingConcreteness()) return true;
  if (lhs.GetRatingConcreteness() > rhs.GetRatingConcreteness()) return false;
  return lhs.GetRatingSpecificity() < rhs.GetRatingSpecificity();

}

/*
bool ribi::cmap::operator<(const boost::shared_ptr<const ribi::cmap::Concept>& lhs, const boost::shared_ptr<const ribi::cmap::Concept>& rhs)
{
  assert(lhs); assert(rhs);
  if (lhs->GetName() < rhs->GetName()) return true;
  if (lhs->GetName() > rhs->GetName()) return false;
  if (lhs->GetExamples() < rhs->GetExamples()) return true;
  if (lhs->GetExamples() != rhs->GetExamples()) return false;
  assert(lhs->GetExamples() == rhs->GetExamples());
  if (lhs->GetRatingComplexity() < rhs->GetRatingComplexity()) return true;
  if (lhs->GetRatingComplexity() > rhs->GetRatingComplexity()) return false;
  if (lhs->GetRatingConcreteness() < rhs->GetRatingConcreteness()) return true;
  if (lhs->GetRatingConcreteness() > rhs->GetRatingConcreteness()) return false;
  return lhs->GetRatingSpecificity() < rhs->GetRatingSpecificity();
}

bool ribi::cmap::operator<(const boost::shared_ptr<const ribi::cmap::Concept>& lhs, const boost::shared_ptr<ribi::cmap::Concept>& rhs)
{
  assert(lhs); assert(rhs);
  return boost::shared_ptr<const ribi::cmap::Concept>(lhs) < boost::shared_ptr<const ribi::cmap::Concept>(rhs);
}

bool ribi::cmap::operator<(const boost::shared_ptr<ribi::cmap::Concept>& lhs, const boost::shared_ptr<const ribi::cmap::Concept>& rhs)
{
  assert(lhs); assert(rhs);
  return boost::shared_ptr<const ribi::cmap::Concept>(lhs) < boost::shared_ptr<const ribi::cmap::Concept>(rhs);
}

bool ribi::cmap::operator<(const boost::shared_ptr<ribi::cmap::Concept>& lhs, const boost::shared_ptr<ribi::cmap::Concept>& rhs)
{
  assert(lhs); assert(rhs);
  return boost::shared_ptr<const ribi::cmap::Concept>(lhs) < boost::shared_ptr<const ribi::cmap::Concept>(rhs);
}
*/

 

 

 

 

 

./CppConceptMap/conceptmapconcept_test.cpp

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#include "conceptmapconcept.h"

#include <cassert>

#include "conceptmaphelper.h"
#include "conceptmapconceptfactory.h"
#include "counter.h"
#include "testtimer.h"
#include "trace.h"
#pragma GCC diagnostic pop

#ifndef NDEBUG
void ribi::cmap::Concept::Test() noexcept
{
  {
    static bool is_tested{false};
    if (is_tested) return;
    is_tested = true;
  }
  TestHelperFunctions();
  const bool verbose{false};
  const TestTimer test_timer(__func__,__FILE__,1.0);
  if (verbose) { TRACE("Test operator== and operator!="); }
  {
    const int sz = static_cast<int>(ConceptFactory().GetTests().size());
    assert(sz > 0);
    for (int i=0; i!=sz; ++i)
    {
      const auto tmp_a = ConceptFactory().GetTests();
      const auto tmp_b = ConceptFactory().GetTests();
      const boost::shared_ptr<const ribi::cmap::Concept> a = tmp_a.at(i);
      const boost::shared_ptr<      ribi::cmap::Concept> b = tmp_b.at(i);
      assert(b); //FAILS AT CROSSCOMPILER
      assert(a);
      assert(a!=b);
      assert(*a == *a);
      assert(*b == *a);
      assert(*a == *b);
      assert(*b == *b);
      for (int j=0; j!=sz; ++j)
      {
        assert(j < static_cast<int>(ConceptFactory().GetTests().size()));
        const boost::shared_ptr<const ribi::cmap::Concept> c = ConceptFactory().GetTests().at(j);
        const boost::shared_ptr<      ribi::cmap::Concept> d = ConceptFactory().GetTests().at(j);
        assert(c); assert(d);
        assert(*c == *c);
        assert(*d == *c);
        assert(*c == *d);
        assert(*d == *d);
        if (i==j)
        {
          assert(*a == *c); assert(*a == *d);
          assert(*b == *c); assert(*b == *d);
          assert(*c == *a); assert(*c == *b);
          assert(*d == *a); assert(*d == *b);
        }
        else
        {
          assert(*a != *c); assert(*a != *d);
          assert(*b != *c); assert(*b != *d);
          assert(*c != *a); assert(*c != *b);
          assert(*d != *a); assert(*d != *b);
        }
      }
    }
  }
  if (verbose) { TRACE("Test operator<"); }
  {
    if (verbose) { TRACE("operator< must order by name"); }
    {
      const boost::shared_ptr<const ribi::cmap::Concept> a = ConceptFactory().Create("1");
      const boost::shared_ptr<      ribi::cmap::Concept> b = ConceptFactory().Create("1");
      const boost::shared_ptr<const ribi::cmap::Concept> c = ConceptFactory().Create("2");
      const boost::shared_ptr<      ribi::cmap::Concept> d = ConceptFactory().Create("2");
      assert(a); assert(b); assert(c); assert(d);
      assert(*a < *c); assert(*a < *d);
      assert(*b < *c); assert(*b < *d);
    }
    if (verbose) { TRACE("operator< must order by examples' size, sizes 0 versus 1"); }
    {
      const boost::shared_ptr<const ribi::cmap::Concept> a = ConceptFactory().Create("1");
      const boost::shared_ptr<      ribi::cmap::Concept> b = ConceptFactory().Create("1");
      const boost::shared_ptr<const ribi::cmap::Concept> c = ConceptFactory().Create("1", { {"2",Competency::misc} } );
      const boost::shared_ptr<      ribi::cmap::Concept> d = ConceptFactory().Create("1", { {"2",Competency::misc} } );
      assert(a); assert(b); assert(c); assert(d);
      assert(*a < *c); assert(*a < *d);
      assert(*b < *c); assert(*b < *d);
    }
    if (verbose) { TRACE("operator< must order by examples' size, sizes 1 versus 2"); }
    {
      const boost::shared_ptr<const ribi::cmap::Concept> a = ConceptFactory().Create("1", { {"2",Competency::misc} } );
      const boost::shared_ptr<      ribi::cmap::Concept> b = ConceptFactory().Create("1", { {"2",Competency::misc} } );
      const boost::shared_ptr<const ribi::cmap::Concept> c = ConceptFactory().Create("1", { {"2",Competency::misc},{"3",Competency::misc} } );
      const boost::shared_ptr<      ribi::cmap::Concept> d = ConceptFactory().Create("1", { {"2",Competency::misc},{"3",Competency::misc} } );
      assert(a); assert(b); assert(c); assert(d);
      assert(*a < *c); assert(*a < *d);
      assert(*b < *c); assert(*b < *d);
    }
    if (verbose) { TRACE("Check correct ordering for equal examples' size, lexicographically in the 2nd text"); }
    {
      const boost::shared_ptr<const ribi::cmap::Concept> a = ConceptFactory().Create("1", { {"2",Competency::misc},{"3",Competency::misc} } );
      const boost::shared_ptr<      ribi::cmap::Concept> b = ConceptFactory().Create("1", { {"2",Competency::misc},{"3",Competency::misc} } );
      const boost::shared_ptr<const ribi::cmap::Concept> c = ConceptFactory().Create("1", { {"2",Competency::misc},{"4",Competency::misc} } );
      const boost::shared_ptr<      ribi::cmap::Concept> d = ConceptFactory().Create("1", { {"2",Competency::misc},{"4",Competency::misc} } );
      assert(a); assert(b); assert(c); assert(d);
      assert(*a < *c); assert(*a < *d);
      assert(*b < *c); assert(*b < *d);
    }
  }
  if (verbose) { TRACE("Test XML conversion"); }
  {
    const auto v = AddConst(ConceptFactory().GetTests());
    std::for_each(v.begin(),v.end(),
      [](const boost::shared_ptr<const ribi::cmap::Concept>& original)
      {
        //Test copy constructor and operator==
        boost::shared_ptr<Concept> c = ConceptFactory().DeepCopy(original);
        assert(c);
        assert(*c == *original);
        //Test operator!=
        c->m_name = c->m_name + " (modified)";
        assert(*c != *original);
        //Test ToXml and FromXml
        const std::string s = c->ToXml();
        const boost::shared_ptr<Concept> d = ConceptFactory().FromXml(s);
        assert(d);
        assert(*c == *d);
      }
    );
  }
  if (verbose) { TRACE("When setting the name, a signal must be emitted"); }
  {
    const auto concept = ConceptFactory().GetTest(0);
    concept->SetName("A");
    Counter c{0}; //For receiving the signal
    concept->m_signal_name_changed.connect(
      boost::bind(&ribi::Counter::Inc,&c) //Do not forget the &
    );
    concept->SetName("B");
    assert(c.Get() == 1);
  }
}
#endif

 

 

 

 

 

./CppConceptMap/conceptmapconceptfactory.h

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#ifndef CONCEPTMAPCONCEPTFACTORY_H
#define CONCEPTMAPCONCEPTFACTORY_H

#include <array>
#include <vector>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#include <boost/array.hpp>
#include <boost/shared_ptr.hpp>

#include "conceptmapcompetency.h"

#include "conceptmapfwd.h"
#pragma GCC diagnostic pop

namespace ribi {
namespace cmap {

///Creates Concepts
struct ConceptFactory
{
  ConceptFactory() noexcept;

  //Default and complete Create member function
  const boost::shared_ptr<Concept> Create(
    const std::string& name,
    const boost::shared_ptr<Examples>& examples,
    const bool is_complex,
    const int rating_complexity,
    const int rating_concreteness,
    const int rating_specificity
  ) const noexcept;

  const boost::shared_ptr<Concept> Create(
    const std::string& name = "...",
    const std::vector<std::pair<std::string,Competency> >& examples = {},
    const bool is_complex = true,
    const int rating_complexity = -1,
    const int rating_concreteness = -1,
    const int rating_specificity = -1
  ) const noexcept;

  #ifndef NDEBUG
  ///Like a Concept deep-copy constructor
  ///DeepCopy is only used for debugging
  const boost::shared_ptr<Concept> DeepCopy(
    const boost::shared_ptr<const Concept>& concept
  ) const noexcept;
  #endif

  ///Read concept from a std::string read from file
  const boost::shared_ptr<Concept> FromXml(const std::string& s) const noexcept;

  ///Obtain some testing concepts
  const boost::shared_ptr<Concept> GetTest(const int i) const noexcept;
  const std::vector<boost::shared_ptr<Concept> > GetTests() const noexcept;
  int GetNumberOfTests() const noexcept { return static_cast<int>(GetTests().size()); }

  #ifndef NDEBUG
  static void Test() noexcept;
  #endif
};

} //~namespace cmap
} //~namespace ribi

#endif // CONCEPTMAPCONCEPTFACTORY_H

 

 

 

 

 

./CppConceptMap/conceptmapconceptfactory.cpp

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#include "conceptmapconceptfactory.h"

#include "conceptmapcompetency.h"
#include "conceptmapconcept.h"
#include "conceptmapexample.h"
#include "conceptmapexamples.h"
#include "conceptmapexamplefactory.h"
#include "conceptmapexamplesfactory.h"
#include "conceptmaphelper.h"
#include "conceptmapregex.h"
#include "testtimer.h"
#include "counter.h"
#include "trace.h"
#include "xml.h"
#pragma GCC diagnostic push

ribi::cmap::ConceptFactory::ConceptFactory() noexcept
{
  #ifndef NDEBUG
  Test();
  #endif
}

const boost::shared_ptr<ribi::cmap::Concept> ribi::cmap::ConceptFactory::Create(
  const std::string& name,
  const boost::shared_ptr<ribi::cmap::Examples>& examples,
  const bool is_complex,
  const int rating_complexity,
  const int rating_concreteness,
  const int rating_specificity
) const noexcept
{
  assert(examples);
  assert(rating_complexity >= -1);
  assert(rating_complexity <=  2);

  boost::shared_ptr<Concept> concept(
    new Concept(
      name,
      examples,
      is_complex,
      rating_complexity,
      rating_concreteness,
      rating_specificity
    )
  );
  assert(concept);
  return concept;
}

#ifndef NDEBUG
const boost::shared_ptr<ribi::cmap::Concept> ribi::cmap::ConceptFactory::DeepCopy(
  const boost::shared_ptr<const ribi::cmap::Concept>& concept
) const noexcept
{
  const boost::shared_ptr<Examples> examples
    = ExamplesFactory().Create(concept->GetExamples());
  assert(examples);
  assert(*examples == *concept->GetExamples());

  assert(concept->GetRatingComplexity() >= -1);
  assert(concept->GetRatingComplexity() <=  2);

  const boost::shared_ptr<Concept> q
    = Create(
      concept->GetName(),
      examples,
      concept->GetIsComplex(),
      concept->GetRatingComplexity(),
      concept->GetRatingConcreteness(),
      concept->GetRatingSpecificity());
  assert(q);
  assert(q->GetExamples());
  assert(*concept == *q);
  return q;
}
#endif

//Do not create this version: it will lead to ambiguities
//static const boost::shared_ptr<ribi::cmap::Concept> ribi::cmap::ConceptFactory::Create(
//  const std::string& name,
//  const std::vector<boost::shared_ptr<const cmap::Example> >& examples)
//{
//  return Create(name,ExamplesFactory::Create(examples));
//}

const boost::shared_ptr<ribi::cmap::Concept> ribi::cmap::ConceptFactory::Create(
  const std::string& name,
  const std::vector<std::pair<std::string,Competency> >& v,
  const bool is_complex,
  const int rating_complexity,
  const int rating_concreteness,
  const int rating_specificity
) const noexcept
{
  assert(rating_complexity >= -1);
  assert(rating_complexity <=  2);

  std::vector<boost::shared_ptr<cmap::Example> > w;
  std::transform(v.begin(),v.end(),std::back_inserter(w),
    [](const std::pair<std::string,Competency>& p)
    {
      const boost::shared_ptr<cmap::Example> q
        = ExampleFactory().Create(
          p.first,
          p.second);
      assert(q);
      return q;
    }
  );

  const boost::shared_ptr<Examples> examples
    = ExamplesFactory().Create(w);
  assert(examples);

  const boost::shared_ptr<Concept> concept
    = Create(
    name,
    examples,
    is_complex,
    rating_complexity,
    rating_concreteness,
    rating_specificity);
  assert(concept);
  return concept;
}

const boost::shared_ptr<ribi::cmap::Concept> ribi::cmap::ConceptFactory::FromXml(const std::string& s) const noexcept
{
  assert(s.size() >= 19);
  assert(s.substr(0,9) == "<concept>");
  assert(s.substr(s.size() - 10,10) == "</concept>");

  std::string name;
  boost::shared_ptr<ribi::cmap::Examples> examples;
  bool is_complex = false;
  int rating_complexity    = -2; //Not even unrated (which has -1 as its value)
  int rating_concreteness  = -2; //Not even unrated (which has -1 as its value)
  int rating_specificity   = -2; //Not even unrated (which has -1 as its value)
  //m_name
  {
    const std::vector<std::string> v
      = Regex().GetRegexMatches(s,Regex().GetRegexName());
    #ifndef NDEBUG
    if (v.size() != 1)
    {
      TRACE("ERROR");
      TRACE(s);
      TRACE(Regex().GetRegexName());
      TRACE(v.size());
      for (const auto& t: v) { TRACE(t); }
      TRACE("BREAK");
    }
    #endif
    assert(v.size() == 1);
    name = ribi::xml::StripXmlTag(v[0]);
  }
  //m_examples
  {
    const std::vector<std::string> v
      = Regex().GetRegexMatches(s,Regex().GetRegexExamples());
    assert(v.size() == 1 && "GetRegexExamples must be present once in a Concept");
    examples = ExamplesFactory().FromXml(v[0]);
  }

  //m_is_complex
  {
    const std::vector<std::string> v
      = Regex().GetRegexMatches(s,Regex().GetRegexConceptIsComplex());
    assert(v.size() == 1 && "GetRegexIsComplex must be present once per Concept");
    is_complex = boost::lexical_cast<bool>(ribi::xml::StripXmlTag(v[0]));
  }


  //m_rating_complexity
  {
    const std::vector<std::string> v
      = Regex().GetRegexMatches(s,Regex().GetRegexComplexity());
    assert(v.size() == 1 && "GetRegexComplexity must be present once per Concept");
    rating_complexity = boost::lexical_cast<int>(ribi::xml::StripXmlTag(v[0]));
    assert(rating_complexity >= -1);
    assert(rating_complexity <=  2);
  }
  //m_rating_concreteness
  {
    const std::vector<std::string> v
      = Regex().GetRegexMatches(s,Regex().GetRegexConcreteness());
    assert(v.size() == 1);
    rating_concreteness = boost::lexical_cast<int>(ribi::xml::StripXmlTag(v[0]));
  }
  //m_rating_specificity
  {
    const std::vector<std::string> v
      = Regex().GetRegexMatches(s,Regex().GetRegexSpecificity());
    assert(v.size() == 1);
    rating_specificity = boost::lexical_cast<int>(ribi::xml::StripXmlTag(v[0]));
  }

  const boost::shared_ptr<Concept> concept {
    ConceptFactory().Create(name,examples,is_complex,rating_complexity,rating_concreteness,rating_specificity)
  };
  return concept;
}

const boost::shared_ptr<ribi::cmap::Concept> ribi::cmap::ConceptFactory::GetTest(
  const int i) const noexcept
{
  assert(i < GetNumberOfTests());
  const boost::shared_ptr<Concept> concept {
    GetTests()[i]
  };
  assert(concept);
  return concept;
}

const std::vector<boost::shared_ptr<ribi::cmap::Concept> > ribi::cmap::ConceptFactory::GetTests() const noexcept
{
  std::vector<boost::shared_ptr<Concept> > v;
  {
    const boost::shared_ptr<Examples> examples = ExamplesFactory().Create();
    assert(examples);
    const boost::shared_ptr<Concept> p = Create("Concept without examples", examples, false, 0, 1, 2);
    assert(p);
    assert(p->GetRatingComplexity() >= -1);
    assert(p->GetRatingComplexity() <=  2);
    v.push_back(p);
  }
  {
    const boost::shared_ptr<Concept> p = Create("Concept with one example", { { "Only example", cmap::Competency::profession } }, 1, 2, 0);
    assert(p);
    assert(p->GetRatingComplexity() >= -1);
    assert(p->GetRatingComplexity() <=  2);
    v.push_back(p);
  }
  /*
  {
    const boost::shared_ptr<Concept> p = Create("Concept with two examples", { { "First example", cmap::Competency::organisations }, { "Second example", cmap::Competency::social_surroundings } }, 2, 0, 1);
    assert(p);
    assert(p->GetRatingComplexity() >= -1);
    assert(p->GetRatingComplexity() <=  2);
    v.push_back(p);
  }
  {
    const boost::shared_ptr<Concept> p = Create("Concept with three examples", { { "Example 1 of 3", cmap::Competency::target_audience }, { "Example 2 of 3", cmap::Competency::ti_knowledge }, { "Example 3 of 3", cmap::Competency::prof_growth } }, 0, 1, 2);
    assert(p);
    assert(p->GetRatingComplexity() >= -1);
    assert(p->GetRatingComplexity() <=  2);
    v.push_back(p);
  }
  {
    const boost::shared_ptr<Concept> p = Create("Concept with four Roman examples", { { "Example I/IV", cmap::Competency::misc }, { "Example II/IV", cmap::Competency::uninitialized }, { "Example III/IV", cmap::Competency::profession }, { "Example III/IV", cmap::Competency::social_surroundings } }, 1, 2, 0);
    assert(p);
    assert(p->GetRatingComplexity() >= -1);
    assert(p->GetRatingComplexity() <=  2);
    v.push_back(p);
  }
  */
  {
    const boost::shared_ptr<Concept> p = Create(
      "Very long multi-line concept with four Roman examples that also each span multiple lines, that is, eighty characters",
      {
        { "Example I/IV, spanning multiple lines (that is, having at least eight characters) and is rated as cmap::Competency::misc", cmap::Competency::misc },
        { "Example II/IV, spanning multiple lines (that is, having at least eight characters) and is rated as cmap::Competency::uninitialized", cmap::Competency::uninitialized },
        { "Example III/IV, spanning multiple lines (that is, having at least eight characters) and is rated as cmap::Competency::profession", cmap::Competency::profession },
        { "Example III/IV, spanning multiple lines (that is, having at least eight characters) and is rated as cmap::Competency::social_surroundings", cmap::Competency::social_surroundings }
      }, 1, 2, 0
    );
    assert(p);
    assert(p->GetRatingComplexity() >= -1);
    assert(p->GetRatingComplexity() <=  2);
    v.push_back(p);
  }
  assert(std::count_if(v.begin(),v.end(),[](const boost::shared_ptr<Concept>& p) { return !p; } ) == 0); //FIX 2012-01-02
  assert(v[0]->GetExamples());

  return v;
}

#ifndef NDEBUG
void ribi::cmap::ConceptFactory::Test() noexcept
{
  {
    static bool is_tested{false};
    if (is_tested) return;
    is_tested = true;
  }
  Counter();
  ConceptFactory().GetTest(0);
  ExamplesFactory();
  const bool verbose{false};
  const TestTimer test_timer(__func__,__FILE__,1.0);
  if (verbose) { TRACE("GetTests all valid"); }
  {
    const auto tests = ConceptFactory().GetTests();
    for (const auto test: tests)
    {
      assert(test);
      assert(test->GetExamples());
    }
  }
  if (verbose) { TRACE("Concept -> XML -> Concept "); }
  {
    const auto concept = ConceptFactory().GetTest(2);
    const auto xml = concept->ToXml();
    const auto new_concept = ConceptFactory().FromXml(xml);
    const auto new_xml = new_concept->ToXml();
    assert(xml == new_xml);
  }
}
#endif

 

 

 

 

 

./CppConceptMap/conceptmapedge.h

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#ifndef CONCEPTMAPEDGE_H
#define CONCEPTMAPEDGE_H

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#include <boost/shared_ptr.hpp>
#include <boost/signals2.hpp>
#include "conceptmapfwd.h"
#include "conceptmapelement.h"
#pragma GCC diagnostic pop


namespace ribi {
namespace cmap {

struct EdgeFactory;

///An Edge is the GUI-independent part of the edges used in QtConceptMap.
///An Edge goes from one Node to another, which must a different Node,
/// at the center of the Edge is a Node
struct Edge : public Element
{
  typedef boost::shared_ptr<const Edge> ReadOnlyEdgePtr;
  typedef boost::shared_ptr<Edge> EdgePtr;
  typedef boost::shared_ptr<const Node> ReadOnlyNodePtr;
  typedef boost::shared_ptr<Node> NodePtr;
  typedef std::vector<ReadOnlyNodePtr> ReadOnlyNodes;
  typedef std::vector<NodePtr> Nodes;

  Edge(const Edge&) = delete;
  Edge& operator=(const Edge&) = delete;
  ReadOnlyNodePtr GetNode() const noexcept { return m_node; }
  NodePtr GetNode()       noexcept { return m_node; }

  ///Get the Node this edge originates from
  ReadOnlyNodePtr GetFrom() const noexcept { return m_from; }
  NodePtr GetFrom()       noexcept { return m_from; }

  ///Get the Node index this edge goes to
  ReadOnlyNodePtr GetTo() const noexcept { return m_to; }
  NodePtr GetTo()       noexcept { return m_to; }

  static std::string GetVersion() noexcept;
  static std::vector<std::string> GetVersionHistory() noexcept;

  ///Does the edge have an arrow at the head?
  bool HasHeadArrow() const noexcept { return m_head_arrow; }

  ///Does the edge have an arrow at the tail?
  bool HasTailArrow() const noexcept { return m_tail_arrow; }

  ///Set the Node index this edge originates from
  //void SetFrom(const NodePtr& from) noexcept;

  ///Set if the head has an arrow
  void SetHeadArrow(const bool has_head_arrow) noexcept;

  ///Set the center Node
  void SetNode(const NodePtr& node) noexcept;

  ///Set if the tail has an arrow
  void SetTailArrow(const bool has_tail_arrow) noexcept;

  ///Set the Node index this edge goes to
  //void SetTo(const NodePtr& to) noexcept;

  std::string ToStr() const noexcept;

  ///Convert an Edge from an XML std::string
  ///The container of nodes is needed to convert the 'to' and 'from'
  ///field to indices
  static std::string ToXml(
    const ReadOnlyEdgePtr& c,
    const ReadOnlyNodes& nodes
    ) noexcept;

  ///Emitted when an Edge attribute has changed
  boost::signals2::signal<void (Edge*)> m_signal_from_changed;
  boost::signals2::signal<void (Edge*)> m_signal_head_arrow_changed;
  mutable boost::signals2::signal<void (Edge*)> m_signal_node_changed;
  boost::signals2::signal<void (Edge*)> m_signal_tail_arrow_changed;
  boost::signals2::signal<void (Edge*)> m_signal_to_changed;

  private:
  ///The Node this edge originates from
  const NodePtr m_from;

  ///Is there an arrowhead at the 'to' node?
  bool m_head_arrow;

  ///The Node on the Edge
  NodePtr m_node;

  ///Is there an arrowhead at the 'from' node?
  bool m_tail_arrow;

  ///The Node this edge goes to
  const NodePtr m_to;

  #ifndef NDEBUG
  static void Test() noexcept;
  #endif

  Edge() = delete;

  ///Block destructor, except for the friend boost::checked_delete
  ~Edge() noexcept;
  friend void boost::checked_delete<>(      Edge*);
  friend void boost::checked_delete<>(const Edge*);

  ///Block constructor, except for EdgeFactory
  friend class EdgeFactory;
  explicit Edge(
    const NodePtr& node,
    const NodePtr& from,
    const bool tail_arrow,
    const NodePtr& to,
    const bool head_arrow
  );

  ///Bundles Node its signals into emitting a signal that the node has changed
  void OnConceptChanged(Node * const node) noexcept;
  void OnFromChanged(Node * const node) noexcept;
  void OnToChanged(Node * const node) noexcept;
};

bool IsConnectedToCenterNode(const boost::shared_ptr<const Edge> edge) noexcept;

std::ostream& operator<<(std::ostream& os, const Edge& edge) noexcept;

bool operator==(const Edge& lhs, const Edge& rhs);
bool operator!=(const Edge& lhs, const Edge& rhs);

bool operator<(const boost::shared_ptr<      Edge>& lhs, const boost::shared_ptr<      Edge>& rhs) = delete;
bool operator<(const boost::shared_ptr<const Edge>& lhs, const boost::shared_ptr<      Edge>& rhs) = delete;
bool operator<(const boost::shared_ptr<      Edge>& lhs, const boost::shared_ptr<const Edge>& rhs) = delete;
bool operator<(const boost::shared_ptr<const Edge>& lhs, const boost::shared_ptr<const Edge>& rhs) = delete;

} //~namespace cmap
} //~namespace ribi

#endif // CONCEPTMAPEDGE_H

 

 

 

 

 

./CppConceptMap/conceptmapedge.cpp

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#include "conceptmapedge.h"

#include <sstream>

#include <boost/lambda/lambda.hpp>

#include "counter.h"
#include "conceptmapconcept.h"
#include "conceptmapedgefactory.h"
#include "conceptmapnode.h"
#include "conceptmapnodefactory.h"
#include "conceptmapcenternode.h"
#include "conceptmapconceptfactory.h"
#include "conceptmaphelper.h"
#include "testtimer.h"
#include "trace.h"
#pragma GCC diagnostic pop

ribi::cmap::Edge::Edge(
  const NodePtr& node,
  const NodePtr& from,
  const bool tail_arrow,
  const NodePtr& to,
  const bool head_arrow)
  : m_signal_from_changed{},
    m_signal_head_arrow_changed{},
    m_signal_node_changed{},
    m_signal_tail_arrow_changed{},
    m_signal_to_changed{},
    m_from(from),
    m_head_arrow(head_arrow),
    m_node(node),
    m_tail_arrow(tail_arrow),
    m_to(to)
{
  #ifndef NDEBUG
  Test();
  #endif
  assert(from);
  assert(to);
  assert(from != to);
  assert(m_from);
  assert(m_to);
  assert(m_from != m_to);
  assert(m_node);

  //Subscribe to all Concept signals to re-emit m_signal_edge_changed
  this->m_node->m_signal_concept_changed.connect(
    boost::bind(&ribi::cmap::Edge::OnConceptChanged,this,boost::lambda::_1)
  );

  this->m_from->m_signal_x_changed.connect(
    boost::bind(&ribi::cmap::Edge::OnFromChanged,this,boost::lambda::_1)
  );
  this->m_from->m_signal_y_changed.connect(
    boost::bind(&ribi::cmap::Edge::OnFromChanged,this,boost::lambda::_1)
  );
  this->m_from->m_signal_concept_changed.connect(
    boost::bind(&ribi::cmap::Edge::OnFromChanged,this,boost::lambda::_1)
  );

  this->m_to->m_signal_x_changed.connect(
    boost::bind(&ribi::cmap::Edge::OnToChanged,this,boost::lambda::_1)
  );
  this->m_to->m_signal_y_changed.connect(
    boost::bind(&ribi::cmap::Edge::OnToChanged,this,boost::lambda::_1)
  );
  this->m_to->m_signal_concept_changed.connect(
    boost::bind(&ribi::cmap::Edge::OnToChanged,this,boost::lambda::_1)
  );

}

ribi::cmap::Edge::~Edge() noexcept
{
  this->m_node->m_signal_concept_changed.disconnect(
    boost::bind(&ribi::cmap::Edge::OnConceptChanged,this)
  );

  this->m_from->m_signal_x_changed.disconnect(
    boost::bind(&ribi::cmap::Edge::OnFromChanged,this,boost::lambda::_1)
  );
  this->m_from->m_signal_y_changed.disconnect(
    boost::bind(&ribi::cmap::Edge::OnFromChanged,this,boost::lambda::_1)
  );
  this->m_from->m_signal_concept_changed.disconnect(
    boost::bind(&ribi::cmap::Edge::OnFromChanged,this,boost::lambda::_1)
  );

  this->m_to->m_signal_x_changed.disconnect(
    boost::bind(&ribi::cmap::Edge::OnToChanged,this,boost::lambda::_1)
  );
  this->m_to->m_signal_y_changed.disconnect(
    boost::bind(&ribi::cmap::Edge::OnToChanged,this,boost::lambda::_1)
  );
  this->m_to->m_signal_concept_changed.disconnect(
    boost::bind(&ribi::cmap::Edge::OnToChanged,this,boost::lambda::_1)
  );

}

std::string ribi::cmap::Edge::GetVersion() noexcept
{
  return "1.1";
}

std::vector<std::string> ribi::cmap::Edge::GetVersionHistory() noexcept
{
  return {
    "2013-xx-xx: Version 1.0: initial version",
    "2014-06-01: Version 1.1: replaced Concept, X and Y by a Node"
  };
}


void ribi::cmap::Edge::OnConceptChanged(Node * const
#ifndef NDEBUG
  node
#endif
) noexcept
{
  assert(node == this->GetNode().get());
  this->m_signal_node_changed(this);
}

void ribi::cmap::Edge::OnFromChanged(Node * const
#ifndef NDEBUG
  node
#endif
) noexcept
{
  const bool verbose{false};
  if (verbose) { TRACE("Slot ribi::cmap::Edge::OnFromChanged"); }
  assert(node == this->GetFrom().get());
  if (verbose) { TRACE("Emitting ribi::cmap::Edge::m_signal_from_changed"); }
  this->m_signal_from_changed(this);
}

void ribi::cmap::Edge::OnToChanged(Node * const
#ifndef NDEBUG
  node
#endif
) noexcept
{
  const bool verbose{false};
  if (verbose) { TRACE("Slot ribi::cmap::Edge::OnFromChanged"); }

  assert(node == this->GetTo().get());
  if (verbose) { TRACE("Emitting ribi::cmap::Edge::m_signal_to_changed"); }

  this->m_signal_to_changed(this);
}

void ribi::cmap::Edge::SetNode(const NodePtr& node) noexcept
{
  assert(node);
  if (m_node != node)
  {
    m_node = node;
    m_signal_node_changed(this);
  }
}

/*
void ribi::cmap::Edge::SetFrom(const NodePtr& from) noexcept
{
  assert(from);
  if (m_from != from)
  {
    m_from = from;
    m_signal_from_changed(this);
  }
}
*/

void ribi::cmap::Edge::SetHeadArrow(const bool has_head_arrow) noexcept
{
  if (m_head_arrow != has_head_arrow)
  {
    m_head_arrow = has_head_arrow;
    m_signal_head_arrow_changed(this);
  }
}

void ribi::cmap::Edge::SetTailArrow(const bool has_tail_arrow) noexcept
{
  if (m_tail_arrow != has_tail_arrow)
  {
    m_tail_arrow = has_tail_arrow;
    m_signal_tail_arrow_changed(this);
  }
}

/*
void ribi::cmap::Edge::SetTo(const NodePtr& to) noexcept
{
  assert(to);
  if (m_to != to)
  {
    m_to = to;
    m_signal_to_changed(this);
  }
}
*/

#ifndef NDEBUG
void ribi::cmap::Edge::Test() noexcept
{
  {
    static bool is_tested{false};
    if (is_tested) return;
    is_tested = true;
  }
  const TestTimer test_timer(__func__,__FILE__,1.0);
  const bool verbose{false};
  const boost::shared_ptr<Node> from{NodeFactory().GetTest(0)};
  const boost::shared_ptr<Node> to{NodeFactory().GetTest(1)};
  const std::vector<boost::shared_ptr<Node>> nodes = {from,to};
  if (verbose) { TRACE("Operator=="); }
  {
    const auto edge1 = EdgeFactory().GetTest(0,from,to);
    const auto edge2 = EdgeFactory().GetTest(0,from,to);
    assert( edge1 !=  edge2);
    assert(*edge1 == *edge2);
  }
  if (verbose) { TRACE("Operator!="); }
  {
    const auto edge1 = EdgeFactory().GetTest(0,from,to);
    const auto edge2 = EdgeFactory().GetTest(1,from,to);
    assert( edge1 !=  edge2);
    assert(*edge1 != *edge2);
  }
  if (verbose) { TRACE("Deep copy"); }
  {
    const auto nodes = Node::GetTests();
    assert(nodes.size() >= 2);
    const auto node_from = nodes[0];
    const auto node_to   = nodes[1];
    const boost::shared_ptr<const Edge> edge{EdgeFactory().GetTest(0,node_from,node_to)};
    const boost::shared_ptr<const Edge> copy{EdgeFactory().DeepCopy(edge,node_from,node_to)};
    assert( edge !=  copy);
    assert(*edge == *copy);
  }
  if (verbose) { TRACE("Edge->XML->Edge must result in the same edge"); }
  {
    const auto edge_before = EdgeFactory().GetTest(0,from,to);
    const std::string s{ToXml(edge_before,AddConst(nodes))};
    const auto edge_after = EdgeFactory().FromXml(s,nodes);
    assert( edge_before !=  edge_after);
    assert(*edge_before == *edge_after);
  }
  if (verbose) { TRACE("When setting the name, a signal must be emitted"); }
  {
    const boost::shared_ptr<Edge> edge{EdgeFactory().GetTest(0,from,to)};
    edge->GetNode()->GetConcept()->SetName("A");
    Counter c{0}; //For receiving the signal
    edge->m_signal_node_changed.connect(
      boost::bind(&ribi::Counter::Inc,&c) //Do not forget the &
    );
    edge->GetNode()->GetConcept()->SetName("B");
    assert(c.Get() == 1);
  }
  if (verbose) { TRACE("If a Edge's head arrow is changed, a signal must be emitted"); }
  {
    const boost::shared_ptr<Edge> edge{EdgeFactory().GetTest(0,from,to)};
    Counter c{0}; //For receiving the signal
    edge->m_signal_head_arrow_changed.connect(
      boost::bind(&ribi::Counter::Inc,&c) //Do not forget the &
    );
    edge->SetHeadArrow(!edge->HasHeadArrow());
    assert(c.Get()==1);
  }
  //From
  if (verbose) { TRACE("If Edge its source/from is equal to the one given in the constructor"); }
  {
    const boost::shared_ptr<Edge> edge{EdgeFactory().GetTest(0,from,to)};
    assert(edge->GetFrom() == from);
    assert(edge->GetTo() == to);
  }
  if (verbose) { TRACE("If Edge its source/from is moved, a signal must be emitted"); }
  {
    const boost::shared_ptr<Edge> edge{EdgeFactory().GetTest(0,from,to)};
    Counter c{0}; //For receiving the signal
    edge->m_signal_from_changed.connect(
      boost::bind(&ribi::Counter::Inc,&c) //Do not forget the &
    );
    from->SetX(from->GetX() + 10.0);
    assert(c.Get() > 0);
  }
  if (verbose) { TRACE("If Edge its target/to is moved, a signal must be emitted"); }
  {
    const boost::shared_ptr<Edge> edge{EdgeFactory().GetTest(0,from,to)};
    Counter c{0}; //For receiving the signal
    edge->m_signal_to_changed.connect(
      boost::bind(&ribi::Counter::Inc,&c) //Do not forget the &
    );
    to->SetX(to->GetX() + 10.0);
    assert(c.Get() > 0);
  }
}
#endif

std::string ribi::cmap::Edge::ToStr() const noexcept
{

  std::stringstream s;
  s << (*this);
  return s.str();
}

std::string ribi::cmap::Edge::ToXml(
  const ReadOnlyEdgePtr& edge,
  const ReadOnlyNodes& nodes
) noexcept
{
  std::stringstream s;
  s << "<edge>";
  s << edge->GetNode()->GetConcept()->ToXml();

  const auto from_iter = std::find(nodes.begin(),nodes.end(),edge->GetFrom());
  const auto to_iter = std::find(nodes.begin(),nodes.end(),edge->GetTo());
  assert(from_iter != nodes.end());
  assert(to_iter != nodes.end());
  const int from_index = std::distance(nodes.begin(),from_iter);
  const int to_index = std::distance(nodes.begin(),to_iter);
  assert(from_index >= 0);
  assert(from_index < boost::numeric_cast<int>(nodes.size()));
  assert(to_index >= 0);
  assert(to_index < boost::numeric_cast<int>(nodes.size()));
  assert(from_index != to_index);

  s << "<from>" << from_index << "</from>";
  s << "<head_arrow>" << edge->HasHeadArrow() << "</head_arrow>";
  s << "<tail_arrow>" << edge->HasTailArrow() << "</tail_arrow>";
  s << "<to>" << to_index << "</to>";
  s << "<x>" << edge->GetNode()->GetX() << "</x>";
  s << "<y>" << edge->GetNode()->GetY() << "</y>";
  s << "</edge>";

  const std::string r = s.str();
  assert(r.size() >= 13);
  assert(r.substr(0,6) == "<edge>");
  assert(r.substr(r.size() - 7,7) == "</edge>");

  return r;
}

bool ribi::cmap::IsConnectedToCenterNode(const boost::shared_ptr<const Edge> edge) noexcept
{
  assert(!(IsCenterNode(edge->GetFrom()) && IsCenterNode(edge->GetTo()))
    && "An Edge cannot be connected to two CenterNodes");
  return IsCenterNode(edge->GetFrom()) || IsCenterNode(edge->GetTo());

}


bool ribi::cmap::operator==(const ribi::cmap::Edge& lhs, const ribi::cmap::Edge& rhs)
{
  const bool verbose{false};
  assert(lhs.GetNode()); assert(rhs.GetNode());
  if (verbose)
  {
    if (*lhs.GetNode()      != *rhs.GetNode()) TRACE("Node differs");
    if (*lhs.GetFrom()      != *rhs.GetFrom()) TRACE("From node differs");
    if (*lhs.GetTo()        != *rhs.GetTo()) TRACE("To node differs");
    if ( lhs.HasHeadArrow() != rhs.HasHeadArrow()) TRACE("Has head arrow differs");
    if ( lhs.HasTailArrow() != rhs.HasTailArrow()) TRACE("Has tail arrow differs");
  }
  return
       *lhs.GetNode()   == *rhs.GetNode()
    && *lhs.GetFrom()      == *rhs.GetFrom()
    && *lhs.GetTo()        == *rhs.GetTo()
    &&  lhs.HasHeadArrow() == rhs.HasHeadArrow()
    &&  lhs.HasTailArrow() == rhs.HasTailArrow()
  ;
}

bool ribi::cmap::operator!=(const cmap::Edge& lhs, const cmap::Edge& rhs)
{
  return !(lhs == rhs);
}

std::ostream& ribi::cmap::operator<<(std::ostream& os, const Edge& edge) noexcept
{
  os << (*edge.GetNode())
    << ", from: " << edge.GetFrom()
    << "(arrowhead: " << edge.HasHeadArrow()
    << "), to: " << edge.GetTo()
    << "(arrowhead: " << edge.HasTailArrow()
    << ")"
  ;

  return os;
}

 

 

 

 

 

./CppConceptMap/conceptmapedgefactory.h

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#ifndef CONCEPTMAPEDGEFACTORY_H
#define CONCEPTMAPEDGEFACTORY_H

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#include <boost/shared_ptr.hpp>

#include "conceptmapfwd.h"
#pragma GCC diagnostic pop

namespace ribi {
namespace cmap {

struct EdgeFactory
{
  EdgeFactory() noexcept;

  typedef boost::shared_ptr<Edge> EdgePtr;
  typedef boost::shared_ptr<const Edge> ReadOnlyEdge;
  typedef boost::shared_ptr<Node> NodePtr;
  typedef boost::shared_ptr<const Node> ReadOnlyNode;
  typedef std::vector<EdgePtr> Edges;
  typedef std::vector<NodePtr> Nodes;

  EdgePtr Create(
    const NodePtr& from,
    const NodePtr& to
  ) const noexcept;

  EdgePtr Create(
    const NodePtr& node,
    const NodePtr& from,
    const bool tail_arrow,
    const NodePtr& to,
    const bool head_arrow
  ) const noexcept;

  #ifndef NDEBUG
  ///DeepCopy is only used for debugging
  ///The nodes need to be the deepcopied ones
  EdgePtr DeepCopy(
    const ReadOnlyEdge& edge,
    const NodePtr& from,
    const NodePtr& to
  ) const noexcept;
  #endif

  ///Obtain an Edge from an XML std::string
  ///You need the real nodes to connect the edge to
  EdgePtr FromXml(
    const std::string& s,
    const Nodes& nodes
  ) const noexcept;


  int GetNumberOfTests() const noexcept;

  EdgePtr GetTest(
    const int index,
    const NodePtr& from,
    const NodePtr& to
) const noexcept;

  ///Get testing edges connecting the two supplied nodes
  Edges GetTests(
    const NodePtr& from,
    const NodePtr& to
  ) const noexcept;

  private:

  #ifndef NDEBUG
  static void Test() noexcept;
  #endif
};

} //~namespace cmap
} //~namespace ribi

#endif // CONCEPTMAPEDGEFACTORY_H

 

 

 

 

 

./CppConceptMap/conceptmapedgefactory.cpp

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#include "conceptmapedgefactory.h"

#include <cassert>
#include <boost/lexical_cast.hpp>

#include "conceptmapconcept.h"
#include "conceptmapconceptfactory.h"
#include "conceptmapedge.h"
#include "conceptmapedgefactory.h"
#include "conceptmaphelper.h"
#include "conceptmapnode.h"
#include "conceptmapnodefactory.h"
#include "conceptmapregex.h"
#include "testtimer.h"
#include "trace.h"
#include "xml.h"
#pragma GCC diagnostic pop

ribi::cmap::EdgeFactory::EdgeFactory() noexcept
{
  #ifndef NDEBUG
  Test();
  #endif
}


ribi::cmap::EdgeFactory::EdgePtr ribi::cmap::EdgeFactory::Create(
  const NodePtr& from,
  const NodePtr& to
) const noexcept
{
  assert(from);
  assert(to);
  assert(from != to);
  const double x{(from->GetX() + to->GetX()) / 2.0};
  const double y{(from->GetY() + to->GetY()) / 2.0};
  const bool tail_arrow{false};
  const bool head_arrow{true};
  const auto concept = ConceptFactory().Create();
  assert(concept->GetExamples());

  const auto node = NodeFactory().Create(concept,x,y);
  assert(node);
  const EdgePtr p {
    new Edge(
      node,
      from,
      tail_arrow,
      to,
      head_arrow
    )
  };
  assert(p);
  return p;
}

ribi::cmap::EdgeFactory::EdgePtr ribi::cmap::EdgeFactory::Create(
  const NodePtr& node,
  const NodePtr& from,
  const bool tail_arrow,
  const NodePtr& to,
  const bool head_arrow
) const noexcept
{
  assert(node);
  assert(node->GetConcept());
  assert(node->GetConcept()->GetExamples());
  assert(from);
  assert(to);
  assert(from != to);
  EdgePtr p(new Edge(node,from,tail_arrow,to,head_arrow));
  assert(p);
  return p;
}

#ifndef NDEBUG
ribi::cmap::EdgeFactory::EdgePtr ribi::cmap::EdgeFactory::DeepCopy(
  const ReadOnlyEdge& edge,
  const NodePtr& from,
  const NodePtr& to
) const noexcept
{
  assert(edge);
  assert(edge->GetNode());
  assert(edge->GetNode()->GetConcept());
  assert(edge->GetNode()->GetConcept()->GetExamples());
  assert(from);
  assert(to);
  assert(from != to);
  //const boost::shared_ptr<Concept> concept = ConceptFactory().DeepCopy(edge->GetNode());
  const auto node = NodeFactory().DeepCopy(edge->GetNode());
  assert(node);
  const EdgePtr p {
    EdgeFactory::Create(
      node,
      from,
      edge->HasTailArrow(),
      to,
      edge->HasHeadArrow()
    )
  };
  assert(p);
  assert(*edge == *p);
  return p;
}
#endif

ribi::cmap::EdgeFactory::EdgePtr ribi::cmap::EdgeFactory::FromXml(
  const std::string& s,
  const Nodes& nodes
) const noexcept
{
  assert(s.size() >= 13);
  assert(s.substr(0,6) == "<edge>");
  assert(s.substr(s.size() - 7,7) == "</edge>");
  //m_concept
  boost::shared_ptr<Concept> concept;
  {
    const std::vector<std::string> v
      = Regex().GetRegexMatches(s,Regex().GetRegexConcept());
    assert(v.size() == 1);
    concept = ConceptFactory().FromXml(v[0]);
  }
  //m_from
  int from = -1;
  {
    const std::vector<std::string> v
      = Regex().GetRegexMatches(s,Regex().GetRegexFrom());
    assert(v.size() == 1);
    from = boost::lexical_cast<int>(ribi::xml::StripXmlTag(v[0]));
  }
  //m_head_arrow
  bool head_arrow = false;
  {
    const std::vector<std::string> v
      = Regex().GetRegexMatches(s,Regex().GetRegexHeadArrow());
    assert(v.size() == 1);
    head_arrow = boost::lexical_cast<bool>(ribi::xml::StripXmlTag(v[0]));
  }
  //m_tail_arrow
  bool tail_arrow = false;
  {
    const std::vector<std::string> v
      = Regex().GetRegexMatches(s,Regex().GetRegexTailArrow());
    assert(v.size() == 1);
    tail_arrow = boost::lexical_cast<bool>(ribi::xml::StripXmlTag(v[0]));
  }
  //m_to
  int to = -1;
  {
    const std::vector<std::string> v
      = Regex().GetRegexMatches(s,Regex().GetRegexTo());
    assert(v.size() == 1);
    to = boost::lexical_cast<int>(ribi::xml::StripXmlTag(v[0]));
  }
  //m_x
  double x = 0.0;
  {
    const std::vector<std::string> v
      = Regex().GetRegexMatches(s,Regex().GetRegexX());
    assert(v.size() == 1);
    x = boost::lexical_cast<double>(ribi::xml::StripXmlTag(v[0]));
  }
  //m_y
  double y = 0.0;
  {
    const std::vector<std::string> v
      = Regex().GetRegexMatches(s,Regex().GetRegexY());
    assert(v.size() == 1);
    y = boost::lexical_cast<double>(ribi::xml::StripXmlTag(v[0]));
  }
  assert(from != to);
  assert(from < boost::numeric_cast<int>(nodes.size()));
  assert(to   < boost::numeric_cast<int>(nodes.size()));
  const auto node = NodeFactory().Create(concept,x,y);
  const EdgePtr edge(new Edge(node,nodes[from],tail_arrow,nodes[to],head_arrow));
  assert(edge);
  return edge;
}

int ribi::cmap::EdgeFactory::GetNumberOfTests() const noexcept
{
  return ConceptFactory().GetNumberOfTests();
}

ribi::cmap::EdgeFactory::EdgePtr ribi::cmap::EdgeFactory::GetTest(
  const int index,
  const NodePtr& from,
  const NodePtr& to
) const noexcept
{
  assert(from);
  assert(to);
  assert(index >= 0);
  assert(index < GetNumberOfTests());
  return GetTests(from,to)[index];
}

ribi::cmap::EdgeFactory::Edges ribi::cmap::EdgeFactory::GetTests(
  const NodePtr& from,
  const NodePtr& to
) const noexcept
{
  assert(from);
  assert(to);
  const int n{NodeFactory().GetNumberOfTests()};
  std::vector<EdgePtr> result;

  for(int i{0}; i!=n; ++i)
  {
    {
      const auto node = NodeFactory().GetTest(i);
      const EdgePtr edge{new Edge(node,from,false,to,true)};
      result.push_back(edge);
    }
    /*
    {
      const EdgePtr edge(new Edge(concept,0,2,true));
      result.push_back(edge);
    }
    {
      const EdgePtr edge(new Edge(concept,0,3,true));
      result.push_back(edge);
    }
    {
      const EdgePtr edge(new Edge(concept,1,2,false));
      result.push_back(edge);
    }
    {
      const EdgePtr edge(new Edge(concept,1,3,false));
      result.push_back(edge);
    }
    {
      const EdgePtr edge(new Edge(concept,2,3,false));
      result.push_back(edge);
    }
    */
  }
  if (GetNumberOfTests() != static_cast<int>(result.size()))
  {
    TRACE("ERROR");
    std::stringstream s;
    s << "GetNumberOfTests should return " << result.size();
    TRACE(s.str());
  }
  assert(GetNumberOfTests() == static_cast<int>(result.size()));
  return result;
}


#ifndef NDEBUG
void ribi::cmap::EdgeFactory::Test() noexcept
{
  {
    static bool is_tested{false};
    if (is_tested) return;
    is_tested = true;
  }
  EdgeFactory().GetTest(
     0,
     NodeFactory().GetTest(0),
     NodeFactory().GetTest(0)
  );
  const TestTimer test_timer(__func__,__FILE__,1.0);
}
#endif // NDEBUG

 

 

 

 

 

./CppConceptMap/conceptmapelement.h

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#ifndef CONCEPTMAPELEMENT_H
#define CONCEPTMAPELEMENT_H

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#include "conceptmapfwd.h"
#pragma GCC diagnostic pop

namespace ribi {
namespace cmap {

///A focusable element of a concept map, which is either a Node or an Edge
struct Element
{
  Element() {}
  virtual ~Element() noexcept {}
};

} //~namespace cmap
} //~namespace ribi

#endif // CONCEPTMAPELEMENT_H

 

 

 

 

 

./CppConceptMap/conceptmapelement.cpp

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#include "conceptmapelement.h"

 

 

 

 

 

./CppConceptMap/conceptmapexample.h

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#ifndef CONCEPTMAPEXAMPLE_H
#define CONCEPTMAPEXAMPLE_H

#include <string>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#include <boost/make_shared.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/signals2.hpp>
#include "conceptmapcompetency.h"
#pragma GCC diagnostic pop

namespace ribi {
namespace cmap {

struct ExampleFactory;

///A concept (on a node or an edge) can have examples
///Example is displayed by:
/// - QtExampleDialog
struct Example
{
  Example(const Example&) = delete;
  Example& operator=(const Example&) = delete;

  ///Convert a cmap::Competency to a std::string
  //static std::string CompetencyToStr(const Competency competency) noexcept;

  ///Get the competency, as might be judged by an assessor
  Competency GetCompetency() const noexcept { return m_competency; }

  ///Has an assessor rated this example as being an addition to the complexity?
  bool GetIsComplex() const noexcept { return m_is_complex; }

  ///Has an assessor rated this example as being an addition to the concreteness?
  bool GetIsConcrete() const noexcept { return m_is_concrete; }

  ///Has an assessor rated this example as being an addition to the specificity?
  bool GetIsSpecific() const noexcept { return m_is_specific; }

  ///Get the text of the example
  const std::string& GetText() const noexcept { return m_text; }

  ///Set the competency
  void SetCompetency(const cmap::Competency competency) noexcept;

  ///Has an assessor rated this example as being an addition to the complexity?
  void SetIsComplex(const bool is_complex) noexcept;

  ///Has an assessor rated this example as being an addition to the concreteness?
  void SetIsConcrete(const bool is_concrete) noexcept;

  ///Has an assessor rated this example as being an addition to the specificity?
  void SetIsSpecific(const bool is_specific) noexcept;

  ///Set the text
  void SetText(const std::string& text) noexcept;

  ///Convert a std::string to a cmap::Competency
  static Competency StrToCompetency(const std::string& s);

  #ifndef NDEBUG
  ///Test this class
  static void Test() noexcept;
  #endif

  ///Convert Example to a short std::string
  std::string ToStr() const noexcept;

  ///Convert Example to an XML std::string
  std::string ToXml() const noexcept;

  ///Emitted when SetCompetency changes the competency
  boost::signals2::signal<void(Example*)> m_signal_competency_changed;

  ///Emitted when m_is_complex is changed
  boost::signals2::signal<void(Example*)> m_signal_is_complex_changed;

  ///Emitted when m_is_concrete is changed
  boost::signals2::signal<void(Example*)> m_signal_is_concrete_changed;

  ///Emitted when m_is_specific is changed
  boost::signals2::signal<void(Example*)> m_signal_is_specific_changed;

  ///Emitted when SetText changes the text
  boost::signals2::signal<void(Example*)> m_signal_text_changed;

private:

  ///The competency, as might be judged by an assessor
  Competency m_competency;

  ///Has an assessor rated this example as being an addition to the complexity?
  bool m_is_complex;

  ///Has an assessor rated this example as being an addition to the concreteness?
  bool m_is_concrete;

  ///Has an assessor rated this example as being an addition to the specificity?
  bool m_is_specific;

  ///The text of the example
  ///For example: 'Plato', 'When I was a kid', 'As I did on holiday'
  std::string m_text;

  ///Set the competency with a string
  void SetCompetencyAsStr(const std::string& s) const;

  ///Use checked_delete only
  ~Example() {}
  friend void boost::checked_delete<>(Example* x);
  friend void boost::checked_delete<>(const Example* x);
  friend class boost::detail::sp_ms_deleter<      Example>;
  friend class boost::detail::sp_ms_deleter<const Example>;

  ///Only let ExampleFactory create Example instances
  explicit Example(
    const ExampleFactory& example_factory, //To enforce its use
    const std::string& text,
    const cmap::Competency competency = cmap::Competency::uninitialized,
    const bool is_complex = true,
    const bool is_concrete = true,
    const bool is_specific = true
  );
  friend class ExampleFactory;
};

bool operator==(const Example& lhs, const Example& rhs) noexcept;
bool operator!=(const Example& lhs, const Example& rhs) noexcept;

bool operator<(const Example& lhs,const Example& rhs) noexcept;
bool operator>(const Example& lhs,const Example& rhs) noexcept;

bool operator<(const boost::shared_ptr<const Example>& lhs,const boost::shared_ptr<const Example>& rhs) = delete;
bool operator<(const boost::shared_ptr<const Example>& lhs,const boost::shared_ptr<Example>& rhs) = delete;
bool operator<(const boost::shared_ptr<Example>& lhs,const boost::shared_ptr<Example>& rhs) = delete;
bool operator<(const boost::shared_ptr<Example>& lhs,const boost::shared_ptr<const Example>& rhs) = delete;
bool operator>(const boost::shared_ptr<const Example>& lhs,const boost::shared_ptr<const Example>& rhs) = delete;
bool operator>(const boost::shared_ptr<const Example>& lhs,const boost::shared_ptr<Example>& rhs) = delete;
bool operator>(const boost::shared_ptr<Example>& lhs,const boost::shared_ptr<const Example>& rhs) = delete;
bool operator>(const boost::shared_ptr<Example>& lhs,const boost::shared_ptr<Example>& rhs) = delete;

} //~namespace cmap
} //~namespace ribi

#endif // CONCEPTMAPEXAMPLE_H

 

 

 

 

 

./CppConceptMap/conceptmapexample.cpp

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#include "conceptmapexample.h"

#include <cassert>
#include <stdexcept>
#include <sstream>

#include <boost/lexical_cast.hpp>
#include <QRegExp>

#include "counter.h"
#include "conceptmapregex.h"
#include "conceptmapcompetencies.h"
#include "conceptmapcompetency.h"
#include "conceptmapexample.h"
#include "conceptmapexamplefactory.h"
#include "conceptmaphelper.h"
#include "ribi_regex.h"
#include "testtimer.h"
#include "trace.h"
#include "xml.h"
#pragma GCC diagnostic pop

ribi::cmap::Example::Example(
  const ExampleFactory&,
  const std::string& text,
  const cmap::Competency competency,
  const bool is_complex,
  const bool is_concrete,
  const bool is_specific
  )
  : m_signal_competency_changed{},
    m_signal_is_complex_changed{},
    m_signal_is_concrete_changed{},
    m_signal_is_specific_changed{},
    m_signal_text_changed{},
    m_competency(competency),
    m_is_complex(is_complex),
    m_is_concrete(is_concrete),
    m_is_specific(is_specific),
    m_text(text)
{
  #ifndef NDEBUG
  Test();
  #endif
}

/*
std::string ribi::cmap::Example::CompetencyToStr(const cmap::Competency competency) noexcept
{
  switch (competency)
  {
    case cmap::Competency::uninitialized: return "uninitialized";
    case cmap::Competency::profession: return "profession";
    case cmap::Competency::organisations: return "organisations";
    case cmap::Competency::social_surroundings: return "social_surroundings";
    case cmap::Competency::target_audience: return "target_audience";
    case cmap::Competency::ti_knowledge: return "ti_knowledge";
    case cmap::Competency::prof_growth: return "prof_growth";
    case cmap::Competency::misc: return "misc";
  }
  assert(!"Should not get here");
  throw std::logic_error("ribi::cmap::Example::CompetencyToStr: unknown Competency");
}
*/

void ribi::cmap::Example::SetCompetency(const Competency competency) noexcept
{
  const bool verbose{false};
  const Competency competency_before = m_competency;
  const Competency competency_after  =   competency;
  if (competency_before != competency_after)
  {
    assert(m_competency == competency_before);

    if (verbose)
    {
      std::stringstream s;
      s << "Example will change Competency from " << Competencies().ToStr(competency_before)
        << " to " << Competencies().ToStr(competency_after);
      TRACE(s.str());
    }

    m_competency = competency;

    assert(m_competency == competency_after);

    m_signal_competency_changed(this);

    assert(m_competency == competency_after);
    if (verbose)
    {
      std::stringstream s;
      s << "Competency changed to " << Competencies().ToStr(m_competency);
      TRACE(s.str());
    }
  }
}

void ribi::cmap::Example::SetIsComplex(const bool is_complex) noexcept
{
  if (m_is_complex != is_complex)
  {
    m_is_complex = is_complex;
    m_signal_is_complex_changed(this);
  }
}

void ribi::cmap::Example::SetIsConcrete(const bool is_concrete) noexcept
{
  if (m_is_concrete != is_concrete)
  {
    m_is_concrete = is_concrete;
    m_signal_is_concrete_changed(this);
  }
}

void ribi::cmap::Example::SetIsSpecific(const bool is_specific) noexcept
{
  if (m_is_specific != is_specific)
  {
    m_is_specific = is_specific;
    m_signal_is_specific_changed(this);
  }
}

void ribi::cmap::Example::SetText(const std::string& text) noexcept
{
  if (m_text != text)
  {
    m_text = text;
    m_signal_text_changed(this);
  }
}

ribi::cmap::Competency ribi::cmap::Example::StrToCompetency(const std::string& s)
{
  if (s == "uninitialized") return cmap::Competency::uninitialized;
  if (s == "profession") return cmap::Competency::profession;
  if (s == "organisations") return cmap::Competency::organisations;
  if (s == "social_surroundings") return cmap::Competency::social_surroundings;
  if (s == "target_audience") return cmap::Competency::target_audience;
  if (s == "ti_knowledge") return cmap::Competency::ti_knowledge;
  if (s == "prof_growth") return cmap::Competency::prof_growth;
  if (s == "misc") return cmap::Competency::misc;
  assert(!"Should not get here");
  throw std::logic_error("ribi::cmap::Example::StrToCompetency: unknown string");
}

#ifndef NDEBUG
void ribi::cmap::Example::Test() noexcept
{
  {
    static bool is_tested{false};
    if (is_tested) return;
    is_tested = true;
  }
  ribi::Regex();
  ribi::cmap::Regex();
  Counter();
  const TestTimer test_timer(__func__,__FILE__,1.0);
  const bool verbose{false};


  if (verbose) { TRACE("Set and get must be symmetric"); }
  {
    const Competency competency_before = Competency::uninitialized;
    const Competency competency_after = Competency::misc;
    const bool is_complex_before  = false;
    const bool is_complex_after   = true;
    const bool is_concrete_before = true;
    const bool is_concrete_after  = false;
    const bool is_specific_before = true;
    const bool is_specific_after  = false;
    const std::string text_before = "before";
    const std::string text_after  = "after";

    auto example  = ExampleFactory().Create(
      text_before,
      competency_before,
      is_complex_before,
      is_concrete_before,
      is_specific_before
    );
    assert(example->GetCompetency() == competency_before);
    assert(example->GetCompetency() != competency_after);
    assert(example->GetIsComplex() == is_complex_before);
    assert(example->GetIsComplex() != is_complex_after);
    assert(example->GetIsConcrete() == is_concrete_before);
    assert(example->GetIsConcrete() != is_concrete_after);
    assert(example->GetIsSpecific() == is_specific_before);
    assert(example->GetIsSpecific() != is_specific_after);
    assert(example->GetText() == text_before);
    assert(example->GetText() != text_after);

    example->SetCompetency(competency_after);
    example->SetIsComplex(is_complex_after);
    example->SetIsConcrete(is_concrete_after);
    example->SetIsSpecific(is_specific_after);
    example->SetText(text_after);

    assert(example->GetCompetency() != competency_before);
    assert(example->GetCompetency() == competency_after);
    assert(example->GetIsComplex() != is_complex_before);
    assert(example->GetIsComplex() == is_complex_after);
    assert(example->GetIsConcrete() != is_concrete_before);
    assert(example->GetIsConcrete() == is_concrete_after);
    assert(example->GetIsSpecific() != is_specific_before);
    assert(example->GetIsSpecific() == is_specific_after);
    assert(example->GetText() != text_before);
    assert(example->GetText() == text_after);
  }
  if (verbose) { TRACE("Test of operator== and operator!="); }
  {
    const int sz = ExampleFactory().GetNumberOfTests();
    for (int i=0; i!=sz; ++i)
    {
      boost::shared_ptr<const Example> a = ExampleFactory().GetTest(i);
      boost::shared_ptr<      Example> b = ExampleFactory().GetTest(i);
      assert(*a == *a);
      assert(*a == *b);
      assert(*b == *a);
      assert(*b == *b);
      for (int j=0; j!=sz; ++j)
      {
        boost::shared_ptr<const Example> c = ExampleFactory().GetTest(j);
        boost::shared_ptr<      Example> d = ExampleFactory().GetTest(j);
        assert(*c == *c);
        assert(*c == *d);
        assert(*d == *c);
        assert(*d == *d);
        if (i==j)
        {
          assert(*a == *c); assert(*a == *d);
          assert(*b == *c); assert(*b == *d);
          assert(*c == *a); assert(*c == *b);
          assert(*d == *a); assert(*d == *b);
        }
        else
        {
          assert(*a != *c); assert(*a != *d);
          assert(*b != *c); assert(*b != *d);
          assert(*c != *a); assert(*c != *b);
          assert(*d != *a); assert(*d != *b);
        }
      }
    }
  }
  if (verbose) { TRACE("Unrated and rated examples must be noticed as different"); }
  {
    const boost::shared_ptr<Example> a = ExampleFactory().Create("1",Competency::misc);
    const boost::shared_ptr<Example> b = ExampleFactory().Create("1",Competency::misc);
    const boost::shared_ptr<Example> c = ExampleFactory().Create("1",Competency::uninitialized);
    assert(*a == *a); assert(*a == *b); assert(*a != *c);
    assert(*b == *a); assert(*b == *b); assert(*b != *c);
    assert(*c != *a); assert(*c != *b); assert(*c == *c);
  }
  //Conversion between std::string and competency
  //Checked by Competencies

  if (verbose) { TRACE("Conversion from class->XML->class must result in something equal to the class"); }
  {
    const std::vector<boost::shared_ptr<const Example>> v = AddConst(ExampleFactory().GetTests());
    std::for_each(v.begin(),v.end(),
      [](const boost::shared_ptr<const Example>& e)
      {
        assert(e);
        const std::string s { e->ToXml() };
        const boost::shared_ptr<const Example> f(ExampleFactory().FromXml(s));
        assert(*e == *f);
      }
    );
  }
  if (verbose) { TRACE("Conversion from class->XML->class must differ between classes"); }
  {
    const auto v = AddConst(ExampleFactory().GetTests());
    const int sz = boost::numeric_cast<int>(v.size());
    for (int i=0; i!=sz; ++i)
    {
      const boost::shared_ptr<const Example>& e = v[i];
      const std::string s { e->ToXml() };
      for (int j=0; j!=sz; ++j)
      {
        const boost::shared_ptr<const Example>& f = v[j];
        const std::string t = f->ToXml();
        if (i == j)
        {
          assert(*e == *f);
          assert(s == t);
        }
        else
        {
          assert(*e != *f);
          assert( s !=  t);
        }
      }
    }
  }
  if (verbose) { TRACE("When setting the competency, a signal must be emitted"); }
  {
    const auto example = ExampleFactory().GetTest(0);
    example->SetCompetency(Competency::uninitialized);
    Counter c{0}; //For receiving the signal
    example->m_signal_competency_changed.connect(
      boost::bind(&ribi::Counter::Inc,&c) //Do not forget the &
    );
    example->SetCompetency(Competency::misc);
    assert(c.Get() == 1);
  }
  if (verbose) { TRACE("When setting the text, a signal must be emitted"); }
  {
    const auto example = ExampleFactory().GetTest(0);
    example->SetText("A");
    Counter c{0}; //For receiving the signal
    example->m_signal_text_changed.connect(
      boost::bind(&ribi::Counter::Inc,&c) //Do not forget the &
    );
    example->SetText("B");
    assert(c.Get() == 1);
  }
}
#endif

std::string ribi::cmap::Example::ToStr() const noexcept
{
  std::stringstream s;
  s
    << GetText() << " "
    << Competencies().ToStr(GetCompetency()) << " "
    << GetIsComplex() << " "
    << GetIsConcrete() << " "
    << GetIsSpecific()
  ;
  return s.str();

}

std::string ribi::cmap::Example::ToXml() const noexcept
{
  std::stringstream s;
  s << "<example>";
  s <<   "<text>";
  s <<     GetText();
  s <<   "</text>";
  s <<   "<competency>";
  s << Competencies().ToStr(GetCompetency());
  //s <<     CompetencyToStr(GetCompetency());
  s <<   "</competency>";
  s <<   "<is_complex>";
  s <<     GetIsComplex();
  s <<   "</is_complex>";
  s <<   "<is_concrete>";
  s <<     GetIsConcrete();
  s <<   "</is_concrete>";
  s <<   "<is_specific>";
  s <<     GetIsSpecific();
  s <<   "</is_specific>";
  s << "</example>";

  const std::string r = s.str();
  assert(r.size() >= 17);
  assert(r.substr(0,9) == "<example>");
  assert(r.substr(r.size() - 10,10) == "</example>");
  return r;
}

bool ribi::cmap::operator==(const cmap::Example& lhs, const cmap::Example& rhs) noexcept
{
  return
       lhs.GetText() == rhs.GetText()
    && lhs.GetCompetency() == rhs.GetCompetency();
}

bool ribi::cmap::operator!=(const cmap::Example& lhs, const cmap::Example& rhs) noexcept
{
  return !(lhs == rhs);
}

bool ribi::cmap::operator<(const cmap::Example& lhs,const cmap::Example& rhs) noexcept
{
  if (lhs.GetText() < rhs.GetText()) return true;
  if (lhs.GetText() > rhs.GetText()) return false;
  return lhs.GetCompetency() < rhs.GetCompetency();
}

bool ribi::cmap::operator>(const cmap::Example& lhs,const cmap::Example& rhs) noexcept
{
  if (lhs.GetText() > rhs.GetText()) return true;
  if (lhs.GetText() < rhs.GetText()) return false;
  return lhs.GetCompetency() > rhs.GetCompetency();
}

 

 

 

 

 

./CppConceptMap/conceptmapexamplefactory.h

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#ifndef CONCEPTMAPEXAMPLEFACTORY_H
#define CONCEPTMAPEXAMPLEFACTORY_H

#include <vector>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#include <boost/shared_ptr.hpp>
#include "conceptmapcompetency.h"
#include "conceptmapexample.h"
#include "conceptmapexamples.h"
#pragma GCC diagnostic pop

namespace ribi {
namespace cmap {

struct ExampleFactory
{
  ExampleFactory() noexcept;

  ///Create an example from string and enum
  boost::shared_ptr<cmap::Example> Create(
    const std::string& text,
    const cmap::Competency& competency,
    const bool is_complex = true,
    const bool is_concrete = true,
    const bool is_specific = true
  ) const noexcept;

  ///Create examples for strings
  ///Note that all cmap::Competency values are set to uninitialized
  //static const std::vector<boost::shared_ptr<cmap::Example> > CreateExamples(const std::vector<std::string>& v);

  ///Create an example from XML
  boost::shared_ptr<Example> FromXml(const std::string& s) const noexcept;

  int GetNumberOfTests() const noexcept { return static_cast<int>(GetTests().size()); }
  boost::shared_ptr<Example> GetTest(const int i) const noexcept;
  std::vector<boost::shared_ptr<Example>> GetTests() const noexcept;

  private:

  #ifndef NDEBUG
  static void Test() noexcept;
  #endif // NDEBUG
};

} //~namespace cmap
} //~namespace ribi

#endif // CONCEPTMAPEXAMPLEFACTORY_H

 

 

 

 

 

./CppConceptMap/conceptmapexamplefactory.cpp

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#include "conceptmapexamplefactory.h"

#include <cassert>

//#include <boost/lexical_cast.hpp>
//#include <boost/make_shared.hpp>

#include "conceptmaphelper.h"
#include "counter.h"
#include "conceptmapexample.h"
#include "conceptmapregex.h"
#include "testtimer.h"
#include "trace.h"
#include "xml.h"
#pragma GCC diagnostic pop

ribi::cmap::ExampleFactory::ExampleFactory() noexcept
{
  #ifndef NDEBUG
  Test();
  #endif
}

boost::shared_ptr<ribi::cmap::Example> ribi::cmap::ExampleFactory::Create(
  const std::string& text,
  const cmap::Competency& competency,
  const bool is_complex,
  const bool is_concrete,
  const bool is_specific
) const noexcept
{
  boost::shared_ptr<Example> example(
    new Example(
      *this,
      text,
      competency,
      is_complex,
      is_concrete,
      is_specific
    )
  );
  assert(example);
  return example;
}

boost::shared_ptr<ribi::cmap::Example> ribi::cmap::ExampleFactory::FromXml(const std::string& s) const noexcept
{
  assert(s.size() >= 17);
  assert(s.substr(0,9) == "<example>");
  assert(s.substr(s.size() - 10,10) == "</example>");

  std::string text;
  cmap::Competency competency = cmap::Competency::uninitialized;
  bool is_complex = false;
  bool is_concrete = false;
  bool is_specific = false;

  //competency
  {
    const std::vector<std::string> v
      = Regex().GetRegexMatches(s,Regex().GetRegexCompetency());
    assert(v.size() == 1);
    competency = Example::StrToCompetency(ribi::xml::StripXmlTag(v[0]));
  }
  //is_complex
  {
    const std::vector<std::string> v
      = Regex().GetRegexMatches(s,Regex().GetRegexIsComplex());
    assert(v.size() == 1);
    is_complex = boost::lexical_cast<bool>(ribi::xml::StripXmlTag(v[0]));
  }
  //is_concrete
  {
    const std::vector<std::string> v
      = Regex().GetRegexMatches(s,Regex().GetRegexIsConcrete());
    assert(v.size() == 1);
    is_concrete = boost::lexical_cast<bool>(ribi::xml::StripXmlTag(v[0]));
  }
  //is_specific
  {
    const std::vector<std::string> v
      = Regex().GetRegexMatches(s,Regex().GetRegexIsSpecific());
    assert(v.size() == 1);
    is_specific = boost::lexical_cast<bool>(ribi::xml::StripXmlTag(v[0]));
  }
  //text
  {
    const std::vector<std::string> v
      = Regex().GetRegexMatches(s,Regex().GetRegexText());
    assert(v.size() == 1 && "GetRegexText must be present once in an Example");
    text = ribi::xml::StripXmlTag(v[0]);
  }

  const boost::shared_ptr<Example> example
    = Create(text,competency,is_complex,is_concrete,is_specific)
  ;
  assert(example);
  assert(example->ToXml() == s);
  return example;
}

boost::shared_ptr<ribi::cmap::Example> ribi::cmap::ExampleFactory::GetTest(const int i) const noexcept
{
  assert(i < GetNumberOfTests());
  return GetTests()[i];
}

std::vector<boost::shared_ptr<ribi::cmap::Example>> ribi::cmap::ExampleFactory::GetTests() const noexcept
{
  return
  {
    Create("Test example 0",Competency::profession,true,false,false),
    Create("Test example 1",Competency::organisations,false,true,false),
    Create("Test example 2",Competency::social_surroundings,false,false,true),
    Create("Test example 3",Competency::target_audience,true,true,false),
    Create("Test example 4",Competency::ti_knowledge,false,true,true),
    Create("Test example 5",Competency::prof_growth,true,false,true),
    Create("Test example 6",Competency::misc,true,true,true),
    Create("",Competency::uninitialized,true,false,true),
  };
}

#ifndef NDEBUG
void ribi::cmap::ExampleFactory::Test() noexcept
{
  {
    static bool is_tested{false};
    if (is_tested) return;
    is_tested = true;
  }
  Counter();
  Example(ExampleFactory(),"Test example 0",Competency::profession,true,false,false);
  ExampleFactory().GetTest(0);
  const TestTimer test_timer(__func__,__FILE__,1.0);
}
#endif // NDEBUG

 

 

 

 

 

./CppConceptMap/conceptmapexamples.h

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#ifndef CONCEPTMAPEXAMPLES_H
#define CONCEPTMAPEXAMPLES_H

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#include <boost/shared_ptr.hpp>
#include <boost/signals2.hpp>
#include "conceptmapfwd.h"
#pragma GCC diagnostic pop

namespace ribi {
namespace cmap {

///Container of Example instances
///Examples is displayed by
/// - ?QtExamplesItem: a QGraphicsItem, to be used in a QGraphicsView
/// - QtExamplesDialog: a QDialog
struct Examples
{
  explicit Examples(const std::vector<boost::shared_ptr<cmap::Example> >& v);
  Examples(const Example& rhs) = delete;
  Examples& operator=(const Example& rhs) = delete;


  std::vector<boost::shared_ptr<Example>>& Get() noexcept { return m_v; }
  std::vector<boost::shared_ptr<const Example>> Get() const noexcept;

  std::string ToStr() const noexcept;
  std::string ToXml() const noexcept;

  ///Something of one of the examples was changed
  mutable boost::signals2::signal<void(Examples*)> m_signal_examples_changed;
private:
  ~Examples() noexcept;

  std::vector<boost::shared_ptr<Example>> m_v;

  //void Add(const boost::shared_ptr<cmap::Example>& example);

  ///All signals emitted from the examples are connected to this member function
  void OnExampleChanged() noexcept;

  ///Test this class
  static void Test() noexcept;

  ///Correct befriending, from http://richelbilderbeek.nl/CppChecked_delete.htm
  friend void boost::checked_delete<>(Examples* x);
};


bool operator==(const Examples& lhs, const Examples& rhs);
bool operator!=(const Examples& lhs, const Examples& rhs);

///Two cmap::Examples instances are sorted as follows:
///(1) By their number of examples
///(2) (if the sizes are equal) Alphabetically on the first different example
bool operator<(const Examples& lhs, const Examples& rhs);

/*
bool operator<(const boost::shared_ptr<const cmap::Examples>& lhs, const boost::shared_ptr<const cmap::Examples>& rhs);
bool operator<(const boost::shared_ptr<const cmap::Examples>& lhs, boost::shared_ptr<const cmap::Examples>& rhs);
bool operator<(const boost::shared_ptr<Examples>& lhs, const boost::shared_ptr<const cmap::Examples>& rhs);
bool operator<(const boost::shared_ptr<Examples>& lhs, boost::shared_ptr<const cmap::Examples>& rhs);
bool operator<=(const boost::shared_ptr<const cmap::Examples>& lhs, const boost::shared_ptr<const cmap::Examples>& rhs) = delete;
bool operator<=(const boost::shared_ptr<const cmap::Examples>& lhs, boost::shared_ptr<const cmap::Examples>& rhs) = delete;
bool operator<=(const boost::shared_ptr<Examples>& lhs, const boost::shared_ptr<const cmap::Examples>& rhs) = delete;
bool operator<=(const boost::shared_ptr<Examples>& lhs, boost::shared_ptr<const cmap::Examples>& rhs) = delete;
bool operator>(const boost::shared_ptr<const cmap::Examples>& lhs, const boost::shared_ptr<const cmap::Examples>& rhs) = delete;
bool operator>(const boost::shared_ptr<const cmap::Examples>& lhs, boost::shared_ptr<const cmap::Examples>& rhs) = delete;
bool operator>(const boost::shared_ptr<Examples>& lhs, const boost::shared_ptr<const cmap::Examples>& rhs) = delete;
bool operator>(const boost::shared_ptr<Examples>& lhs, boost::shared_ptr<const cmap::Examples>& rhs) = delete;
bool operator>=(const boost::shared_ptr<const cmap::Examples>& lhs, const boost::shared_ptr<const cmap::Examples>& rhs) = delete;
bool operator>=(const boost::shared_ptr<const cmap::Examples>& lhs, boost::shared_ptr<const cmap::Examples>& rhs) = delete;
bool operator>=(const boost::shared_ptr<Examples>& lhs, const boost::shared_ptr<const cmap::Examples>& rhs) = delete;
bool operator>=(const boost::shared_ptr<Examples>& lhs, boost::shared_ptr<const cmap::Examples>& rhs) = delete;
*/

} //~namespace cmap
} //~namespace ribi

#endif // CONCEPTMAPEXAMPLES_H

 

 

 

 

 

./CppConceptMap/conceptmapexamples.cpp

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#include "conceptmapexamples.h"

#include <cassert>
#include <sstream>

#include <boost/bind.hpp>
#include <boost/lambda/lambda.hpp>
#include <QRegExp>
#include "counter.h"
#include "conceptmaphelper.h"
#include "conceptmapexample.h"
#include "conceptmapexamplefactory.h"
#include "conceptmapexamplesfactory.h"
#include "testtimer.h"
#include "trace.h"
#pragma GCC diagnostic pop

ribi::cmap::Examples::Examples(const std::vector<boost::shared_ptr<cmap::Example> >& v)
  : m_signal_examples_changed{},
    m_v(v)
{
  #ifndef NDEBUG
  Test();
  #endif

  for(const auto example: m_v)
  {
    assert(example);
    example->m_signal_competency_changed.connect(
      boost::bind(&Examples::OnExampleChanged,this)
    );
    example->m_signal_is_complex_changed.connect(
      boost::bind(&Examples::OnExampleChanged,this)
    );
    example->m_signal_is_concrete_changed.connect(
      boost::bind(&Examples::OnExampleChanged,this)
    );
    example->m_signal_is_specific_changed.connect(
      boost::bind(&Examples::OnExampleChanged,this)
    );
    example->m_signal_text_changed.connect(
      boost::bind(&Examples::OnExampleChanged,this)
    );
  }

  assert(std::count_if(m_v.begin(),m_v.end(),
    [](const boost::shared_ptr<Example>& e) { return !e; }
    ) == 0 && "All Example instances must be initialized");
}

ribi::cmap::Examples::~Examples() noexcept
{
  for(const auto example: m_v)
  {
    assert(example);
    example->m_signal_competency_changed.disconnect(
      boost::bind(&Examples::OnExampleChanged,this)
    );
    example->m_signal_is_complex_changed.disconnect(
      boost::bind(&Examples::OnExampleChanged,this)
    );
    example->m_signal_is_concrete_changed.disconnect(
      boost::bind(&Examples::OnExampleChanged,this)
    );
    example->m_signal_is_specific_changed.disconnect(
      boost::bind(&Examples::OnExampleChanged,this)
    );
    example->m_signal_text_changed.disconnect(
      boost::bind(&Examples::OnExampleChanged,this)
    );
  }

}

/*
void ribi::cmap::Examples::Add(const boost::shared_ptr<cmap::Example>& example)
{
  assert(example);
  //Connect the example
  example->m_signal_competency_changed.connect(
    boost::bind(
      &Examples::OnExampleChanged,
      this
    )
  );
  example->m_signal_text_changed.connect(
    boost::bind(
      &Examples::OnExampleChanged,
      this
    )
  );
  //Add the example and notify this change
  m_v.push_back(example);
  m_signal_examples_changed(this);
}
*/


std::vector<boost::shared_ptr<const ribi::cmap::Example> > ribi::cmap::Examples::Get() const noexcept
{
  return AddConst(m_v);
}

void ribi::cmap::Examples::OnExampleChanged() noexcept
{
  m_signal_examples_changed(this);
}

void ribi::cmap::Examples::Test() noexcept
{
  {
    static bool is_tested{false};
    if (is_tested) return;
    is_tested = true;
  }
  Counter();
  ExampleFactory().GetTest(0);
  ExamplesFactory();
  ExamplesFactory().GetTest(0);
  const TestTimer test_timer(__func__,__FILE__,1.0);
  //Test of operator== and operator!=
  {
    const int sz = ExamplesFactory().GetNumberOfTests();
    for (int i=0; i!=sz; ++i)
    {
      boost::shared_ptr<const Examples> a = ExamplesFactory().GetTest(i);
      boost::shared_ptr<      Examples> b = ExamplesFactory().GetTest(i);
      assert(*a == *a);
      assert(*a == *b);
      assert(*b == *a);
      assert(*b == *b);
      for (int j=0; j!=sz; ++j)
      {
        boost::shared_ptr<const Examples> c = ExamplesFactory().GetTest(j);
        boost::shared_ptr<      Examples> d = ExamplesFactory().GetTest(j);
        assert(*c == *c);
        assert(*c == *d);
        assert(*d == *c);
        assert(*d == *d);
        if (i==j)
        {
          assert(*a == *c); assert(*a == *d);
          assert(*b == *c); assert(*b == *d);
          assert(*c == *a); assert(*c == *b);
          assert(*d == *a); assert(*d == *b);
        }
        else
        {
          assert(*a != *c); assert(*a != *d);
          assert(*b != *c); assert(*b != *d);
          assert(*c != *a); assert(*c != *b);
          assert(*d != *a); assert(*d != *b);
        }
      }
    }
  }
  //Conversion between class and XML, test for equality
  {
    const std::vector<boost::shared_ptr<const Examples> > v = AddConst(ExamplesFactory().GetTests());
    std::for_each(v.begin(),v.end(),
      [](const boost::shared_ptr<const Examples>& e)
      {
        assert(e);
        const std::string s { e->ToXml() };
        const boost::shared_ptr<const Examples> f(ExamplesFactory().FromXml(s));
        assert(*e == *f);
      }
    );
  }
  {
    const std::vector<boost::shared_ptr<const Examples> > v = AddConst(ExamplesFactory().GetTests());
    const int sz = boost::numeric_cast<int>(v.size());
    for (int i=0; i!=sz; ++i)
    {
      const boost::shared_ptr<const Examples>& e = v[i];
      const std::string s { e->ToXml() };
      for (int j=0; j!=sz; ++j)
      {
        const boost::shared_ptr<const Examples>& f = v[j];
        const std::string t { f->ToXml() };
        if (i == j)
        {
          assert(*e == *f);
          assert( s ==  t);
        }
        else
        {
          assert(*e != *f);
          assert( s !=  t);
        }
      }
    }
  }
  //Test if unrated and rated examples are noticed as different
  {
    const boost::shared_ptr<Example> a = ExampleFactory().Create("1",Competency::misc);
    const boost::shared_ptr<Example> b = ExampleFactory().Create("1",Competency::misc);
    const boost::shared_ptr<Example> c = ExampleFactory().Create("1",Competency::uninitialized);
    assert(*a == *a); assert(*a == *b); assert(*a != *c);
    assert(*b == *a); assert(*b == *b); assert(*b != *c);
    assert(*c != *a); assert(*c != *b); assert(*c == *c);
    std::vector<boost::shared_ptr<const Example> > v; v.push_back(a);
    std::vector<boost::shared_ptr<const Example> > w; w.push_back(b);
    std::vector<boost::shared_ptr<const Example> > x; x.push_back(c);
    const boost::shared_ptr<Examples> d = ExamplesFactory().Create(v);
    const boost::shared_ptr<Examples> e = ExamplesFactory().Create(w);
    const boost::shared_ptr<Examples> f = ExamplesFactory().Create(x);
    assert(*d == *d); assert(*d == *e); assert(*d != *f);
    assert(*e == *d); assert(*e == *e); assert(*e != *f);
    assert(*f != *d); assert(*f != *e); assert(*f == *f);
  }
}

std::string ribi::cmap::Examples::ToStr() const noexcept
{
  std::stringstream s;
  s << "{ ";

  //const std::vector<boost::shared_ptr<const Example> > examples = c->GetExamples();
  for (const auto& example: Get())
  {
    s << example->ToStr() << " ";
  };
  s << "}";
  return s.str();
}

std::string ribi::cmap::Examples::ToXml() const noexcept
{
  std::stringstream s;
  s << "<examples>";

  //const std::vector<boost::shared_ptr<const Example> > examples = c->GetExamples();
  const auto example = Get();
  std::for_each(example.begin(),example.end(),
    [&s](const boost::shared_ptr<const Example>& t)
    {
      s << t->ToXml();
    }
  );
  s << "</examples>";

  const std::string r = s.str();
  assert(r.size() >= 20);
  assert(r.substr(0,10) == "<examples>");
  assert(r.substr(r.size() - 11,11) == "</examples>");
  return r;
}

bool ribi::cmap::operator==(const cmap::Examples& lhs, const cmap::Examples& rhs)
{
  if (lhs.Get().size() != rhs.Get().size())
  {
    return false;
  }
  if (lhs.Get().empty()) { assert(rhs.Get().empty()); return true; }
  const std::vector<boost::shared_ptr<const Example> > v = lhs.Get();
  const std::vector<boost::shared_ptr<const Example> > w = rhs.Get();
  return std::equal(v.begin(),v.end(),w.begin(),
    [](const boost::shared_ptr<const Example>& a, const boost::shared_ptr<const Example>& b)
    {
      return *a == *b;
    }
  );
}

bool ribi::cmap::operator!=(const cmap::Examples& lhs, const cmap::Examples& rhs)
{
  return !(lhs == rhs);
}

bool ribi::cmap::operator<(const cmap::Examples& lhs, const cmap::Examples& rhs)
{
  if (lhs.Get().size() < rhs.Get().size()) return true;
  if (lhs.Get().size() > rhs.Get().size()) return false;
  assert(lhs.Get().size() == rhs.Get().size());
  const int sz = lhs.Get().size();
  for (int i = 0; i!=sz; ++i)
  {
    if (*lhs.Get()[i] < *rhs.Get()[i]) return true;
    if (*lhs.Get()[i] > *rhs.Get()[i]) return false;
  }
  return false;
}

 

 

 

 

 

./CppConceptMap/conceptmapexamplesfactory.h

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#ifndef CONCEPTMAPEXAMPLESFACTORY_H
#define CONCEPTMAPEXAMPLESFACTORY_H

#include <vector>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#include <boost/shared_ptr.hpp>
#include "conceptmapcompetency.h"

#include "conceptmapfwd.h"
#pragma GCC diagnostic pop

namespace ribi {

namespace cmap {

struct ExamplesFactory
{
  ExamplesFactory() noexcept;

  ///Constructor like
  boost::shared_ptr<Examples> Create() const noexcept;

  ///Copy-constructor like
  boost::shared_ptr<Examples> Create(
    const boost::shared_ptr<const cmap::Examples>& examples) const noexcept;

  boost::shared_ptr<Examples> Create(
    const std::vector<boost::shared_ptr<cmap::Example> >& v) const noexcept;

  boost::shared_ptr<Examples> Create(
    const std::vector<boost::shared_ptr<const cmap::Example> >& v) const noexcept;

  boost::shared_ptr<Examples> Create(
    const std::vector<std::pair<std::string,Competency> >& v) const noexcept;

  ///Create an Examples from XML
  boost::shared_ptr<Examples> FromXml(const std::string& s) const;

  int GetNumberOfTests() const noexcept { return static_cast<int>(GetTests().size()); }
  boost::shared_ptr<Examples> GetTest(const int i) const noexcept;
  std::vector<boost::shared_ptr<Examples>> GetTests() const noexcept;

  private:

  #ifndef NDEBUG
  static void Test() noexcept;
  #endif // NDEBUG
};

} //~namespace cmap

} //~namespace ribi

#endif // CONCEPTMAPEXAMPLESFACTORY_H

 

 

 

 

 

./CppConceptMap/conceptmapexamplesfactory.cpp

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#include "conceptmapexamplesfactory.h"

#include <cassert>

#include "conceptmapexample.h"
#include "conceptmapexamplefactory.h"
#include "conceptmapexamples.h"
#include "conceptmaphelper.h"
#include "conceptmapregex.h"
#include "testtimer.h"
#include "trace.h"
#pragma GCC diagnostic pop

ribi::cmap::ExamplesFactory::ExamplesFactory() noexcept
{
  #ifndef NDEBUG
  Test();
  #endif
}

boost::shared_ptr<ribi::cmap::Examples> ribi::cmap::ExamplesFactory::Create() const noexcept
{
  boost::shared_ptr<Examples> examples(new Examples( {} ));
  assert(examples);
  return examples;
}

boost::shared_ptr<ribi::cmap::Examples> ribi::cmap::ExamplesFactory::Create(
  const boost::shared_ptr<const cmap::Examples>& examples) const noexcept
{
  assert(examples);
  const boost::shared_ptr<Examples> p = Create(examples->Get());
  assert(p);
  return p;
}

boost::shared_ptr<ribi::cmap::Examples> ribi::cmap::ExamplesFactory::Create(
  const std::vector<boost::shared_ptr<cmap::Example> >& v) const noexcept
{
  boost::shared_ptr<Examples> p(new Examples(v));
  assert(p);
  return p;
}

boost::shared_ptr<ribi::cmap::Examples> ribi::cmap::ExamplesFactory::Create(
  const std::vector<boost::shared_ptr<const cmap::Example> >& v) const noexcept
{
  std::vector<boost::shared_ptr<cmap::Example> > w;
  std::transform(v.begin(),v.end(),std::back_inserter(w),
    [](const boost::shared_ptr<const cmap::Example>& p)
    {
      boost::shared_ptr<Example> q
        = ExampleFactory().Create(p->GetText(),p->GetCompetency());
      assert(q);
      return q;
    }
  );

  const boost::shared_ptr<ribi::cmap::Examples> examples(new Examples(w));
  assert(examples);
  return examples;
}

boost::shared_ptr<ribi::cmap::Examples> ribi::cmap::ExamplesFactory::Create(
  const std::vector<std::pair<std::string,Competency> >& v) const noexcept
{
  std::vector<boost::shared_ptr<Example> > w;
  std::transform(v.begin(),v.end(),std::back_inserter(w),
    [](const std::pair<std::string,Competency>& p)
    {
      const boost::shared_ptr<Example> q
        = ExampleFactory().Create(p.first,p.second);
      assert(q);
      return q;
    }
  );
  const boost::shared_ptr<ribi::cmap::Examples> q = Create(w);
  assert(q);
  return q;
}

boost::shared_ptr<ribi::cmap::Examples> ribi::cmap::ExamplesFactory::FromXml(const std::string& s) const
{
  if (s.size() < 20)
  {
    return boost::shared_ptr<Examples>();
  }
  if (s.substr(0,10) != "<examples>")
  {
    return boost::shared_ptr<Examples>();
  }
  if (s.substr(s.size() - 11,11) != "</examples>")
  {
    return boost::shared_ptr<Examples>();
  }
  assert(Regex().GetRegexMatches(s,"(<examples>)").size()
      == Regex().GetRegexMatches(s,"(</examples>)").size());

  std::vector<boost::shared_ptr<Example> > examples;
  {

    assert(Regex().GetRegexMatches(s,"(<example>)").size()
        == Regex().GetRegexMatches(s,"(</example>)").size());
    const auto v = Regex().GetRegexMatches(s,Regex().GetRegexExample());
    std::transform(v.begin(),v.end(),std::back_inserter(examples),
      [](const std::string& s)
      {
        return ExampleFactory().FromXml(s);
      }
    );
  }
  const boost::shared_ptr<Examples> result {
    Create(examples)
  };
  return result;
}

boost::shared_ptr<ribi::cmap::Examples> ribi::cmap::ExamplesFactory::GetTest(const int i) const noexcept
{
  assert(i >= 0);
  assert(i < GetNumberOfTests());
  return GetTests()[i];
}

std::vector<boost::shared_ptr<ribi::cmap::Examples> > ribi::cmap::ExamplesFactory::GetTests() const noexcept
{
  const std::vector<std::vector<int> > is = { {0}, {1}, {0,1,2,3}, {} };
  std::vector<boost::shared_ptr<Examples> > v;
  std::transform(is.begin(),is.end(),std::back_inserter(v),
    [this](const std::vector<int>& js)
    {
      std::vector<boost::shared_ptr<Example> > w;
      std::transform(js.begin(),js.end(),std::back_inserter(w),
        [](const int& j)
        {
          const boost::shared_ptr<Example> p
            = ExampleFactory().GetTest(j);
          assert(p);
          return p;
        }
      );
      const boost::shared_ptr<Examples> q
        = Create(w);
      assert(q);
      return q;
    }
  );

  return v;

}

#ifndef NDEBUG
void ribi::cmap::ExamplesFactory::Test() noexcept
{
  {
    static bool is_tested{false};
    if (is_tested) return;
    is_tested = true;
  }
  ExamplesFactory().Create();
  const bool verbose{false};
  const TestTimer test_timer(__func__,__FILE__,1.0);
  ExamplesFactory f;
  if (verbose) { TRACE("Create must return a valid Examples"); }
  {
    assert(f.Create());
  }
  if (verbose) { TRACE("Examples -> XML -> Examples "); }
  {
    const auto examples = ExamplesFactory().GetTest(2);
    const auto xml = examples->ToXml();
    const auto new_examples = ExamplesFactory().FromXml(xml);
    const auto new_xml = new_examples->ToXml();
    assert(xml == new_xml);
  }
}
#endif // NDEBUG

 

 

 

 

 

./CppConceptMap/conceptmapfactory.h

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#ifndef CONCEPTMAPCONCEPTMAPFACTORY_H
#define CONCEPTMAPCONCEPTMAPFACTORY_H

#include <array>
#include <vector>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#include <boost/shared_ptr.hpp>

#include "conceptmapfwd.h"
#pragma GCC diagnostic pop

namespace ribi {

namespace cmap {

///Factory class to create ConceptMaps
///ConceptMapFactory is the only class using the ConceptMap constructor
struct ConceptMapFactory
{
  typedef std::vector<boost::shared_ptr<Node>> Nodes;
  typedef std::vector<boost::shared_ptr<Edge>> Edges;
  typedef std::vector<boost::shared_ptr<ConceptMap>> ConceptMaps;

  ConceptMapFactory() noexcept;

  boost::shared_ptr<ConceptMap> Create(
    const Nodes& nodes = {},
    const Edges& edges = {}
  ) const noexcept;

  #ifndef NDEBUG
  ///DeepCopy is only used for debugging
  boost::shared_ptr<ConceptMap> DeepCopy(
    const boost::shared_ptr<const ConceptMap> map
  ) const noexcept;
  #endif

  ///Obtain a ConceptMap from an XML std::string
  boost::shared_ptr<ConceptMap> FromXml(const std::string& s) const noexcept;

  ///Get all the other tests as one vector
  ConceptMaps GetAllTests() const noexcept;

  ///Get the documented heteromorphous test concept maps
  ConceptMaps GetHeteromorphousTestConceptMaps() const noexcept;
  boost::shared_ptr<ConceptMap> GetHeteromorphousTestConceptMap(const int index) const noexcept;

  ///Get the documented complex homomorphous test concept maps
  ConceptMaps GetComplexHomomorphousTestConceptMaps() const noexcept;
  boost::shared_ptr<ConceptMap> GetComplexHomomorphousTestConceptMap(const int index) const noexcept;
  int GetNumberOfComplexHomomorphousTestConceptMaps() const noexcept { return 12; }

  ///Get the documented simple homomorphous test concept maps
   ConceptMaps GetSimpleHomomorphousTestConceptMaps() const noexcept;

  private:
  boost::shared_ptr<ConceptMap> GetComplexHomomorphousTestConceptMap0() const noexcept;
  boost::shared_ptr<ConceptMap> GetComplexHomomorphousTestConceptMap1() const noexcept;
  boost::shared_ptr<ConceptMap> GetComplexHomomorphousTestConceptMap2() const noexcept;
  boost::shared_ptr<ConceptMap> GetComplexHomomorphousTestConceptMap3() const noexcept;
  boost::shared_ptr<ConceptMap> GetComplexHomomorphousTestConceptMap4() const noexcept;
  boost::shared_ptr<ConceptMap> GetComplexHomomorphousTestConceptMap5() const noexcept;
  boost::shared_ptr<ConceptMap> GetComplexHomomorphousTestConceptMap6() const noexcept;
  boost::shared_ptr<ConceptMap> GetComplexHomomorphousTestConceptMap7() const noexcept;
  boost::shared_ptr<ConceptMap> GetComplexHomomorphousTestConceptMap8() const noexcept;
  boost::shared_ptr<ConceptMap> GetComplexHomomorphousTestConceptMap9() const noexcept;
  boost::shared_ptr<ConceptMap> GetComplexHomomorphousTestConceptMap10() const noexcept;
  boost::shared_ptr<ConceptMap> GetComplexHomomorphousTestConceptMap11() const noexcept;

  boost::shared_ptr<ConceptMap> GetHeteromorphousTestConceptMap0() const noexcept;
  boost::shared_ptr<ConceptMap> GetHeteromorphousTestConceptMap1() const noexcept;
  boost::shared_ptr<ConceptMap> GetHeteromorphousTestConceptMap2() const noexcept;
  boost::shared_ptr<ConceptMap> GetHeteromorphousTestConceptMap3() const noexcept;
  boost::shared_ptr<ConceptMap> GetHeteromorphousTestConceptMap4() const noexcept;
  boost::shared_ptr<ConceptMap> GetHeteromorphousTestConceptMap5() const noexcept;
  boost::shared_ptr<ConceptMap> GetHeteromorphousTestConceptMap6() const noexcept;
  boost::shared_ptr<ConceptMap> GetHeteromorphousTestConceptMap7() const noexcept;
  boost::shared_ptr<ConceptMap> GetHeteromorphousTestConceptMap8() const noexcept;
  boost::shared_ptr<ConceptMap> GetHeteromorphousTestConceptMap9() const noexcept;
  boost::shared_ptr<ConceptMap> GetHeteromorphousTestConceptMap10() const noexcept;
  boost::shared_ptr<ConceptMap> GetHeteromorphousTestConceptMap11() const noexcept;
  boost::shared_ptr<ConceptMap> GetHeteromorphousTestConceptMap12() const noexcept;
  boost::shared_ptr<ConceptMap> GetHeteromorphousTestConceptMap13() const noexcept;
  boost::shared_ptr<ConceptMap> GetHeteromorphousTestConceptMap14() const noexcept;
  boost::shared_ptr<ConceptMap> GetHeteromorphousTestConceptMap15() const noexcept;
  boost::shared_ptr<ConceptMap> GetHeteromorphousTestConceptMap16() const noexcept;
  boost::shared_ptr<ConceptMap> GetHeteromorphousTestConceptMap17() const noexcept;
  boost::shared_ptr<ConceptMap> GetHeteromorphousTestConceptMap18() const noexcept;
  boost::shared_ptr<ConceptMap> GetHeteromorphousTestConceptMap19() const noexcept;
  boost::shared_ptr<ConceptMap> GetHeteromorphousTestConceptMap20() const noexcept;

  #ifndef NDEBUG
  static void Test() noexcept;
  #endif

};

} //~namespace cmap

} //~namespace ribi

#endif // CONCEPTMAPCONCEPTMAPFACTORY_H

 

 

 

 

 

./CppConceptMap/conceptmapfactory.cpp

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#include "conceptmapfactory.h"

#include <cassert>

#include <boost/lexical_cast.hpp>

#include "conceptmapcenternodefactory.h"
#include "conceptmapcenternode.h"
#include "conceptmapconcept.h"
#include "conceptmapconceptfactory.h"
#include "conceptmap.h"
#include "conceptmaphelper.h"
#include "conceptmapexamplefactory.h"
#include "conceptmapedge.h"
#include "conceptmapedgefactory.h"
#include "conceptmapnode.h"
#include "conceptmapnodefactory.h"
#include "conceptmapregex.h"
#include "trace.h"
#include "testtimer.h"
#include "xml.h"
#pragma GCC diagnostic pop

ribi::cmap::ConceptMapFactory::ConceptMapFactory() noexcept
{
  #ifndef NDEBUG
  Test();
  #endif
}

boost::shared_ptr<ribi::cmap::ConceptMap> ribi::cmap::ConceptMapFactory::Create(
  const std::vector<boost::shared_ptr<Node>>& nodes,
  const std::vector<boost::shared_ptr<Edge>>& edges
) const noexcept
{
  boost::shared_ptr<ConceptMap> p(new ConceptMap(nodes,edges));
  assert(p);
  assert(p->IsValid());
  return p;
}

#ifndef NDEBUG
boost::shared_ptr<ribi::cmap::ConceptMap> ribi::cmap::ConceptMapFactory::DeepCopy(
  const boost::shared_ptr<const ribi::cmap::ConceptMap> map) const noexcept
{
  if (!map) return boost::shared_ptr<ConceptMap>();
  assert(map->IsValid() && "Must be a valid original");

  //Deep-copy the center node if present
  //Deep-copy the non-center nodes
  const std::vector<boost::shared_ptr<const Node>> nodes = map->GetNodes();
  std::vector<boost::shared_ptr<Node>> new_nodes;
  for (const boost::shared_ptr<const Node> node: nodes)
  {
    assert(node);
    boost::shared_ptr<Node> new_node;
    if (const boost::shared_ptr<const CenterNode> center_node
     = boost::dynamic_pointer_cast<const CenterNode>(node))
    {
      assert(center_node);
      new_node = CenterNodeFactory().DeepCopy(center_node);
    }
    else
    {
      new_node = NodeFactory().DeepCopy(node);
    }
    assert(new_node);
    assert(*new_node == *node);
    new_nodes.push_back(new_node);
  }


  //Deep-copy the edges
  const std::vector<boost::shared_ptr<const Edge> > edges = map->GetEdges();
  std::vector<boost::shared_ptr<Edge>> new_edges;
  for (const boost::shared_ptr<const Edge> edge: edges)
  {
    assert(edge);
    //Find the new from node
    const auto from_iter = std::find(nodes.begin(),nodes.end(),edge->GetFrom());
    assert(from_iter != nodes.end());
    const int from_index = std::distance(nodes.begin(),from_iter);
    assert(from_index < boost::numeric_cast<int>(new_nodes.size()));
    const boost::shared_ptr<Node> from = new_nodes[from_index];

    //Find the new to node
    const auto to_iter = std::find(nodes.begin(),nodes.end(),edge->GetTo());
    assert(to_iter != nodes.end());
    const int to_index = std::distance(nodes.begin(),to_iter);
    assert(to_index < boost::numeric_cast<int>(new_nodes.size()));
    const boost::shared_ptr<Node> to = new_nodes[to_index];

    assert(from_index != to_index);
    assert(from);
    assert(to);
    assert(from != to);
    const boost::shared_ptr<Edge> new_edge {
      EdgeFactory().DeepCopy(edge,from,to)
    };
    assert(new_edge);
    assert(*new_edge == *edge);
    new_edges.push_back(new_edge);
  }

  const boost::shared_ptr<ConceptMap> p = Create(new_nodes,new_edges);
  assert(p);
  assert(*p == *map && "Must be a copy");
  assert( p !=  map && "Must be a deep copy");
  assert(p->IsValid() && "Must be a valid copy");
  return p;
}
#endif

///TODO: let CenterNodes manage their own <center_node> tags
boost::shared_ptr<ribi::cmap::ConceptMap> ribi::cmap::ConceptMapFactory::FromXml(const std::string &s) const noexcept
{
  assert(s.size() >= 27);
  assert(s.substr(0,13) == "<concept_map>");
  assert(s.substr(s.size() - 14,14) == "</concept_map>");


  //Obtain the <concept_map> ... </concept_map> string
  const std::vector<std::string> v
    = Regex().GetRegexMatches(s,("(<concept_map>.*</concept_map>)"));
  assert(v.size() == 1);
  //Strip the <concept_map> tags
  const std::string concept_map_str = ribi::xml::StripXmlTag(v[0]);

  std::vector<boost::shared_ptr<Node>> nodes;
  {
    //Obtain the <nodes> ... </nodes> strings
    const std::vector<std::string> w
      = Regex().GetRegexMatches(concept_map_str,Regex().GetRegexNodes());
    assert(w.size() == 1);
    //Strip the <nodes> tags
    const std::string nodes_str = ribi::xml::StripXmlTag(w[0]);

    //CenterNode
    {
      const std::vector<std::string> x
        = Regex().GetRegexMatches(nodes_str,Regex().GetRegexCenterNode());
      assert(x.empty() || x.size() == 1);
      std::for_each(x.begin(),x.end(),
        [&nodes](const std::string& s)
        {
          const boost::shared_ptr<CenterNode> node {
            CenterNodeFactory().FromXml(s)
          };
          assert(node);
          nodes.push_back(node);
        }
      );
    }
    //Regular nodes
    {
      const std::vector<std::string> x
        = Regex().GetRegexMatches(nodes_str,Regex().GetRegexNode());
      std::for_each(x.begin(),x.end(),
        [&nodes](const std::string& s)
        {
          const boost::shared_ptr<Node> node {
            NodeFactory().FromXml(s)
          };
          assert(node);
          nodes.push_back(node);
        }
      );
    }
    //Replace the first node by its CenterNode equivalent
    if (!nodes.empty() && !IsCenterNode(nodes[0]))
    {
      const boost::shared_ptr<Node> old_node = nodes[0];
      const boost::shared_ptr<Concept> concept = old_node->GetConcept();
      const double x = old_node->GetX();
      const double y = old_node->GetY();
      const boost::shared_ptr<CenterNode> center_node {
        CenterNodeFactory().Create(concept,x,y)
      };
      nodes[0] = center_node;
      assert(*old_node == *center_node);
    }
    assert(nodes.empty() || IsCenterNode(nodes[0]));
  }
  std::vector<boost::shared_ptr<Edge>> edges;
  {
    //Obtain the <edges> ... </edges> strings
    const std::vector<std::string> w
      = Regex().GetRegexMatches(concept_map_str,Regex().GetRegexEdges());
    assert(w.size() == 1);
    //Strip the <edges> tags
    const std::string nodes_str = ribi::xml::StripXmlTag(w[0]);
    //Obtain the <edge> ... </edge> strings
    const std::vector<std::string> x
      = Regex().GetRegexMatches(nodes_str,Regex().GetRegexEdge());
    for (const std::string& s: x)
    {
      const boost::shared_ptr<Edge> edge {
        EdgeFactory().FromXml(s,nodes)
      };
      assert(edge);
      edges.push_back(edge);
    }
  }

  const boost::shared_ptr<ConceptMap> concept_map(new ConceptMap(nodes,edges));
  assert(concept_map);
  assert(concept_map->IsValid());
  return concept_map;
}

std::vector<boost::shared_ptr<ribi::cmap::ConceptMap> > ribi::cmap::ConceptMapFactory::GetAllTests() const noexcept
{
  ConceptMaps v;
  {
    {
      const auto w = ConceptMapFactory::GetSimpleHomomorphousTestConceptMaps();
      std::copy(w.begin(),w.end(),std::back_inserter(v));
    }
    {
      const std::vector<boost::shared_ptr<ConceptMap> > w = ConceptMapFactory::GetComplexHomomorphousTestConceptMaps();
      std::copy(w.begin(),w.end(),std::back_inserter(v));
    }
    {
      const auto w = ConceptMapFactory::GetHeteromorphousTestConceptMaps();
      std::copy(w.begin(),w.end(),std::back_inserter(v));
    }
  }
  #ifndef NDEBUG
  for (const auto& concept_map: v)
  {
    assert(concept_map);
    assert(concept_map->IsValid());
    for (const auto& node: concept_map->GetNodes())
    {
      assert(node);
    }
    for (const auto& edge: concept_map->GetEdges())
    {
      assert(edge);
      assert(edge->GetTo());
      assert(edge->GetFrom());
      assert(std::count(
        concept_map->GetNodes().begin(),
        concept_map->GetNodes().end(),
        edge->GetTo()) == 1);
      assert(std::count(
        concept_map->GetNodes().begin(),
        concept_map->GetNodes().end(),
        edge->GetFrom()) == 1);
    }
  }
  #endif
  //Add empty concept map
  {
    boost::shared_ptr<ConceptMap> p;
    assert(!p);
    v.push_back(p);
  }

  return v;
}

boost::shared_ptr<ribi::cmap::ConceptMap> ribi::cmap::ConceptMapFactory::GetHeteromorphousTestConceptMap(const int i) const noexcept
{
  switch (i)
  {
    case 0: return GetHeteromorphousTestConceptMap0();
    case 1: return GetHeteromorphousTestConceptMap1();
    case 2: return GetHeteromorphousTestConceptMap2();
    case 3: return GetHeteromorphousTestConceptMap3();
    case 4: return GetHeteromorphousTestConceptMap4();
    case 5: return GetHeteromorphousTestConceptMap5();
    case 6: return GetHeteromorphousTestConceptMap6();
    case 7: return GetHeteromorphousTestConceptMap7();
    case 8: return GetHeteromorphousTestConceptMap8();
    case 9: return GetHeteromorphousTestConceptMap9();
    case 10: return GetHeteromorphousTestConceptMap10();
    case 11: return GetHeteromorphousTestConceptMap11();
    case 12: return GetHeteromorphousTestConceptMap12();
    case 13: return GetHeteromorphousTestConceptMap13();
    case 14: return GetHeteromorphousTestConceptMap14();
    case 15: return GetHeteromorphousTestConceptMap15();
    case 16: return GetHeteromorphousTestConceptMap16();
    case 17: return GetHeteromorphousTestConceptMap17();
    case 18: return GetHeteromorphousTestConceptMap18();
    case 19: return GetHeteromorphousTestConceptMap19();
    default: assert(!"Should not get here");
  }
  assert(!"Should not get here");
  return boost::shared_ptr<ConceptMap>();
}

boost::shared_ptr<ribi::cmap::ConceptMap> ribi::cmap::ConceptMapFactory::GetHeteromorphousTestConceptMap0() const noexcept
{
  //[0]: empty concept map
  const Nodes nodes
    =
    {

    };

  const Edges edges
    =
    {

    };

  const boost::shared_ptr<ConceptMap> concept_map{
    ConceptMapFactory::Create(nodes,edges)
  };
  assert(concept_map);
  return concept_map;
}

boost::shared_ptr<ribi::cmap::ConceptMap> ribi::cmap::ConceptMapFactory::GetHeteromorphousTestConceptMap1() const noexcept
{
  //[1]
  const Nodes nodes
    =
    {
      CenterNodeFactory().CreateFromStrings("X"),
      NodeFactory().CreateFromStrings("A")
    };

  const Edges edges
    =
    {

    };

  const boost::shared_ptr<ConceptMap> concept_map(
    ConceptMapFactory::Create(nodes,edges)
  );
  assert(concept_map);
  return concept_map;
}

boost::shared_ptr<ribi::cmap::ConceptMap> ribi::cmap::ConceptMapFactory::GetHeteromorphousTestConceptMap2() const noexcept
{
  //[2]
  const Nodes nodes
    =
    {
      CenterNodeFactory().CreateFromStrings("X"),
      NodeFactory().CreateFromStrings("A"),
      NodeFactory().CreateFromStrings("B")
    };

  const Edges edges
    =
    {

    };
  const boost::shared_ptr<ConceptMap> concept_map(
    ConceptMapFactory::Create(nodes,edges));
  assert(concept_map);
  return concept_map;
}

boost::shared_ptr<ribi::cmap::ConceptMap> ribi::cmap::ConceptMapFactory::GetHeteromorphousTestConceptMap3() const noexcept
{
  //[3]
  const Nodes nodes
    =
    {
      CenterNodeFactory().CreateFromStrings("X"),
      NodeFactory().CreateFromStrings("A"),
      NodeFactory().CreateFromStrings("B")
    };

  const auto concept_d(ConceptFactory().Create("edge_a concept"));
  const auto node_d(NodeFactory().Create(concept_d,1.2,3.4));

  const Edges edges
    =
    {
      //cmap::EdgeFactory().Create(concept_d,1.2,3.4,nodes.at(1),false,nodes.at(2),true)
      EdgeFactory().Create(node_d,nodes.at(1),false,nodes.at(2),true)
    };

  const boost::shared_ptr<ConceptMap> concept_map
    = ConceptMapFactory::Create(nodes,edges);

  assert(concept_map);
  return concept_map;
}

boost::shared_ptr<ribi::cmap::ConceptMap> ribi::cmap::ConceptMapFactory::GetHeteromorphousTestConceptMap4() const noexcept
{
  //[4]
  const Nodes nodes
    =
    {
      CenterNodeFactory().CreateFromStrings("X"),
      NodeFactory().CreateFromStrings("A"),
      NodeFactory().CreateFromStrings("B")
    };

  const auto concept_d(ConceptFactory().Create("edge_a concept"));
  const auto node_d(NodeFactory().Create(concept_d,1.2,3.4));

  const Edges edges
    =
    {
      //cmap::EdgeFactory().Create(concept_d,1.2,3.4,nodes.at(2),false,nodes.at(1),true)
      EdgeFactory().Create(node_d,nodes.at(2),false,nodes.at(1),true)
    };

  const auto concept_map
    = ConceptMapFactory::Create(nodes,edges);

  assert(concept_map);
  return concept_map;
}

boost::shared_ptr<ribi::cmap::ConceptMap> ribi::cmap::ConceptMapFactory::GetHeteromorphousTestConceptMap5() const noexcept
{
  //[5]
  const Nodes nodes
    =
    {
      CenterNodeFactory().CreateFromStrings("X"),
      NodeFactory().CreateFromStrings("A"),
      NodeFactory().CreateFromStrings("B")
    };

  const auto concept_d(ConceptFactory().Create("1"));
  const auto node_d(NodeFactory().Create(concept_d,1.2,3.4));

  const Edges edges
    =
    {
      EdgeFactory().Create(node_d,nodes.at(1),false,nodes.at(2),true)
    };

  const boost::shared_ptr<ConceptMap> concept_map
    = ConceptMapFactory::Create(nodes,edges);

  assert(concept_map);
  return concept_map;
}

boost::shared_ptr<ribi::cmap::ConceptMap> ribi::cmap::ConceptMapFactory::GetHeteromorphousTestConceptMap6() const noexcept
{
  //[6]
  const Nodes nodes
    =
    {
      CenterNodeFactory().CreateFromStrings("X"),
      NodeFactory().CreateFromStrings("A"),
      NodeFactory().CreateFromStrings("B")
    };
  const auto concept_d(ConceptFactory().Create("1"));
  const auto node_d(NodeFactory().Create(concept_d,1.2,3.4));

  const Edges edges
    =
    {
      EdgeFactory().Create(node_d,nodes.at(2),false,nodes.at(1),true)
    };

  const boost::shared_ptr<ConceptMap> concept_map
    = ConceptMapFactory::Create(nodes,edges);

  assert(concept_map);
  return concept_map;
}

boost::shared_ptr<ribi::cmap::ConceptMap> ribi::cmap::ConceptMapFactory::GetHeteromorphousTestConceptMap7() const noexcept
{
  //[7]
  const Nodes nodes
    =
    {
      CenterNodeFactory().CreateFromStrings("X"),
      NodeFactory().CreateFromStrings("A"),
      NodeFactory().CreateFromStrings("B"),
      NodeFactory().CreateFromStrings("C")
    };

  const Edges edges
    =
    {

    };

  const boost::shared_ptr<ConceptMap> concept_map
    = ConceptMapFactory::Create(nodes,edges);

  assert(concept_map);
  return concept_map;
}

boost::shared_ptr<ribi::cmap::ConceptMap> ribi::cmap::ConceptMapFactory::GetHeteromorphousTestConceptMap8() const noexcept
{
  //[8]
  const Nodes nodes
    =
    {
      CenterNodeFactory().CreateFromStrings("X"),
      NodeFactory().CreateFromStrings("A"),
      NodeFactory().CreateFromStrings("B"),
      NodeFactory().CreateFromStrings("C")
    };

  const auto concept_e(ConceptFactory().Create());
  const auto node_e(NodeFactory().Create(concept_e,1.2,3.4));
  const auto edge_a(EdgeFactory().Create(node_e,nodes.at(1),false,nodes.at(2),true));


  const Edges edges
    =
    {
      edge_a
    };

  const boost::shared_ptr<ConceptMap> concept_map
    = ConceptMapFactory::Create(nodes,edges);

  assert(concept_map);
  return concept_map;
}

boost::shared_ptr<ribi::cmap::ConceptMap> ribi::cmap::ConceptMapFactory::GetHeteromorphousTestConceptMap9() const noexcept
{
  //[9]
  const Nodes nodes
    =
    {
      CenterNodeFactory().CreateFromStrings("X"),
      NodeFactory().CreateFromStrings("A"),
      NodeFactory().CreateFromStrings("B"),
      NodeFactory().CreateFromStrings("C")
    };

  const auto concept_e(ConceptFactory().Create());
  const auto node_e(NodeFactory().Create(concept_e,1.2,3.4));
  const boost::shared_ptr<Edge> edge_a(EdgeFactory().Create(node_e,nodes.at(2),false,nodes.at(3),true));

  const Edges edges
    =
    {
      edge_a
    };

  const boost::shared_ptr<ConceptMap> concept_map
    = ConceptMapFactory::Create(nodes,edges);

  assert(concept_map);
  return concept_map;
}

boost::shared_ptr<ribi::cmap::ConceptMap> ribi::cmap::ConceptMapFactory::GetHeteromorphousTestConceptMap10() const noexcept
{
  //[10]
  const Nodes nodes
    =
    {
      CenterNodeFactory().CreateFromStrings("X"),
      NodeFactory().CreateFromStrings("A"),
      NodeFactory().CreateFromStrings("B"),
      NodeFactory().CreateFromStrings("C")
    };

  const auto concept_e(ConceptFactory().Create());
  const auto concept_f(ConceptFactory().Create());
  const auto node_e(NodeFactory().Create(concept_e,1.2,3.4));
  const auto node_f(NodeFactory().Create(concept_f,1.2,3.4));

  const Edges edges
    =
    {
      EdgeFactory().Create(node_e,nodes.at(1),false,nodes.at(2),true),
      EdgeFactory().Create(node_f,nodes.at(2),false,nodes.at(3),true)
    };

  const boost::shared_ptr<ConceptMap> concept_map
    = ConceptMapFactory::Create(nodes,edges);

  assert(concept_map);
  return concept_map;
}

boost::shared_ptr<ribi::cmap::ConceptMap> ribi::cmap::ConceptMapFactory::GetHeteromorphousTestConceptMap11() const noexcept
{
  //[11]
  const Nodes nodes
    =
    {
      CenterNodeFactory().CreateFromStrings("X"),
      NodeFactory().CreateFromStrings("A"),
      NodeFactory().CreateFromStrings("B"),
      NodeFactory().CreateFromStrings("C")
    };

  const auto concept_e(ConceptFactory().Create("1"));
  const auto concept_f(ConceptFactory().Create("2"));
  const auto concept_g(ConceptFactory().Create("3"));

  const auto node_e(NodeFactory().Create(concept_e,1.2,3.4));
  const auto node_f(NodeFactory().Create(concept_f,2.3,4.5));
  const auto node_g(NodeFactory().Create(concept_g,3.4,5.6));

  const Edges edges
    =
    {
      EdgeFactory().Create(node_e,nodes.at(1),false,nodes.at(2),true),
      EdgeFactory().Create(node_f,nodes.at(2),false,nodes.at(3),true),
      EdgeFactory().Create(node_g,nodes.at(3),false,nodes.at(1),true)
    };

  const boost::shared_ptr<ConceptMap> concept_map
    = ConceptMapFactory::Create(nodes,edges);

  assert(concept_map);
  return concept_map;
}

boost::shared_ptr<ribi::cmap::ConceptMap> ribi::cmap::ConceptMapFactory::GetHeteromorphousTestConceptMap12() const noexcept
{
  //[12]
  const Nodes nodes
    =
    {
      CenterNodeFactory().CreateFromStrings("X"),
      NodeFactory().CreateFromStrings("A"),
      NodeFactory().CreateFromStrings("B"),
      NodeFactory().CreateFromStrings("C")
    };

  const auto concept_e(ConceptFactory().Create("1"));
  const auto concept_f(ConceptFactory().Create("2"));
  const auto concept_g(ConceptFactory().Create("3"));

  const auto node_e(NodeFactory().Create(concept_e,1.2,3.4));
  const auto node_f(NodeFactory().Create(concept_f,2.3,4.5));
  const auto node_g(NodeFactory().Create(concept_g,3.4,5.6));

  const Edges edges
    =
    {
      EdgeFactory().Create(node_e,nodes.at(2),false,nodes.at(1),true),
      EdgeFactory().Create(node_f,nodes.at(3),false,nodes.at(2),true),
      EdgeFactory().Create(node_g,nodes.at(1),false,nodes.at(3),true)
    };

  const boost::shared_ptr<ConceptMap> concept_map(
    ConceptMapFactory::Create(nodes,edges));

  assert(concept_map);
  return concept_map;
}

boost::shared_ptr<ribi::cmap::ConceptMap> ribi::cmap::ConceptMapFactory::GetHeteromorphousTestConceptMap13() const noexcept
{
  //[13]
  const Nodes nodes
    =
    {
      CenterNodeFactory().CreateFromStrings("X"),
      NodeFactory().CreateFromStrings("A"),
      NodeFactory().CreateFromStrings("B"),
      NodeFactory().CreateFromStrings("C")
    };

  const auto concept_e(ConceptFactory().Create("1"));
  const auto concept_f(ConceptFactory().Create("3"));
  const auto concept_g(ConceptFactory().Create("2"));

  const auto node_e(NodeFactory().Create(concept_e,1.2,3.4));
  const auto node_f(NodeFactory().Create(concept_f,2.3,4.5));
  const auto node_g(NodeFactory().Create(concept_g,3.4,5.6));

  const Edges edges
    =
    {
      EdgeFactory().Create(node_e,nodes.at(1),false,nodes.at(2),true),
      EdgeFactory().Create(node_f,nodes.at(2),false,nodes.at(3),true),
      EdgeFactory().Create(node_g,nodes.at(3),false,nodes.at(1),true)
    };

  const boost::shared_ptr<ConceptMap> concept_map(
    ConceptMapFactory::Create(nodes,edges));

  assert(concept_map);
  return concept_map;
}

boost::shared_ptr<ribi::cmap::ConceptMap> ribi::cmap::ConceptMapFactory::GetHeteromorphousTestConceptMap14() const noexcept
{
  //[14]
  const Nodes nodes
    =
    {
      CenterNodeFactory().CreateFromStrings("X"),
      NodeFactory().CreateFromStrings("A"),
      NodeFactory().CreateFromStrings("B"),
      NodeFactory().CreateFromStrings("C")
    };

  const auto concept_e(ConceptFactory().Create("1"));
  const auto concept_f(ConceptFactory().Create("3"));
  const auto concept_g(ConceptFactory().Create("2"));
  const auto node_e(NodeFactory().Create(concept_e,1.2,3.4));
  const auto node_f(NodeFactory().Create(concept_f,2.3,4.5));
  const auto node_g(NodeFactory().Create(concept_g,3.4,5.6));

  const Edges edges
    =
    {
      EdgeFactory().Create(node_e,nodes.at(2),false,nodes.at(1),true),
      EdgeFactory().Create(node_f,nodes.at(3),false,nodes.at(2),true),
      EdgeFactory().Create(node_g,nodes.at(1),false,nodes.at(3),true)
    };

  const boost::shared_ptr<ConceptMap> concept_map(
    ConceptMapFactory::Create(nodes,edges));

  assert(concept_map);
  return concept_map;
}

boost::shared_ptr<ribi::cmap::ConceptMap> ribi::cmap::ConceptMapFactory::GetHeteromorphousTestConceptMap15() const noexcept
{
  //[15]
  const auto concept_c(ConceptFactory().Create("B", { {"B-1",cmap::Competency::uninitialized} },0,1,2));
  const auto concept_d(ConceptFactory().Create("C", { {"C-1",cmap::Competency::uninitialized},{"C-2",cmap::Competency::misc}},-1,1,2));
  const auto concept_e(ConceptFactory().Create("D", { {"D-1",cmap::Competency::misc},{"D-2",cmap::Competency::misc},{"D-3",cmap::Competency::misc}},-1,-1,-1));
  const boost::shared_ptr<Node> node_c(NodeFactory().Create(concept_c));
  const boost::shared_ptr<Node> node_d(NodeFactory().Create(concept_d));
  const boost::shared_ptr<Node> node_e(NodeFactory().Create(concept_e));

  const Nodes nodes
    =
    {
      CenterNodeFactory().CreateFromStrings("X"),
      NodeFactory().CreateFromStrings("A"),
      node_c,
      node_d,
      node_e
    };

  const auto concept_f(ConceptFactory().Create("1"));
  const auto concept_h(ConceptFactory().Create("2",{{"2-I",cmap::Competency::misc} } ));
  const auto concept_g(ConceptFactory().Create("3",{{"3-I",cmap::Competency::misc},{"3-II",cmap::Competency::misc} } ));
  const auto concept_i(ConceptFactory().Create("4",{{"4-I",cmap::Competency::misc},{"4-II",cmap::Competency::misc},{"4-III",cmap::Competency::misc} } ));
  const auto concept_j(ConceptFactory().Create("5",{{"5-I",cmap::Competency::misc},{"5-II",cmap::Competency::misc},{"5-III",cmap::Competency::misc},{"5-IV",cmap::Competency::misc} } ));
  const auto node_f(NodeFactory().Create(concept_f,1.2,3.4));
  const auto node_g(NodeFactory().Create(concept_g,2.3,4.5));
  const auto node_h(NodeFactory().Create(concept_h,3.4,5.6));
  const auto node_i(NodeFactory().Create(concept_i,4.5,6.7));
  const auto node_j(NodeFactory().Create(concept_j,5.6,7.8));

  const Edges edges
    =
    {
      EdgeFactory().Create(node_f,nodes.at(2),false,nodes.at(1),true),
      EdgeFactory().Create(node_g,nodes.at(3),false,nodes.at(2),true),
      EdgeFactory().Create(node_h,nodes.at(4),false,nodes.at(3),true),
      EdgeFactory().Create(node_i,nodes.at(1),false,nodes.at(4),true),
      EdgeFactory().Create(node_j,nodes.at(0),false,nodes.at(1),true)
    };

  const boost::shared_ptr<ConceptMap> concept_map(
    ConceptMapFactory::Create(nodes,edges));

  assert(concept_map);
  return concept_map;
}

boost::shared_ptr<ribi::cmap::ConceptMap> ribi::cmap::ConceptMapFactory::GetHeteromorphousTestConceptMap16() const noexcept
{
  //[16]: complex rated concept map
  const auto concept_c(ConceptFactory().Create("B", { {"B-1: profession",cmap::Competency::profession} },0,1,2));
  const auto concept_d(ConceptFactory().Create("C", { {"C-1: organisations",cmap::Competency::organisations},{"C-2: social_surroundings",cmap::Competency::social_surroundings}},2,1,0));
  const auto concept_e(ConceptFactory().Create("D", { {"D-1: target_audience",cmap::Competency::target_audience},{"D-2: ti_knowledge",cmap::Competency::ti_knowledge},{"D-3: prof_growth",cmap::Competency::prof_growth},{"D-4: misc",cmap::Competency::misc}},0,1,2));
  const boost::shared_ptr<Node> node_c(NodeFactory().Create(concept_c));
  const boost::shared_ptr<Node> node_d(NodeFactory().Create(concept_d));
  const boost::shared_ptr<Node> node_e(NodeFactory().Create(concept_e));

  const Nodes nodes
    =
    {
      CenterNodeFactory().CreateFromStrings("X"),
      NodeFactory().CreateFromStrings("A"),
      node_c,
      node_d,
      node_e
    };

  const auto concept_f(ConceptFactory().Create("1"));
  const auto concept_h(ConceptFactory().Create("2",{{"2-I",cmap::Competency::misc} } ));
  const auto concept_g(ConceptFactory().Create("3",{{"3-I",cmap::Competency::misc},{"3-II",cmap::Competency::misc} } ));
  const auto concept_i(ConceptFactory().Create("4",{{"4-I",cmap::Competency::misc},{"4-II",cmap::Competency::misc},{"4-III",cmap::Competency::misc} } ));
  const auto concept_j(ConceptFactory().Create("5",{{"5-I",cmap::Competency::misc},{"5-II",cmap::Competency::misc},{"5-III",cmap::Competency::misc},{"5-IV",cmap::Competency::misc} } ));
  const auto node_f(NodeFactory().Create(concept_f,1.2,3.4));
  const auto node_g(NodeFactory().Create(concept_g,2.3,4.5));
  const auto node_h(NodeFactory().Create(concept_h,3.4,5.6));
  const auto node_i(NodeFactory().Create(concept_i,4.5,6.7));
  const auto node_j(NodeFactory().Create(concept_j,5.6,7.8));


  const Edges edges
    =
    {
      EdgeFactory().Create(node_f,nodes.at(2),false,nodes.at(1),true),
      EdgeFactory().Create(node_g,nodes.at(3),false,nodes.at(2),true),
      EdgeFactory().Create(node_h,nodes.at(4),false,nodes.at(3),true),
      EdgeFactory().Create(node_i,nodes.at(1),false,nodes.at(4),true),
      EdgeFactory().Create(node_j,nodes.at(0),false,nodes.at(1),true)
    };

  const boost::shared_ptr<ConceptMap> concept_map(
    ConceptMapFactory::Create(nodes,edges));
  assert(concept_map);
  return concept_map;
}

boost::shared_ptr<ribi::cmap::ConceptMap> ribi::cmap::ConceptMapFactory::GetHeteromorphousTestConceptMap17() const noexcept
{
  //[17]: complex rated concept map with many examples
  const auto concept_c(ConceptFactory().Create("B",
    {
      {"B-P",cmap::Competency::profession},
      {"B-O",cmap::Competency::organisations},
      {"B-S",cmap::Competency::social_surroundings},
      {"B-TA",cmap::Competency::target_audience},
      {"B-TK",cmap::Competency::ti_knowledge},
      {"B-PG",cmap::Competency::prof_growth},
      {"B-M",cmap::Competency::misc}
    },
    0,1,2));
  const auto concept_d(ConceptFactory().Create("C",
    { {"C-1: organisations",cmap::Competency::organisations},{"C-2: social_surroundings",cmap::Competency::social_surroundings}},
    2,1,0));
  const auto concept_e(ConceptFactory().Create("D",
    { {"D-1: target_audience",cmap::Competency::target_audience},{"D-2: ti_knowledge",cmap::Competency::ti_knowledge},{"D-3: prof_growth",cmap::Competency::prof_growth},{"D-4: misc",cmap::Competency::misc}},
    0,1,2));
  const boost::shared_ptr<Node> node_c(NodeFactory().Create(concept_c));
  const boost::shared_ptr<Node> node_d(NodeFactory().Create(concept_d));
  const boost::shared_ptr<Node> node_e(NodeFactory().Create(concept_e));

  const Nodes nodes
    =
    {
      CenterNodeFactory().CreateFromStrings("X"),
      NodeFactory().CreateFromStrings("A"),
      node_c,
      node_d,
      node_e
    };

  const auto concept_f(ConceptFactory().Create("1",
    {{"2-I",cmap::Competency::misc}}
    ));
  const auto concept_h(ConceptFactory().Create("2",
    {{"2-I",cmap::Competency::misc} }
    ));
  const auto concept_g(ConceptFactory().Create("3",
    {{"3-I",cmap::Competency::misc},{"3-II",cmap::Competency::misc} }
    ));
  const auto concept_i(ConceptFactory().Create("4",
    {{"4-I",cmap::Competency::misc},{"4-II",cmap::Competency::misc},{"4-III",cmap::Competency::misc} }
    ));
  const auto concept_j(ConceptFactory().Create("5",
    {{"5-I",cmap::Competency::misc},{"5-II",cmap::Competency::misc},{"5-III",cmap::Competency::misc},{"5-IV",cmap::Competency::misc} }
    ));

  const auto node_f(NodeFactory().Create(concept_f,1.2,3.4));
  const auto node_g(NodeFactory().Create(concept_g,2.3,4.5));
  const auto node_h(NodeFactory().Create(concept_h,3.4,5.6));
  const auto node_i(NodeFactory().Create(concept_i,4.5,6.7));
  const auto node_j(NodeFactory().Create(concept_j,5.6,7.8));

  const Edges edges
    =
    {
      EdgeFactory().Create(node_f,nodes.at(2),false,nodes.at(1),true),
      EdgeFactory().Create(node_g,nodes.at(3),false,nodes.at(2),true),
      EdgeFactory().Create(node_h,nodes.at(4),false,nodes.at(3),true),
      EdgeFactory().Create(node_i,nodes.at(1),false,nodes.at(4),true),
      EdgeFactory().Create(node_j,nodes.at(0),false,nodes.at(1),true)
    };

  const boost::shared_ptr<ConceptMap> concept_map(
    ConceptMapFactory::Create(nodes,edges));
  return concept_map;
}

boost::shared_ptr<ribi::cmap::ConceptMap> ribi::cmap::ConceptMapFactory::GetHeteromorphousTestConceptMap18() const noexcept
{
  //[18]: complex rated concept map with many long concept names and examples
  const auto concept_c(ConceptFactory().Create(
    "B: This is a concept that has all types of competencies as its examples, each example name being multiple lines as well",
    {
      {"B-P: this is B its first example (out of seven) and it is categorized as a competency in the profession domain",cmap::Competency::profession},
      {"B-O: this is B its second example (out of seven) and it is categorized as a competency in the organisation domain",cmap::Competency::organisations},
      {"B-S: this is B its third example (out of seven) and it is categorized as a competency in the social surroundings domain",cmap::Competency::social_surroundings},
      {"B-TA: this is B its fourth example (out of seven) and it is categorized as a competency in the target audience domain",cmap::Competency::target_audience},
      {"B-TK: this is B its fifth example (out of seven) and it is categorized as a competency in the technical instrumental knowledge domain",cmap::Competency::ti_knowledge},
      {"B-PG: this is B its sixth example (out of seven) and it is categorized as a competency in the professional growth domain",cmap::Competency::prof_growth},
      {"B-M: this is B its seventh example (out of seven) and it is categorized as a competency in the misc domain",cmap::Competency::misc}
    },
    0,1,2));
  const auto concept_d(ConceptFactory().Create(
    "C: This is a concept that has only two of the seven types of competencies as its examples, each example name being multiple lines as well",
    {
      {"C-O: this is C its first example (out of two) and it is categorized as a competency in the organisation domain",cmap::Competency::organisations},
      {"C-S: this is C its second example (out of two) and it is categorized as a competency in the social surroundings domain",cmap::Competency::social_surroundings}
    },
    2,1,0));
  const auto concept_e(ConceptFactory().Create(
    "D: This is a concept that has only four of the seven types of competencies as its examples, each example name being multiple lines as well",
    {
      {"D-TA: this is D its first example (out of four) and it is categorized as a competency in the target audience domain",cmap::Competency::target_audience},
      {"D-TK: this is D its second example (out of four) and it is categorized as a competency in the technical instrumental knowledge domain",cmap::Competency::ti_knowledge},
      {"D-PG: this is D its third example (out of four) and it is categorized as a competency in the professional growth domain",cmap::Competency::prof_growth},
      {"D-M: this is D its fourth example (out of four) and it is categorized as a competency in the misc domain",cmap::Competency::misc}
    },
    0,1,2));
  const boost::shared_ptr<Node> node_c(NodeFactory().Create(concept_c));
  const boost::shared_ptr<Node> node_d(NodeFactory().Create(concept_d));
  const boost::shared_ptr<Node> node_e(NodeFactory().Create(concept_e));

  const Nodes nodes
    =
    {
      CenterNodeFactory().CreateFromStrings("X: This is the center node concept that can have no examples, oterwise each of its example name would be multiple lines"),
      NodeFactory().CreateFromStrings("A: This is a concept that has none of all types of competencies as its examples, oterwise each of its example name would be multiple lines"),
      node_c,
      node_d,
      node_e
    };

  const auto concept_f(
    ConceptFactory().Create(
      "1: the first description of a relation that has one example. This description spans multiple lines as it is longer than eighty characters",
      {
        //{"2-I: this misc example ",cmap::Competency::misc}
      }
    )
  );
  const auto concept_h(
    ConceptFactory().Create(
      "2: the second description of a relation that has one example. This description spans multiple lines as it is longer than eighty characters",
      {
        {"2-I: an example of a description of a relation. This example spans multiple lines as it is longer than eighty characters",cmap::Competency::misc}
      }
    )
  );
  const auto concept_g(
    ConceptFactory().Create(
      "3: the third description of a relation that has one example. This description spans multiple lines as it is longer than eighty characters",
      {
        {"3-I: an example of a description of a relation. This example spans multiple lines as it is longer than eighty characters",cmap::Competency::misc},
        {"3-II: an example of a description of a relation. This example spans multiple lines as it is longer than eighty characters",cmap::Competency::misc}
      }
    )
  );
  const auto concept_i(
    ConceptFactory().Create(
      "4: the fourth description of a relation that has one example. This description spans multiple lines as it is longer than eighty characters",
      {
        {"4-I: an example of a description of a relation. This example spans multiple lines as it is longer than eighty characters",cmap::Competency::misc},
        {"4-II: an example of a description of a relation. This example spans multiple lines as it is longer than eighty characters",cmap::Competency::misc},
        {"4-III: an example of a description of a relation. This example spans multiple lines as it is longer than eighty characters",cmap::Competency::misc}
      }
    )
  );
  const auto concept_j(
    ConceptFactory().Create(
      "5: the fifth description of a relation that has one example. This description spans multiple lines as it is longer than eighty characters",
      {
        {"5-I: an example of a description of a relation. This example spans multiple lines as it is longer than eighty characters",cmap::Competency::misc},
        {"5-II: an example of a description of a relation. This example spans multiple lines as it is longer than eighty characters",cmap::Competency::misc},
        {"5-III: an example of a description of a relation. This example spans multiple lines as it is longer than eighty characters",cmap::Competency::misc},
        {"5-IV: an example of a description of a relation. This example spans multiple lines as it is longer than eighty characters",cmap::Competency::misc}
      }
    )
  );

  const auto node_f(NodeFactory().Create(concept_f,1.2,3.4));
  const auto node_g(NodeFactory().Create(concept_g,2.3,4.5));
  const auto node_h(NodeFactory().Create(concept_h,3.4,5.6));
  const auto node_i(NodeFactory().Create(concept_i,4.5,6.7));
  const auto node_j(NodeFactory().Create(concept_j,5.6,7.8));

  const Edges edges
    =
    {
      EdgeFactory().Create(node_f,nodes.at(2),false,nodes.at(1),true),
      EdgeFactory().Create(node_g,nodes.at(3),false,nodes.at(2),true),
      EdgeFactory().Create(node_h,nodes.at(4),false,nodes.at(3),true),
      EdgeFactory().Create(node_i,nodes.at(1),false,nodes.at(4),true),
      EdgeFactory().Create(node_j,nodes.at(0),false,nodes.at(1),true)
    };

  const boost::shared_ptr<ConceptMap> concept_map(
    ConceptMapFactory::Create(nodes,edges));
  return concept_map;
}

boost::shared_ptr<ribi::cmap::ConceptMap> ribi::cmap::ConceptMapFactory::GetHeteromorphousTestConceptMap19() const noexcept
{
  //[19]: complex rated concept map with all nodes connected
  const auto concept_c(ConceptFactory().Create("B", { {"B-1: profession",cmap::Competency::profession} },0,1,2));
  const auto concept_d(ConceptFactory().Create("C", { {"C-1: organisations",cmap::Competency::organisations},{"C-2: social_surroundings",cmap::Competency::social_surroundings}},2,1,0));
  const auto concept_e(ConceptFactory().Create("D", { {"D-1: target_audience",cmap::Competency::target_audience},{"D-2: ti_knowledge",cmap::Competency::ti_knowledge},{"D-3: prof_growth",cmap::Competency::prof_growth},{"D-4: misc",cmap::Competency::misc}},0,1,2));
  const boost::shared_ptr<Node> node_c(NodeFactory().Create(concept_c));
  const boost::shared_ptr<Node> node_d(NodeFactory().Create(concept_d));
  const boost::shared_ptr<Node> node_e(NodeFactory().Create(concept_e));

  const Nodes nodes
    =
    {
      CenterNodeFactory().CreateFromStrings("X"),
      NodeFactory().CreateFromStrings("A"),
      node_c,
      node_d,
      node_e
    };

  const auto concept_f(ConceptFactory().Create("1"));
  const auto concept_h(ConceptFactory().Create("2",{{"2-I",cmap::Competency::misc} } ));
  const auto concept_g(ConceptFactory().Create("3",{{"3-I",cmap::Competency::misc},{"3-II",cmap::Competency::misc} } ));
  const auto concept_i(ConceptFactory().Create("4",{{"4-I",cmap::Competency::misc},{"4-II",cmap::Competency::misc},{"4-III",cmap::Competency::misc} } ));

  ///Concepts connected to the center should never be visible
  const auto concept_j(ConceptFactory().Create("..."));
  const auto concept_k(ConceptFactory().Create("..."));
  const auto concept_l(ConceptFactory().Create("..."));
  const auto concept_m(ConceptFactory().Create("..."));
  const auto concept_n(ConceptFactory().Create("..."));

  const auto node_f(NodeFactory().Create(concept_f,1.2,3.4));
  const auto node_g(NodeFactory().Create(concept_g,2.3,4.5));
  const auto node_h(NodeFactory().Create(concept_h,3.4,5.6));
  const auto node_i(NodeFactory().Create(concept_i,4.5,6.7));
  const auto node_j(NodeFactory().Create(concept_j,5.6,7.8));
  const auto node_k(NodeFactory().Create(concept_k,6.7,8.9));
  const auto node_l(NodeFactory().Create(concept_l,7.8,9.0));
  const auto node_m(NodeFactory().Create(concept_m,8.9,0.1));

  const Edges edges
    =
    {
      EdgeFactory().Create(node_f,nodes.at(2),false,nodes.at(1),true ),
      EdgeFactory().Create(node_g,nodes.at(3),false,nodes.at(2),true ),
      EdgeFactory().Create(node_h,nodes.at(4),false,nodes.at(3),true ),
      EdgeFactory().Create(node_i,nodes.at(1),false,nodes.at(4),true ),
      EdgeFactory().Create(node_j,nodes.at(0),false,nodes.at(1),true ),
      EdgeFactory().Create(node_k,nodes.at(0),false,nodes.at(2),false),
      EdgeFactory().Create(node_l,nodes.at(0),false,nodes.at(3),true ),
      EdgeFactory().Create(node_m,nodes.at(0),true ,nodes.at(4),false)
    };

  const boost::shared_ptr<ConceptMap> concept_map(
    ConceptMapFactory::Create(nodes,edges));
  return concept_map;
}

std::vector<boost::shared_ptr<ribi::cmap::ConceptMap> > ribi::cmap::ConceptMapFactory::GetHeteromorphousTestConceptMaps() const noexcept
{
  std::vector<boost::shared_ptr<ConceptMap> > v{
    GetHeteromorphousTestConceptMap0(),
    GetHeteromorphousTestConceptMap1(),
    GetHeteromorphousTestConceptMap2(),
    GetHeteromorphousTestConceptMap3(),
    GetHeteromorphousTestConceptMap4(),
    GetHeteromorphousTestConceptMap5(),
    GetHeteromorphousTestConceptMap6(),
    GetHeteromorphousTestConceptMap7(),
    GetHeteromorphousTestConceptMap8(),
    GetHeteromorphousTestConceptMap9(),
    GetHeteromorphousTestConceptMap10(),
    GetHeteromorphousTestConceptMap11(),
    GetHeteromorphousTestConceptMap12(),
    GetHeteromorphousTestConceptMap13(),
    GetHeteromorphousTestConceptMap14(),
    GetHeteromorphousTestConceptMap15(),
    GetHeteromorphousTestConceptMap16(),
    GetHeteromorphousTestConceptMap17(),
    GetHeteromorphousTestConceptMap18(),
    GetHeteromorphousTestConceptMap19()
  };
  return v;
}


boost::shared_ptr<ribi::cmap::ConceptMap> ribi::cmap::ConceptMapFactory::GetComplexHomomorphousTestConceptMap(const int i) const noexcept
{
  switch (i)
  {
    case 0: return GetComplexHomomorphousTestConceptMap0();
    case 1: return GetComplexHomomorphousTestConceptMap1();
    case 2: return GetComplexHomomorphousTestConceptMap2();
    case 3: return GetComplexHomomorphousTestConceptMap3();
    case 4: return GetComplexHomomorphousTestConceptMap4();
    case 5: return GetComplexHomomorphousTestConceptMap5();
    case 6: return GetComplexHomomorphousTestConceptMap6();
    case 7: return GetComplexHomomorphousTestConceptMap7();
    case 8: return GetComplexHomomorphousTestConceptMap8();
    case 9: return GetComplexHomomorphousTestConceptMap9();
    case 10: return GetComplexHomomorphousTestConceptMap10();
    case 11: return GetComplexHomomorphousTestConceptMap11();
    default: assert(!"Should not get here");
  }
  assert(!"Should not get here");
  return boost::shared_ptr<ConceptMap>();
}

boost::shared_ptr<ribi::cmap::ConceptMap> ribi::cmap::ConceptMapFactory::GetComplexHomomorphousTestConceptMap0() const noexcept
{
  //[0] (note: same as heteromorphous[11])
  const Nodes nodes
    =
    {
      CenterNodeFactory().CreateFromStrings("X"),
      NodeFactory().CreateFromStrings("A"),
      NodeFactory().CreateFromStrings("B"),
      NodeFactory().CreateFromStrings("C"),
    };

  const auto concept_e(ConceptFactory().Create("1"));
  const auto concept_f(ConceptFactory().Create("2"));
  const auto concept_g(ConceptFactory().Create("3"));

  const auto node_e(NodeFactory().Create(concept_e,1.2,3.4));
  const auto node_f(NodeFactory().Create(concept_f,1.2,3.4));
  const auto node_g(NodeFactory().Create(concept_g,2.3,4.5));

  const Edges edges
    =
    {
      EdgeFactory().Create(node_e,nodes.at(1),false,nodes.at(2),true),
      EdgeFactory().Create(node_f,nodes.at(2),false,nodes.at(3),true),
      EdgeFactory().Create(node_g,nodes.at(3),false,nodes.at(1),true)
    };

  const boost::shared_ptr<ConceptMap> concept_map(
    ConceptMapFactory::Create(nodes,edges));
  assert(concept_map);
  return concept_map;
}

boost::shared_ptr<ribi::cmap::ConceptMap> ribi::cmap::ConceptMapFactory::GetComplexHomomorphousTestConceptMap1() const noexcept
{
  //[1]
  const Nodes nodes
    =
    {
      CenterNodeFactory().CreateFromStrings("X"),
      NodeFactory().CreateFromStrings("A"),
      NodeFactory().CreateFromStrings("C"),
      NodeFactory().CreateFromStrings("B")
    };

  const auto concept_e(ConceptFactory().Create("1"));
  const auto concept_f(ConceptFactory().Create("2"));
  const auto concept_g(ConceptFactory().Create("3"));
  const auto node_e(NodeFactory().Create(concept_e,1.2,3.4));
  const auto node_f(NodeFactory().Create(concept_f,2.3,4.5));
  const auto node_g(NodeFactory().Create(concept_g,3.4,5.6));

  const Edges edges
    =
    {
      EdgeFactory().Create(node_e,nodes.at(1),false,nodes.at(3),true),
      EdgeFactory().Create(node_f,nodes.at(3),false,nodes.at(2),true),
      EdgeFactory().Create(node_g,nodes.at(2),false,nodes.at(1),true)
    };

  const boost::shared_ptr<ConceptMap> concept_map(
    ConceptMapFactory::Create(nodes,edges));
  assert(concept_map);
  return concept_map;
}

boost::shared_ptr<ribi::cmap::ConceptMap> ribi::cmap::ConceptMapFactory::GetComplexHomomorphousTestConceptMap2() const noexcept
{
  //[2]
  const Nodes nodes
    =
    {
      CenterNodeFactory().CreateFromStrings("X"),
      NodeFactory().CreateFromStrings("B"),
      NodeFactory().CreateFromStrings("A"),
      NodeFactory().CreateFromStrings("C")
    };

  const auto concept_e(ConceptFactory().Create("1"));
  const auto concept_f(ConceptFactory().Create("2"));
  const auto concept_g(ConceptFactory().Create("3"));
  const auto node_e(NodeFactory().Create(concept_e,1.2,3.4));
  const auto node_f(NodeFactory().Create(concept_f,2.3,4.5));
  const auto node_g(NodeFactory().Create(concept_g,3.4,5.6));

  const Edges edges
    =
    {
      EdgeFactory().Create(node_e,nodes.at(2),false,nodes.at(1),true),
      EdgeFactory().Create(node_f,nodes.at(1),false,nodes.at(3),true),
      EdgeFactory().Create(node_g,nodes.at(3),false,nodes.at(2),true)
    };

  const boost::shared_ptr<ConceptMap> concept_map(
    ConceptMapFactory::Create(nodes,edges));
  assert(concept_map);
  return concept_map;
}

boost::shared_ptr<ribi::cmap::ConceptMap> ribi::cmap::ConceptMapFactory::GetComplexHomomorphousTestConceptMap3() const noexcept
{
  //[3]
  const Nodes nodes
    =
    {
      CenterNodeFactory().CreateFromStrings("X"),
      NodeFactory().CreateFromStrings("B"),
      NodeFactory().CreateFromStrings("C"),
      NodeFactory().CreateFromStrings("A")
    };

  const auto concept_e(ConceptFactory().Create("1"));
  const auto concept_f(ConceptFactory().Create("2"));
  const auto concept_g(ConceptFactory().Create("3"));
  const auto node_e(NodeFactory().Create(concept_e,1.2,3.4));
  const auto node_f(NodeFactory().Create(concept_f,2.3,4.5));
  const auto node_g(NodeFactory().Create(concept_g,3.4,5.6));

  const Edges edges
    =
    {
      EdgeFactory().Create(node_e,nodes.at(3),false,nodes.at(1),true),
      EdgeFactory().Create(node_f,nodes.at(1),false,nodes.at(2),true),
      EdgeFactory().Create(node_g,nodes.at(2),false,nodes.at(3),true)
    };

  const boost::shared_ptr<ConceptMap> concept_map(
    ConceptMapFactory::Create(nodes,edges));
  assert(concept_map);
  return concept_map;
}

boost::shared_ptr<ribi::cmap::ConceptMap> ribi::cmap::ConceptMapFactory::GetComplexHomomorphousTestConceptMap4() const noexcept
{
  //[4]
  const Nodes nodes
    =
    {
      CenterNodeFactory().CreateFromStrings("X"),
      NodeFactory().CreateFromStrings("C"),
      NodeFactory().CreateFromStrings("A"),
      NodeFactory().CreateFromStrings("B")
    };

  const auto concept_e(ConceptFactory().Create("1"));
  const auto concept_f(ConceptFactory().Create("2"));
  const auto concept_g(ConceptFactory().Create("3"));
  const auto node_e(NodeFactory().Create(concept_e,1.2,3.4));
  const auto node_f(NodeFactory().Create(concept_f,2.3,4.5));
  const auto node_g(NodeFactory().Create(concept_g,3.4,5.6));

  const Edges edges
    =
    {
      EdgeFactory().Create(node_e,nodes.at(2),false,nodes.at(3),true),
      EdgeFactory().Create(node_f,nodes.at(3),false,nodes.at(1),true),
      EdgeFactory().Create(node_g,nodes.at(1),false,nodes.at(2),true)
    };

  const boost::shared_ptr<ConceptMap> concept_map(
    ConceptMapFactory::Create(nodes,edges));
  assert(concept_map);

  return concept_map;
}

boost::shared_ptr<ribi::cmap::ConceptMap> ribi::cmap::ConceptMapFactory::GetComplexHomomorphousTestConceptMap5() const noexcept
{
  //[5]
  const Nodes nodes
    =
    {
      CenterNodeFactory().CreateFromStrings("X"),
      NodeFactory().CreateFromStrings("C"),
      NodeFactory().CreateFromStrings("B"),
      NodeFactory().CreateFromStrings("A")
    };

  const auto concept_e(ConceptFactory().Create("1"));
  const auto concept_f(ConceptFactory().Create("2"));
  const auto concept_g(ConceptFactory().Create("3"));
  const auto node_e(NodeFactory().Create(concept_e,1.2,3.4));
  const auto node_f(NodeFactory().Create(concept_f,2.3,4.5));
  const auto node_g(NodeFactory().Create(concept_g,3.4,5.6));

  const Edges edges
    =
    {
      EdgeFactory().Create(node_e,nodes.at(3),false,nodes.at(2),true),
      EdgeFactory().Create(node_f,nodes.at(2),false,nodes.at(1),true),
      EdgeFactory().Create(node_g,nodes.at(1),false,nodes.at(3),true)
    };

  const boost::shared_ptr<ConceptMap> concept_map(
    ConceptMapFactory::Create(nodes,edges));
  assert(concept_map);

  return concept_map;
}

boost::shared_ptr<ribi::cmap::ConceptMap> ribi::cmap::ConceptMapFactory::GetComplexHomomorphousTestConceptMap6() const noexcept
{
  //[6] (note: same as heteromorphous[11], yet arrows reversed
  const Nodes nodes
    =
    {
      CenterNodeFactory().CreateFromStrings("X"),
      NodeFactory().CreateFromStrings("A"),
      NodeFactory().CreateFromStrings("B"),
      NodeFactory().CreateFromStrings("C")
    };

  const auto concept_e(ConceptFactory().Create("1"));
  const auto concept_f(ConceptFactory().Create("2"));
  const auto concept_g(ConceptFactory().Create("3"));
  const auto node_e(NodeFactory().Create(concept_e,1.2,3.4));
  const auto node_f(NodeFactory().Create(concept_f,2.3,4.5));
  const auto node_g(NodeFactory().Create(concept_g,3.4,5.6));

  const Edges edges
    =
    {
      EdgeFactory().Create(node_e,nodes.at(2),true,nodes.at(1),false),
      EdgeFactory().Create(node_f,nodes.at(3),true,nodes.at(2),false),
      EdgeFactory().Create(node_g,nodes.at(1),true,nodes.at(3),false)
    };

  const boost::shared_ptr<ConceptMap> concept_map(
    ConceptMapFactory::Create(nodes,edges));
  assert(concept_map);
  return concept_map;
}

boost::shared_ptr<ribi::cmap::ConceptMap> ribi::cmap::ConceptMapFactory::GetComplexHomomorphousTestConceptMap7() const noexcept
{
  //[7]
  const Nodes nodes
    =
    {
      CenterNodeFactory().CreateFromStrings("X"),
      NodeFactory().CreateFromStrings("A"),
      NodeFactory().CreateFromStrings("C"),
      NodeFactory().CreateFromStrings("B")
    };

  const auto concept_e(ConceptFactory().Create("1"));
  const auto concept_f(ConceptFactory().Create("2"));
  const auto concept_g(ConceptFactory().Create("3"));
  const auto node_e(NodeFactory().Create(concept_e,1.2,3.4));
  const auto node_f(NodeFactory().Create(concept_f,2.3,4.5));
  const auto node_g(NodeFactory().Create(concept_g,3.4,5.6));

  const Edges edges
    =
    {
      EdgeFactory().Create(node_e,nodes.at(3),true,nodes.at(1),false),
      EdgeFactory().Create(node_f,nodes.at(2),true,nodes.at(3),false),
      EdgeFactory().Create(node_g,nodes.at(1),true,nodes.at(2),false)
    };

  const boost::shared_ptr<ConceptMap> concept_map(
    ConceptMapFactory::Create(nodes,edges));
  assert(concept_map);
  return concept_map;
}

boost::shared_ptr<ribi::cmap::ConceptMap> ribi::cmap::ConceptMapFactory::GetComplexHomomorphousTestConceptMap8() const noexcept
{
  //[8]
  const Nodes nodes
    =
    {
      CenterNodeFactory().CreateFromStrings("X"),
      NodeFactory().CreateFromStrings("B"),
      NodeFactory().CreateFromStrings("A"),
      NodeFactory().CreateFromStrings("C")
    };
  const auto concept_a(ConceptFactory().Create("X"));
  const auto concept_b(ConceptFactory().Create("B"));
  const auto concept_c(ConceptFactory().Create("A"));
  const auto concept_d(ConceptFactory().Create("C"));
  const boost::shared_ptr<Node> node_a(NodeFactory().Create(concept_a));
  const boost::shared_ptr<Node> node_b(NodeFactory().Create(concept_b));
  const boost::shared_ptr<Node> node_c(NodeFactory().Create(concept_c));
  const boost::shared_ptr<Node> node_d(NodeFactory().Create(concept_d));

  const auto concept_e(ConceptFactory().Create("1"));
  const auto concept_f(ConceptFactory().Create("2"));
  const auto concept_g(ConceptFactory().Create("3"));
  const auto node_e(NodeFactory().Create(concept_e,1.2,3.4));
  const auto node_f(NodeFactory().Create(concept_f,2.3,4.5));
  const auto node_g(NodeFactory().Create(concept_g,3.4,5.6));

  const Edges edges
    =
    {
      EdgeFactory().Create(node_e,nodes.at(1),true,nodes.at(2),false),
      EdgeFactory().Create(node_f,nodes.at(3),true,nodes.at(1),false),
      EdgeFactory().Create(node_g,nodes.at(2),true,nodes.at(3),false)
    };

  const boost::shared_ptr<ConceptMap> concept_map(
    ConceptMapFactory::Create(nodes,edges));
  assert(concept_map);
  return concept_map;
}

boost::shared_ptr<ribi::cmap::ConceptMap> ribi::cmap::ConceptMapFactory::GetComplexHomomorphousTestConceptMap9() const noexcept
{
  //[9]
  const Nodes nodes
    =
    {
      CenterNodeFactory().CreateFromStrings("X"),
      NodeFactory().CreateFromStrings("B"),
      NodeFactory().CreateFromStrings("C"),
      NodeFactory().CreateFromStrings("A")
    };
  const auto concept_a(ConceptFactory().Create("X"));
  const auto concept_b(ConceptFactory().Create("B"));
  const auto concept_c(ConceptFactory().Create("C"));
  const auto concept_d(ConceptFactory().Create("A"));
  const boost::shared_ptr<Node> node_a(NodeFactory().Create(concept_a));
  const boost::shared_ptr<Node> node_b(NodeFactory().Create(concept_b));
  const boost::shared_ptr<Node> node_c(NodeFactory().Create(concept_c));
  const boost::shared_ptr<Node> node_d(NodeFactory().Create(concept_d));

  const auto concept_e(ConceptFactory().Create("1"));
  const auto concept_f(ConceptFactory().Create("2"));
  const auto concept_g(ConceptFactory().Create("3"));
  const auto node_e(NodeFactory().Create(concept_e,1.2,3.4));
  const auto node_f(NodeFactory().Create(concept_f,2.3,4.5));
  const auto node_g(NodeFactory().Create(concept_g,3.4,5.6));

  const Edges edges
    =
    {
      EdgeFactory().Create(node_e,nodes.at(1),true,nodes.at(3),false),
      EdgeFactory().Create(node_f,nodes.at(2),true,nodes.at(1),false),
      EdgeFactory().Create(node_g,nodes.at(3),true,nodes.at(2),false)
    };

  const boost::shared_ptr<ConceptMap> concept_map(
    ConceptMapFactory::Create(nodes,edges));
  assert(concept_map);

  return concept_map;
}

boost::shared_ptr<ribi::cmap::ConceptMap> ribi::cmap::ConceptMapFactory::GetComplexHomomorphousTestConceptMap10() const noexcept
{
  //[10]
  const Nodes nodes
    =
    {
      CenterNodeFactory().CreateFromStrings("X"),
      NodeFactory().CreateFromStrings("C"),
      NodeFactory().CreateFromStrings("A"),
      NodeFactory().CreateFromStrings("B")
    };
  const auto concept_e(ConceptFactory().Create("1"));
  const auto concept_f(ConceptFactory().Create("2"));
  const auto concept_g(ConceptFactory().Create("3"));
  const auto node_e(NodeFactory().Create(concept_e,1.2,3.4));
  const auto node_f(NodeFactory().Create(concept_f,2.3,4.5));
  const auto node_g(NodeFactory().Create(concept_g,3.4,5.6));

  const Edges edges
    =
    {
      EdgeFactory().Create(node_e,nodes.at(3),true,nodes.at(2),false),
      EdgeFactory().Create(node_f,nodes.at(1),true,nodes.at(3),false),
      EdgeFactory().Create(node_g,nodes.at(2),true,nodes.at(1),false)
    };

  const boost::shared_ptr<ConceptMap> concept_map(
    ConceptMapFactory::Create(nodes,edges));
  assert(concept_map);

  return concept_map;
}


boost::shared_ptr<ribi::cmap::ConceptMap> ribi::cmap::ConceptMapFactory::GetComplexHomomorphousTestConceptMap11() const noexcept
{
  //[11]
  const Nodes nodes
    =
    {
      CenterNodeFactory().CreateFromStrings("X"),
      NodeFactory().CreateFromStrings("C"),
      NodeFactory().CreateFromStrings("B"),
      NodeFactory().CreateFromStrings("A")
    };

  const auto concept_e(ConceptFactory().Create("1"));
  const auto concept_f(ConceptFactory().Create("2"));
  const auto concept_g(ConceptFactory().Create("3"));
  const auto node_e(NodeFactory().Create(concept_e,1.2,3.4));
  const auto node_f(NodeFactory().Create(concept_f,2.3,4.5));
  const auto node_g(NodeFactory().Create(concept_g,3.4,5.6));

  const Edges edges
    =
    {
      EdgeFactory().Create(node_e,nodes.at(2),true,nodes.at(3),false),
      EdgeFactory().Create(node_f,nodes.at(1),true,nodes.at(2),false),
      EdgeFactory().Create(node_g,nodes.at(3),true,nodes.at(1),false)
    };

  const boost::shared_ptr<ConceptMap> concept_map(
    ConceptMapFactory::Create(nodes,edges));
  assert(concept_map);
  return concept_map;
}

std::vector<boost::shared_ptr<ribi::cmap::ConceptMap> > ribi::cmap::ConceptMapFactory::GetComplexHomomorphousTestConceptMaps() const noexcept
{
  std::vector<boost::shared_ptr<ConceptMap> > v;
  for (int i=0; i!=12; ++i) { v.push_back(GetComplexHomomorphousTestConceptMap(i)); }
  return v;
}

std::vector<boost::shared_ptr<ribi::cmap::ConceptMap> > ribi::cmap::ConceptMapFactory::GetSimpleHomomorphousTestConceptMaps() const noexcept
{
  std::vector<boost::shared_ptr<ConceptMap> > v(6);
  assert(std::count_if(v.begin(),v.end(),[](const boost::shared_ptr<ConceptMap>& p) { return p; } ) == 0);
  //[0]
  {
    const Nodes nodes
      =
      {
        CenterNodeFactory().CreateFromStrings("X"),
        NodeFactory().CreateFromStrings("A"),
        NodeFactory().CreateFromStrings("B"),
        NodeFactory().CreateFromStrings("C")
      };
    const Edges edges
      =
      {

      };

    const boost::shared_ptr<ConceptMap> concept_map(
      ConceptMapFactory::Create(nodes,edges));
    assert(concept_map);
    v[0] = concept_map;
  }

  //[1]
  {
    const Nodes nodes
      =
      {
        CenterNodeFactory().CreateFromStrings("X"),
        NodeFactory().CreateFromStrings("A"),
        NodeFactory().CreateFromStrings("C"),
        NodeFactory().CreateFromStrings("B")
      };
    const Edges edges
      =
      {

      };
    const boost::shared_ptr<ConceptMap> concept_map(
      ConceptMapFactory::Create(nodes,edges));
    assert(concept_map);
    v[1] = concept_map;
  }
  //[2]
  {
    const Nodes nodes
      =
      {
        CenterNodeFactory().CreateFromStrings("X"),
        NodeFactory().CreateFromStrings("B"),
        NodeFactory().CreateFromStrings("A"),
        NodeFactory().CreateFromStrings("C")
      };

    const Edges edges
      =
      {

      };

    const boost::shared_ptr<ConceptMap> concept_map(
      ConceptMapFactory::Create(nodes,edges));
    assert(concept_map);
    v[2] = concept_map;
  }
  //[3]
  {
    const Nodes nodes
      =
      {
        CenterNodeFactory().CreateFromStrings("X"),
        NodeFactory().CreateFromStrings("B"),
        NodeFactory().CreateFromStrings("C"),
        NodeFactory().CreateFromStrings("A")
      };

    const Edges edges
      =
      {

      };
    const boost::shared_ptr<ConceptMap> concept_map(
      ConceptMapFactory::Create(nodes,edges));
    assert(concept_map);
    v[3] = concept_map;
  }

  //[4]
  {
    const Nodes nodes
      =
      {
        CenterNodeFactory().CreateFromStrings("X"),
        NodeFactory().CreateFromStrings("C"),
        NodeFactory().CreateFromStrings("A"),
        NodeFactory().CreateFromStrings("B")
      };

    const Edges edges
      =
      {

      };

    const boost::shared_ptr<ConceptMap> concept_map(
      ConceptMapFactory::Create(nodes,edges));
    assert(concept_map);
    v[4] = concept_map;
  }

  //[5]
  {
    const Nodes nodes
      =
      {
        CenterNodeFactory().CreateFromStrings("X"),
        NodeFactory().CreateFromStrings("C"),
        NodeFactory().CreateFromStrings("B"),
        NodeFactory().CreateFromStrings("A")
      };

    const Edges edges
      =
      {

      };

    const boost::shared_ptr<ConceptMap> concept_map(
      ConceptMapFactory::Create(nodes,edges));
    assert(concept_map);
    v[5] = concept_map;
  }
  return v;
}

#ifndef NDEBUG
void ribi::cmap::ConceptMapFactory::Test() noexcept
{
  {
    static bool is_tested{false};
    if (is_tested) return;
    is_tested = true;
  }
  const bool verbose{false};
  CenterNodeFactory();
  EdgeFactory();
  ConceptMapFactory().GetHeteromorphousTestConceptMap(0);
  const TestTimer test_timer(__func__,__FILE__,1.0);
  if (verbose) { TRACE("All testing concept maps must be valid"); }
  {
    for (const auto& concept_map: ConceptMapFactory().GetAllTests())
    {
      if (!concept_map) continue;
      assert(concept_map);
      for (const auto& node: concept_map->GetNodes())
      {
        assert(node);
      }
      for (const auto& edge: concept_map->GetEdges())
      {
        assert(edge);
        assert(edge->GetTo());
        assert(edge->GetFrom());
        assert(std::count(
          concept_map->GetNodes().begin(),
          concept_map->GetNodes().end(),
          edge->GetTo()) == 1);
        assert(std::count(
          concept_map->GetNodes().begin(),
          concept_map->GetNodes().end(),
          edge->GetFrom()) == 1);
      }
    }
  }
}
#endif // NDEBUG

 

 

 

 

 

./CppConceptMap/conceptmapfwd.h

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#ifndef CONCEPTMAPFWD_H
#define CONCEPTMAPFWD_H

//struct QRegExp;
//struct QTimer;

namespace ribi {
namespace cmap {

struct CenterNode;
struct CenterNodeFactory;
//struct Cluster; //Remove for now, must be added at ProjectBrainweaver later
struct Command;
struct CommandAddSelectedRandom;
struct CommandDeleteFocusNode;
struct CommandUnselectRandom;
struct Concept;
struct ConceptFactory;
struct ConceptMap;
struct ConceptMapFactory;
struct Edge;
struct EdgeFactory;
struct Element;
struct Example;
struct Examples;
//struct File;
struct Node;
struct Widget;

} //~namespace cmap
} //~namespace ribi

#endif // CONCEPTMAPFWD_H

 

 

 

 

 

./CppConceptMap/conceptmaphelper.h

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#ifndef CONCEPTMAPHELPER_H
#define CONCEPTMAPHELPER_H

#include <array>
#include <vector>
#include <string>
#include <vector>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#include <boost/array.hpp>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/shared_ptr.hpp>
#pragma GCC diagnostic pop

namespace ribi {

///Help adding constness a bit
template <class T>
std::vector<boost::shared_ptr<const T> > AddConst(
  const std::vector<boost::shared_ptr<T> > v) noexcept
{
  const std::vector<boost::shared_ptr<const T> > w(v.begin(),v.end());
  return w;
}

///Help adding constness a bit
template <class T>
std::vector<const T *> AddConst(
  const std::vector<T *> v) noexcept
{
  const std::vector<const T *> w(v.begin(),v.end());
  return w;
}

template <class T>
std::vector<boost::shared_ptr<T> > RemoveConst(
  std::vector<boost::shared_ptr<const T> > v) noexcept
{
  std::vector<boost::shared_ptr<T>> w;
  std::transform(
    std::begin(v),
    std::end(v),
    std::back_inserter(w),
    [](boost::shared_ptr<const T>& edge)
    {
      return boost::const_pointer_cast<T>(edge);
    }
  );
  return w;
}

namespace cmap {

///Obtain all possible selections of a std::vector, preserving the ordering of its elements
///Examples:
/// {     } -> { {}                                              }
/// {1    } -> { {}, {1}                                         }
/// {1,2  } -> { {}, {1}, {2},      {1,2}                        }
/// {1,2,3} -> { {}, {1}, {2}, {3}, {1,2}, {1,3}, {2,3}, {1,2,3} }
//From http://www.richelbilderbeek.nl/GetPermutations.htm
template <class T>
const std::vector<std::vector<T> > GetCombinations(const std::vector<T>& v)
{
  std::vector<std::vector<T> > result;
  const int sz = boost::numeric_cast<int>(v.size());
  const int n_combinations = (1 << sz);

  for (int i=0; i!=n_combinations; ++i)
  {
    std::vector<T> w;
    for (int j=0; j!=sz; ++j)
    {
      if ((1 << j) & i)
      {
        w.push_back(v[j]);
      }
    }
    result.push_back(w);
  }
  return result;
}

///Obtain the Pythagorian distance from two delta's
//From www.richelbilderbeek.nl/CppGetDistance.htm
double GetDistance(const double delta_x, const double delta_y);

///Obtain the Pythagorian distance from two coordinats
//From www.richelbilderbeek.nl/CppGetDistance.htm
double GetDistance(const double x1, const double y1, const double x2, const double y2);

///SafeFileToVector calls FileToVector and
///removes an empty trailing line that can be created under
///the Windows operating system, due to different line endings
std::vector<std::string> SafeFileToVector(const std::string& filename) noexcept;

#ifndef NDEBUG
///Test the helper functions
void TestHelperFunctions() noexcept;
#endif

///Undo a Wordwrap
std::string Unwordwrap(const std::vector<std::string>& v) noexcept;

///Wordwrap the text to obtain lines of max_len characters
///If the string _must_ be seperable by spaces; a word can have a maximum length of max_len
std::vector<std::string> Wordwrap(const std::string& s, const std::size_t max_len) noexcept;

} //~namespace cmap
} //~namespace ribi

#endif // CONCEPTMAPHELPER_H

 

 

 

 

 

./CppConceptMap/conceptmaphelper.cpp

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#include "conceptmaphelper.h"

#include <cassert>
#include <iostream>
#include <fstream>

#include <boost/algorithm/string.hpp>
#include <QFile>
#include <QRegExp>

#include "fileio.h"
#include "conceptmapregex.h"
#include "testtimer.h"
#include "trace.h"
#pragma GCC diagnostic pop

double ribi::cmap::GetDistance(const double delta_x, const double delta_y)
{
  #ifndef NDEBUG
  cmap::TestHelperFunctions();
  #endif
  return std::sqrt( (delta_x * delta_x) + (delta_y * delta_y) );
}

double ribi::cmap::GetDistance(const double x1, const double y1, const double x2, const double y2)
{
  #ifndef NDEBUG
  cmap::TestHelperFunctions();
  #endif
  return GetDistance(x1-x2,y1-y2);
}

std::vector<std::string> ribi::cmap::SafeFileToVector(const std::string& filename) noexcept
{
  std::vector<std::string> v = ribi::fileio::FileIo().FileToVector(filename);
  if (!v.empty() && v.back().empty()) v.pop_back();
  return v;
}

#ifndef NDEBUG
void ribi::cmap::TestHelperFunctions() noexcept
{
  {
    static bool is_tested{false};
    if (is_tested) return;
    is_tested = true;
  }
  const TestTimer test_timer(__func__,__FILE__,1.0);
  //GetRegexMatches
  {
    const std::string s = "In the Netherlands, 1234 AB and 2345 BC are valid zip codes";
    std::vector<std::string> expected;
    expected.push_back("1234 AB");
    expected.push_back("2345 BC");
    {
      const std::string r = "(\\d{4} [A-Z]{2})";
      assert(Regex().GetRegexMatches(s,(r.c_str())) == expected);
    }
  }
  {
    const std::string s = "<concept><name>Concept with examples</name><example>Example 1</example><example>Example 2</example><example>Example 3</example></concept>";
    assert(std::count(s.begin(),s.end(),'\b') == 0);
    std::vector<std::string> expected;
    expected.push_back("<example>Example 1</example>");
    expected.push_back("<example>Example 2</example>");
    expected.push_back("<example>Example 3</example>");
    {
      const std::string r = "(<example>.*?</example>)";
      assert(Regex().GetRegexMatches(s,(r.c_str())) == expected);
    }
  }
  //GetCombinations
  //Assume the number of elements is correct
  assert(GetCombinations(std::vector<int>( {         } ) ).size() ==  1);
  assert(GetCombinations(std::vector<int>( {1        } ) ).size() ==  2);
  assert(GetCombinations(std::vector<int>( {1,2      } ) ).size() ==  4);
  assert(GetCombinations(std::vector<int>( {1,2,3    } ) ).size() ==  8);
  assert(GetCombinations(std::vector<int>( {1,2,3,4  } ) ).size() == 16);
  assert(GetCombinations(std::vector<int>( {1,2,3,4,5} ) ).size() == 32);
  //Assume the elements are correct
  {
    const std::vector<std::vector<int> > v = GetCombinations(std::vector<int>( { 1 } ) );
    const std::vector<int> expected_0 = {};
    const std::vector<int> expected_1 = {1};
    assert(std::count(v.begin(),v.end(),expected_0));
    assert(std::count(v.begin(),v.end(),expected_1));
  }
  {
    const std::vector<std::vector<int> > v = GetCombinations(std::vector<int>( { 1,2 } ) );
    const std::vector<int> expected_0 = {};
    const std::vector<int> expected_1 = {1};
    const std::vector<int> expected_2 = {2};
    const std::vector<int> expected_3 = {1,2};
    assert(std::count(v.begin(),v.end(),expected_0));
    assert(std::count(v.begin(),v.end(),expected_1));
    assert(std::count(v.begin(),v.end(),expected_2));
    assert(std::count(v.begin(),v.end(),expected_3));
  }
  {
    const std::vector<std::vector<int> > v = GetCombinations(std::vector<int>( { 1,2,3 } ) );
    const std::vector<int> expected_0 = {};
    const std::vector<int> expected_1 = {1};
    const std::vector<int> expected_2 = {2};
    const std::vector<int> expected_3 = {3};
    const std::vector<int> expected_4 = {1,2};
    const std::vector<int> expected_5 = {1,3};
    const std::vector<int> expected_6 = {2,3};
    const std::vector<int> expected_7 = {1,2,3};
    assert(std::count(v.begin(),v.end(),expected_0));
    assert(std::count(v.begin(),v.end(),expected_1));
    assert(std::count(v.begin(),v.end(),expected_2));
    assert(std::count(v.begin(),v.end(),expected_3));
    assert(std::count(v.begin(),v.end(),expected_4));
    assert(std::count(v.begin(),v.end(),expected_5));
    assert(std::count(v.begin(),v.end(),expected_6));
    assert(std::count(v.begin(),v.end(),expected_7));
  }
  {
    const std::vector<std::vector<int> > v = GetCombinations(std::vector<int>( { 1,2,3,4 } ) );
    const std::vector<int> expected_0 = {};
    const std::vector<int> expected_1 = {1};
    const std::vector<int> expected_2 = {2};
    const std::vector<int> expected_3 = {3};
    const std::vector<int> expected_4 = {4};
    const std::vector<int> expected_5 = {1,2};
    const std::vector<int> expected_6 = {1,3};
    const std::vector<int> expected_7 = {1,4};
    const std::vector<int> expected_8 = {2,3};
    const std::vector<int> expected_9 = {2,4};
    const std::vector<int> expected_10 = {3,4};
    const std::vector<int> expected_11 = {1,2,3};
    const std::vector<int> expected_12 = {1,2,4};
    const std::vector<int> expected_13 = {1,3,4};
    const std::vector<int> expected_14 = {2,3,4};
    const std::vector<int> expected_15 = {1,2,3,4};
    assert(std::count(v.begin(),v.end(),expected_0));
    assert(std::count(v.begin(),v.end(),expected_1));
    assert(std::count(v.begin(),v.end(),expected_2));
    assert(std::count(v.begin(),v.end(),expected_3));
    assert(std::count(v.begin(),v.end(),expected_4));
    assert(std::count(v.begin(),v.end(),expected_5));
    assert(std::count(v.begin(),v.end(),expected_6));
    assert(std::count(v.begin(),v.end(),expected_7));
    assert(std::count(v.begin(),v.end(),expected_8));
    assert(std::count(v.begin(),v.end(),expected_9));
    assert(std::count(v.begin(),v.end(),expected_10));
    assert(std::count(v.begin(),v.end(),expected_11));
    assert(std::count(v.begin(),v.end(),expected_12));
    assert(std::count(v.begin(),v.end(),expected_13));
    assert(std::count(v.begin(),v.end(),expected_14));
    assert(std::count(v.begin(),v.end(),expected_15));
  }
  //Wordwrap
  {
    const auto v {
      "",
      "1",
      "12",
      "123",
      "1234",
      "12345",
      "123456",
      "1234567",
      "12345678",
      "123456789",
      "1234567890",
      "12345678901",
      "123456789012",
      "1234567890123",
      "12345678901234",
      "123456789012345",
      "1234567890123456",
      "12345678901234567",
      "123456789012345678",
      "1234567890123456789",
      "12345678901234567890",
      "123456789012345678901",
      "1234567890123456789012",
      "12345678901234567890123",
      "123456789012345678901234",
      "1234567890123456789012345",
      "12345678901234567890123456",
      "123456789012345678901234567",
      "1234567890123456789012345678",
      "12345678901234567890123456789",
      "123456789012345678901234567890",
      "1234567890123456789012345678901",
      "12345678901234567890123456789012",
      "123456789012345678901234567890123",
      "1234567890123456789012345678901234",
      "12345678901234567890123456789012345",
      "123456789012345678901234567890123456",
      "1234567890123456789012345678901234567",
      "12345678901234567890123456789012345678",
      "123456789012345678901234567890123456789",
      "1234567890123456789012345678901234567890",
      "1 1",
      "12 12",
      "123 123",
      "1234 1234",
      "12345 12345",
      "123456 123456",
      "1234567 1234567",
      "12345678 8",
      "123456789 9",
      "1234567890 0",
      "1234567890 1234567890",
      "1234567890 1234567890 1234567890",
      "1234567890 1234567890 1234567890 1234567890",
      "1234567890 1234567890 1234567890 1234567890 1234567890",
      "1234567890 1234567890 1234567890 1234567890 1234567890 1234567890",
      "1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890",
      "1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890",
      "1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890",
      "1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890",
      "1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890",
      "1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890",
      "1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890",
      "1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890",
      " 1",
      "  1",
      "  1 ",
      "  1  ",
      "  1 2 ",
      "  1 23 ",
      "  12 34  ",
      "  12  34  ",
      "   12   34   ",
      "   12   34   5",
      "   12   34   5 ",
      "   12   34   5 6",
      "0   12   34   5 6",
      "0   12   34   5 6  ",
      "                    ",
      "                      ",
      "                        ",
      "                            ",
      "                                    ",
      "                                                    ",
      "                                                                                     "
    };
    for (int len=1; len!=1000; ++len)
    {
      for (const std::string& s: v)
      {
        //Wordwrap calls Unwordwrap
        Wordwrap(s,len);
      }
    }
  }
}
#endif

std::string ribi::cmap::Unwordwrap(const std::vector<std::string>& v) noexcept
{
  //Simply concatenate
  std::string t;
  for (const std::string& s: v) { t += s; }
  return t;
}

std::vector<std::string> ribi::cmap::Wordwrap(
  const std::string& s_original, const std::size_t max_len) noexcept
{
  if (max_len == 0)
  {
    throw std::logic_error("Cannot wordwrap for a max_len of zero");
  }
  //std::clog << "Wordwrap \'" << s_original << '\'' << std::endl;
  std::string s{s_original};
  assert(s.size() == s_original.size());

  ///Replace multiple spaces with '\b ', where x is a char not in the string
  std::string::value_type x = '\b'; //Bell
  {
    const std::size_t sz = s.size();

    ///Replace spaces at beginning
    for (std::size_t i=0; i!=sz; ++i)
    {
      if (s[i] == ' ')
        s[i] = x;
      else
        break;
    }
    //Replace spaces at end
    if (sz > 0)
    {
      //i!=0, because if s[0] is a space, it is already converted to bell
      for (std::size_t i=sz-1; i!=0; ++i)
      {
        if (s[i] == ' ')
          s[i] = x;
        else
          break;
      }
    }
    ///Replace "  " by "\b "
    for (std::size_t i=0; i!=sz-1; ++i)
    {
      if (s[i] == ' ' && s[i+1] == ' ')
        s[i] = x;
      else
        break;
    }
  }

  std::vector<std::string> v;

  //Start the actual wordwrapping
  while (!s.empty())
  {
    //Is the word short enough?
    if (s.size() < max_len)
    {
      //Copy entire word
      v.push_back(s);
      s = {};
      assert(s.empty());
      continue;
    }
    //No spaces, or space beyond max_len: cut word
    if (s.find(' ') == std::string::npos || s.find(' ') > max_len)
    {
      v.push_back(s.substr(0,max_len));
      s = s.substr(max_len,s.size() - max_len);
      continue;
    }
    //Find last space before max_len
    std::size_t len = s.find(' ');
    assert(len != std::string::npos);
    assert(len < s.size());
    while (1)
    {
      const std::size_t new_len = s.find(' ',len + 1);
      if (new_len > max_len || new_len == std::string::npos) break;
      len = new_len;
    }
    assert(len + 0 < s.size());
    assert(len + 1 < s.size());
    //cut s, put cut part in vector
    const std::string line = s.substr(0,len+1); //Keep space
    assert(!line.empty());
    v.push_back(line);
    const std::size_t new_index = len+1; //After the space found
    assert(new_index < s.size());
    const std::string new_s = s.substr(new_index,s.size() - new_index);
    assert(s != new_s);
    s = new_s;
  }

  ///Replace bell characters by spaces again
  for (std::string& s: v)
  {
    assert(x != ' ');
    std::size_t pos = s.find(x);
    while (pos != std::string::npos)
    {
      assert(pos != std::string::npos);
      assert(pos < s.size());
      assert(pos == s.find(x)); //To prevent infinite while loop
      s[pos] = ' ';
      assert(s[pos] == ' ');
      assert(pos != s.find(x)); //To prevent infinite while loop
      pos = s.find(x);
    }
    assert(s.find(x) == std::string::npos);
  }

  #ifndef NDEBUG
  //Test if Unwordwrap the result produces the original input
  if (Unwordwrap(v) != s_original)
  {
    std::cerr << v.size() << '\n';
    std::copy(v.begin(),v.end(),std::ostream_iterator<std::string>(std::cerr,"\n"));
    std::cerr << Unwordwrap(v) << '\n';
    std::cerr << s_original << std::endl;

  }
  #endif
  assert(Unwordwrap(v) == s_original);
  return v;
}

 

 

 

 

 

./CppConceptMap/conceptmapnode.h

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#ifndef CONCEPTMAPNODE_H
#define CONCEPTMAPNODE_H

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#include <boost/signals2.hpp>
#include <boost/shared_ptr.hpp>
#include "conceptmapfwd.h"
#include "conceptmapelement.h"
#pragma GCC diagnostic pop

namespace ribi {
namespace cmap {

struct NodeFactory;

///A Node is a Concept with coordinats, that is used as an Element in a ConceptMap
///A Node is the GUI independent part of a node. It is displayed as:
/// - QtNode (as QtConceptMapElement: a QGraphicsItem, to be used in a QGraphicsView)
/// - QtNodeDialog (as a QDialog, to be used in a QDialog)
///Node is used as a base class by:
/// - CenterNode
struct  Node : public Element
{
  Node(const Node&) = delete;
  Node& operator=(const Node&) = delete;

  ///Get the Concept
  boost::shared_ptr<const Concept>  GetConcept() const noexcept { return m_concept; }
  boost::shared_ptr<      Concept>& GetConcept()       noexcept { return m_concept; }

  ///Get some test nodes
  static std::vector<boost::shared_ptr<Node>> GetTests() noexcept;

  ///Get the x coordinat
  double GetX() const noexcept { return m_x; }

  ///Get the y coordinat
  double GetY() const noexcept { return m_y; }

  ///Similar to operator==, except that GUI elements are not tested for equality
  static bool HasSameContent(const boost::shared_ptr<const Node>& lhs, const boost::shared_ptr<const Node>& rhs) noexcept;

  ///Set the concept
  void SetConcept(const boost::shared_ptr<Concept>& concept) noexcept;

  ///Set the position
  void SetPos(const double x, const double y) noexcept { SetX(x); SetY(y); }

  ///Set the x coordinat
  void SetX(const double x) noexcept;

  ///Set the y coordinat
  void SetY(const double y) noexcept;

  virtual std::string ToXml() const noexcept;
  std::string ToStr() const noexcept;

  mutable boost::signals2::signal<void(Node *)> m_signal_concept_changed;
  mutable boost::signals2::signal<void(Node *)> m_signal_x_changed;
  mutable boost::signals2::signal<void(Node *)> m_signal_y_changed;

  protected:
  ///Block construction, except for NodeFactory and derived classes
  Node() = delete;
  friend class NodeFactory;

  ///Use NodeFactory as an unused argument to enforce using it
  explicit Node(
    const boost::shared_ptr<Concept>& concept,
    const double x,
    const double y,
    const NodeFactory& lock
  );

  ///Block destructor, except for the friend boost::checked_delete
  virtual ~Node() noexcept {}
  friend void boost::checked_delete<>(Node* x);

  private:

  ///The Concept
  boost::shared_ptr<Concept> m_concept;

  ///The x-coordinat
  double m_x;

  ///The y-coordinat
  double m_y;

  ///Called whenever something on Concept changes
  ///Re-emits m_concept_changed with 'this'
  void OnConceptChanged(Concept * const this_concept) noexcept;

  #ifndef NDEBUG
  static void Test() noexcept;
  #endif

};


bool operator==(const Node& lhs, const Node& rhs) noexcept;
bool operator!=(const Node& lhs, const Node& rhs) noexcept;
bool operator<(const Node& lhs, const Node& rhs) noexcept;
std::ostream& operator<<(std::ostream& os, const Node& node) noexcept;

} //~namespace cmap
} //~namespace ribi

#endif // CONCEPTMAPNODE_H

 

 

 

 

 

./CppConceptMap/conceptmapnode.cpp

 

//---------------------------------------------------------------------------
/*
ConceptMap, concept map classes
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppConceptMap.htm
//---------------------------------------------------------------------------
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#include "conceptmapnode.h"

//#include <boost/lexical_cast.hpp>
#include <boost/lambda/lambda.hpp>
//#include <QRegExp>

#include "counter.h"
#include "conceptmapconcept.h"
#include "conceptmapconceptfactory.h"
#include "conceptmapnodefactory.h"
#include "conceptmapexamplefactory.h"
#include "conceptmaphelper.h"
#include "testtimer.h"
#include "trace.h"
#include "xml.h"
#pragma GCC diagnostic pop

ribi::cmap::Node::Node(
  const boost::shared_ptr<ribi::cmap::Concept>& concept,
  const double x,
  const double y,
  const NodeFactory&
) : m_signal_concept_changed{},
    m_signal_x_changed{},
    m_signal_y_changed{},
    m_concept{},
    m_x(x),
    m_y(y)
{
  #ifndef NDEBUG
  Test();
  #endif
  SetConcept(concept);
  assert(m_concept == concept);
}


std::vector<boost::shared_ptr<ribi::cmap::Node> > ribi::cmap::Node::GetTests() noexcept
{
  const auto test_concepts = ConceptFactory().GetTests();
  std::vector<boost::shared_ptr<Node> > result;
  std::for_each(test_concepts.begin(),test_concepts.end(),
    [&result](const boost::shared_ptr<Concept>& concept)
    {
      const int x = (std::rand() % 256) - 128;
      const int y = (std::rand() % 256) - 128;
      const auto node = NodeFactory().Create(concept,x,y);
      result.push_back(node);
    }
  );
  return result;
}

bool ribi::cmap::Node::HasSameContent(const boost::shared_ptr<const Node>& lhs, const boost::shared_ptr<const Node>& rhs) noexcept
{
  assert(lhs);
  assert(rhs);
  return *lhs->GetConcept() == *rhs->GetConcept();
}

void ribi::cmap::Node::OnConceptChanged(Concept * const) noexcept
{
  m_signal_concept_changed(this);
}

void ribi::cmap::Node::SetConcept(const boost::shared_ptr<Concept>& concept) noexcept
{
  const bool verbose{false};

  assert(concept);
  if (m_concept == concept)
  {
    return;
  }

  if (verbose)
  {
    std::stringstream s;
    s << "Setting concept '" << concept->ToStr() << "'\n";
  }

  const auto examples_after = concept->GetExamples();
  const auto is_complex_after = concept->GetIsComplex();
  const auto name_after = concept->GetName();
  const auto rating_complexity_after = concept->GetRatingComplexity();
  const auto rating_concreteness_after = concept->GetRatingConcreteness();
  const auto rating_specificity_after = concept->GetRatingSpecificity();

  bool examples_changed{true};
  bool is_complex_changed{true};
  bool name_changed{true};
  bool rating_complexity_changed{true};
  bool rating_concreteness_changed{true};
  bool rating_specificity_changed{true};

  if (m_concept)
  {
    const auto examples_before = m_concept->GetExamples();
    const auto is_complex_before = m_concept->GetIsComplex();
    const auto name_before = m_concept->GetName();
    const auto rating_complexity_before = m_concept->GetRatingComplexity();
    const auto rating_concreteness_before = m_concept->GetRatingConcreteness();
    const auto rating_specificity_before = m_concept->GetRatingSpecificity();

    examples_changed = examples_before != examples_after;
    is_complex_changed = is_complex_before != is_complex_after;
    name_changed = name_before != name_after;
    rating_complexity_changed = rating_complexity_before != rating_complexity_after;
    rating_concreteness_changed = rating_concreteness_before != rating_concreteness_after;
    rating_specificity_changed = rating_specificity_before != rating_specificity_after;

    if (verbose)
    {
      if (examples_changed)
      {
        std::stringstream s;
        s
          << "Examples will change from "
          << examples_before->ToStr()
          << " to "
          << examples_after->ToStr()
          << '\n'
        ;
        TRACE(s.str());
      }
      if (is_complex_changed)
      {
        std::stringstream s;
        s << "Is complex will change from " << is_complex_before
          << " to " << is_complex_after << '\n';
        TRACE(s.str());
      }
      if (name_changed)
      {
        std::stringstream s;
        s << "Name will change from " << name_before
          << " to " << name_after << '\n';
        TRACE(s.str());
      }
      if (rating_complexity_changed)
      {
        std::stringstream s;
        s << "Rating_complexicity will change from " << rating_complexity_before
          << " to " << rating_complexity_after << '\n';
        TRACE(s.str());
      }
      if (rating_concreteness_changed)
      {
        std::stringstream s;
        s << "Rating_concreteness will change from " << rating_concreteness_before
          << " to " << rating_concreteness_after << '\n';
        TRACE(s.str());
      }
      if (rating_specificity_changed)
      {
        std::stringstream s;
        s << "Rating_specificity will change from " << rating_specificity_before
          << " to " << rating_specificity_after << '\n';
        TRACE(s.str());
      }

    }
    //Disconnect
    m_concept->m_signal_examples_changed.disconnect(
      boost::bind(&ribi::cmap::Node::OnConceptChanged,this,boost::lambda::_1)
    );
    m_concept->m_signal_is_complex_changed.disconnect(
      boost::bind(&ribi::cmap::Node::OnConceptChanged,this,boost::lambda::_1)
    );
    m_concept->m_signal_name_changed.disconnect(
      boost::bind(&ribi::cmap::Node::OnConceptChanged,this,boost::lambda::_1)
    );
    m_concept->m_signal_rating_complexity_changed.disconnect(
      boost::bind(&ribi::cmap::Node::OnConceptChanged,this,boost::lambda::_1)
    );
    m_concept->m_signal_rating_concreteness_changed.disconnect(
      boost::bind(&ribi::cmap::Node::OnConceptChanged,this,boost::lambda::_1)
    );
    m_concept->m_signal_rating_specificity_changed.disconnect(
      boost::bind(&ribi::cmap::Node::OnConceptChanged,this,boost::lambda::_1)
    );
  }

  //Replace m_example by the new one
  m_concept = concept;


  assert(m_concept->GetExamples() == examples_after );
  assert(m_concept->GetIsComplex() == is_complex_after );
  assert(m_concept->GetName() == name_after);
  assert(m_concept->GetRatingComplexity() == rating_complexity_after);
  assert(m_concept->GetRatingConcreteness() == rating_concreteness_after);
  assert(m_concept->GetRatingSpecificity() == rating_specificity_after);


  m_concept->m_signal_examples_changed.connect(
    boost::bind(&ribi::cmap::Node::OnConceptChanged,this,boost::lambda::_1)
  );
  m_concept->m_signal_is_complex_changed.connect(
    boost::bind(&ribi::cmap::Node::OnConceptChanged,this,boost::lambda::_1)
  );
  m_concept->m_signal_name_changed.connect(
    boost::bind(&ribi::cmap::Node::OnConceptChanged,this,boost::lambda::_1)
  );
  m_concept->m_signal_rating_complexity_changed.connect(
    boost::bind(&ribi::cmap::Node::OnConceptChanged,this,boost::lambda::_1)
  );
  m_concept->m_signal_rating_concreteness_changed.connect(
    boost::bind(&ribi::cmap::Node::OnConceptChanged,this,boost::lambda::_1)
  );
  m_concept->m_signal_rating_specificity_changed.connect(
    boost::bind(&ribi::cmap::Node::OnConceptChanged,this,boost::lambda::_1)
  );

  //Emit everything that has changed
  if (examples_changed)
  {
    m_concept->m_signal_examples_changed(m_concept.get());
  }
  if (is_complex_changed)
  {
    m_concept->m_signal_is_complex_changed(m_concept.get());
  }
  if (name_changed)
  {
    m_concept->m_signal_name_changed(m_concept.get());
  }
  if (rating_complexity_changed)
  {
    m_concept->m_signal_rating_complexity_changed(m_concept.get());
  }
  if (rating_concreteness_changed)
  {
    m_concept->m_signal_rating_concreteness_changed(m_concept.get());
  }
  if (rating_specificity_changed)
  {
    m_concept->m_signal_rating_specificity_changed(m_concept.get());
  }

  assert( concept ==  m_concept);
  assert(*concept == *m_concept);
}

void ribi::cmap::Node::SetX(const double x) noexcept
{
  const bool verbose{false};
  if (m_x != x)
  {
    m_x = x;
    if (verbose) { TRACE("Emitting m_signal_x_changed"); }
    m_signal_x_changed(this);
  }
}

void ribi::cmap::Node::SetY(const double y) noexcept
{
  if (m_y != y)
  {
    m_y = y;
    m_signal_y_changed(this);
  }
}

#ifndef NDEBUG
void ribi::cmap::Node::Test() noexcept
{
  {
    static bool is_tested{false};
    if (is_tested) return;
    is_tested = true;
  }
  const TestTimer test_timer(__func__,__FILE__,1.0);
  const bool verbose{false};
  {
    const std::vector<boost::shared_ptr<Node> > v = Node::GetTests();