#include #include #include #include /////////////////////////////////////////////////////////// // Callbacks /////////////////////////////////////////////////////////// HIDDEN bool callback_compare_node(TTree& node, void* jolly, word when) { const TString& id = *((TString*)jolly); TString cur_id; node.curr_id(cur_id); return id == cur_id; } HIDDEN bool callback_expand_node(TTree& node, void* jolly, word when) { if (when == SCAN_PRE_ORDER) node.expand(); return false; } HIDDEN bool callback_find_father(TTree& node, void* jolly, word when) { TString_array& father_and_son = *(TString_array*)jolly; TString myself; node.curr_id(myself); if (when == SCAN_PRE_ORDER) { if (myself == father_and_son.row(1)) father_and_son.add(myself, 0); } else { if (father_and_son.objptr(0)) { father_and_son.add(myself, 0); return true; } } return false; } HIDDEN bool callback_find_brother(TTree& node, void* jolly, word when) { TString_array& brother_and_sister = *(TString_array*)jolly; TString myself; node.curr_id(myself); if (when == SCAN_PRE_ORDER) { if (myself == brother_and_sister.row(1)) brother_and_sister.add(myself, 0); } else { if (brother_and_sister.objptr(0)) { brother_and_sister.add(myself, 0); return true; } } return false; } /////////////////////////////////////////////////////////// // TTtree /////////////////////////////////////////////////////////// bool TTree::scan_depth_first(NODE_HANDLER nh, void* jolly, word flags) { if ((flags & 0x7) == 0) flags |= SCAN_PRE_ORDER; bool test_myself = true; if ((flags & SCAN_IGNORING_LEAVES) && !has_son()) test_myself = false; TString myself; curr_id(myself); if (test_myself) { if ((flags & SCAN_PRE_ORDER) && nh(*this, jolly, SCAN_PRE_ORDER)) return true; const bool stop = (flags & SCAN_IGNORING_UNEXPANDED) && !expanded(); if (!stop && goto_firstson()) { if (scan_depth_first(nh, jolly, flags)) return true; goto_node(myself); } if ((flags & SCAN_IN_ORDER) && nh(*this, jolly, SCAN_IN_ORDER)) return true; } if (goto_rbrother()) { if (scan_depth_first(nh, jolly, flags)) return true; goto_node(myself); } if (test_myself) { if ((flags & SCAN_POST_ORDER) && nh(*this, jolly, SCAN_POST_ORDER)) return true; } return false; } bool TTree::scan_breadth_first(NODE_HANDLER nh, void* jolly, word flags) { if ((flags & 0x7) == 0) flags |= SCAN_PRE_ORDER; bool test_myself = true; if ((flags & SCAN_IGNORING_LEAVES) && !has_son()) test_myself = false; if (test_myself) { if ((flags & SCAN_PRE_ORDER) && nh(*this, jolly, SCAN_PRE_ORDER)) return true; } TString myself; curr_id(myself); if (goto_rbrother()) { if (scan_breadth_first(nh, jolly, flags)) return true; goto_node(myself); } if (test_myself) { if ((flags & SCAN_IN_ORDER) && nh(*this, jolly, SCAN_IN_ORDER)) return true; const bool stop = (flags & SCAN_IGNORING_UNEXPANDED) && !expanded(); if (!stop && goto_firstson()) { if (scan_breadth_first(nh, jolly, flags)) return true; goto_node(myself); } if ((flags & SCAN_POST_ORDER) && nh(*this, jolly, SCAN_POST_ORDER)) return true; } return false; } bool TTree::has_root() const { TString myself; curr_id(myself); bool ok = ((TTree*)this)->goto_root(); if (ok) ((TTree*)this)->goto_node(myself); return ok; } bool TTree::has_father() const { TString myself; curr_id(myself); bool ok = ((TTree*)this)->goto_father(); if (ok) ((TTree*)this)->goto_node(myself); return ok; } bool TTree::goto_father() { TString myself; curr_id(myself); bool ok = goto_root(); if (ok) { TString_array father_and_son; father_and_son.add(myself, 1); ok = scan_breadth_first(callback_find_father, &father_and_son, SCAN_PRE_ORDER | SCAN_IN_ORDER); } if (!ok) goto_node(myself); return ok; } bool TTree::has_lbrother() const { TString myself; curr_id(myself); bool ok = ((TTree*)this)->goto_lbrother(); if (ok) ((TTree*)this)->goto_node(myself); return ok; } bool TTree::goto_lbrother() { TString myself; curr_id(myself); bool ok = goto_root(); if (ok) { TString_array brother_and_sister; brother_and_sister.add(myself, 1); ok = scan_depth_first(callback_find_brother, &brother_and_sister, SCAN_PRE_ORDER | SCAN_POST_ORDER); } if (!ok) goto_node(myself); return ok; } bool TTree::has_rbrother() const { TString myself; curr_id(myself); bool ok = ((TTree*)this)->goto_rbrother(); if (ok) ((TTree*)this)->goto_node(myself); return ok; } bool TTree::has_son() const { TString myself; curr_id(myself); bool ok = ((TTree*)this)->goto_firstson(); if (ok) ((TTree*)this)->goto_node(myself); return ok; } bool TTree::expanded() const { TString str; curr_id(str); bool yes = _expanded.is_key(str); return yes; } bool TTree::expand() { bool ok = enabled() && has_son(); if (ok) { TString str; curr_id(str); ok = !_expanded.is_key(str); if (ok) _expanded.add(str); } return ok; } bool TTree::shrink() { TString str; curr_id(str); bool ok = _expanded.is_key(str); if (ok) _expanded.remove(str); return ok; } bool TTree::expand_all() { bool ok = goto_root(); if (ok) scan_breadth_first(callback_expand_node, NULL); return ok; } bool TTree::shrink_all() { _expanded.destroy(); return goto_root(); } TImage* TTree::get_res_image(short bmp_id) const { TImage* bmp = (TImage*)_image.objptr(bmp_id); if (bmp == NULL) { bmp = new TImage(bmp_id); if (bmp->ok()) { bmp->convert_transparent_color(NORMAL_BACK_COLOR); ((TTree*)this)->_image.add(bmp, bmp_id); } else { delete bmp; bmp = NULL; } } return bmp; } TImage* TTree::image(bool selected) const { short bmp_id = BMP_FILE; if (has_son()) bmp_id = selected ? BMP_DIRDN : BMP_DIR; return get_res_image(bmp_id); } /////////////////////////////////////////////////////////// // TBidirectional_tree /////////////////////////////////////////////////////////// bool TBidirectional_tree::scan_depth_first(NODE_HANDLER nh, void* jolly, word flags) { if ((flags & 0x7) == 0) flags |= SCAN_PRE_ORDER; bool test_myself = true; if ((flags & SCAN_IGNORING_LEAVES) && !has_son()) test_myself = false; if (test_myself) { if ((flags & SCAN_PRE_ORDER) && nh(*this, jolly, SCAN_PRE_ORDER)) return true; const bool stop = (flags & SCAN_IGNORING_UNEXPANDED) && !expanded(); if (!stop && goto_firstson()) { if (scan_depth_first(nh, jolly, flags)) return true; goto_father(); } if ((flags & SCAN_IN_ORDER) && nh(*this, jolly, SCAN_IN_ORDER)) return true; } if (goto_rbrother()) { if (scan_depth_first(nh, jolly, flags)) return true; goto_lbrother(); } if (test_myself) { if ((flags & SCAN_POST_ORDER) && nh(*this, jolly, SCAN_POST_ORDER)) return true; } return false; } bool TBidirectional_tree::scan_breadth_first(NODE_HANDLER nh, void* jolly, word flags) { if ((flags & 0x7) == 0) flags |= SCAN_PRE_ORDER; bool test_myself = true; if ((flags & SCAN_IGNORING_LEAVES) && !has_son()) test_myself = false; if (test_myself) { if ((flags & SCAN_PRE_ORDER) && nh(*this, jolly, SCAN_PRE_ORDER)) return true; } if (goto_rbrother()) { if (scan_breadth_first(nh, jolly, flags)) return true; goto_lbrother(); } if (test_myself) { if ((flags & SCAN_IN_ORDER) && nh(*this, jolly, SCAN_IN_ORDER)) return true; const bool stop = (flags & SCAN_IGNORING_UNEXPANDED) && !expanded(); if (!stop && goto_firstson()) { if (scan_breadth_first(nh, jolly, flags)) return true; goto_father(); } if ((flags & SCAN_POST_ORDER) && nh(*this, jolly, SCAN_POST_ORDER)) return true; } return false; } bool TBidirectional_tree::goto_node(const TString &id) { bool ok = goto_root(); if (ok && id.not_empty()) ok = scan_breadth_first(callback_compare_node, (void *)&id); return ok; } /////////////////////////////////////////////////////////// // TObject tree /////////////////////////////////////////////////////////// bool TObject_tree::expanded() const { bool ok = _current && _current->_expanded; return ok; } bool TObject_tree::expand() { bool ok = _current && _current->_son && !_current->_expanded && enabled(); if (ok) _current->_expanded = true; return ok; } bool TObject_tree::shrink() { bool ok = _current && _current->_expanded; if (ok) _current->_expanded = false; return ok; } void TObject_tree::node2id(const TObject* node, TString& id) const { id.format("%p", (const void*)node); } bool TObject_tree::goto_node(const TString& node) { void* p = NULL; if (node.not_empty()) { #ifdef DBG_TREE if (!_expanded.is_key(node)) // Usa l'assoc array per testare i nodi validi! { NFCHECK("Invalid node: %s", (const char*)node); return goto_root(); } #endif sscanf(node, "%p", &p); } bool ok = true; if (p == NULL) ok = goto_root(); else _current = (TTree_node*)p; return ok; } bool TObject_tree::goto_root() { _current = _root; return _root != NULL; } bool TObject_tree::goto_firstson() { TTree_node* n = _current ? _current->_son : NULL; if (n) _current = n; return n != NULL; } bool TObject_tree::goto_rbrother() { TTree_node* n = _current ? _current->_rbrother : NULL; if (n) _current = n; return n != NULL; } bool TObject_tree::goto_father() { TTree_node* n = _current ? _current->_father : NULL; if (n) _current = n; return n != NULL; } bool TObject_tree::goto_lbrother() { TTree_node* n = _current ? _current->_lbrother : NULL; if (n) _current = n; return n != NULL; } bool TObject_tree::set_object(TObject* obj) { if (_current) { #ifdef DBG_TREE TString str; curr_id(str); _expanded.add(str); // Usa l'assoc array per memorizzare i nodi validi! #endif if (_current->_obj) delete _current->_obj; _current->_obj = obj; } return _current != NULL; } bool TObject_tree::set_object(const TObject& obj) { bool ok = false; if (_current) { TObject* ptr = obj.dup(); ok = set_object(ptr); if (!ok) delete ptr; } return ok; } bool TObject_tree::create_root() { if (!has_root()) _root = _current = new TTree_node; return goto_root(); } bool TObject_tree::add_son(TObject* obj) { bool ok = false; if (_root) { TTree_node*& curson = _current->_son; TTree_node* newson = new TTree_node; newson->_father = _current; if (curson != NULL) { curson->_lbrother = newson; newson->_rbrother = curson; } curson = newson; ok = goto_firstson(); } else ok = create_root(); if (ok) ok = set_object(obj); return ok; } bool TObject_tree::add_son(const TObject& obj) { TObject* ptr = obj.dup(); bool ok = add_son(ptr); if (!ok) delete ptr; return ok; } bool TObject_tree::add_brother(TObject* obj) { bool ok = false; if (goto_father()) ok = add_son(obj); else ok = create_root() && set_object(obj); return ok; } bool TObject_tree::add_brother(const TObject& obj) { TObject* ptr = obj.dup(); bool ok = add_brother(ptr); if (!ok) delete ptr; return ok; } bool TObject_tree::add_rbrother(TObject* obj) { bool ok = false; if (has_father()) { TTree_node* newbrother = new TTree_node; newbrother->_father = _current->_father; newbrother->_lbrother = _current; newbrother->_rbrother = _current->_rbrother; _current->_rbrother = newbrother; ok = goto_rbrother(); } else ok = create_root(); if (ok) set_object(obj); return ok; } bool TObject_tree::add_rbrother(const TObject& obj) { TObject* ptr = obj.dup(); bool ok = add_rbrother(ptr); if (!ok) delete ptr; return ok; } bool TObject_tree::add_lbrother(TObject* obj) { bool ok = false; if (has_father()) { if (_current->_lbrother == NULL) ok = add_brother(obj); else { TTree_node* newbrother = new TTree_node; newbrother->_father = _current->_father; newbrother->_rbrother = _current; newbrother->_lbrother = _current->_lbrother; _current->_lbrother = newbrother; ok = goto_lbrother(); } } else ok = create_root(); if (ok) set_object(obj); return ok; } bool TObject_tree::add_lbrother(const TObject& obj) { TObject* ptr = obj.dup(); bool ok = add_lbrother(ptr); if (!ok) delete ptr; return ok; } bool TObject_tree::kill_node() { bool ok = false; if (_current) { TTree_node* cur = _current; while (goto_firstson()) { kill_node(); _current = cur; } if (_current->_lbrother) { _current->_lbrother->_rbrother = _current->_rbrother; } else { if (_current->_father) _current->_father->_son = _current->_rbrother; } if (_current->_rbrother) _current->_rbrother->_lbrother = _current->_lbrother; #ifdef DBG_TREE TString id; curr_id(id); _expanded.remove(id); #endif TTree_node* to_be_killed = _current; if (_current == _root) _root = NULL; if (_current->_rbrother) _current = _current->_rbrother; else { if (_current->_lbrother) _current = _current->_lbrother; else _current = _current->_father; } delete to_be_killed; ok = true; } return ok; } bool TObject_tree::get_description(TString& str) const { TObject* obj = curr_node(); if (obj) str << *obj; return obj != NULL; } TObject_tree::TObject_tree() { _root = _current = NULL; } TObject_tree::~TObject_tree() { if (goto_root()) kill_node(); } /////////////////////////////////////////////////////////// // TString_tree /////////////////////////////////////////////////////////// bool TString_tree::get_description(TString& str) const { const TString* obj = (const TString*)curr_node(); if (obj) str = *obj; else str.cut(0); return obj != NULL; }