/*
This file is part of Ingen.
Copyright 2007-2015 David Robillard
Ingen is free software: you can redistribute it and/or modify it under the
terms of the GNU Affero General Public License as published by the Free
Software Foundation, either version 3 of the License, or any later version.
Ingen 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 Affero General Public License for details.
You should have received a copy of the GNU Affero General Public License
along with Ingen. If not, see .
*/
#include "ingen/client/GraphModel.hpp"
#include "ingen/URIs.hpp"
#include "ingen/client/ArcModel.hpp"
#include "ingen/client/BlockModel.hpp"
#include "ingen/client/ClientStore.hpp"
#include
#include
#include
namespace ingen {
namespace client {
void
GraphModel::add_child(SPtr c)
{
assert(c->parent().get() == this);
SPtr pm = dynamic_ptr_cast(c);
if (pm) {
add_port(pm);
return;
}
SPtr bm = dynamic_ptr_cast(c);
if (bm) {
_signal_new_block.emit(bm);
}
}
bool
GraphModel::remove_child(SPtr o)
{
assert(o->path().is_child_of(path()));
assert(o->parent().get() == this);
SPtr pm = dynamic_ptr_cast(o);
if (pm) {
remove_arcs_on(pm);
remove_port(pm);
}
SPtr bm = dynamic_ptr_cast(o);
if (bm) {
_signal_removed_block.emit(bm);
}
return true;
}
void
GraphModel::remove_arcs_on(SPtr p)
{
// Remove any connections which referred to this object,
// since they can't possibly exist anymore
for (auto j = _arcs.begin(); j != _arcs.end();) {
auto next = j;
++next;
SPtr arc = dynamic_ptr_cast(j->second);
if (arc->tail_path().parent() == p->path()
|| arc->tail_path() == p->path()
|| arc->head_path().parent() == p->path()
|| arc->head_path() == p->path()) {
_signal_removed_arc.emit(arc);
_arcs.erase(j); // Cuts our reference
}
j = next;
}
}
void
GraphModel::clear()
{
_arcs.clear();
BlockModel::clear();
assert(_arcs.empty());
assert(_ports.empty());
}
SPtr
GraphModel::get_arc(const Node* tail, const Node* head)
{
auto i = _arcs.find(std::make_pair(tail, head));
if (i != _arcs.end()) {
return dynamic_ptr_cast(i->second);
} else {
return SPtr();
}
}
/** Add a connection to this graph.
*
* A reference to `arc` is taken, released on deletion or removal.
* If `arc` only contains paths (not pointers to the actual ports), the ports
* will be found and set. The ports referred to not existing as children of
* this graph is a fatal error.
*/
void
GraphModel::add_arc(SPtr arc)
{
// Store should have 'resolved' the connection already
assert(arc);
assert(arc->tail());
assert(arc->head());
assert(arc->tail()->parent());
assert(arc->head()->parent());
assert(arc->tail_path() != arc->head_path());
assert(arc->tail()->parent().get() == this
|| arc->tail()->parent()->parent().get() == this);
assert(arc->head()->parent().get() == this
|| arc->head()->parent()->parent().get() == this);
SPtr existing = get_arc(
arc->tail().get(), arc->head().get());
if (existing) {
assert(arc->tail() == existing->tail());
assert(arc->head() == existing->head());
} else {
_arcs.emplace(std::make_pair(arc->tail().get(), arc->head().get()),
arc);
_signal_new_arc.emit(arc);
}
}
void
GraphModel::remove_arc(const Node* tail, const Node* head)
{
auto i = _arcs.find(std::make_pair(tail, head));
if (i != _arcs.end()) {
SPtr arc = dynamic_ptr_cast(i->second);
_signal_removed_arc.emit(arc);
_arcs.erase(i);
}
}
bool
GraphModel::enabled() const
{
const Atom& enabled = get_property(_uris.ingen_enabled);
return (enabled.is_valid() && enabled.get());
}
uint32_t
GraphModel::internal_poly() const
{
const Atom& poly = get_property(_uris.ingen_polyphony);
return poly.is_valid() ? poly.get() : 1;
}
bool
GraphModel::polyphonic() const
{
const Atom& poly = get_property(_uris.ingen_polyphonic);
return poly.is_valid() && poly.get();
}
} // namespace client
} // namespace ingen