MythTV  master
mythgenerictree.cpp
Go to the documentation of this file.
1 
2 // Mythui headers
3 #include "mythgenerictree.h"
4 #include "mythuibuttonlist.h"
5 
6 // Myth headers
7 #include "mythlogging.h"
8 #include "mythsorthelper.h"
9 
10 // QT headers
11 #include <algorithm>
12 
13 class SortableMythGenericTreeList : public QList<MythGenericTree*>
14 {
15  public:
16  SortableMythGenericTreeList() = default;
18 
19  void SetSortType(SortType stype) { m_sortType = stype; }
20  void SetAttributeIndex(int index)
21  { m_attributeIndex = (index >= 0) ? index : 0; }
22 
24  {
25  return one->GetSortText() < two->GetSortText();
26  }
27 
29  {
30  bool onesel = one->isSelectable();
31  bool twosel = two->isSelectable();
32 
33  if (onesel == twosel)
34  return 0;
35  if (onesel && !twosel)
36  return 1;
37  return -1;
38  }
39 
40  void Sort(SortType stype, int attributeIndex = 0)
41  {
42  m_sortType = stype;
43  m_attributeIndex = attributeIndex;
44  switch (m_sortType)
45  {
46  case SORT_STRING:
47  std::sort(begin(), end(), sortByString);
48  break;
49  case SORT_SELECTABLE:
50  std::sort(begin(), end(), sortBySelectable);
51  break;
52  }
53  }
54 
55  private:
57  int m_attributeIndex {0}; // for getAttribute
58 };
59 
61 
62 MythGenericTree::MythGenericTree(const QString &a_string, int an_int,
63  bool selectable_flag)
64 {
66 
67  m_text = a_string;
68  m_int = an_int;
69  m_selectable = selectable_flag;
70 
72 }
73 
75 {
77  delete m_subnodes;
78 }
79 
81 {
82  std::shared_ptr<MythSortHelper>sh = getMythSortHelper();
83  if (m_sortText.isEmpty() and not m_text.isEmpty())
84  m_sortText = sh->doTitle(m_text);
85 }
86 
87 MythGenericTree* MythGenericTree::addNode(const QString &a_string, int an_int,
88  bool selectable_flag, bool visible)
89 {
90  auto *new_node = new MythGenericTree(a_string.simplified(),
91  an_int, selectable_flag);
92  new_node->SetVisible(visible);
93  return addNode(new_node);
94 }
95 
96 MythGenericTree* MythGenericTree::addNode(const QString &a_string,
97  const QString &sortText, int an_int, bool
98  selectable_flag, bool visible)
99 {
100  auto *new_node = new MythGenericTree(a_string.simplified(),
101  an_int, selectable_flag);
102  new_node->SetVisible(visible);
103  new_node->SetSortText(sortText);
104 
105  return addNode(new_node);
106 }
107 
109 {
110  child->setParent(this);
111  m_subnodes->append(child);
112  if (child->IsVisible())
113  IncVisibleCount();
114 
115  return child;
116 }
117 
119 {
120  if (!m_parent)
121  return;
122 
123  m_parent->removeNode(this);
124 }
125 
127 {
128  if (!child)
129  return;
130 
131  if (m_selectedSubnode == child)
132  m_selectedSubnode = nullptr;
133 
134  m_subnodes->removeAll(child);
135  child->setParent(nullptr);
136 
137  if (child && child->IsVisible())
138  DecVisibleCount();
139 }
140 
142 {
143  if (!child)
144  return;
145 
146  removeNode(child);
147  delete child;
148 }
149 
151 {
152  if (m_subnodes->count() > 0)
153  return m_subnodes->first()->findLeaf();
154 
155  return this;
156 }
157 
158 MythGenericTree* MythGenericTree::findNode(QList<int> route_of_branches)
159 {
160  // Starting from *this* node (which will often be root) find a set of
161  // branches that have id's that match the collection passed in
162  // route_of_branches. Return the end point of those branches.
163  //
164  // In practical terms, mythmusic will use this to force the playback
165  // screen's ManagedTreeList to move to a given track in a given playlist
166 
167  MythGenericTree *node = nullptr;
168  for (int i = 0; i < route_of_branches.count(); i++)
169  {
170  if (!node)
171  node = this;
172 
173  bool foundit = false;
174  QList<MythGenericTree*>::iterator it;
175  QList<MythGenericTree*> *children = node->getAllChildren();
176 
177  if (!children)
178  break;
179 
180  MythGenericTree *child = nullptr;
181 
182  for (it = children->begin(); it != children->end(); ++it)
183  {
184  child = *it;
185  if (!child)
186  continue;
187  if (child->getInt() == route_of_branches[i])
188  {
189  node = child;
190  foundit = true;
191  break;
192  }
193  }
194 
195  if (!foundit)
196  break;
197  }
198 
199  return nullptr;
200 }
201 
203 {
204  return m_subnodes->indexOf(child);
205 }
206 
208 {
209  if (m_parent)
210  return m_parent->getChildPosition(this);
211  return 0;
212 }
213 
215 {
216  QList<int> routeByID;
217 
218  routeByID.push_front(getInt());
219 
220  MythGenericTree *parent = this;
221  while( (parent = parent->getParent()) )
222  {
223  routeByID.push_front(parent->getInt());
224  }
225  return routeByID;
226 }
227 
229 {
230  QStringList routeByString;
231 
232  routeByString.push_front(GetText());
233 
234  MythGenericTree *parent = this;
235  while( (parent = parent->getParent()) )
236  {
237  routeByString.push_front(parent->GetText());
238  }
239  return routeByString;
240 }
241 
242 QList<MythGenericTree*> MythGenericTree::getRoute(void)
243 {
244  QList<MythGenericTree*> route;
245 
246  route.push_front(this);
247 
248  MythGenericTree *parent = this;
249  while( (parent = parent->getParent()) )
250  {
251  route.push_front(parent);
252  }
253  return route;
254 }
255 
257 {
258  return m_subnodes->count();
259 }
260 
262 {
263  if (m_parent)
264  return m_parent->childCount();
265  return 1;
266 }
267 
272 {
273  QList<MythGenericTree *> route = getRoute();
274 
275  return (route.size() - 1);
276 }
277 
278 QList<MythGenericTree*> *MythGenericTree::getAllChildren() const
279 {
280  return m_subnodes;
281 }
282 
284 {
285  if (reference >= (uint)m_subnodes->count())
286  return nullptr;
287 
288  return m_subnodes->at(reference);
289 }
290 
292 {
293  if (reference >= (uint)m_subnodes->count())
294  return nullptr;
295 
296  QList<MythGenericTree*> *list = m_subnodes;
297 
298  uint n = 0;
299  for (int i = 0; i < list->size(); ++i)
300  {
301  MythGenericTree *child = list->at(i);
302  if (child->IsVisible())
303  {
304  if (n == reference)
305  return child;
306  n++;
307  }
308  }
309 
310  return nullptr;
311 }
312 
314 {
315  MythGenericTree *selectedChild = nullptr;
316 
317  if (m_selectedSubnode)
318  selectedChild = m_selectedSubnode;
319  else if (onlyVisible)
320  selectedChild = getVisibleChildAt(0);
321  else
322  selectedChild = getChildAt(0);
323 
324  return selectedChild;
325 }
326 
328 {
329  if (m_parent)
330  m_parent->setSelectedChild(this);
331  else
332  LOG(VB_GENERAL, LOG_ERR, "Top level can't become selected child");
333 }
334 
336 {
337  if (!m_parent)
338  {
339  // I'm root = no siblings
340  return nullptr;
341  }
342 
343  int position = m_parent->getChildPosition(this);
344 
345  if (position < number_up)
346  {
347  // not enough siblings "above" me
348  return nullptr;
349  }
350 
351  return m_parent->getChildAt(position - number_up);
352 }
353 
355 {
356  if (!m_parent)
357  {
358  // I'm root = no siblings
359  return nullptr;
360  }
361 
362  int position = m_parent->getChildPosition(this);
363 
364  if (position + number_down >= m_parent->childCount())
365  {
366  // not enough siblings "below" me
367  return nullptr;
368  }
369 
370  return m_parent->getChildAt(position + number_down);
371 }
372 
374 {
375  if (m_parent)
376  return m_parent;
377  return nullptr;
378 }
379 
381 {
382  QList<MythGenericTree*> *children = getAllChildren();
383  if (children && children->count() > 0)
384  {
385  SortableMythGenericTreeList::Iterator it;
386  MythGenericTree *child = nullptr;
387 
388  for (it = children->begin(); it != children->end(); ++it)
389  {
390  child = *it;
391  if (!child)
392  continue;
393  if (child->GetText() == a_name)
394  return child;
395  }
396  }
397 
398  return nullptr;
399 }
400 
402 {
403  QList<MythGenericTree*> *children = getAllChildren();
404  if (children && children->count() > 0)
405  {
406  SortableMythGenericTreeList::Iterator it;
407  MythGenericTree *child = nullptr;
408 
409  for (it = children->begin(); it != children->end(); ++it)
410  {
411  child = *it;
412  if (!child)
413  continue;
414  if (child->getInt() == an_int)
415  return child;
416  }
417  }
418 
419  return nullptr;
420 }
421 
423 {
425 
426  QList<MythGenericTree*> *children = getAllChildren();
427  if (children && children->count() > 0)
428  {
429  SortableMythGenericTreeList::Iterator it;
430  MythGenericTree *child = nullptr;
431 
432  for (it = children->begin(); it != children->end(); ++it)
433  {
434  child = *it;
435  if (!child)
436  continue;
437  child->sortByString();
438  }
439  }
440 }
441 
443 {
445 
446  QList<MythGenericTree*>::iterator it;
447  it = m_subnodes->begin();
448  MythGenericTree *child = nullptr;
449  while ((child = *it) != nullptr)
450  {
451  child->sortBySelectable();
452  ++it;
453  }
454 }
455 
457 {
458  m_selectedSubnode = nullptr;
459  while (!m_subnodes->isEmpty())
460  {
461  MythGenericTree *child = m_subnodes->takeFirst();
462  delete child;
463  child = nullptr;
464  }
465  m_subnodes->clear();
466 }
467 
469 {
470  if (item == m_subnodes->first() && flag)
471  return;
472  if (item == m_subnodes->last() && !flag)
473  return;
474 
475  int num = m_subnodes->indexOf(item);
476 
477  int insertat = 0;
478  if (flag)
479  insertat = num - 1;
480  else
481  insertat = num + 1;
482 
483  m_subnodes->removeAt(num);
484  m_subnodes->insert(insertat, item);
485 }
486 
487 void MythGenericTree::SetVisible(bool visible)
488 {
489  if (m_visible == visible)
490  return;
491 
492  m_visible = visible;
493 
494  if (!m_parent)
495  return;
496 
497  if (visible)
499  else
501 }
502 
504 {
505  auto *item = new MythUIButtonListItem(list, GetText());
506  item->SetData(qVariantFromValue(this));
507  item->SetTextFromMap(m_strings);
508  item->SetImageFromMap(m_imageFilenames);
509  item->SetStatesFromMap(m_states);
510 
511  if (visibleChildCount() > 0)
512  item->setDrawArrow(true);
513 
514  return item;
515 }
516 
517 void MythGenericTree::SetText(const QString &text, const QString &name,
518  const QString &state)
519 {
520  if (!name.isEmpty())
521  {
522  TextProperties textprop;
523  textprop.text = text;
524  textprop.state = state;
525  m_strings.insert(name, textprop);
526  }
527  else
528  {
529  m_text = text;
530  m_sortText = nullptr;
532  }
533 }
534 
536  const QString &state)
537 {
538  InfoMap::const_iterator map_it = infoMap.begin();
539  while (map_it != infoMap.end())
540  {
541  TextProperties textprop;
542  textprop.text = (*map_it);
543  textprop.state = state;
544  m_strings[map_it.key()] = textprop;
545  ++map_it;
546  }
547 }
548 
549 QString MythGenericTree::GetText(const QString &name) const
550 {
551  if (name.isEmpty())
552  return m_text;
553  if (m_strings.contains(name))
554  return m_strings[name].text;
555  return QString();
556 }
557 
558 void MythGenericTree::SetImage(const QString &filename, const QString &name)
559 {
560  if (!name.isEmpty())
561  m_imageFilenames.insert(name, filename);
562 }
563 
565 {
566  m_imageFilenames.clear();
567  m_imageFilenames = infoMap;
568 }
569 
570 QString MythGenericTree::GetImage(const QString &name) const
571 {
572  if (name.isEmpty())
573  return QString();
574 
575  InfoMap::const_iterator it = m_imageFilenames.find(name);
576  if (it != m_imageFilenames.end())
577  return *it;
578 
579  return QString();
580 }
581 
583 {
584  m_states.clear();
585  m_states = infoMap;
586 }
587 
588 void MythGenericTree::DisplayState(const QString &state, const QString &name)
589 {
590  if (!name.isEmpty())
591  m_states.insert(name, state);
592 }
593 
594 QString MythGenericTree::GetState(const QString &name) const
595 {
596  if (name.isEmpty())
597  return QString();
598 
599  InfoMap::const_iterator it = m_states.find(name);
600  if (it != m_states.end())
601  return *it;
602 
603  return QString();
604 }
void setParent(MythGenericTree *a_parent)
MythGenericTree * getSelectedChild(bool onlyVisible=false) const
MythGenericTree * addNode(const QString &a_string, int an_int=0, bool selectable_flag=false, bool visible=true)
uint visibleChildCount() const
QList< MythGenericTree * > * getAllChildren() const
void SetText(const QString &text, const QString &name="", const QString &state="")
QHash< QString, QString > InfoMap
Definition: mythtypes.h:15
bool IsVisible() const
int childCount(void) const
void deleteNode(MythGenericTree *child)
MythGenericTree * m_parent
QString GetImage(const QString &name="") const
InfoMap m_imageFilenames
MythGenericTree * getVisibleChildAt(uint reference) const
void removeNode(MythGenericTree *child)
MythGenericTree(const QString &a_string="", int an_int=0, bool selectable_flag=false)
void DisplayState(const QString &state, const QString &name="")
void SetVisible(bool visible)
QList< MythGenericTree * > getRoute(void)
QString GetSortText() const
QList< int > getRouteById(void)
void DetachParent(void)
Detach this node/branch from it's parent without deleting it, it can then be reattached elsewhere or ...
QString GetText(const QString &name="") const
void SetImage(const QString &filename, const QString &name="")
void SetTextFromMap(const InfoMap &infoMap, const QString &state="")
QString GetState(const QString &name="") const
MythGenericTree * prevSibling(int number_up)
int currentDepth(void)
Establish how deep in the current tree this node lies.
SortableMythGenericTreeList * m_subnodes
static int sortBySelectable(MythGenericTree *one, MythGenericTree *two)
QMap< QString, TextProperties > m_strings
MythGenericTree * getChildById(int an_int) const
void Sort(SortType stype, int attributeIndex=0)
void SetImageFromMap(const InfoMap &infoMap)
MythGenericTree * findNode(QList< int > route_of_branches)
unsigned int uint
Definition: compat.h:140
List widget, displays list items in a variety of themeable arrangements and can trigger signals when ...
MythGenericTree * nextSibling(int number_down)
virtual MythUIButtonListItem * CreateListButton(MythUIButtonList *list)
void ensureSortFields(void)
static bool sortByString(MythGenericTree *one, MythGenericTree *two)
int getInt() const
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
MythGenericTree * findLeaf()
int siblingCount(void) const
MythGenericTree * getChildByName(const QString &a_name) const
MythGenericTree * m_selectedSubnode
bool isSelectable() const
int getChildPosition(MythGenericTree *child) const
virtual ~MythGenericTree()
void SetSortType(SortType stype)
MythGenericTree * getParent(void) const
void MoveItemUpDown(MythGenericTree *item, bool flag)
MythGenericTree * getChildAt(uint reference) const
void becomeSelectedChild(void)
void setSelectedChild(MythGenericTree *a_node)
QStringList getRouteByString(void)
void DisplayStateFromMap(const InfoMap &infoMap)
std::shared_ptr< MythSortHelper > getMythSortHelper(void)
Get a pointer to the MythSortHelper singleton.