00001
00002
00003 #include "mythgenerictree.h"
00004 #include "mythuibuttonlist.h"
00005
00006
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
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
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
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
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
00083
00084
00085 case SORT_STRING:
00086 qSort(begin(), end(), sortByString);
00087 break;
00088 case SORT_SELECTABLE:
00089 qSort(begin(), end(), sortBySelectable);
00090 break;
00091
00092
00093
00094 }
00095 }
00096
00097 private:
00098 SortType m_sortType;
00099 int m_attributeIndex;
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
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
00211
00212
00213
00214
00215
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
00404 return NULL;
00405 }
00406
00407 int position = m_parent->getChildPosition(this);
00408
00409 if (position < number_up)
00410 {
00411
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
00423 return NULL;
00424 }
00425
00426 int position = m_parent->getChildPosition(this);
00427
00428 if (position + number_down >= m_parent->childCount())
00429 {
00430
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
00457
00458
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
00486
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
00510
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
00675
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 }