BVB Source Codes

cmus Show tree.c Source code

Return Download cmus: download tree.c Source code - Download cmus Source code - Type:.c
  1. /*
  2.  * Copyright 2008-2013 Various Authors
  3.  * Copyright 2006 Timo Hirvonen
  4.  *
  5.  * This program is free software; you can redistribute it and/or
  6.  * modify it under the terms of the GNU General Public License as
  7.  * published by the Free Software Foundation; either version 2 of the
  8.  * License, or (at your option) any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful, but
  11.  * WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13.  * General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  17.  */
  18.  
  19. #include "lib.h"
  20. #include "search_mode.h"
  21. #include "xmalloc.h"
  22. #include "utils.h"
  23. #include "debug.h"
  24. #include "mergesort.h"
  25. #include "options.h"
  26. #include "u_collate.h"
  27. #include "rbtree.h"
  28.  
  29. #include <ctype.h>
  30. #include <stdio.h>
  31. #include <string.h>
  32. #include <strings.h>
  33.  
  34. struct searchable *tree_searchable;
  35. struct window *lib_tree_win;
  36. struct window *lib_track_win;
  37. struct window *lib_cur_win;
  38. struct rb_root lib_artist_root;
  39.  
  40. struct track_iter {
  41.         struct rb_root *root;
  42.         struct tree_track *track;
  43.         struct album *album;
  44. };
  45.  
  46. static inline int tree_album_selected(void)
  47. {
  48.         return iter_to_album(&lib_tree_win->sel) != NULL;
  49. }
  50.  
  51. static inline int track_visible(struct tree_track *track)
  52. {
  53.         if (tree_album_selected())
  54.                 return track->album == iter_to_album(&lib_tree_win->sel);
  55.         else if (show_all_tracks)
  56.                 return track->album->artist == iter_to_artist(&lib_tree_win->sel);
  57.         else
  58.                 return 0;
  59. }
  60.  
  61. static inline void tree_search_track_to_iter(struct tree_track *track, struct iter *iter)
  62. {
  63.         iter->data0 = &lib_artist_root;
  64.         iter->data1 = track;
  65.         iter->data2 = NULL;
  66. }
  67.  
  68. static inline void album_to_iter(struct album *album, struct iter *iter)
  69. {
  70.         iter->data0 = &lib_artist_root;
  71.         iter->data1 = album->artist;
  72.         iter->data2 = album;
  73. }
  74.  
  75. static inline void album_to_track_iter(struct album *album, struct track_iter *iter)
  76. {
  77.         iter->root = &album->artist->album_root;
  78.         iter->album = album;
  79.         iter->track = (struct tree_track *)album;
  80. }
  81.  
  82. static inline void artist_to_iter(struct artist *artist, struct iter *iter)
  83. {
  84.         iter->data0 = &lib_artist_root;
  85.         iter->data1 = artist;
  86.         iter->data2 = NULL;
  87. }
  88.  
  89. static inline void tree_track_to_track_iter(struct tree_track *track, struct track_iter *iter)
  90. {
  91.         if (tree_album_selected()) {
  92.                 iter->root = &track->album->track_root;
  93.                 iter->album = NULL;
  94.         } else {
  95.                 iter->root = &track->album->artist->album_root;
  96.                 iter->album = track->album;
  97.         }
  98.         iter->track = track;
  99. }
  100.  
  101. static void tree_set_expand_artist(struct artist *artist, int expand)
  102. {
  103.         struct iter sel;
  104.  
  105.         if (!expand) {
  106.                 /* deselect album, select artist */
  107.                 artist_to_iter(artist, &sel);
  108.                 window_set_sel(lib_tree_win, &sel);
  109.  
  110.                 if (!show_all_tracks)
  111.                         lib_cur_win = lib_tree_win;
  112.         }
  113.         artist->expanded = expand;
  114.         window_changed(lib_tree_win);
  115. }
  116.  
  117. /* tree (search) iterators {{{ */
  118. static int tree_search_get_prev(struct iter *iter)
  119. {
  120.         struct rb_root *root = iter->data0;
  121.         struct tree_track *track = iter->data1;
  122.         struct artist *artist;
  123.         struct album *album;
  124.  
  125.         BUG_ON(iter->data2);
  126.         if (root == NULL)
  127.                 return 0;
  128.         if (track == NULL) {
  129.                 /* head, get last track */
  130.                 if (rb_root_empty(root)) {
  131.                         /* empty, iter points to the head already */
  132.                         return 0;
  133.                 }
  134.                 artist = to_artist(rb_last(root));
  135.                 album = to_album(rb_last(&artist->album_root));
  136.                 iter->data1 = to_tree_track(rb_last(&album->track_root));
  137.                 return 1;
  138.         }
  139.         /* prev track */
  140.         if (rb_prev(&track->tree_node) == NULL || search_restricted) {
  141.                 /* prev album */
  142.                 if (rb_prev(&track->album->tree_node) == NULL) {
  143.                         /* prev artist */
  144.                         if (rb_prev(&track->album->artist->tree_node) == NULL)
  145.                                 return 0;
  146.                         artist = to_artist(rb_prev(&track->album->artist->tree_node));
  147.                         album = to_album(rb_last(&artist->album_root));
  148.                         track = to_tree_track(rb_last(&album->track_root));
  149.                 } else {
  150.                         album = to_album(rb_prev(&track->album->tree_node));
  151.                         track = to_tree_track(rb_last(&album->track_root));
  152.                 }
  153.         } else {
  154.                 track = to_tree_track(rb_prev(&track->tree_node));
  155.         }
  156.         iter->data1 = track;
  157.         return 1;
  158. }
  159.  
  160. static int tree_search_get_next(struct iter *iter)
  161. {
  162.         struct rb_root *root = iter->data0;
  163.         struct tree_track *track = iter->data1;
  164.         struct artist *artist;
  165.         struct album *album;
  166.  
  167.         BUG_ON(iter->data2);
  168.         if (root == NULL)
  169.                 return 0;
  170.         if (track == NULL) {
  171.                 /* head, get first track */
  172.                 if (rb_root_empty(root)) {
  173.                         /* empty, iter points to the head already */
  174.                         return 0;
  175.                 }
  176.                 artist = to_artist(rb_first(root));
  177.                 album = to_album(rb_first(&artist->album_root));
  178.                 iter->data1 = to_tree_track(rb_first(&album->track_root));
  179.                 return 1;
  180.         }
  181.         /* next track */
  182.         if (rb_next(&track->tree_node) == NULL || search_restricted) {
  183.                 /* next album */
  184.                 if (rb_next(&track->album->tree_node) == NULL) {
  185.                         /* next artist */
  186.                         if (rb_next(&track->album->artist->tree_node) == NULL)
  187.                                 return 0;
  188.                         artist = to_artist(rb_next(&track->album->artist->tree_node));
  189.                         album = to_album(rb_first(&artist->album_root));
  190.                         track = to_tree_track(rb_first(&album->track_root));
  191.                 } else {
  192.                         album = to_album(rb_next(&track->album->tree_node));
  193.                         track = to_tree_track(rb_first(&album->track_root));
  194.                 }
  195.         } else {
  196.                 track = to_tree_track(rb_next(&track->tree_node));
  197.         }
  198.         iter->data1 = track;
  199.         return 1;
  200. }
  201. /* }}} */
  202.  
  203. /* tree window iterators {{{ */
  204. static int tree_get_prev(struct iter *iter)
  205. {
  206.         struct rb_root *root = iter->data0;
  207.         struct artist *artist = iter->data1;
  208.         struct album *album = iter->data2;
  209.  
  210.         BUG_ON(root == NULL);
  211.         BUG_ON(artist == NULL && album != NULL);
  212.         if (artist == NULL) {
  213.                 /* head, get last artist and/or album */
  214.                 if (rb_root_empty(root)) {
  215.                         /* empty, iter points to the head already */
  216.                         return 0;
  217.                 }
  218.                 artist = to_artist(rb_last(root));
  219.                 if (artist->expanded) {
  220.                         album = to_album(rb_last(&artist->album_root));
  221.                 } else {
  222.                         album = NULL;
  223.                 }
  224.                 iter->data1 = artist;
  225.                 iter->data2 = album;
  226.                 return 1;
  227.         }
  228.         if (artist->expanded && album) {
  229.                 /* prev album */
  230.                 if (rb_prev(&album->tree_node) == NULL) {
  231.                         iter->data2 = NULL;
  232.                         return 1;
  233.                 } else {
  234.                         iter->data2 = to_album(rb_prev(&album->tree_node));
  235.                         return 1;
  236.                 }
  237.         }
  238.  
  239.         /* prev artist */
  240.         if (rb_prev(&artist->tree_node) == NULL) {
  241.                 iter->data1 = NULL;
  242.                 iter->data2 = NULL;
  243.                 return 0;
  244.         }
  245.         artist = to_artist(rb_prev(&artist->tree_node));
  246.         iter->data1 = artist;
  247.         iter->data2 = NULL;
  248.         if (artist->expanded) {
  249.                 /* last album */
  250.                 iter->data2 = to_album(rb_last(&artist->album_root));
  251.         }
  252.         return 1;
  253. }
  254.  
  255. static int tree_get_next(struct iter *iter)
  256. {
  257.         struct rb_root *root = iter->data0;
  258.         struct artist *artist = iter->data1;
  259.         struct album *album = iter->data2;
  260.  
  261.         BUG_ON(root == NULL);
  262.         BUG_ON(artist == NULL && album != NULL);
  263.         if (artist == NULL) {
  264.                 /* head, get first artist */
  265.                 if (rb_root_empty(root)) {
  266.                         /* empty, iter points to the head already */
  267.                         return 0;
  268.                 }
  269.                 iter->data1 = to_artist(rb_first(root));
  270.                 iter->data2 = NULL;
  271.                 return 1;
  272.         }
  273.         if (artist->expanded) {
  274.                 /* next album */
  275.                 if (album == NULL) {
  276.                         /* first album */
  277.                         iter->data2 = to_album(rb_first(&artist->album_root));
  278.                         return 1;
  279.                 }
  280.                 if (rb_next(&album->tree_node) != NULL) {
  281.                         iter->data2 = to_album(rb_next(&album->tree_node));
  282.                         return 1;
  283.                 }
  284.         }
  285.  
  286.         /* next artist */
  287.         if (rb_next(&artist->tree_node) == NULL) {
  288.                 iter->data1 = NULL;
  289.                 iter->data2 = NULL;
  290.                 return 0;
  291.         }
  292.         iter->data1 = to_artist(rb_next(&artist->tree_node));
  293.         iter->data2 = NULL;
  294.         return 1;
  295. }
  296. /* }}} */
  297.  
  298. static GENERIC_TREE_ITER_PREV(tree_track_get_prev_by_album, struct tree_track, tree_node)
  299. static GENERIC_TREE_ITER_NEXT(tree_track_get_next_by_album, struct tree_track, tree_node)
  300.  
  301. /* track window iterators by artist */
  302. static int tree_track_get_prev_by_artist(struct iter *iter)
  303. {
  304.         struct track_iter *it = (struct track_iter *)iter;
  305.  
  306.         /* get last album */
  307.         if (it->album == NULL) {
  308.                 if (rb_root_empty(it->root))
  309.                         return 0;
  310.                 it->album = to_album(rb_last(it->root));
  311.                 it->track = NULL;
  312.                 return tree_track_get_prev_by_artist(iter);
  313.         }
  314.  
  315.         /* get previous album */
  316.         if (it->track == (struct tree_track *)it->album) {
  317.                 /* no more albums */
  318.                 if (rb_prev(&it->album->tree_node) == NULL)
  319.                         return 0;
  320.                 it->album = to_album(rb_prev(&it->album->tree_node));
  321.                 it->track = NULL;
  322.                 return tree_track_get_prev_by_artist(iter);
  323.         }
  324.  
  325.         /* get last track */
  326.         if (it->track == NULL) {
  327.                 if (rb_root_empty(&it->album->track_root))
  328.                         it->track = (struct tree_track *)it->album;
  329.                 else
  330.                         it->track = to_tree_track(rb_last(&it->album->track_root));
  331.                 return 1;
  332.         }
  333.  
  334.         /* get previous track */
  335.         if (rb_prev(&it->track->tree_node) != NULL) {
  336.                 it->track = to_tree_track(rb_prev(&it->track->tree_node));
  337.                 return 1;
  338.         }
  339.  
  340.         /* no more tracks
  341.          * get album header */
  342.         it->track = (struct tree_track *)it->album;
  343.         return 1;
  344. }
  345.  
  346. static int tree_track_get_next_by_artist(struct iter *iter)
  347. {
  348.         struct track_iter *it = (struct track_iter *)iter;
  349.  
  350.         /* get first album */
  351.         if (it->album == NULL) {
  352.                 if (rb_root_empty(it->root))
  353.                         return 0;
  354.                 it->album = to_album(rb_first(it->root));
  355.                 it->track = (struct tree_track *)it->album;
  356.                 return 1;
  357.         }
  358.  
  359.         /* get first track */
  360.         if (it->track == (struct tree_track *)it->album) {
  361.                 /* this happens when the last track in an album is deleted but
  362.                  * the album header is still referenced in lib_track_win->top
  363.                  * set track = NULL to skip the next `if` without goto */
  364.                 if (rb_root_empty(&it->album->track_root)) {
  365.                         it->track = NULL;
  366.                 } else {
  367.                         it->track = to_tree_track(rb_first(&it->album->track_root));
  368.                         return 1;
  369.                 }
  370.         }
  371.  
  372.         /* get next track */
  373.         if (it->track != NULL && rb_next(&it->track->tree_node) != NULL) {
  374.                 it->track = to_tree_track(rb_next(&it->track->tree_node));
  375.                 return 1;
  376.         }
  377.  
  378.         /* no more tracks
  379.          * get next album */
  380.         if (rb_next(&it->album->tree_node) != NULL) {
  381.                 it->album = to_album(rb_next(&it->album->tree_node));
  382.                 it->track = (struct tree_track *)it->album;
  383.                 return 1;
  384.         }
  385.  
  386.         /* no more albums */
  387.         return 0;
  388. }
  389.  
  390. /* track window iterators */
  391. static int tree_track_get_prev(struct iter *iter)
  392. {
  393.         if (tree_album_selected())
  394.                 return tree_track_get_prev_by_album(iter);
  395.         else
  396.                 return tree_track_get_prev_by_artist(iter);
  397. }
  398.  
  399. static int tree_track_get_next(struct iter *iter)
  400. {
  401.         if (tree_album_selected())
  402.                 return tree_track_get_next_by_album(iter);
  403.         else
  404.                 return tree_track_get_next_by_artist(iter);
  405. }
  406.  
  407. /* search (tree) {{{ */
  408. static int tree_search_get_current(void *data, struct iter *iter)
  409. {
  410.         struct artist *artist;
  411.         struct album *album;
  412.         struct tree_track *track;
  413.         struct iter tmpiter;
  414.  
  415.         if (rb_root_empty(&lib_artist_root))
  416.                 return 0;
  417.         if (window_get_sel(lib_track_win, &tmpiter)) {
  418.                 track = iter_to_tree_track(&tmpiter);
  419.                 tree_search_track_to_iter(track, iter);
  420.                 return 1;
  421.         }
  422.  
  423.         /* artist not expanded. track_win is empty
  424.          * set tmp to the first track of the selected artist */
  425.         window_get_sel(lib_tree_win, &tmpiter);
  426.         artist = iter_to_artist(&tmpiter);
  427.         album = to_album(rb_first(&artist->album_root));
  428.         track = to_tree_track(rb_first(&album->track_root));
  429.         tree_search_track_to_iter(track, iter);
  430.         return 1;
  431. }
  432.  
  433. static inline struct tree_track *iter_to_tree_search_track(const struct iter *iter)
  434. {
  435.         BUG_ON(iter->data0 != &lib_artist_root);
  436.         return iter->data1;
  437. }
  438.  
  439. static int tree_search_matches(void *data, struct iter *iter, const char *text);
  440.  
  441. static const struct searchable_ops tree_search_ops = {
  442.         .get_prev = tree_search_get_prev,
  443.         .get_next = tree_search_get_next,
  444.         .get_current = tree_search_get_current,
  445.         .matches = tree_search_matches
  446. };
  447. /* search (tree) }}} */
  448.  
  449. static void tree_sel_changed(void)
  450. {
  451.         tree_sel_update(1);
  452. }
  453.  
  454. void tree_sel_update(int changed)
  455. {
  456.         struct iter sel;
  457.         struct album *album;
  458.         struct artist *artist;
  459.  
  460.         window_get_sel(lib_tree_win, &sel);
  461.         album = iter_to_album(&sel);
  462.         artist = show_all_tracks ? iter_to_artist(&sel) : NULL;
  463.  
  464.         if (album != NULL) {
  465.                 if (changed)
  466.                         window_set_contents(lib_track_win, &album->track_root);
  467.         } else if (artist != NULL) {
  468.                 window_set_contents(lib_track_win, &artist->album_root);
  469.         } else {
  470.                 if (lib_cur_win != lib_tree_win) {
  471.                         lib_cur_win = lib_tree_win;
  472.                         lib_tree_win->changed = 1;
  473.                 }
  474.                 window_set_empty(lib_track_win);
  475.         }
  476. }
  477.  
  478. static inline void tree_win_get_selected(struct artist **artist, struct album **album)
  479. {
  480.         struct iter sel;
  481.  
  482.         *artist = NULL;
  483.         *album = NULL;
  484.         if (window_get_sel(lib_tree_win, &sel)) {
  485.                 *artist = iter_to_artist(&sel);
  486.                 *album = iter_to_album(&sel);
  487.         }
  488. }
  489.  
  490. static char *auto_artist_sort_name(const char *name)
  491. {
  492.         const char *name_orig = name;
  493.         char *buf;
  494.  
  495.         if (strncasecmp(name, "the ", 4) != 0)
  496.                 return NULL;
  497.  
  498.         name += 4;
  499.         while (isspace((int)*name))
  500.                 ++name;
  501.  
  502.         if (*name == '\0')
  503.                 return NULL;
  504.  
  505.         buf = xnew(char, strlen(name_orig) + 2);
  506.         sprintf(buf, "%s, %c%c%c", name, name_orig[0],
  507.                                          name_orig[1],
  508.                                          name_orig[2]);
  509.         return buf;
  510. }
  511.  
  512. static struct artist *artist_new(const char *name, const char *sort_name, int is_compilation)
  513. {
  514.         struct artist *a = xnew(struct artist, 1);
  515.  
  516.         a->name = xstrdup(name);
  517.         a->sort_name = sort_name ? xstrdup(sort_name) : NULL;
  518.         a->auto_sort_name = auto_artist_sort_name(name);
  519.         a->collkey_name = u_strcasecoll_key(a->name);
  520.         a->collkey_sort_name = u_strcasecoll_key0(a->sort_name);
  521.         a->collkey_auto_sort_name = u_strcasecoll_key0(a->auto_sort_name);
  522.         a->expanded = 0;
  523.         a->is_compilation = is_compilation;
  524.         rb_root_init(&a->album_root);
  525.  
  526.         return a;
  527. }
  528.  
  529. static struct artist *artist_copy(const struct artist *artist)
  530. {
  531.         return artist_new(artist->name, artist->sort_name, artist->is_compilation);
  532. }
  533.  
  534. static void artist_free(struct artist *artist)
  535. {
  536.         free(artist->name);
  537.         free(artist->sort_name);
  538.         free(artist->auto_sort_name);
  539.         free(artist->collkey_name);
  540.         free(artist->collkey_sort_name);
  541.         free(artist->collkey_auto_sort_name);
  542.         free(artist);
  543. }
  544.  
  545. static struct album *album_new(struct artist *artist, const char *name,
  546.                 const char *sort_name, int date)
  547. {
  548.         struct album *album = xnew(struct album, 1);
  549.  
  550.         album->name = xstrdup(name);
  551.         album->sort_name = sort_name ? xstrdup(sort_name) : NULL;
  552.         album->collkey_name = u_strcasecoll_key(name);
  553.         album->collkey_sort_name = u_strcasecoll_key0(sort_name);
  554.         album->date = date;
  555.         album->min_date = date;
  556.         rb_root_init(&album->track_root);
  557.         album->artist = artist;
  558.  
  559.         return album;
  560. }
  561.  
  562. static void album_free(struct album *album)
  563. {
  564.         free(album->name);
  565.         free(album->sort_name);
  566.         free(album->collkey_name);
  567.         free(album->collkey_sort_name);
  568.         free(album);
  569. }
  570.  
  571. static int track_selectable(struct iter *iter)
  572. {
  573.         struct track_iter *it = (struct track_iter *)iter;
  574.         return it->album != (struct album *)it->track;
  575. }
  576.  
  577. void tree_init(void)
  578. {
  579.         struct iter iter;
  580.  
  581.         rb_root_init(&lib_artist_root);
  582.  
  583.         lib_tree_win = window_new(tree_get_prev, tree_get_next);
  584.         lib_track_win = window_new(tree_track_get_prev, tree_track_get_next);
  585.         lib_cur_win = lib_tree_win;
  586.  
  587.         lib_tree_win->sel_changed = tree_sel_changed;
  588.         lib_track_win->selectable = track_selectable;
  589.  
  590.         window_set_empty(lib_track_win);
  591.         window_set_contents(lib_tree_win, &lib_artist_root);
  592.  
  593.         iter.data0 = &lib_artist_root;
  594.         iter.data1 = NULL;
  595.         iter.data2 = NULL;
  596.         tree_searchable = searchable_new(NULL, &iter, &tree_search_ops);
  597. }
  598.  
  599. struct tree_track *tree_get_selected(void)
  600. {
  601.         struct artist *artist;
  602.         struct album *album;
  603.         struct tree_track *track;
  604.         struct iter sel;
  605.  
  606.         if (rb_root_empty(&lib_artist_root))
  607.                 return NULL;
  608.  
  609.         tree_win_get_selected(&artist, &album);
  610.         if (album == NULL && !show_all_tracks) {
  611.                 /* track window is empty
  612.                  * => get first album of the selected artist and first track of that album
  613.                  */
  614.                 album = to_album(rb_first(&artist->album_root));
  615.                 track = to_tree_track(rb_first(&album->track_root));
  616.         } else {
  617.                 window_get_sel(lib_track_win, &sel);
  618.                 track = iter_to_tree_track(&sel);
  619.         }
  620.  
  621.         return track;
  622. }
  623.  
  624. struct track_info *tree_activate_selected(void)
  625. {
  626.         struct track_info *info;
  627.  
  628.         lib_cur_track = tree_get_selected();
  629.         if (!lib_cur_track)
  630.                 return NULL;
  631.  
  632.         lib_tree_win->changed = 1;
  633.         lib_track_win->changed = 1;
  634.  
  635.         info = tree_track_info(lib_cur_track);
  636.         track_info_ref(info);
  637.         return info;
  638. }
  639.  
  640. static int special_name_cmp(const char *a, const char *collkey_a,
  641.                                const char *b, const char *collkey_b)
  642. {
  643.         /* keep <Stream> etc. top */
  644.         int cmp = (*a != '<') - (*b != '<');
  645.  
  646.         if (cmp)
  647.                 return cmp;
  648.         return strcmp(collkey_a, collkey_b);
  649. }
  650.  
  651. static inline const char *album_sort_collkey(const struct album *a)
  652. {
  653.         if (a->sort_name)
  654.                 return a->collkey_sort_name;
  655.  
  656.         return a->collkey_name;
  657. }
  658.  
  659. static int special_album_cmp(const struct album *a, const struct album *b)
  660. {
  661.         return special_name_cmp(a->name, album_sort_collkey(a), b->name, album_sort_collkey(b));
  662. }
  663.  
  664. static int special_album_cmp_date(const struct album *a, const struct album *b)
  665. {
  666.         /* keep <Stream> etc. top */
  667.         int cmp = (*a->name != '<') - (*b->name != '<');
  668.         if (cmp)
  669.                 return cmp;
  670.  
  671.         cmp = a->date - b->date;
  672.         if (cmp)
  673.                 return cmp;
  674.  
  675.         return strcmp(album_sort_collkey(a), album_sort_collkey(b));
  676. }
  677.  
  678. /* has to follow the same logic as artist_sort_name() */
  679. static inline const char *artist_sort_collkey(const struct artist *a)
  680. {
  681.         if (a->sort_name)
  682.                 return a->collkey_sort_name;
  683.  
  684.         if (smart_artist_sort && a->auto_sort_name)
  685.                 return a->collkey_auto_sort_name;
  686.  
  687.         return a->collkey_name;
  688. }
  689.  
  690. static struct artist *do_find_artist(const struct artist *artist,
  691.                                      struct rb_root *root,
  692.                                      struct rb_node ***p_new,
  693.                                      struct rb_node **p_parent)
  694. {
  695.         struct rb_node **new = &(root->rb_node), *parent = NULL;
  696.         const char *a = artist_sort_name(artist);
  697.         const char *collkey_a = artist_sort_collkey(artist);
  698.  
  699.         while (*new) {
  700.                 struct artist *cur_artist = to_artist(*new);
  701.                 const char *b = artist_sort_name(cur_artist);
  702.                 const char *collkey_b = artist_sort_collkey(cur_artist);
  703.                 int result = special_name_cmp(a, collkey_a, b, collkey_b);
  704.  
  705.                 parent = *new;
  706.                 if (result < 0)
  707.                         new = &((*new)->rb_left);
  708.                 else if (result > 0)
  709.                         new = &((*new)->rb_right);
  710.                 else
  711.                         return cur_artist;
  712.         }
  713.         if (p_new)
  714.                 *p_new = new;
  715.         if (p_parent)
  716.                 *p_parent = parent;
  717.         return NULL;
  718. }
  719.  
  720. /* search (tree) {{{ */
  721. static struct artist *collapse_artist;
  722.  
  723. static int tree_search_matches(void *data, struct iter *iter, const char *text)
  724. {
  725.         struct tree_track *track;
  726.         struct iter tmpiter;
  727.         unsigned int flags = TI_MATCH_ARTIST | TI_MATCH_ALBUM | TI_MATCH_ALBUMARTIST;
  728.  
  729.         if (!search_restricted)
  730.                 flags |= TI_MATCH_TITLE;
  731.         track = iter_to_tree_search_track(iter);
  732.         if (!track_info_matches(tree_track_info(track), text, flags))
  733.                 return 0;
  734.  
  735.         if (auto_expand_albums_search) {
  736.                 /* collapse old search result */
  737.                 if (collapse_artist) {
  738.                         struct artist *artist = do_find_artist(collapse_artist, &lib_artist_root, NULL, NULL);
  739.                         if (artist && artist != track->album->artist) {
  740.                                 if (artist->expanded)
  741.                                         tree_set_expand_artist(artist, 0);
  742.                                 artist_free(collapse_artist);
  743.                                 collapse_artist = (!track->album->artist->expanded) ? artist_copy(track->album->artist) : NULL;
  744.                         }
  745.                 } else if (!track->album->artist->expanded) {
  746.                         collapse_artist = artist_copy(track->album->artist);
  747.                 }
  748.  
  749.                 track->album->artist->expanded = 1;
  750.                 album_to_iter(track->album, &tmpiter);
  751.         } else {
  752.                 artist_to_iter(track->album->artist, &tmpiter);
  753.         }
  754.  
  755.         window_set_sel(lib_tree_win, &tmpiter);
  756.  
  757.         tree_track_to_track_iter(track, (struct track_iter *)&tmpiter);
  758.         window_set_sel(lib_track_win, &tmpiter);
  759.  
  760.         return 1;
  761. }
  762. /* search (tree) }}} */
  763.  
  764. static void insert_artist(struct artist *artist, struct rb_root *root)
  765. {
  766.         struct rb_node **new = &(root->rb_node), *parent = NULL;
  767.         struct artist *found;
  768.  
  769.         found = do_find_artist(artist, root, &new, &parent);
  770.         if (!found) {
  771.                 rb_link_node(&artist->tree_node, parent, new);
  772.                 rb_insert_color(&artist->tree_node, root);
  773.         }
  774. }
  775.  
  776. static void add_artist(struct artist *artist)
  777. {
  778.         insert_artist(artist, &lib_artist_root);
  779. }
  780.  
  781. static struct artist *find_artist(const struct artist *artist)
  782. {
  783.         return do_find_artist(artist, &lib_artist_root, NULL, NULL);
  784. }
  785.  
  786. static struct album *do_find_album(const struct album *album,
  787.                                    int (*cmp)(const struct album *, const struct album *),
  788.                                    struct rb_node ***p_new,
  789.                                    struct rb_node **p_parent)
  790. {
  791.         struct rb_node **new = &(album->artist->album_root.rb_node), *parent = NULL;
  792.  
  793.         while (*new) {
  794.                 struct album *a = to_album(*new);
  795.  
  796.                 int result = cmp(album, a);
  797.  
  798.                 parent = *new;
  799.                 if (result < 0)
  800.                         new = &((*new)->rb_left);
  801.                 else if (result > 0)
  802.                         new = &((*new)->rb_right);
  803.                 else
  804.                         return a;
  805.         }
  806.         if (p_new)
  807.                 *p_new = new;
  808.         if (p_parent)
  809.                 *p_parent = parent;
  810.         return NULL;
  811. }
  812.  
  813. static struct album *find_album(const struct album *album)
  814. {
  815.         struct album *a;
  816.         struct rb_node *tmp;
  817.  
  818.         /* do a linear search because we want find albums with different date */
  819.         rb_for_each_entry(a, tmp, &album->artist->album_root, tree_node) {
  820.                 if (special_album_cmp(album, a) == 0)
  821.                         return a;
  822.         }
  823.         return NULL;
  824. }
  825.  
  826. static void add_album(struct album *album)
  827. {
  828.         struct rb_node **new = &(album->artist->album_root.rb_node), *parent = NULL;
  829.         struct album *found;
  830.  
  831.         /*
  832.          * Sort regular albums by date, but sort compilations
  833.          * alphabetically.
  834.          */
  835.         found = do_find_album(album,
  836.                               album->artist->is_compilation ? special_album_cmp
  837.                                                             : special_album_cmp_date,
  838.                               &new, &parent);
  839.         if (!found) {
  840.                 rb_link_node(&album->tree_node, parent, new);
  841.                 rb_insert_color(&album->tree_node, &album->artist->album_root);
  842.         }
  843. }
  844.  
  845. static void album_add_track(struct album *album, struct tree_track *track)
  846. {
  847.         /*
  848.          * NOTE: This is not perfect.  You should ignore track numbers if
  849.          *       either is unset and use filename instead, but usually you
  850.          *       have all track numbers set or all unset (within one album
  851.          *       of course).
  852.          */
  853.         static const sort_key_t album_track_sort_keys[] = {
  854.                 SORT_DISCNUMBER, SORT_TRACKNUMBER, SORT_FILENAME, SORT_INVALID
  855.         };
  856.         struct rb_node **new = &(album->track_root.rb_node), *parent = NULL;
  857.  
  858.         track->album = album;
  859.         while (*new) {
  860.                 const struct simple_track *a = (const struct simple_track *) track;
  861.                 const struct simple_track *b = (const struct simple_track *) to_tree_track(*new);
  862.                 int result = track_info_cmp(a->info, b->info, album_track_sort_keys);
  863.  
  864.                 parent = *new;
  865.                 if (result < 0)
  866.                         new = &((*new)->rb_left);
  867.                 else
  868.                         new = &((*new)->rb_right);
  869.         }
  870.  
  871.         rb_link_node(&track->tree_node, parent, new);
  872.         rb_insert_color(&track->tree_node, &album->track_root);
  873. }
  874.  
  875. static const char *tree_artist_name(const struct track_info* ti)
  876. {
  877.         const char *val = ti->albumartist;
  878.  
  879.         if (ti->is_va_compilation)
  880.                 val = "<Various Artists>";
  881.         if (!val || strcmp(val, "") == 0)
  882.                 val = "<No Name>";
  883.  
  884.         return val;
  885. }
  886.  
  887. static const char *tree_album_name(const struct track_info* ti)
  888. {
  889.         const char *val = ti->album;
  890.  
  891.         if (!val || strcmp(val, "") == 0)
  892.                 val = "<No Name>";
  893.  
  894.         return val;
  895. }
  896.  
  897. static void remove_album(struct album *album)
  898. {
  899.         if (album->artist->expanded) {
  900.                 struct iter iter;
  901.  
  902.                 album_to_iter(album, &iter);
  903.                 window_row_vanishes(lib_tree_win, &iter);
  904.         }
  905.         rb_erase(&album->tree_node, &album->artist->album_root);
  906. }
  907.  
  908. static void remove_artist(struct artist *artist)
  909. {
  910.         struct iter iter;
  911.  
  912.         artist_to_iter(artist, &iter);
  913.         window_row_vanishes(lib_tree_win, &iter);
  914.         rb_erase(&artist->tree_node, &lib_artist_root);
  915. }
  916.  
  917. void tree_add_track(struct tree_track *track)
  918. {
  919.         const struct track_info *ti = tree_track_info(track);
  920.         const char *album_name, *artist_name, *artistsort_name = NULL;
  921.         const char *albumsort_name = NULL;
  922.         struct artist *artist, *new_artist;
  923.         struct album *album, *new_album;
  924.         int date;
  925.         int is_va_compilation = 0;
  926.  
  927.         date = ti->originaldate;
  928.         if (date < 0)
  929.                 date = ti->date;
  930.  
  931.         if (is_http_url(ti->filename)) {
  932.                 artist_name = "<Stream>";
  933.                 album_name = "<Stream>";
  934.         } else {
  935.                 album_name      = tree_album_name(ti);
  936.                 artist_name     = tree_artist_name(ti);
  937.                 artistsort_name = ti->artistsort;
  938.                 albumsort_name  = ti->albumsort;
  939.  
  940.                 is_va_compilation = ti->is_va_compilation;
  941.         }
  942.  
  943.         new_artist = artist_new(artist_name, artistsort_name, is_va_compilation);
  944.         album = NULL;
  945.  
  946.         artist = find_artist(new_artist);
  947.         if (artist) {
  948.                 artist_free(new_artist);
  949.                 new_album = album_new(artist, album_name, albumsort_name, date);
  950.                 album = find_album(new_album);
  951.                 if (album)
  952.                         album_free(new_album);
  953.         } else
  954.                 new_album = album_new(new_artist, album_name, albumsort_name, date);
  955.  
  956.         if (artist) {
  957.                 int changed = 0;
  958.                 /* If it makes sense to update sort_name, do it */
  959.                 if (!artist->sort_name && artistsort_name) {
  960.                         artist->sort_name = xstrdup(artistsort_name);
  961.                         artist->collkey_sort_name = u_strcasecoll_key(artistsort_name);
  962.                         changed = 1;
  963.                 }
  964.                 /* If names differ, update */
  965.                 if (!artist->auto_sort_name) {
  966.                         char *auto_sort_name = auto_artist_sort_name(artist_name);
  967.                         if (auto_sort_name) {
  968.                                 free(artist->name);
  969.                                 free(artist->collkey_name);
  970.                                 artist->name = xstrdup(artist_name);
  971.                                 artist->collkey_name = u_strcasecoll_key(artist_name);
  972.                                 artist->auto_sort_name = auto_sort_name;
  973.                                 artist->collkey_auto_sort_name = u_strcasecoll_key(auto_sort_name);
  974.                                 changed = 1;
  975.                         }
  976.                 }
  977.                 if (changed) {
  978.                         remove_artist(artist);
  979.                         add_artist(artist);
  980.                         window_changed(lib_tree_win);
  981.                 }
  982.         }
  983.  
  984.         if (album) {
  985.                 album_add_track(album, track);
  986.  
  987.                 /* If it makes sense to update album date, do it */
  988.                 if (album->date < date) {
  989.                         album->date = date;
  990.  
  991.                         remove_album(album);
  992.                         add_album(album);
  993.                         if (artist->expanded)
  994.                                 window_changed(lib_tree_win);
  995.                 }
  996.  
  997.                 if (album->min_date <= 0 || (album->min_date > date && date > 0)) {
  998.                         album->min_date = date;
  999.  
  1000.                         remove_album(album);
  1001.                         add_album(album);
  1002.                         if (artist->expanded)
  1003.                                 window_changed(lib_tree_win);
  1004.                 }
  1005.  
  1006.         } else if (artist) {
  1007.                 add_album(new_album);
  1008.                 album_add_track(new_album, track);
  1009.  
  1010.                 if (artist->expanded)
  1011.                         window_changed(lib_tree_win);
  1012.         } else {
  1013.                 add_artist(new_artist);
  1014.                 add_album(new_album);
  1015.                 album_add_track(new_album, track);
  1016.  
  1017.                 window_changed(lib_tree_win);
  1018.         }
  1019.  
  1020.         if (track_visible(track))
  1021.                 window_changed(lib_track_win);
  1022. }
  1023.  
  1024. static void remove_sel_artist(struct artist *artist)
  1025. {
  1026.         struct rb_node *a_node, *a_tmp;
  1027.  
  1028.         rb_for_each_safe(a_node, a_tmp, &artist->album_root) {
  1029.                 struct rb_node *t_node, *t_tmp;
  1030.                 struct album *album = to_album(a_node);
  1031.  
  1032.                 rb_for_each_safe(t_node, t_tmp, &album->track_root) {
  1033.                         struct tree_track *track = to_tree_track(t_node);
  1034.  
  1035.                         editable_remove_track(&lib_editable, (struct simple_track *)track);
  1036.                 }
  1037.                 /* all tracks removed => album removed
  1038.                  * if the last album was removed then the artist was removed too
  1039.                  */
  1040.         }
  1041. }
  1042.  
  1043. static void remove_sel_album(struct album *album)
  1044. {
  1045.         struct rb_node *node, *tmp;
  1046.  
  1047.         rb_for_each_safe(node, tmp, &album->track_root) {
  1048.                 struct tree_track *track = to_tree_track(node);
  1049.  
  1050.                 editable_remove_track(&lib_editable, (struct simple_track *)track);
  1051.         }
  1052. }
  1053.  
  1054. static void tree_win_remove_sel(void)
  1055. {
  1056.         struct artist *artist;
  1057.         struct album *album;
  1058.  
  1059.         tree_win_get_selected(&artist, &album);
  1060.         if (album) {
  1061.                 remove_sel_album(album);
  1062.         } else if (artist) {
  1063.                 remove_sel_artist(artist);
  1064.         }
  1065. }
  1066.  
  1067. static void track_win_remove_sel(void)
  1068. {
  1069.         struct iter sel;
  1070.         struct tree_track *track;
  1071.  
  1072.         if (window_get_sel(lib_track_win, &sel)) {
  1073.                 track = iter_to_tree_track(&sel);
  1074.                 BUG_ON(track == NULL);
  1075.                 editable_remove_track(&lib_editable, (struct simple_track *)track);
  1076.         }
  1077. }
  1078.  
  1079. void tree_toggle_active_window(void)
  1080. {
  1081.         if (lib_cur_win == lib_tree_win) {
  1082.                 struct artist *artist;
  1083.                 struct album *album;
  1084.  
  1085.                 tree_win_get_selected(&artist, &album);
  1086.                 if (album || (artist && show_all_tracks)) {
  1087.                         lib_cur_win = lib_track_win;
  1088.                         lib_tree_win->changed = 1;
  1089.                         lib_track_win->changed = 1;
  1090.                 }
  1091.         } else if (lib_cur_win == lib_track_win) {
  1092.                 lib_cur_win = lib_tree_win;
  1093.                 lib_tree_win->changed = 1;
  1094.                 lib_track_win->changed = 1;
  1095.         }
  1096. }
  1097.  
  1098. void tree_toggle_expand_artist(void)
  1099. {
  1100.         struct track_iter sel;
  1101.         struct artist *artist;
  1102.         struct album *album;
  1103.         struct tree_track *track;
  1104.  
  1105.         tree_win_get_selected(&artist, &album);
  1106.         if (album != NULL && show_all_tracks) {
  1107.                 window_get_sel(lib_track_win, (struct iter *)&sel);
  1108.                 track = sel.track;
  1109.                 tree_set_expand_artist(artist, !artist->expanded);
  1110.                 tree_track_to_track_iter(track, &sel);
  1111.                 window_set_sel(lib_track_win, (struct iter *)&sel);
  1112.         } else if (artist != NULL) {
  1113.                 tree_set_expand_artist(artist, !artist->expanded);
  1114.         }
  1115.  
  1116. }
  1117.  
  1118. void tree_expand_matching(const char *text)
  1119. {
  1120.         struct artist *artist;
  1121.         struct rb_node *tmp1;
  1122.         int have_track_selected = 0;
  1123.  
  1124.         rb_for_each_entry(artist, tmp1, &lib_artist_root, tree_node) {
  1125.                 struct album *album = NULL;
  1126.                 struct rb_node *tmp2;
  1127.                 int album_matched = 0;
  1128.  
  1129.                 rb_for_each_entry(album, tmp2, &artist->album_root, tree_node) {
  1130.                         struct tree_track *tree_track = to_tree_track(rb_first(&album->track_root));
  1131.                         struct track_info *ti = ((struct simple_track *) tree_track)->info;
  1132.                         album_matched = track_info_matches_full(ti, text, TI_MATCH_ALBUM, TI_MATCH_ARTIST | TI_MATCH_ALBUMARTIST, 0);
  1133.                         if (album_matched)
  1134.                                 break;
  1135.                 }
  1136.                 artist->expanded = album_matched;
  1137.                 if (!have_track_selected) {
  1138.                         struct tree_track *tree_track;
  1139.                         int track_matched = 0;
  1140.  
  1141.                         if (!album)
  1142.                                 album = to_album(rb_first(&artist->album_root));
  1143.  
  1144.                         rb_for_each_entry(tree_track, tmp2, &album->track_root, tree_node) {
  1145.                                 struct track_info *ti = ((struct simple_track *) tree_track)->info;
  1146.                                 track_matched = track_info_matches_full(ti, text, TI_MATCH_TITLE, 0, 0);
  1147.                                 if (track_matched)
  1148.                                         break;
  1149.                         }
  1150.                         if (album_matched || track_matched) {
  1151.                                 if (!tree_track)
  1152.                                         tree_track = to_tree_track(rb_first(&album->track_root));
  1153.                                 tree_sel_track(tree_track, auto_expand_albums_search);
  1154.                                 have_track_selected = 1;
  1155.                         }
  1156.                 }
  1157.         }
  1158.         window_changed(lib_tree_win);
  1159. }
  1160.  
  1161. void tree_expand_all(void)
  1162. {
  1163.         struct artist *artist;
  1164.         struct rb_node *tmp;
  1165.  
  1166.         rb_for_each_entry(artist, tmp, &lib_artist_root, tree_node) {
  1167.                 artist->expanded = 1;
  1168.         }
  1169.         window_changed(lib_tree_win);
  1170. }
  1171.  
  1172. static void remove_track(struct tree_track *track)
  1173. {
  1174.         if (track_visible(track)) {
  1175.                 struct track_iter iter;
  1176.                 tree_track_to_track_iter(track, &iter);
  1177.                 window_row_vanishes(lib_track_win, (struct iter *)&iter);
  1178.         }
  1179.         rb_erase(&track->tree_node, &track->album->track_root);
  1180. }
  1181.  
  1182. void tree_remove(struct tree_track *track)
  1183. {
  1184.         struct album *album = track->album;
  1185.         struct artist *sel_artist;
  1186.         struct album *sel_album;
  1187.  
  1188.         tree_win_get_selected(&sel_artist, &sel_album);
  1189.  
  1190.         remove_track(track);
  1191.         /* don't free the track */
  1192.  
  1193.         if (rb_root_empty(&album->track_root)) {
  1194.                 struct artist *artist = album->artist;
  1195.  
  1196.                 if (sel_album == album)
  1197.                         lib_cur_win = lib_tree_win;
  1198.  
  1199.                 if (track_visible(track) && !tree_album_selected()) {
  1200.                         struct iter iter;
  1201.                         album_to_track_iter(album, (struct track_iter*)&iter);
  1202.                         window_row_vanishes(lib_track_win, &iter);
  1203.                 }
  1204.  
  1205.                 remove_album(album);
  1206.                 album_free(album);
  1207.  
  1208.                 if (rb_root_empty(&artist->album_root)) {
  1209.                         artist->expanded = 0;
  1210.                         remove_artist(artist);
  1211.                         artist_free(artist);
  1212.                 }
  1213.         }
  1214. }
  1215.  
  1216. void tree_remove_sel(void)
  1217. {
  1218.         if (lib_cur_win == lib_tree_win) {
  1219.                 tree_win_remove_sel();
  1220.         } else {
  1221.                 track_win_remove_sel();
  1222.         }
  1223. }
  1224.  
  1225. void tree_sort_artists(void)
  1226. {
  1227.         struct rb_node *a_node, *a_tmp;
  1228.  
  1229.         rb_for_each_safe(a_node, a_tmp, &lib_artist_root) {
  1230.                 struct rb_node *l_node, *l_tmp;
  1231.                 struct artist *artist = to_artist(a_node);
  1232.  
  1233.                 rb_for_each_safe(l_node, l_tmp, &artist->album_root) {
  1234.                         struct rb_node *t_node, *t_tmp;
  1235.                         struct album *album = to_album(l_node);
  1236.  
  1237.                         rb_for_each_safe(t_node, t_tmp, &album->track_root) {
  1238.                                 struct tree_track *track = to_tree_track(t_node);
  1239.  
  1240.                                 tree_remove(track);
  1241.                                 tree_add_track(track);
  1242.                         }
  1243.                 }
  1244.         }
  1245. }
  1246.  
  1247. void tree_sel_current(int auto_expand_albums)
  1248. {
  1249.         tree_sel_track(lib_cur_track, auto_expand_albums);
  1250. }
  1251.  
  1252. void tree_sel_first(void)
  1253. {
  1254.         if (!rb_root_empty(&lib_artist_root)) {
  1255.                 struct artist *artist = to_artist(rb_first(&lib_artist_root));
  1256.                 struct album *album = to_album(rb_first(&artist->album_root));
  1257.                 struct tree_track *tree_track = to_tree_track(rb_first(&album->track_root));
  1258.                 tree_sel_track(tree_track, auto_expand_albums_search);
  1259.         }
  1260. }
  1261.  
  1262. void tree_sel_track(struct tree_track *t, int auto_expand_albums )
  1263. {
  1264.         if (t) {
  1265.                 struct iter iter;
  1266.  
  1267.                 if (auto_expand_albums)
  1268.                         t->album->artist->expanded = 1;
  1269.                 if (t->album->artist->expanded)
  1270.                         album_to_iter(t->album, &iter);
  1271.                 else
  1272.                         artist_to_iter(t->album->artist, &iter);
  1273.  
  1274.                 window_set_sel(lib_tree_win, &iter);
  1275.  
  1276.                 tree_track_to_track_iter(t, (struct track_iter *)&iter);
  1277.                 window_set_sel(lib_track_win, &iter);
  1278.  
  1279.                 if (lib_cur_win == lib_tree_win) {
  1280.                         lib_cur_win = lib_track_win;
  1281.                         lib_tree_win->changed = 1;
  1282.                         lib_track_win->changed = 1;
  1283.                 }
  1284.         }
  1285. }
  1286.  
  1287. static int album_for_each_track(struct album *album, int (*cb)(void *data, struct track_info *ti),
  1288.                 void *data, int reverse)
  1289. {
  1290.         struct tree_track *track;
  1291.         struct rb_node *tmp;
  1292.         int rc = 0;
  1293.  
  1294.         if (reverse) {
  1295.                 rb_for_each_entry_reverse(track, tmp, &album->track_root, tree_node) {
  1296.                         rc = cb(data, tree_track_info(track));
  1297.                         if (rc)
  1298.                                 break;
  1299.                 }
  1300.         } else {
  1301.                 rb_for_each_entry(track, tmp, &album->track_root, tree_node) {
  1302.                         rc = cb(data, tree_track_info(track));
  1303.                         if (rc)
  1304.                                 break;
  1305.                 }
  1306.         }
  1307.         return rc;
  1308. }
  1309.  
  1310. static int artist_for_each_track(struct artist *artist, int (*cb)(void *data, struct track_info *ti),
  1311.                 void *data, int reverse)
  1312. {
  1313.         struct album *album;
  1314.         struct rb_node *tmp;
  1315.         int rc = 0;
  1316.  
  1317.         if (reverse) {
  1318.                 rb_for_each_entry_reverse(album, tmp, &artist->album_root, tree_node) {
  1319.                         rc = album_for_each_track(album, cb, data, 1);
  1320.                         if (rc)
  1321.                                 break;
  1322.                 }
  1323.         } else {
  1324.                 rb_for_each_entry(album, tmp, &artist->album_root, tree_node) {
  1325.                         rc = album_for_each_track(album, cb, data, 0);
  1326.                         if (rc)
  1327.                                 break;
  1328.                 }
  1329.         }
  1330.         return rc;
  1331. }
  1332.  
  1333. int _tree_for_each_sel(int (*cb)(void *data, struct track_info *ti), void *data, int reverse)
  1334. {
  1335.         int rc = 0;
  1336.  
  1337.         if (lib_cur_win == lib_tree_win) {
  1338.                 struct artist *artist;
  1339.                 struct album *album;
  1340.  
  1341.                 tree_win_get_selected(&artist, &album);
  1342.                 if (artist) {
  1343.                         if (album == NULL) {
  1344.                                 rc = artist_for_each_track(artist, cb, data, reverse);
  1345.                         } else {
  1346.                                 rc = album_for_each_track(album, cb, data, reverse);
  1347.                         }
  1348.                 }
  1349.         } else {
  1350.                 struct iter sel;
  1351.                 struct tree_track *track;
  1352.  
  1353.                 if (window_get_sel(lib_track_win, &sel)) {
  1354.                         track = iter_to_tree_track(&sel);
  1355.                         rc = cb(data, tree_track_info(track));
  1356.                 }
  1357.         }
  1358.         return rc;
  1359. }
  1360.  
  1361. int tree_for_each_sel(int (*cb)(void *data, struct track_info *ti), void *data, int reverse)
  1362. {
  1363.         int rc = _tree_for_each_sel(cb, data, reverse);
  1364.  
  1365.         window_down(lib_cur_win, 1);
  1366.         return rc;
  1367. }
  1368.  
downloadtree.c Source code - Download cmus Source code
Related Source Codes/Software:
Ink - An HTML5/CSS3 framework used at SAPO for fast and ... 2017-04-22
memory-stats.js - minimal monitor for JS Heap Size via performance.m... 2017-04-22
LayoutKit - LayoutKit is a fast view layout library for iOS, m... 2017-04-22
Cpp-Primer - C++ Primer 5 answer 2017-04-22
RBBAnimation - Block-based animations made easy, comes with easin... 2017-04-22
phpDocumentor2 - Documentation Generator for PHP ... 2017-04-22
flexboxfroggy - A game for learning CSS flexbox ... 2017-04-22
wicked - Use wicked to turn your controller into a wizard ... 2017-04-22
Begin-Latex-in-minutes - Brief Intro to LaTeX for beginners that helps you ... 2017-04-22
guard-livereload - Guard::LiveReload automatically reload your browse... 2017-04-22
swifter - Tiny http server engine written in Swift programmi... 2017-04-29
Chartbuilder - A front-end charting application that facilitates ... 2017-04-29
offline-first - 2017-04-29
plotly.py - An interactive, browser-based graphing library for... 2017-04-29
statsmodels - Statsmodels: statistical modeling and econometrics... 2017-04-29
android-maps-utils - Handy extensions to the Google Maps Android API. 2017-04-29
enyo - A JavaScript application framework emphasizing mod... 2017-04-29
darkforestGo - DarkForest, the Facebook Go engine. 2017-04-29
erpnext - ERP made Simple http://erpn... 2017-04-29
SwiftInFlux - An attempt to gather all that is in flux in Swift. 2017-04-29

 Back to top