void ribi::cmap::QtEdge::OnNodeChanged(const Edge& edge) noexcept
{
  assert(!"Am I called?");
  m_qtnode->SetCenterX(edge.GetNode().GetX());
  m_qtnode->SetCenterY(edge.GetNode().GetY());
  m_qtnode->SetText( { edge.GetNode().GetConcept().GetName() } );
  this->update();
  if (this->scene()) { this->scene()->update(); }
}
void ribi::cmap::qtconceptmapedgedialog_test::all_tests()
{
  using namespace ribi::cmap;
  const bool verbose{false};
  const Node from = NodeFactory().GetTest(0);
  const Node to = NodeFactory().GetTest(0);
  Edge edge = EdgeFactory().GetTest(0);
  QtEdgeDialog dialog(edge);
  if (verbose) { TRACE("X of QtNode and QtNodeDialog must match at start"); }
  {
    QVERIFY(std::abs(dialog.GetUiX() - edge.GetNode().GetX()) < 2.0);
  }
  if (verbose) { TRACE("SetX and GetX must be symmetric"); }
  {
    const double new_x{dialog.GetUiX() + 10.0};
    dialog.SetUiX(new_x);
    QVERIFY(std::abs(dialog.GetUiX() - new_x) < 1.0);
  }
  if (verbose) { TRACE("SetY and GetY must be symmetric"); }
  {
    const double new_y{dialog.GetUiY() + 10.0};
    dialog.SetUiY(new_y);
    QVERIFY(std::abs(dialog.GetUiY() - new_y) < 1.0);
  }
  if (verbose) { TRACE("If X is set via Edge, QtNodeDialog must sync"); }
  {
    const double old_x{edge.GetNode().GetX()};
    const double new_x{old_x + 10.0};
    edge.GetNode().SetX(new_x);
    QVERIFY(std::abs(new_x - dialog.GetUiX()) < 2.0);
  }
  if (verbose) { TRACE("SetUiHasHeadArrow and GetUiHasHeadArrow must be symmetric"); }
  {
    dialog.SetUiHasHeadArrow(true);
    QVERIFY(dialog.GetUiHasHeadArrow());
    dialog.SetUiHasHeadArrow(false);
    QVERIFY(!dialog.GetUiHasHeadArrow());
  }
  if (verbose) { TRACE("SetUiHasTailArrow and GetUiHasTailArrow must be symmetric"); }
  {
    dialog.SetUiHasHeadArrow(true);
    QVERIFY(dialog.GetUiHasHeadArrow());
    dialog.SetUiHasHeadArrow(false);
    QVERIFY(!dialog.GetUiHasHeadArrow());
  }
}
ribi::cmap::QtEdge::QtEdge(
    const Edge& edge,
    QtNode * const from,
    QtNode * const to
)
  : m_arrow{nullptr}, //Will be initialized below
    m_edge{edge},
    m_from{from},
    m_qtnode{new QtNode(edge.GetNode(), this)}, //parent
    m_show_bounding_rect{false},
    m_to{to}
{
  //Allow mouse tracking
  //OTOH: must be done by the other thing
  //this->setAcceptHoverEvents(true);

  //const_cast because Arrow constant
  //I just need to have an initialized m_qtnode
  const_cast<Arrow&>(m_arrow) = new QtQuadBezierArrowItem(
    from,
    false, //edge.HasTailArrow(),
    this->GetQtNode(),
    false, //edge.HasHeadArrow(),
    to,
    this // parent
  );

  //QtEdge is just the glue between a collection of things
  //this->setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsFocusable);

  this->m_arrow->setFlags(0);

  #define BELIEF_THAT_QTEDGE_SHOULD_NOT_BE_SELECTABLE
  #ifdef  BELIEF_THAT_QTEDGE_SHOULD_NOT_BE_SELECTABLE
  this->setFlags(0);
  #else
  this->setFlags(
      QGraphicsItem::ItemIsFocusable
    | QGraphicsItem::ItemIsMovable
    | QGraphicsItem::ItemIsSelectable
  );
  #endif

  GetQtNode()->setFlags(
      QGraphicsItem::ItemIsFocusable
    | QGraphicsItem::ItemIsMovable
    | QGraphicsItem::ItemIsSelectable
  );

  assert(m_from);
  assert(m_to);
  assert(from != to);
  assert(m_from != m_to);
  //m_edge must be initialized before m_arrow
  //if 'from' or 'to' are CenterNodes, then no item must be put at the center
  const bool is_connected_to_center_node
    = dynamic_cast<QtCenterNode*>(from) || dynamic_cast<QtCenterNode*>(to);
  if (is_connected_to_center_node)
  {
    m_arrow->SetMidX( (m_arrow->GetFromX() + m_arrow->GetToX()) / 2.0 );
    m_arrow->SetMidY( (m_arrow->GetFromY() + m_arrow->GetToY()) / 2.0 );
  }

  m_edge.GetNode().SetX( (from->GetCenterX() + to->GetCenterX()) / 2.0 );
  m_edge.GetNode().SetY( (from->GetCenterY() + to->GetCenterY()) / 2.0 );

  m_qtnode->SetCenterX(m_edge.GetNode().GetX());
  m_qtnode->SetCenterY(m_edge.GetNode().GetY());
  m_qtnode->SetText( { m_edge.GetNode().GetConcept().GetName() } );
  assert(std::abs(m_edge.GetNode().GetY() - m_qtnode->GetCenterY()) < 2.0);

  //Set Z values
  this->setZValue(-1.0);
  m_arrow->setZValue(-1.0);
  m_qtnode->setZValue(1.0);
}