2 * Copyright 2006 Timo Hirvonen
8 #include "track_info.h"
12 #include "mergesort.h"
15 pthread_mutex_t editable_mutex
= CMUS_MUTEX_INITIALIZER
;
17 static const struct searchable_ops simple_search_ops
= {
18 .get_prev
= simple_track_get_prev
,
19 .get_next
= simple_track_get_next
,
20 .get_current
= simple_track_search_get_current
,
21 .matches
= simple_track_search_matches
24 static struct simple_track
*get_selected(struct editable
*e
)
28 if (window_get_sel(e
->win
, &sel
))
29 return iter_to_simple_track(&sel
);
33 void editable_init(struct editable
*e
, void (*free_track
)(struct list_head
*item
))
41 e
->sort_keys
= xnew(const char *, 1);
42 e
->sort_keys
[0] = NULL
;
44 e
->free_track
= free_track
;
46 e
->win
= window_new(simple_track_get_prev
, simple_track_get_next
);
47 window_set_contents(e
->win
, &e
->head
);
49 iter
.data0
= &e
->head
;
52 e
->searchable
= searchable_new(e
->win
, &iter
, &simple_search_ops
);
55 void editable_add(struct editable
*e
, struct simple_track
*track
)
57 sorted_list_add_track(&e
->head
, track
, e
->sort_keys
);
59 if (track
->info
->duration
!= -1)
60 e
->total_time
+= track
->info
->duration
;
61 window_changed(e
->win
);
64 void editable_remove_track(struct editable
*e
, struct simple_track
*track
)
66 struct track_info
*ti
= track
->info
;
69 editable_track_to_iter(e
, track
, &iter
);
70 window_row_vanishes(e
->win
, &iter
);
73 e
->nr_marked
-= track
->marked
;
74 if (ti
->duration
!= -1)
75 e
->total_time
-= ti
->duration
;
77 list_del(&track
->node
);
79 e
->free_track(&track
->node
);
82 void editable_remove_sel(struct editable
*e
)
84 struct simple_track
*t
;
87 /* treat marked tracks as selected */
88 struct list_head
*next
, *item
= e
->head
.next
;
90 while (item
!= &e
->head
) {
92 t
= to_simple_track(item
);
94 editable_remove_track(e
, t
);
100 editable_remove_track(e
, t
);
104 static const char **sort_keys
;
106 static int list_cmp(const struct list_head
*a_head
, const struct list_head
*b_head
)
108 const struct simple_track
*a
= to_simple_track(a_head
);
109 const struct simple_track
*b
= to_simple_track(b_head
);
111 return track_info_cmp(a
->info
, b
->info
, sort_keys
);
114 void editable_sort(struct editable
*e
)
116 sort_keys
= e
->sort_keys
;
117 list_mergesort(&e
->head
, list_cmp
);
118 window_changed(e
->win
);
119 window_goto_top(e
->win
);
122 static void keys_to_str(const char **keys
, char *buf
)
126 for (i
= 0; keys
[i
]; i
++) {
127 const char *key
= keys
[i
];
128 int len
= strlen(key
);
130 if (sizeof(buf
) - pos
- len
- 2 < 0)
133 memcpy(buf
+ pos
, key
, len
);
142 void editable_set_sort_keys(struct editable
*e
, const char **keys
)
147 keys_to_str(keys
, e
->sort_str
);
150 void editable_toggle_mark(struct editable
*e
)
152 struct simple_track
*t
;
156 e
->nr_marked
-= t
->marked
;
158 e
->nr_marked
+= t
->marked
;
160 window_down(e
->win
, 1);
164 static void move_item(struct editable
*e
, struct list_head
*head
, struct list_head
*item
)
166 struct simple_track
*t
= to_simple_track(item
);
169 editable_track_to_iter(e
, t
, &iter
);
170 window_row_vanishes(e
->win
, &iter
);
173 list_add(item
, head
);
176 static void move_sel(struct editable
*e
, struct list_head
*after
)
178 struct simple_track
*t
;
179 struct list_head
*item
, *next
;
186 while (item
!= &e
->head
) {
187 t
= to_simple_track(item
);
190 move_item(e
, &tmp_head
, item
);
194 /* collect the selected track */
196 move_item(e
, &tmp_head
, &t
->node
);
199 /* put them back to the list after @after */
200 item
= tmp_head
.next
;
201 while (item
!= &tmp_head
) {
203 list_add(item
, after
);
207 /* select top-most of the moved tracks */
208 editable_track_to_iter(e
, to_simple_track(after
->next
), &iter
);
209 window_set_sel(e
->win
, &iter
);
210 window_changed(e
->win
);
213 static struct list_head
*find_insert_after_point(struct editable
*e
, struct list_head
*item
)
215 if (e
->nr_marked
== 0) {
216 /* move the selected track down one row */
220 /* move marked after the selected
222 * if the selected track itself is marked we find the first unmarked
223 * track (or head) before the selected one
225 while (item
!= &e
->head
) {
226 struct simple_track
*t
= to_simple_track(item
);
235 static struct list_head
*find_insert_before_point(struct editable
*e
, struct list_head
*item
)
238 if (e
->nr_marked
== 0) {
239 /* move the selected track up one row */
243 /* move marked before the selected
245 * if the selected track itself is marked we find the first unmarked
246 * track (or head) before the selected one
248 while (item
!= &e
->head
) {
249 struct simple_track
*t
= to_simple_track(item
);
258 void editable_move_after(struct editable
*e
)
260 struct simple_track
*sel
;
262 if (e
->nr_tracks
<= 1 || e
->sort_keys
[0])
265 sel
= get_selected(e
);
267 move_sel(e
, find_insert_after_point(e
, &sel
->node
));
270 void editable_move_before(struct editable
*e
)
272 struct simple_track
*sel
;
274 if (e
->nr_tracks
<= 1 || e
->sort_keys
[0])
277 sel
= get_selected(e
);
279 move_sel(e
, find_insert_before_point(e
, &sel
->node
));
282 void editable_clear(struct editable
*e
)
284 struct list_head
*item
, *next
;
287 while (item
!= &e
->head
) {
289 editable_remove_track(e
, to_simple_track(item
));
294 void editable_mark(struct editable
*e
, const char *filter
)
296 struct expr
*expr
= NULL
;
297 struct simple_track
*t
;
300 expr
= parse_filter(filter
);
305 list_for_each_entry(t
, &e
->head
, node
) {
306 e
->nr_marked
-= t
->marked
;
308 if (expr
== NULL
|| expr_eval(expr
, t
->info
)) {
316 void editable_unmark(struct editable
*e
)
318 struct simple_track
*t
;
320 list_for_each_entry(t
, &e
->head
, node
) {
321 e
->nr_marked
-= t
->marked
;
327 void editable_invert_marks(struct editable
*e
)
329 struct simple_track
*t
;
331 list_for_each_entry(t
, &e
->head
, node
) {
332 e
->nr_marked
-= t
->marked
;
334 e
->nr_marked
+= t
->marked
;
339 int __editable_for_each_sel(struct editable
*e
, int (*cb
)(void *data
, struct track_info
*ti
),
340 void *data
, int reverse
)
345 /* treat marked tracks as selected */
346 rc
= simple_list_for_each_marked(&e
->head
, cb
, data
, reverse
);
348 struct simple_track
*t
= get_selected(e
);
351 rc
= cb(data
, t
->info
);
356 int editable_for_each_sel(struct editable
*e
, int (*cb
)(void *data
, struct track_info
*ti
),
357 void *data
, int reverse
)
361 rc
= __editable_for_each_sel(e
, cb
, data
, reverse
);
362 if (e
->nr_marked
== 0)
363 window_down(e
->win
, 1);