5 public List
<string> paste_queue
;
6 const string log_domain
= "Gmpc.DataView";
8 /** The Default column width. */
9 const int default_column_width
= 200;
13 * * List of column ids to show.
14 * * Name of each column
15 * * Default set of enabled columns.
17 const int NUM_COLS
= 20;
18 const int[] gmpc_data_view_col_ids
= {
19 Gmpc
.MpdData
.ColumnTypes
.COL_MARKUP
,
20 Gmpc
.MpdData
.ColumnTypes
.COL_SONG_ARTIST
, /* album name */
21 Gmpc
.MpdData
.ColumnTypes
.COL_SONG_ALBUM
, /* album name */
22 Gmpc
.MpdData
.ColumnTypes
.COL_SONG_TITLE
, /* song title */
23 Gmpc
.MpdData
.ColumnTypes
.COL_SONG_TITLEFILE
, /* song title */
24 Gmpc
.MpdData
.ColumnTypes
.COL_SONG_GENRE
, /* song genre */
25 Gmpc
.MpdData
.ColumnTypes
.COL_SONG_TRACK
, /* song track */
26 Gmpc
.MpdData
.ColumnTypes
.COL_SONG_NAME
, /* stream name */
27 Gmpc
.MpdData
.ColumnTypes
.COL_SONG_COMPOSER
, /* composer name */
28 Gmpc
.MpdData
.ColumnTypes
.COL_SONG_PERFORMER
, /* performer */
29 Gmpc
.MpdData
.ColumnTypes
.COL_SONG_DATE
, /* date */
30 Gmpc
.MpdData
.ColumnTypes
.COL_SONG_LENGTH_FORMAT
, /* length formatted */
31 Gmpc
.MpdData
.ColumnTypes
.COL_SONG_DISC
, /* disc */
32 Gmpc
.MpdData
.ColumnTypes
.COL_SONG_COMMENT
, /* comment */
33 Gmpc
.MpdData
.ColumnTypes
.COL_ICON_ID
, /* icon id */
34 Gmpc
.MpdData
.ColumnTypes
.COL_SONG_POS
,
35 Gmpc
.MpdData
.ColumnTypes
.COL_SONG_ALBUMARTIST
,
36 Gmpc
.MpdData
.ColumnTypes
.COL_PATH_EXTENSION
, /* Extension */
37 Gmpc
.MpdData
.ColumnTypes
.COL_PATH_DIRECTORY
, /* Directory */
38 Gmpc
.MpdData
.ColumnTypes
.COL_SONG_PRIORITY
40 const string[] gmpc_data_view_col_names
= {
63 const bool[] gmpc_data_view_col_enabled
= {
87 const int[] gmpc_data_view_col_position
= {
110 public class Gmpc
.DataView
: Gtk
.TreeView
112 public enum ViewType
{
118 private Gtk
.TreeViewColumn
[] tree_columns
= new Gtk
.TreeViewColumn
[NUM_COLS
];
120 * If we are a play-queue we should treat the content.
121 * slightly different.
122 * e.g. add-replace will be play-crop
124 public ViewType view_mode
{get; set;default=ViewType
.SONG_LIST
;}
126 * If we 'view' a playlist, we need to know the name of the play queue.
127 * This can be set here.
129 private string __playlist_name
= null;
130 public string playlist_name
{
132 return __playlist_name
;
135 if(view_mode
== ViewType
.PLAYLIST
) {
136 stdout
.printf("Set playlist name: %s\n", value
);
137 __playlist_name
= value
;
139 error("Cannot set playlist name on non-playlist view.");
145 * The name of the treeview.
146 * This is used to store the column layout.
148 public string uid
{get; set; default="default";}
152 * Construction function.
154 public DataView(string name
, ViewType mode
= ViewType
.SONG_LIST
)
156 log(log_domain
, LogLevelFlags
.LEVEL_INFO
, "Constructing dataview: "+name
);
157 this
.view_mode
= mode
;
159 // Connect row activated signal.
160 this
.row_activated
.connect(__row_activated
);
161 this
.key_press_event
.connect(__key_press_event_callback
);
162 this
.button_press_event
.connect(__button_press_event_callback
);
163 this
.button_release_event
.connect(__button_release_event_callback
);
164 // When it getst he destroy signal.
165 this
.destroy
.connect(column_store_state
);
167 this
.set_rules_hint(true);
168 this
.set_enable_search(false);
170 this
.get_selection().set_mode(Gtk
.SelectionMode
.MULTIPLE
);
171 this
.set_fixed_height_mode(true);
176 // Update the sorting when it changed.
177 this
.notify
["model"].connect((source
) => {
178 // Only the SONG_LIST is sortable.
179 if(this
.model is Gtk
.TreeSortable
&& view_mode
== ViewType
.SONG_LIST
) {
180 int sort_column
= config
.get_int_with_default(uid
,
181 "sort-column", Gmpc
.MpdData
.ColumnTypes
.COL_ICON_ID
);
182 Gtk
.SortType sort_order
= (Gtk
.SortType
)config
.get_int_with_default(uid
,
183 "sort-order",(int)Gtk
.SortType
.ASCENDING
);
185 (this
.model as Gtk
.TreeSortable
).set_sort_column_id(
186 sort_column
, sort_order
199 /** small wrapper.. */
200 private void playlist_editor_add_new(Gtk
.Widget menu
)
202 string playlist
= menu
.get_data("playlist");
203 selected_songs_add_to_playlist(playlist
);
206 public void right_mouse_menu(Gtk
.Menu menu
)
208 int selected_rows
= this
.get_selection().count_selected_rows();
209 if(selected_rows
== 1) {
211 var path
= this
.get_selection().get_selected_rows(out model
).first().data
;
213 if(model
.get_iter(out iter
, path
))
215 MPD
.Data
.Type row_type
;
216 model
.get(iter
, Gmpc
.MpdData
.ColumnTypes
.ROW_TYPE
, out row_type
);
217 if(row_type
== MPD
.Data
.Type
.SONG
) {
218 var item
= new Gtk
.ImageMenuItem
.from_stock(Gtk
.Stock
.MEDIA_PLAY
,null);
219 item
.activate
.connect((source
)=>{
220 selected_songs_play();
224 item
= new Gtk
.ImageMenuItem
.from_stock(Gtk
.Stock
.INFO
, null);
225 item
.activate
.connect((source
)=>{
226 selected_songs_info();
233 if(view_mode
== ViewType
.PLAY_QUEUE
|| view_mode
== ViewType
.PLAYLIST
)
235 if(selected_rows
> 0) {
236 var item
= new Gtk
.ImageMenuItem
.from_stock(Gtk
.Stock
.REMOVE
,null);
237 item
.activate
.connect((source
)=>{
238 selected_songs_remove();
243 var item
= new Gtk
.ImageMenuItem
.from_stock(Gtk
.Stock
.ADD
,null);
244 item
.activate
.connect((source
)=>{
245 selected_songs_add();
248 item
= new Gtk
.ImageMenuItem
.with_label(_("Replace"));
249 item
.activate
.connect((source
)=>{
250 MPD
.PlayQueue
.clear(server
);
251 selected_songs_add();
255 if(server
.check_command_allowed("prioid") == MPD
.Server
.Command
.ALLOWED
)
257 menu
.append( new Gtk
.SeparatorMenuItem());
258 var item
= new Gtk
.MenuItem
.with_label(_("Queue"));
259 item
.activate
.connect((source
)=>{ selected_songs_raise_priority();});
262 if(view_mode
== ViewType
.PLAY_QUEUE
) {
263 item
= new Gtk
.MenuItem
.with_label(_("Dequeue"));
264 item
.activate
.connect((source
)=>{ selected_songs_remove_priority();});
269 if(selected_rows
> 0)
272 item
= new Gtk
.SeparatorMenuItem();
274 if(view_mode
== ViewType
.PLAY_QUEUE
|| view_mode
== ViewType
.PLAYLIST
) {
275 item
= new Gtk
.ImageMenuItem
.from_stock(Gtk
.Stock
.CUT
, null);
276 item
.activate
.connect((source
)=>{ selected_songs_paste_queue_cut();});
280 item
= new Gtk
.ImageMenuItem
.from_stock(Gtk
.Stock
.COPY
, null);
281 item
.activate
.connect((source
)=>{ selected_songs_paste_queue_copy();});
284 if( (view_mode
== ViewType
.PLAY_QUEUE
||
285 view_mode
== ViewType
.PLAYLIST
)
286 && paste_queue
!= null) {
287 item
= new Gtk
.ImageMenuItem
.with_label(_("Paste before"));
288 (item as Gtk
.ImageMenuItem
).set_image(new Image
.from_stock(Gtk
.Stock
.PASTE
, Gtk
.IconSize
.MENU
));
289 item
.activate
.connect((source
)=>{ selected_songs_paste_before();});
292 item
= new Gtk
.ImageMenuItem
.with_label(_("Paste after"));
293 (item as Gtk
.ImageMenuItem
).set_image(new Image
.from_stock(Gtk
.Stock
.PASTE
, Gtk
.IconSize
.MENU
));
294 item
.activate
.connect((source
)=>{ selected_songs_paste_after();});
298 // Add to playlist integration.
301 if(selected_rows
== 1)
304 var list
= get_selection().get_selected_rows(out model
);
305 var path
= list
.first().data
;
307 if(model
.get_iter(out iter
, path
))
309 unowned MPD
.Song? song
;
310 model
.get(iter
, MpdData
.ColumnTypes
.COL_MPDSONG
, out song
);
312 MpdInteraction
.submenu_for_song(menu
, song
);
317 // Tool menu integration.
318 bool initial
= false;
319 var item
= new Gtk
.MenuItem
.with_label(_("Tools"));
320 var smenu
= new Gtk
.Menu();
321 item
.set_submenu(smenu
);
322 for(int i
= 0; i
< Gmpc
.num_plugins
; i
++){
323 if(plugins
[i
].get_enabled() &&
324 plugins
[i
].browser_song_list_option_menu(this
,smenu
) > 0){
325 stdout
.printf("adding entry\n");
330 menu
.append(new Gtk
.SeparatorMenuItem());
334 Gmpc
.Browser
.PlaylistEditor
.right_mouse(menu
, playlist_editor_add_new
);
338 item
= new Gtk
.MenuItem
.with_label(_("Edit Columns"));
339 smenu
= new Gtk
.Menu();
340 item
.set_submenu(smenu
);
341 generate_column_selection_menu(smenu
);
347 * Internal functions.
351 * Store the position, visibility and width of the columns
353 private void column_store_state()
355 // Save the position of the columns
356 var columns
= get_columns();
358 foreach(var column
in columns
)
360 int col_index
= column
.get_data("index");
361 int width
= column
.get_width();
362 config
.set_int(uid
+"-colpos", gmpc_data_view_col_names
[col_index
], index
);
363 config
.set_bool(uid
+"-colshow", gmpc_data_view_col_names
[col_index
], column
.visible
);
364 // Only store width if bigger then 0.
366 config
.set_int(uid
+"-colsize",gmpc_data_view_col_names
[col_index
], width
);
371 if(this
.model is Gtk
.TreeSortable
) {
374 if((this
.model as Gtk
.TreeSortable
).get_sort_column_id(out sort_column
, out sort_order
)) {
375 config
.set_int(uid
, "sort-column", sort_column
);
376 config
.set_int(uid
, "sort-order", sort_order
);
380 // Hack to make vala not destroy the menu directly.
382 private void generate_column_selection_menu(Gtk
.Menu menu
)
384 foreach(var col
in tree_columns
)
386 int index
= col
.get_data("index");
387 // Do not show the icon id in the selection list.
388 if(gmpc_data_view_col_ids
[index
] == MpdData
.ColumnTypes
.COL_ICON_ID
) continue;
389 var item
= new Gtk
.CheckMenuItem
.with_label(FixGtk
.gettext(gmpc_data_view_col_names
[index
]));
391 item
.set_active(true);
393 // On activation toggle the state.
394 item
.activate
.connect((source
) => {
395 col
.visible
= (source as Gtk
.CheckMenuItem
).get_active();
402 private Gtk
.Menu column_selection_menu
= null;
403 private void column_show_selection_menu()
405 column_selection_menu
= new Gtk
.Menu();
406 generate_column_selection_menu(column_selection_menu
);
407 column_selection_menu
.show_all();
408 column_selection_menu
.popup(null, null, null, 0, Gtk
.get_current_event_time());
411 * Populate the treeview with the right columns.
412 * The treeview should have a name now.
414 private void column_populate()
416 for(int i
= 0; i
< NUM_COLS
; i
++)
418 Gtk
.TreeViewColumn col
= new Gtk
.TreeViewColumn();
419 col
.set_data("index", i
);
420 if(gmpc_data_view_col_ids
[i
] == Gmpc
.MpdData
.ColumnTypes
.COL_ICON_ID
)
425 var renderer
= new Gtk
.CellRendererPixbuf();
426 renderer
.xalign
= 0.0f
;
428 col
.pack_start(renderer
, true);
429 col
.set_attributes(renderer
, "icon-name", Gmpc
.MpdData
.ColumnTypes
.COL_ICON_ID
);
430 col
.set_resizable(false);
431 col
.set_fixed_width(20);
432 col
.clickable
= true;
437 col
.set_title(FixGtk
.gettext(gmpc_data_view_col_names
[i
]));
438 var renderer
= new Gtk
.CellRendererText();
439 renderer
.ellipsize
= Pango
.EllipsizeMode
.END
;
441 if(view_mode
== ViewType
.PLAY_QUEUE
) {
442 renderer
.weight_set
= true;
443 renderer
.style_set
= true;
444 col
.set_cell_data_func(renderer
, highlight_row_current_song_playing
);
446 col
.pack_start(renderer
, true);
447 col
.set_attributes(renderer
, "text", gmpc_data_view_col_ids
[i
]);
448 col
.set_resizable(true);
450 int width
= config
.get_int_with_default(uid
+"-colsize",
451 gmpc_data_view_col_names
[i
], default_column_width
);
452 // Do not set to size 0, then revert back to 200.
453 col
.set_fixed_width(width
>0?width
:default_column_width
);
455 col
.set_sizing(Gtk
.TreeViewColumnSizing
.FIXED
);
456 col
.set_reorderable(true);
459 if(view_mode
== ViewType
.SONG_LIST
) {
460 col
.set_sort_indicator(true);
461 col
.set_sort_column_id(gmpc_data_view_col_ids
[i
]);
465 int pos
= config
.get_int_with_default(uid
+"-colpos",
466 gmpc_data_view_col_names
[i
], gmpc_data_view_col_position
[i
]);
467 this
.tree_columns
[pos
] = col
;
470 // Add the columns (in right order)
471 for(int i
= 0; i
< NUM_COLS
; i
++) {
472 int index
= this
.tree_columns
[i
].get_data("index");
473 this
.insert_column(this
.tree_columns
[i
], i
);
474 this
.tree_columns
[i
].set_visible(config
.get_bool_with_default(uid
+"-colshow",
475 gmpc_data_view_col_names
[index
], gmpc_data_view_col_enabled
[index
]));
484 * Function handles the row-activate signal.
486 private void __row_activated (Gtk
.TreePath path
, Gtk
.TreeViewColumn col
)
488 Gtk
.TreeModel? model
= this
.get_model();
491 MPD
.Data
.Type row_type
;
493 if(!model
.get_iter(out iter
, path
)) return;
495 model
.get(iter
, Gmpc
.MpdData
.ColumnTypes
.ROW_TYPE
, out row_type
);
496 if(view_mode
== ViewType
.PLAY_QUEUE
) {
497 /* If we are play-queue, play the selected song. */
499 model
.get(iter
, Gmpc
.MpdData
.ColumnTypes
.COL_SONG_ID
, out song_id
);
500 MPD
.Player
.play_id(Gmpc
.server
, song_id
);
503 model
.get(iter
, Gmpc
.MpdData
.ColumnTypes
.COL_PATH
, out song_path
);
504 if(row_type
== MPD
.Data
.Type
.SONG
) {
505 /* If we are a song browser, add the path and play it. */
506 MpdInteraction
.play_path(song_path
);
507 } else if (row_type
== MPD
.Data
.Type
.PLAYLIST
) {
508 MPD
.PlayQueue
.queue_load_playlist(server
, song_path
);
509 MPD
.PlayQueue
.queue_commit(server
);
515 * Check if current row is playing.
517 private void highlight_row_current_song_playing(
519 Gtk
.CellRenderer renderer
,
523 // The current song we make bold.
524 if(model is Gmpc
.MpdData
.ModelPlaylist
&&
525 (model as Gmpc
.MpdData
.ModelPlaylist
).is_current_song(iter
)){
526 (renderer as Gtk
.CellRendererText
).weight
= Pango
.Weight
.BOLD
;
528 (renderer as Gtk
.CellRendererText
).weight
= Pango
.Weight
.NORMAL
;
531 // A prioritized song we make italic.
533 model
.get(iter
, Gmpc
.MpdData
.ColumnTypes
.COL_SONG_PRIORITY
, out prio
);
535 (renderer as Gtk
.CellRendererText
).style
= Pango
.Style
.ITALIC
;
537 (renderer as Gtk
.CellRendererText
).style
= Pango
.Style
.NORMAL
;
543 * Handle keyboard input.
545 private bool __key_press_event_callback_song_list(Gdk
.EventKey event
)
547 if(event
.keyval
== Gdk
.Key_i
)
549 return selected_songs_add();
551 else if (event
.keyval
== Gdk
.Key_r
)
553 // If there are songs selected, clear the play queue,
554 // and add selection.
555 if(this
.get_selection().count_selected_rows() > 0) {
556 MPD
.PlayQueue
.clear(server
);
557 return selected_songs_add();
563 * Keybinding for playlists.
565 private bool __key_press_event_callback_playlist(Gdk
.EventKey event
)
567 if (event
.keyval
== Gdk
.Key_x
)
569 // Cut (if available) into clipboard
570 selected_songs_paste_queue_cut();
572 else if (event
.keyval
== Gdk
.Key_P
)
575 return selected_songs_paste_before();
577 else if (event
.keyval
== Gdk
.Key_p
)
580 return selected_songs_paste_after();
582 else if (event
.keyval
== Gdk
.Key_d
)
584 if(!selected_songs_remove())
586 // Clear the playlist
587 MPD
.Database
.playlist_clear(server
, playlist_name
);
591 else if (event
.keyval
== Gdk
.Key_D
)
593 MPD
.Database
.playlist_clear(server
, playlist_name
);
598 private bool __key_press_event_callback_play_queue(Gdk
.EventKey event
)
600 if (event
.keyval
== Gdk
.Key_Q
)
603 return selected_songs_remove_priority();
605 else if (event
.keyval
== Gdk
.Key_x
)
607 // Cut (if available) into clipboard
608 selected_songs_paste_queue_cut();
610 else if (event
.keyval
== Gdk
.Key_P
)
613 return selected_songs_paste_before();
615 else if (event
.keyval
== Gdk
.Key_p
)
618 return selected_songs_paste_after();
620 else if (event
.keyval
== Gdk
.Key_d
)
622 if(!selected_songs_remove())
624 // Detach model (for some reason keeping it attached
625 // Makes thing break, work-around for now)
627 var model
= get_model();
630 MPD
.PlayQueue
.clear(server
);
636 else if (event
.keyval
== Gdk
.Key_D
)
638 var model
= get_model();
641 MPD
.PlayQueue
.clear(server
);
648 private bool __key_press_event_callback(Gdk
.EventKey event
)
650 if(event
.keyval
== Gdk
.Key_j
)
655 else if (event
.keyval
== Gdk
.Key_k
)
660 else if (event
.keyval
== Gdk
.Key_g
)
664 else if (event
.keyval
== Gdk
.Key_G
)
666 move_cursor_bottom();
668 else if(event
.keyval
== Gdk
.Key_y
)
670 // Copy data to clipboard
671 return selected_songs_paste_queue_copy();
673 else if (event
.keyval
== Gdk
.Key_o
)
675 return selected_songs_info();
677 else if (event
.keyval
== Gdk
.Key_Escape
)
681 else if (event
.keyval
== Gdk
.Key_m
)
684 column_show_selection_menu();
687 else if (event
.keyval
== Gdk
.Key_q
)
690 return selected_songs_raise_priority();
692 else if (event
.keyval
== Gdk
.Key_Menu
)
694 __button_press_menu
= new Gtk
.Menu();
696 right_mouse_menu(__button_press_menu
);
701 __button_press_menu
.show_all();
702 __button_press_menu
.popup(null, null,null,0, Gtk
.get_current_event_time());
706 // Commands specific to play_queue
707 if(view_mode
== ViewType
.PLAY_QUEUE
)
709 if(__key_press_event_callback_play_queue(event
)) return true;
711 else if (view_mode
== ViewType
.PLAYLIST
)
713 if(__key_press_event_callback_playlist(event
)) return true;
715 else if (view_mode
== ViewType
.SONG_LIST
)
717 if(__key_press_event_callback_song_list(event
)) return true;
725 // Hack to stop vala from destroying my menu.
726 private Gtk
.Menu __button_press_menu
= null;
727 private bool __button_press_event_callback(Gdk
.EventButton event
)
729 if(event
.button
== 3)
731 __button_press_menu
= new Gtk
.Menu();
732 right_mouse_menu(__button_press_menu
);
734 __button_press_menu
.show_all();
735 __button_press_menu
.popup(null, null,null, event
.button
, event
.time
);
740 private bool __button_release_event_callback(Gdk
.EventButton event
)
747 * Interaction on selected songs.
749 // Set priority on the selected songs.
750 private bool selected_songs_raise_priority()
752 if(server
.check_command_allowed("prioid") != MPD
.Server
.Command
.ALLOWED
) return false;
753 var selection
= this
.get_selection();
755 if(selection
.count_selected_rows() > 254) {
756 Gmpc
.Messages
.show(_("You can only queue 254 songs at the time."), Gmpc
.Messages
.Level
.WARNING
);
762 foreach(var path
in selection
.get_selected_rows(out model
))
765 if(model
.get_iter(out iter
, path
))
767 MPD
.Data
.Type row_type
;
770 Gmpc
.MpdData
.ColumnTypes
.COL_SONG_ID
, out song_id
,
771 Gmpc
.MpdData
.ColumnTypes
.ROW_TYPE
, out row_type
);
772 // Only act on songs.
773 if(row_type
!= MPD
.Data
.Type
.SONG
) continue;
776 MPD
.PlayQueue
.set_priority(server
, song_id
, priority
--);
779 model
.get(iter
, Gmpc
.MpdData
.ColumnTypes
.COL_PATH
, out song_path
);
780 song_id
= MPD
.PlayQueue
.add_song_get_id(server
,song_path
);
781 MPD
.PlayQueue
.set_priority(server
, song_id
, priority
--);
787 // Remove the set priority from the selected songs.
788 private bool selected_songs_remove_priority()
790 if(server
.check_command_allowed("prioid") != MPD
.Server
.Command
.ALLOWED
) return false;
791 var selection
= this
.get_selection();
794 foreach(var path
in selection
.get_selected_rows(out model
))
797 if(model
.get_iter(out iter
, path
))
800 model
.get(iter
,Gmpc
.MpdData
.ColumnTypes
.COL_SONG_ID
, out song_id
);
801 if ( song_id
>= 0 ) {
802 MPD
.PlayQueue
.set_priority(server
, song_id
, 0);
808 // Add the selected song
809 private bool selected_songs_add()
812 var selection
= this
.get_selection();
815 foreach(var path
in selection
.get_selected_rows(out model
))
818 if(model
.get_iter(out iter
, path
))
821 MPD
.Data
.Type row_type
;
823 Gmpc
.MpdData
.ColumnTypes
.ROW_TYPE
, out row_type
,
824 Gmpc
.MpdData
.ColumnTypes
.COL_PATH
, out song_path
);
825 if ( row_type
== MPD
.Data
.Type
.SONG
|| row_type
== MPD
.Data
.Type
.DIRECTORY
) {
826 MPD
.PlayQueue
.queue_add_song(server
, song_path
);
828 }else if (row_type
== MPD
.Data
.Type
.PLAYLIST
) {
829 MPD
.PlayQueue
.queue_load_playlist(server
, song_path
);
834 MPD
.PlayQueue
.queue_commit(server
);
840 // Play the selected song
841 private bool selected_songs_play()
843 var selection
= this
.get_selection();
845 foreach(var path
in selection
.get_selected_rows(out model
))
848 if(model
.get_iter(out iter
, path
))
850 if(view_mode
== ViewType
.PLAY_QUEUE
) {
852 model
.get(iter
, Gmpc
.MpdData
.ColumnTypes
.COL_SONG_ID
, out song_id
);
854 MPD
.Player
.play_id(server
, song_id
);
859 model
.get(iter
, Gmpc
.MpdData
.ColumnTypes
.COL_PATH
, out song_path
);
860 MpdInteraction
.play_path(song_path
);
865 return selection
.count_selected_rows() > 0;
867 // Remove the selected songs from the play queue.
868 private bool selected_songs_remove()
870 int deleted_rows
= 0;
871 var selection
= this
.get_selection();
874 var sel_rows
= selection
.get_selected_rows(out model
);
876 foreach(var path
in sel_rows
)
879 if(model
.get_iter(out iter
, path
))
881 if(view_mode
== ViewType
.PLAY_QUEUE
) {
883 model
.get(iter
,Gmpc
.MpdData
.ColumnTypes
.COL_SONG_ID
, out song_id
);
884 MPD
.PlayQueue
.queue_delete_id(server
, song_id
);
885 }else if ( view_mode
== ViewType
.PLAYLIST
) {
886 var indc
= path
.get_indices();
887 int song_pos
= indc
[0];
888 MPD
.Database
.playlist_list_delete(server
, playlist_name
, song_pos
);
890 error("Invalid state, cannot call this here.");
895 MPD
.PlayQueue
.queue_commit(server
);
896 if(deleted_rows
> 0) {
897 selection
.unselect_all();
902 // Show the Information of the first selected song.
903 private bool selected_songs_info()
905 var selection
= this
.get_selection();
907 foreach(var path
in selection
.get_selected_rows(out model
))
910 if(model
.get_iter(out iter
, path
))
912 unowned MPD
.Song? song
= null;
913 model
.get(iter
, Gmpc
.MpdData
.ColumnTypes
.COL_MPDSONG
, out song
);
915 Browser
.Metadata
.show();
916 Browser
.Metadata
.show_song(song
);
921 return selection
.count_selected_rows() > 0;
924 // Cut the selected songs in the play queue
925 private bool selected_songs_paste_queue_cut()
927 if(selected_songs_paste_queue_copy()){
928 selected_songs_remove();
932 // Copy the selected songs in the play queue
933 private bool selected_songs_paste_queue_copy()
935 var selection
= this
.get_selection();
936 // If nothing to copy , do nothing.
937 if(selection
.count_selected_rows() == 0) return false;
941 foreach(var path
in selection
.get_selected_rows(out model
))
944 if(model
.get_iter(out iter
, path
))
947 model
.get(iter
,Gmpc
.MpdData
.ColumnTypes
.COL_PATH
, out insert_path
);
948 paste_queue
.prepend(insert_path
);
951 paste_queue
.reverse();
956 private bool selected_songs_paste_before()
958 var selection
= this
.get_selection();
959 // If nothing selected.
960 if(selection
.count_selected_rows() == 0|| paste_queue
== null)
966 Gtk
.TreePath path
= selection
.get_selected_rows(out model
).last().data
;
967 if(model
.get_iter(out iter
, path
))
970 if( view_mode
== ViewType
.PLAY_QUEUE
) {
971 model
.get(iter
, Gmpc
.MpdData
.ColumnTypes
.COL_SONG_POS
, out songpos
);
974 paste_queue
.reverse();
975 foreach(var fpath
in paste_queue
)
977 int nsongid
= MPD
.PlayQueue
.add_song_get_id(server
,fpath
);
978 MPD
.PlayQueue
.song_move_id(server
, nsongid
, songpos
);
980 paste_queue
.reverse();
982 }else if (view_mode
== ViewType
.PLAYLIST
) {
983 int length
= this
.model
.iter_n_children(null);
984 var indc
= path
.get_indices();
986 paste_queue
.reverse();
987 foreach(var fpath
in paste_queue
)
989 MPD
.Database
.playlist_list_add(server
, playlist_name
, fpath
);
990 MPD
.Database
.playlist_move(server
, playlist_name
, length
,songpos
);
993 paste_queue
.reverse();
996 error("We should be able to be here.");
1001 private bool selected_songs_paste_after()
1003 var selection
= this
.get_selection();
1004 // If nothing selected.
1005 if(selection
.count_selected_rows() == 0|| paste_queue
== null)
1009 Gtk
.TreeModel model
;
1011 Gtk
.TreePath path
= selection
.get_selected_rows(out model
).last().data
;
1012 if(model
.get_iter(out iter
, path
))
1015 if(view_mode
== ViewType
.PLAY_QUEUE
) {
1016 model
.get(iter
, Gmpc
.MpdData
.ColumnTypes
.COL_SONG_POS
, out songpos
);
1018 paste_queue
.reverse();
1019 foreach(var fpath
in paste_queue
)
1021 int nsongid
= MPD
.PlayQueue
.add_song_get_id(server
,fpath
);
1022 MPD
.PlayQueue
.song_move_id(server
, nsongid
, songpos
);
1024 paste_queue
.reverse();
1027 else if (view_mode
== ViewType
.PLAYLIST
) {
1028 int length
= this
.model
.iter_n_children(null);
1029 var indc
= path
.get_indices();
1030 songpos
= indc
[0]+1;
1031 paste_queue
.reverse();
1032 foreach(var fpath
in paste_queue
)
1034 MPD
.Database
.playlist_list_add(server
, playlist_name
, fpath
);
1035 MPD
.Database
.playlist_move(server
, playlist_name
, length
,songpos
);
1038 paste_queue
.reverse();
1040 error("We should be able to be here.");
1047 private bool selected_songs_add_to_playlist(string playlist
)
1049 int songs_added
= 0;
1050 var selection
= this
.get_selection();
1051 // If nothing selected.
1052 if(selection
.count_selected_rows() == 0)
1056 Gtk
.TreeModel model
;
1057 foreach (var path
in selection
.get_selected_rows(out model
))
1060 if(model
.get_iter(out iter
, path
))
1062 string? song_path
= null;
1063 model
.get(iter
, Gmpc
.MpdData
.ColumnTypes
.COL_PATH
, out song_path
);
1064 if(song_path
!= null) {
1065 MPD
.Database
.playlist_list_add(server
, playlist
, song_path
);
1070 return (songs_added
> 0);
1076 private void move_cursor_down()
1079 Gtk
.TreeViewColumn? col
;
1080 this
.get_cursor(out path
, out col
);
1085 if(this
.model
.get_iter(out iter
, path
))
1087 this
.set_cursor(path
, col
, false);
1091 private void move_cursor_top()
1093 Gtk
.TreeViewColumn? col
;
1094 var rows
= this
.model
.iter_n_children(null);
1097 this
.get_cursor(null, out col
);
1098 path
= new Gtk
.TreePath
.from_indices(0);
1099 this
.set_cursor(path
, col
, false);
1102 private void move_cursor_bottom()
1104 Gtk
.TreeViewColumn? col
;
1105 var rows
= this
.model
.iter_n_children(null);
1108 this
.get_cursor(null, out col
);
1109 path
= new Gtk
.TreePath
.from_indices(rows
-1);
1110 this
.set_cursor(path
, col
, false);
1113 private void move_cursor_up()
1116 Gtk
.TreeViewColumn? col
;
1117 this
.get_cursor(out path
, out col
);
1122 this
.set_cursor(path
, col
, false);