|
MythTV
0.26-pre
|
00001 00002 // Mythui headers 00003 #include "mythgenerictree.h" 00004 #include "mythuibuttonlist.h" 00005 00006 // Myth headers 00007 #include "mythlogging.h" 00008 00009 class SortableMythGenericTreeList : public QList<MythGenericTree*> 00010 { 00011 public: 00012 SortableMythGenericTreeList() : m_sortType(SORT_ATTRIBUTE), 00013 m_attributeIndex(0) { } 00014 enum SortType {SORT_ATTRIBUTE=0, SORT_STRING=1, SORT_SELECTABLE=3, 00015 SORT_ATT_THEN_STRING}; 00016 00017 void SetSortType(SortType stype) { m_sortType = stype; } 00018 void SetAttributeIndex(int index) 00019 { m_attributeIndex = (index >= 0) ? index : 0; } 00020 00021 // static int sortByAttribute(MythGenericTree *one, MythGenericTree *two) 00022 // { 00023 // int onea = one->getAttribute(m_attributeIndex); 00024 // int twoa = two->getAttribute(m_attributeIndex); 00025 // 00026 // if (onea == twoa) 00027 // return 0; 00028 // else if (onea < twoa) 00029 // return -1; 00030 // else 00031 // return 1; 00032 // } 00033 00034 static int sortByString(MythGenericTree *one, MythGenericTree *two) 00035 { 00036 QString ones = one->getString().toLower(); 00037 QString twos = two->getString().toLower(); 00038 return QString::localeAwareCompare(ones, twos); 00039 } 00040 00041 static int sortBySelectable(MythGenericTree *one, MythGenericTree *two) 00042 { 00043 bool onesel = one->isSelectable(); 00044 bool twosel = two->isSelectable(); 00045 00046 if (onesel == twosel) 00047 return 0; 00048 else if (onesel && !twosel) 00049 return 1; 00050 else 00051 return -1; 00052 } 00053 00054 // static int sortByAttributeThenString(MythGenericTree *one, MythGenericTree *two) 00055 // { 00056 // // 00057 // // Sort by attribute (ordering index), but, it if those are 00058 // // equal, then sort by string 00059 // // 00060 // 00061 // int onea = one->getAttribute(m_attributeIndex); 00062 // int twoa = two->getAttribute(m_attributeIndex); 00063 // 00064 // if (onea == twoa) 00065 // { 00066 // QString ones = one->getString().toLower(); 00067 // QString twos = two->getString().toLower(); 00068 // return QString::localeAwareCompare(ones, twos); 00069 // } 00070 // else if (onea < twoa) 00071 // return -1; 00072 // else 00073 // return 1; 00074 // } 00075 00076 void Sort(SortType stype, int attributeIndex = 0) 00077 { 00078 m_sortType = stype; 00079 m_attributeIndex = attributeIndex; 00080 switch (m_sortType) 00081 { 00082 // case SORT_ATTRIBUTE: 00083 // std::sort(begin(), end(), sortByAttribute); 00084 // break; 00085 case SORT_STRING: 00086 qSort(begin(), end(), sortByString); 00087 break; 00088 case SORT_SELECTABLE: 00089 qSort(begin(), end(), sortBySelectable); 00090 break; 00091 // case SORT_ATT_THEN_STRING: 00092 // std::sort(begin(), end(), sortByAttributeThenString); 00093 // break; 00094 } 00095 } 00096 00097 private: 00098 SortType m_sortType; 00099 int m_attributeIndex; // for getAttribute 00100 }; 00101 00103 00104 MythGenericTree::MythGenericTree(const QString &a_string, int an_int, 00105 bool selectable_flag) 00106 { 00107 m_subnodes = new SortableMythGenericTreeList; 00108 m_ordered_subnodes = new SortableMythGenericTreeList; 00109 m_flatenedSubnodes = new SortableMythGenericTreeList; 00110 00111 m_parent = NULL; 00112 m_selected_subnode = NULL; 00113 m_currentOrderingIndex = -1; 00114 00115 // TODO Switch to a QT List, or drop the attribute concept entirely 00116 m_attributes = new IntVector(6); 00117 00118 m_text = a_string; 00119 m_int = an_int; 00120 m_data = 0; 00121 00122 m_selectable = selectable_flag; 00123 m_visible = true; 00124 m_visibleCount = 0; 00125 } 00126 00127 MythGenericTree::~MythGenericTree() 00128 { 00129 deleteAllChildren(); 00130 delete m_subnodes; 00131 delete m_ordered_subnodes; 00132 delete m_flatenedSubnodes; 00133 delete m_attributes; 00134 } 00135 00136 MythGenericTree* MythGenericTree::addNode(const QString &a_string, int an_int, 00137 bool selectable_flag, bool visible) 00138 { 00139 MythGenericTree *new_node = new MythGenericTree(a_string.simplified(), 00140 an_int, selectable_flag); 00141 new_node->SetVisible(visible); 00142 00143 return addNode(new_node); 00144 } 00145 00146 MythGenericTree *MythGenericTree::addNode(MythGenericTree *child) 00147 { 00148 child->setParent(this); 00149 m_subnodes->append(child); 00150 m_ordered_subnodes->append(child); 00151 if (child->IsVisible()) 00152 IncVisibleCount(); 00153 00154 return child; 00155 } 00156 00157 void MythGenericTree::DetachParent(void) 00158 { 00159 if (!m_parent) 00160 return; 00161 00162 m_parent->removeNode(this); 00163 } 00164 00165 void MythGenericTree::removeNode(MythGenericTree *child) 00166 { 00167 if (!child) 00168 return; 00169 00170 if (m_selected_subnode == child) 00171 m_selected_subnode = NULL; 00172 00173 m_ordered_subnodes->removeAll(child); 00174 m_flatenedSubnodes->removeAll(child); 00175 m_subnodes->removeAll(child); 00176 child->setParent(NULL); 00177 00178 if (child && child->IsVisible()) 00179 DecVisibleCount(); 00180 } 00181 00182 void MythGenericTree::deleteNode(MythGenericTree *child) 00183 { 00184 if (!child) 00185 return; 00186 00187 removeNode(child); 00188 delete child; 00189 child = NULL; 00190 } 00191 00192 MythGenericTree* MythGenericTree::findLeaf() 00193 { 00194 if (m_subnodes->count() > 0) 00195 { 00196 if (m_currentOrderingIndex == -1) 00197 return m_subnodes->first()->findLeaf(); 00198 00199 MythGenericTree *first_child = getChildAt(0); 00200 00201 return first_child->findLeaf(); 00202 } 00203 00204 return this; 00205 } 00206 00207 MythGenericTree* MythGenericTree::findNode(QList<int> route_of_branches, 00208 int depth) 00209 { 00210 // Starting from *this* node (which will often be root) find a set of 00211 // branches that have id's that match the collection passed in 00212 // route_of_branches. Return the end point of those branches. 00213 // 00214 // In practical terms, mythmusic will use this to force the playback 00215 // screen's ManagedTreeList to move to a given track in a given playlist 00216 00217 MythGenericTree *node = NULL; 00218 for (int i = 0; i < route_of_branches.count(); i++) 00219 { 00220 if (!node) 00221 node = this; 00222 00223 bool foundit = false; 00224 QList<MythGenericTree*>::iterator it; 00225 QList<MythGenericTree*> *children = node->getAllChildren(); 00226 00227 if (!children) 00228 break; 00229 00230 MythGenericTree *child = NULL; 00231 00232 for (it = children->begin(); it != children->end(); ++it) 00233 { 00234 child = *it; 00235 if (!child) 00236 continue; 00237 if (child->getInt() == route_of_branches[i]) 00238 { 00239 node = child; 00240 foundit = true; 00241 break; 00242 } 00243 } 00244 00245 if (!foundit) 00246 break; 00247 } 00248 00249 return NULL; 00250 } 00251 00252 int MythGenericTree::getChildPosition(MythGenericTree *child) const 00253 { 00254 if (m_currentOrderingIndex == -1) 00255 return m_subnodes->indexOf(child); 00256 00257 return m_ordered_subnodes->indexOf(child); 00258 } 00259 00260 int MythGenericTree::getPosition() 00261 { 00262 if (m_parent) 00263 return m_parent->getChildPosition(this); 00264 return 0; 00265 } 00266 00267 QList<int> MythGenericTree::getRouteById() 00268 { 00269 QList<int> routeByID; 00270 00271 routeByID.push_front(getInt()); 00272 00273 MythGenericTree *parent = this; 00274 while( (parent = parent->getParent()) ) 00275 { 00276 routeByID.push_front(parent->getInt()); 00277 } 00278 return routeByID; 00279 } 00280 00281 QStringList MythGenericTree::getRouteByString() 00282 { 00283 QStringList routeByString; 00284 00285 routeByString.push_front(getString()); 00286 00287 MythGenericTree *parent = this; 00288 while( (parent = parent->getParent()) ) 00289 { 00290 routeByString.push_front(parent->getString()); 00291 } 00292 return routeByString; 00293 } 00294 00295 QList<MythGenericTree*> MythGenericTree::getRoute(void) 00296 { 00297 QList<MythGenericTree*> route; 00298 00299 route.push_front(this); 00300 00301 MythGenericTree *parent = this; 00302 while( (parent = parent->getParent()) ) 00303 { 00304 route.push_front(parent); 00305 } 00306 return route; 00307 } 00308 00309 int MythGenericTree::childCount(void) const 00310 { 00311 return m_subnodes->count(); 00312 } 00313 00314 int MythGenericTree::siblingCount(void) const 00315 { 00316 if (m_parent) 00317 return m_parent->childCount(); 00318 return 1; 00319 } 00320 00324 int MythGenericTree::currentDepth(void) 00325 { 00326 QList<MythGenericTree *> route = getRoute(); 00327 00328 return (route.size() - 1); 00329 } 00330 00331 QList<MythGenericTree*> *MythGenericTree::getAllChildren() const 00332 { 00333 if (m_currentOrderingIndex == -1) 00334 return m_subnodes; 00335 00336 return m_ordered_subnodes; 00337 } 00338 00339 MythGenericTree* MythGenericTree::getChildAt(uint reference) const 00340 { 00341 if (reference >= (uint)m_ordered_subnodes->count()) 00342 return NULL; 00343 00344 if (m_currentOrderingIndex == -1) 00345 return m_subnodes->at(reference); 00346 00347 return m_ordered_subnodes->at(reference); 00348 } 00349 00350 MythGenericTree* MythGenericTree::getVisibleChildAt(uint reference) const 00351 { 00352 if (reference >= (uint)m_ordered_subnodes->count()) 00353 return NULL; 00354 00355 QList<MythGenericTree*> *list; 00356 00357 if (m_currentOrderingIndex == -1) 00358 list = m_subnodes; 00359 else 00360 list = m_ordered_subnodes; 00361 00362 uint n = 0; 00363 for (int i = 0; i < list->size(); ++i) 00364 { 00365 MythGenericTree *child = list->at(i); 00366 if (child->IsVisible()) 00367 { 00368 if (n == reference) 00369 return child; 00370 n++; 00371 } 00372 } 00373 00374 return NULL; 00375 } 00376 00377 MythGenericTree* MythGenericTree::getSelectedChild(bool onlyVisible) const 00378 { 00379 MythGenericTree *selectedChild = NULL; 00380 00381 if (m_selected_subnode) 00382 selectedChild = m_selected_subnode; 00383 else if (onlyVisible) 00384 selectedChild = getVisibleChildAt(0); 00385 else 00386 selectedChild = getChildAt(0); 00387 00388 return selectedChild; 00389 } 00390 00391 void MythGenericTree::becomeSelectedChild() 00392 { 00393 if (m_parent) 00394 m_parent->setSelectedChild(this); 00395 else 00396 LOG(VB_GENERAL, LOG_ERR, "Top level can't become selected child"); 00397 } 00398 00399 MythGenericTree* MythGenericTree::prevSibling(int number_up) 00400 { 00401 if (!m_parent) 00402 { 00403 // I'm root = no siblings 00404 return NULL; 00405 } 00406 00407 int position = m_parent->getChildPosition(this); 00408 00409 if (position < number_up) 00410 { 00411 // not enough siblings "above" me 00412 return NULL; 00413 } 00414 00415 return m_parent->getChildAt(position - number_up); 00416 } 00417 00418 MythGenericTree* MythGenericTree::nextSibling(int number_down) 00419 { 00420 if (!m_parent) 00421 { 00422 // I'm root = no siblings 00423 return NULL; 00424 } 00425 00426 int position = m_parent->getChildPosition(this); 00427 00428 if (position + number_down >= m_parent->childCount()) 00429 { 00430 // not enough siblings "below" me 00431 return NULL; 00432 } 00433 00434 return m_parent->getChildAt(position + number_down); 00435 } 00436 00437 QList<MythGenericTree*>::iterator MythGenericTree::getFirstChildIterator() const 00438 { 00439 QList<MythGenericTree*>::iterator it; 00440 if (m_currentOrderingIndex == -1) 00441 it = m_subnodes->begin(); 00442 else 00443 it = m_ordered_subnodes->begin(); 00444 return it; 00445 } 00446 00447 MythGenericTree* MythGenericTree::getParent() const 00448 { 00449 if (m_parent) 00450 return m_parent; 00451 return NULL; 00452 } 00453 00454 void MythGenericTree::setAttribute(uint attribute_position, int value_of_attribute) 00455 { 00456 // You can use attributes for anything you like. Mythmusic, for example, 00457 // stores a value for random ordering in the first "column" (0) and a value 00458 // for "intelligent" (1) ordering in the second column 00459 00460 if (m_attributes->size() < (int)(attribute_position + 1)) 00461 m_attributes->resize(attribute_position + 1); 00462 (*m_attributes)[attribute_position] = value_of_attribute; 00463 } 00464 00465 int MythGenericTree::getAttribute(uint which_one) const 00466 { 00467 if (m_attributes->size() < (int)(which_one + 1)) 00468 { 00469 LOG(VB_GENERAL, LOG_ERR, 00470 "Asked a MythGenericTree node for a non-existent attribute"); 00471 return 0; 00472 } 00473 00474 return m_attributes->at(which_one); 00475 } 00476 00477 void MythGenericTree::setOrderingIndex(int ordering_index) 00478 { 00479 m_currentOrderingIndex = ordering_index; 00480 reorderSubnodes(); 00481 } 00482 00483 void MythGenericTree::reorderSubnodes() 00484 { 00485 // The nodes are there, we just want to re-order them according to 00486 // attribute column defined by ordering_index 00487 00488 m_ordered_subnodes->Sort(SortableMythGenericTreeList::SORT_ATTRIBUTE, 00489 m_currentOrderingIndex); 00490 } 00491 00492 void MythGenericTree::addYourselfIfSelectable(QList<MythGenericTree*> *flat_list) 00493 { 00494 if (m_selectable) 00495 flat_list->append(this); 00496 00497 QList<MythGenericTree*>::iterator it; 00498 it = m_subnodes->begin(); 00499 MythGenericTree *child; 00500 while ((child = *it) != 0) 00501 { 00502 child->addYourselfIfSelectable(flat_list); 00503 ++it; 00504 } 00505 } 00506 00507 void MythGenericTree::buildFlatListOfSubnodes(bool scrambled_parents) 00508 { 00509 // This builds a flat list of every selectable child according to the 00510 // current ordering index. 00511 00512 m_flatenedSubnodes->clear(); 00513 00514 QList<MythGenericTree*>::iterator it; 00515 it = m_subnodes->begin(); 00516 MythGenericTree *child; 00517 while ((child = *it) != 0) 00518 { 00519 child->addYourselfIfSelectable(m_flatenedSubnodes); 00520 ++it; 00521 } 00522 00523 if (m_currentOrderingIndex > -1) 00524 m_flatenedSubnodes->SetAttributeIndex(m_currentOrderingIndex); 00525 } 00526 00527 MythGenericTree* MythGenericTree::nextPrevFromFlatList(bool forward_or_backward, 00528 bool wrap_around, 00529 MythGenericTree *active) const 00530 { 00531 int i = m_flatenedSubnodes->indexOf(active); 00532 if (i < 0) 00533 { 00534 LOG(VB_GENERAL, LOG_ERR, "Can't find active item on flatened list"); 00535 return NULL; 00536 } 00537 00538 if (forward_or_backward) 00539 { 00540 ++i; 00541 if (i >= (int)m_flatenedSubnodes->count()) 00542 { 00543 if (wrap_around) 00544 i = 0; 00545 else 00546 return NULL; 00547 } 00548 } 00549 else 00550 { 00551 --i; 00552 if (i < 0) 00553 { 00554 if (wrap_around) 00555 i = m_flatenedSubnodes->count() - 1; 00556 else 00557 return NULL; 00558 } 00559 } 00560 00561 return m_flatenedSubnodes->at(i); 00562 } 00563 00564 MythGenericTree* MythGenericTree::getChildByName(const QString &a_name) const 00565 { 00566 QList<MythGenericTree*> *children = getAllChildren(); 00567 if (children && children->count() > 0) 00568 { 00569 SortableMythGenericTreeList::Iterator it; 00570 MythGenericTree *child = NULL; 00571 00572 for (it = children->begin(); it != children->end(); ++it) 00573 { 00574 child = *it; 00575 if (!child) 00576 continue; 00577 if (child->getString() == a_name) 00578 return child; 00579 } 00580 } 00581 00582 return NULL; 00583 } 00584 00585 MythGenericTree* MythGenericTree::getChildById(int an_int) const 00586 { 00587 QList<MythGenericTree*> *children = getAllChildren(); 00588 if (children && children->count() > 0) 00589 { 00590 SortableMythGenericTreeList::Iterator it; 00591 MythGenericTree *child = NULL; 00592 00593 for (it = children->begin(); it != children->end(); ++it) 00594 { 00595 child = *it; 00596 if (!child) 00597 continue; 00598 if (child->getInt() == an_int) 00599 return child; 00600 } 00601 } 00602 00603 return NULL; 00604 } 00605 00606 void MythGenericTree::sortByString() 00607 { 00608 m_ordered_subnodes->Sort(SortableMythGenericTreeList::SORT_STRING); 00609 00610 QList<MythGenericTree*> *children = getAllChildren(); 00611 if (children && children->count() > 0) 00612 { 00613 SortableMythGenericTreeList::Iterator it; 00614 MythGenericTree *child = NULL; 00615 00616 for (it = children->begin(); it != children->end(); ++it) 00617 { 00618 child = *it; 00619 if (!child) 00620 continue; 00621 child->sortByString(); 00622 } 00623 } 00624 } 00625 00626 void MythGenericTree::sortByAttributeThenByString(int which_attribute) 00627 { 00628 m_ordered_subnodes->Sort(SortableMythGenericTreeList::SORT_ATT_THEN_STRING, 00629 which_attribute); 00630 00631 QList<MythGenericTree*>::iterator it; 00632 it = m_subnodes->begin(); 00633 MythGenericTree *child; 00634 while ((child = *it) != 0) 00635 { 00636 child->sortByAttributeThenByString(which_attribute); 00637 ++it; 00638 } 00639 } 00640 00641 void MythGenericTree::sortBySelectable() 00642 { 00643 m_ordered_subnodes->Sort(SortableMythGenericTreeList::SORT_SELECTABLE); 00644 00645 QList<MythGenericTree*>::iterator it; 00646 it = m_subnodes->begin(); 00647 MythGenericTree *child; 00648 while ((child = *it) != 0) 00649 { 00650 child->sortBySelectable(); 00651 ++it; 00652 } 00653 } 00654 00655 void MythGenericTree::deleteAllChildren() 00656 { 00657 m_flatenedSubnodes->clear(); 00658 m_ordered_subnodes->clear(); 00659 m_selected_subnode = NULL; 00660 m_currentOrderingIndex = -1; 00661 MythGenericTree *child; 00662 while (!m_subnodes->isEmpty()) 00663 { 00664 child = m_subnodes->takeFirst(); 00665 delete child; 00666 child = NULL; 00667 } 00668 m_subnodes->clear(); 00669 } 00670 00671 void MythGenericTree::reOrderAsSorted() 00672 { 00673 // 00674 // Arrange (recursively) my subnodes in the same order as my ordered 00675 // subnodes 00676 // 00677 00678 if (m_subnodes->count() != m_ordered_subnodes->count()) 00679 { 00680 LOG(VB_GENERAL, LOG_ERR, "Can't reOrderAsSorted(), because the number " 00681 "of subnodes is different than the number of ordered subnodes"); 00682 return; 00683 } 00684 00685 m_subnodes->clear(); 00686 m_currentOrderingIndex = -1; 00687 00688 QList<MythGenericTree*>::iterator it; 00689 it = m_ordered_subnodes->begin(); 00690 MythGenericTree *child; 00691 while ((child = *it) != 0) 00692 { 00693 m_subnodes->append(child); 00694 child->reOrderAsSorted(); 00695 ++it; 00696 } 00697 } 00698 00699 void MythGenericTree::MoveItemUpDown(MythGenericTree *item, bool flag) 00700 { 00701 if (item == m_subnodes->first() && flag) 00702 return; 00703 if (item == m_subnodes->last() && !flag) 00704 return; 00705 00706 int num = m_subnodes->indexOf(item); 00707 00708 int insertat = 0; 00709 if (flag) 00710 insertat = num - 1; 00711 else 00712 insertat = num + 1; 00713 00714 m_subnodes->removeAt(num); 00715 m_subnodes->insert(insertat, item); 00716 } 00717 00718 void MythGenericTree::SetVisible(bool visible) 00719 { 00720 if (m_visible == visible) 00721 return; 00722 00723 m_visible = visible; 00724 00725 if (!m_parent) 00726 return; 00727 00728 if (visible) 00729 m_parent->IncVisibleCount(); 00730 else 00731 m_parent->DecVisibleCount(); 00732 } 00733 00734 MythUIButtonListItem *MythGenericTree::CreateListButton(MythUIButtonList *list) 00735 { 00736 MythUIButtonListItem *item = new MythUIButtonListItem(list, getString()); 00737 item->SetData(qVariantFromValue(this)); 00738 item->SetTextFromMap(m_strings); 00739 item->SetImageFromMap(m_imageFilenames); 00740 item->SetStatesFromMap(m_states); 00741 00742 if (visibleChildCount() > 0) 00743 item->setDrawArrow(true); 00744 00745 return item; 00746 } 00747 00748 void MythGenericTree::SetText(const QString &text, const QString &name, 00749 const QString &state) 00750 { 00751 if (!name.isEmpty()) 00752 { 00753 TextProperties textprop; 00754 textprop.text = text; 00755 textprop.state = state; 00756 m_strings.insert(name, textprop); 00757 } 00758 else 00759 m_text = text; 00760 } 00761 00762 void MythGenericTree::SetTextFromMap(InfoMap &infoMap, 00763 const QString &state) 00764 { 00765 InfoMap::iterator map_it = infoMap.begin(); 00766 while (map_it != infoMap.end()) 00767 { 00768 TextProperties textprop; 00769 textprop.text = (*map_it); 00770 textprop.state = state; 00771 m_strings[map_it.key()] = textprop; 00772 ++map_it; 00773 } 00774 } 00775 00776 QString MythGenericTree::GetText(const QString &name) const 00777 { 00778 if (name.isEmpty()) 00779 return m_text; 00780 else if (m_strings.contains(name)) 00781 return m_strings[name].text; 00782 else 00783 return QString(); 00784 } 00785 00786 void MythGenericTree::SetImage(const QString &filename, const QString &name) 00787 { 00788 if (!name.isEmpty()) 00789 m_imageFilenames.insert(name, filename); 00790 } 00791 00792 void MythGenericTree::SetImageFromMap(InfoMap &infoMap) 00793 { 00794 m_imageFilenames.clear(); 00795 m_imageFilenames = infoMap; 00796 } 00797 00798 QString MythGenericTree::GetImage(const QString &name) const 00799 { 00800 if (name.isEmpty()) 00801 return QString(); 00802 00803 InfoMap::const_iterator it = m_imageFilenames.find(name); 00804 if (it != m_imageFilenames.end()) 00805 return *it; 00806 00807 return QString(); 00808 } 00809 00810 void MythGenericTree::DisplayStateFromMap(QHash<QString,QString> &infoMap) 00811 { 00812 m_states.clear(); 00813 m_states = infoMap; 00814 } 00815 00816 void MythGenericTree::DisplayState(const QString &state, const QString &name) 00817 { 00818 if (!name.isEmpty()) 00819 m_states.insert(name, state); 00820 } 00821 00822 QString MythGenericTree::GetState(const QString &name) const 00823 { 00824 if (name.isEmpty()) 00825 return QString(); 00826 00827 InfoMap::const_iterator it = m_states.find(name); 00828 if (it != m_states.end()) 00829 return *it; 00830 00831 return QString(); 00832 }
1.7.6.1