#include #include "TreeView.h" using namespace ts; using namespace std; using LinkedTreeEntry = ts::TreeView::LinkedTreeEntry; TreeView::TreeView() {} TreeView::~TreeView() { std::deque> heads = {this->head}; while(!heads.empty()) { auto e = std::move(heads.front()); heads.pop_front(); while(e) { if(e->child_head) heads.push_back(e->child_head); //Release reference if(e->previous) e->previous->next = nullptr; e->previous = nullptr; e->child_head = nullptr; e = e->next; } } } std::shared_ptr TreeView::linked(const std::shared_ptr& entry) const { if(!entry) return nullptr; std::deque> heads = {this->head}; while(!heads.empty()) { auto e = std::move(heads.front()); heads.pop_front(); while(e) { if(e->entry->channelId() == entry->channelId()) return e; else { if(e->child_head) heads.push_back(e->child_head); e = e->next; } } } return nullptr; } std::deque> TreeView::query_deep(const std::shared_ptr& root, int deep) const { std::deque> result; this->query_deep_(result, root ? root : this->head, deep); return result; } void TreeView::query_deep_(deque>& result, const shared_ptr& root, int deep) const { if(deep == 0) return; shared_ptr entry = root; while(entry) { result.push_back(entry); if(entry->child_head) this->query_deep_(result, entry->child_head, deep - 1); entry = entry->next; } } size_t TreeView::entry_count() const { size_t result = 0; std::deque> heads = {this->head}; while(!heads.empty()) { auto e = std::move(heads.front()); heads.pop_front(); while(e) { result++; if(e->child_head) heads.push_back(e->child_head); e = e->next; } } return result; } std::shared_ptr TreeView::find_entry(ts::ChannelId channelId) const { auto result = this->find_linked_entry(channelId); return result ? result->entry : nullptr; } std::shared_ptr TreeView::find_linked_entry(ChannelId channelId, const std::shared_ptr& head, int deep) const { std::deque> heads; heads.push_back(head ? head : this->head); while(!heads.empty()) { auto e = std::move(heads.front()); heads.pop_front(); while(e) { if(e->entry->channelId() == channelId) return e; if(e->child_head) { if(deep-- == 0) { //Reached max deep. Dont go deeper deep++; } else { if(e->next) heads.push_back(e->next); e = e->child_head; continue; } } e = e->next; } deep++; } return nullptr; } std::deque> TreeView::entries(const std::shared_ptr& root, int deep) const { return this->query_deep_entry(this->linked(root), deep); } std::deque> TreeView::entries_sub(const std::shared_ptr &root, int deep) const { auto l_root = this->linked(root); if(l_root && !l_root->child_head) return {root}; auto result = this->query_deep_entry(l_root ? l_root->child_head : l_root, deep); result.push_back(root); return result; } std::deque> TreeView::query_deep_entry(const shared_ptr& root, int deep) const { auto result = this->query_deep(root, deep); std::deque> mapped; for(const auto& e : result) if(e->entry) mapped.push_back(e->entry); return mapped; } bool TreeView::has_entry(const std::shared_ptr &entry, const std::shared_ptr &root, int deep) const { auto l_root = this->linked(root); if(!l_root && root) return false; return this->has_entry_(entry, l_root ? l_root : this->head, deep); } bool TreeView::has_entry_(const shared_ptr &entry, const shared_ptr &head, int deep) const { shared_ptr element = head; while(element && deep != 0) { if(element->entry->channelId() == entry->channelId()) return true; if(element->child_head) if(this->has_entry_(entry, element->child_head, deep - 1)) return true; element = element->next; } return false; } bool TreeView::insert_entry(const shared_ptr &entry, const std::shared_ptr &t_parent, const shared_ptr &t_previous) { auto linked = make_shared(entry); linked->entry->setLinkedHandle(linked); /* Insert channel at the root at the back */ if(!this->head) { this->head = linked; linked->entry->setPreviousChannelId(0); linked->entry->setParentChannelId(0); return true; } auto last = this->head; while(last->next) last = last->next; last->next = linked; linked->previous = last; if(!this->move_entry(entry, t_parent, t_previous)) { //FIXME delete it again return false; } return true; } bool TreeView::move_entry(const std::shared_ptr &t_entry, const std::shared_ptr &t_parent, const std::shared_ptr &t_previous) { if(t_entry == t_parent || t_entry == t_previous || (t_parent && t_parent == t_previous)) return false; auto entry = this->linked(t_entry); if(!entry) return false; auto parent = this->linked(t_parent); if(!parent && t_parent) return false; if(parent && entry->child_head) { auto childs = this->query_deep(entry->child_head); for(const auto& child : childs) if(child == parent) return false; } auto previous = this->linked(t_previous); if(!previous && t_previous) return false; if(previous && !this->has_entry_(t_previous, parent ? parent : this->head, 2)) return false; //Test if the t_parent channel contains t_previous /* cut the entry out */ this->cut_entry(entry); entry->parent.reset(); /* insert again */ if(!this->head) { this->head = entry; entry->entry->setPreviousChannelId(0); return true; } entry->parent = parent; entry->entry->setParentChannelId(parent ? parent->entry->channelId() : 0); if(previous) { //Insert within the mid auto old_next = previous->next; //previous insert previous->next = entry; entry->previous = previous; entry->entry->setPreviousChannelId(previous->entry->channelId()); //next insert entry->next = old_next; if(old_next) { old_next->previous = entry; old_next->entry->setPreviousChannelId(entry->entry->channelId()); } } else { if(parent) { entry->next = parent->child_head; parent->child_head = entry; } else { entry->next = this->head; this->head = entry; } if(entry->next) { entry->next->previous = entry; entry->next->entry->setPreviousChannelId(entry->entry->channelId()); } entry->entry->setPreviousChannelId(0); } return true; } void TreeView::cut_entry(const std::shared_ptr& entry) { if(this->head == entry) { this->head = entry->next; if(this->head) { this->head->previous = nullptr; this->head->entry->setPreviousChannelId(0); } } else { if(entry->previous) { assert(entry->previous->next == entry); entry->previous->next = entry->next; } else if(entry->parent.lock()) { auto e_parent = entry->parent.lock(); assert(e_parent->child_head == entry); e_parent->child_head = entry->next; } if(entry->next) { assert(entry->next->previous == entry); entry->next->previous = entry->previous; entry->next->entry->setPreviousChannelId(entry->previous ? entry->previous->entry->channelId() : 0); } } entry->next = nullptr; entry->previous = nullptr; } std::deque> TreeView::delete_entry(shared_ptr t_entry) { auto entry = this->linked(t_entry); if(!entry) return {}; this->cut_entry(entry); std::deque> result; std::deque> heads = {entry}; while(!heads.empty()) { auto e = std::move(heads.front()); heads.pop_front(); while(e) { if(e->child_head) heads.push_back(e->child_head); result.push_back(e->entry); //Release reference if(e->previous) e->previous->next = nullptr; e->previous = nullptr; e->child_head = nullptr; //e->entry = nullptr; if(e->entry->channelId() == t_entry->channelId()) { e = nullptr; } else { e = e->next; } } } std::reverse(result.begin(), result.end()); //Delete channels from the bottom to the top return result; } void TreeView::print_tree(const std::function &, int)> &print) const { return this->print_tree_(print, this->head, 0); } void TreeView::print_tree_(const std::function &, int)> &print, shared_ptr head, int deep) const { while(head) { print(head->entry, deep); this->print_tree_(print, head->child_head, deep + 1); head = head->next; } }