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  foreach (auto child, *list)
300  {
301  if (child->IsVisible())
302  {
303  if (n == reference)
304  return child;
305  n++;
306  }
307  }
308 
309  return nullptr;
310 }
311 
313 {
314  MythGenericTree *selectedChild = nullptr;
315 
316  if (m_selectedSubnode)
317  selectedChild = m_selectedSubnode;
318  else if (onlyVisible)
319  selectedChild = getVisibleChildAt(0);
320  else
321  selectedChild = getChildAt(0);
322 
323  return selectedChild;
324 }
325 
327 {
328  if (m_parent)
329  m_parent->setSelectedChild(this);
330  else
331  LOG(VB_GENERAL, LOG_ERR, "Top level can't become selected child");
332 }
333 
335 {
336  if (!m_parent)
337  {
338  // I'm root = no siblings
339  return nullptr;
340  }
341 
342  int position = m_parent->getChildPosition(this);
343 
344  if (position < number_up)
345  {
346  // not enough siblings "above" me
347  return nullptr;
348  }
349 
350  return m_parent->getChildAt(position - number_up);
351 }
352 
354 {
355  if (!m_parent)
356  {
357  // I'm root = no siblings
358  return nullptr;
359  }
360 
361  int position = m_parent->getChildPosition(this);
362 
363  if (position + number_down >= m_parent->childCount())
364  {
365  // not enough siblings "below" me
366  return nullptr;
367  }
368 
369  return m_parent->getChildAt(position + number_down);
370 }
371 
373 {
374  if (m_parent)
375  return m_parent;
376  return nullptr;
377 }
378 
380 {
381  QList<MythGenericTree*> *children = getAllChildren();
382  if (children && children->count() > 0)
383  {
384  SortableMythGenericTreeList::Iterator it;
385  MythGenericTree *child = nullptr;
386 
387  for (it = children->begin(); it != children->end(); ++it)
388  {
389  child = *it;
390  if (!child)
391  continue;
392  if (child->GetText() == a_name)
393  return child;
394  }
395  }
396 
397  return nullptr;
398 }
399 
401 {
402  QList<MythGenericTree*> *children = getAllChildren();
403  if (children && children->count() > 0)
404  {
405  SortableMythGenericTreeList::Iterator it;
406  MythGenericTree *child = nullptr;
407 
408  for (it = children->begin(); it != children->end(); ++it)
409  {
410  child = *it;
411  if (!child)
412  continue;
413  if (child->getInt() == an_int)
414  return child;
415  }
416  }
417 
418  return nullptr;
419 }
420 
422 {
424 
425  QList<MythGenericTree*> *children = getAllChildren();
426  if (children && children->count() > 0)
427  {
428  SortableMythGenericTreeList::Iterator it;
429  MythGenericTree *child = nullptr;
430 
431  for (it = children->begin(); it != children->end(); ++it)
432  {
433  child = *it;
434  if (!child)
435  continue;
436  child->sortByString();
437  }
438  }
439 }
440 
442 {
444 
445  QList<MythGenericTree*>::iterator it;
446  it = m_subnodes->begin();
447  MythGenericTree *child = nullptr;
448  while ((child = *it) != nullptr)
449  {
450  child->sortBySelectable();
451  ++it;
452  }
453 }
454 
456 {
457  m_selectedSubnode = nullptr;
458  while (!m_subnodes->isEmpty())
459  {
460  MythGenericTree *child = m_subnodes->takeFirst();
461  delete child;
462  child = nullptr;
463  }
464  m_subnodes->clear();
465 }
466 
468 {
469  if (item == m_subnodes->first() && flag)
470  return;
471  if (item == m_subnodes->last() && !flag)
472  return;
473 
474  int num = m_subnodes->indexOf(item);
475 
476  int insertat = 0;
477  if (flag)
478  insertat = num - 1;
479  else
480  insertat = num + 1;
481 
482  m_subnodes->removeAt(num);
483  m_subnodes->insert(insertat, item);
484 }
485 
486 void MythGenericTree::SetVisible(bool visible)
487 {
488  if (m_visible == visible)
489  return;
490 
491  m_visible = visible;
492 
493  if (!m_parent)
494  return;
495 
496  if (visible)
498  else
500 }
501 
503 {
504  auto *item = new MythUIButtonListItem(list, GetText());
505  item->SetData(QVariant::fromValue(this));
506  item->SetTextFromMap(m_strings);
507  item->SetImageFromMap(m_imageFilenames);
508  item->SetStatesFromMap(m_states);
509 
510  if (visibleChildCount() > 0)
511  item->setDrawArrow(true);
512 
513  return item;
514 }
515 
516 void MythGenericTree::SetText(const QString &text, const QString &name,
517  const QString &state)
518 {
519  if (!name.isEmpty())
520  {
521  TextProperties textprop;
522  textprop.text = text;
523  textprop.state = state;
524  m_strings.insert(name, textprop);
525  }
526  else
527  {
528  m_text = text;
529  m_sortText = nullptr;
531  }
532 }
533 
535  const QString &state)
536 {
537  InfoMap::const_iterator map_it = infoMap.begin();
538  while (map_it != infoMap.end())
539  {
540  TextProperties textprop;
541  textprop.text = (*map_it);
542  textprop.state = state;
543  m_strings[map_it.key()] = textprop;
544  ++map_it;
545  }
546 }
547 
548 QString MythGenericTree::GetText(const QString &name) const
549 {
550  if (name.isEmpty())
551  return m_text;
552  if (m_strings.contains(name))
553  return m_strings[name].text;
554  return QString();
555 }
556 
557 void MythGenericTree::SetImage(const QString &filename, const QString &name)
558 {
559  if (!name.isEmpty())
560  m_imageFilenames.insert(name, filename);
561 }
562 
564 {
565  m_imageFilenames.clear();
566  m_imageFilenames = infoMap;
567 }
568 
569 QString MythGenericTree::GetImage(const QString &name) const
570 {
571  if (name.isEmpty())
572  return QString();
573 
574  InfoMap::const_iterator it = m_imageFilenames.find(name);
575  if (it != m_imageFilenames.end())
576  return *it;
577 
578  return QString();
579 }
580 
582 {
583  m_states.clear();
584  m_states = infoMap;
585 }
586 
587 void MythGenericTree::DisplayState(const QString &state, const QString &name)
588 {
589  if (!name.isEmpty())
590  m_states.insert(name, state);
591 }
592 
593 QString MythGenericTree::GetState(const QString &name) const
594 {
595  if (name.isEmpty())
596  return QString();
597 
598  InfoMap::const_iterator it = m_states.find(name);
599  if (it != m_states.end())
600  return *it;
601 
602  return QString();
603 }
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.