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_m
)
680 column_show_selection_menu();
683 else if (event
.keyval
== Gdk
.Key_q
)
686 return selected_songs_raise_priority();
688 else if (event
.keyval
== Gdk
.Key_Menu
)
690 __button_press_menu
= new Gtk
.Menu();
692 right_mouse_menu(__button_press_menu
);
697 __button_press_menu
.show_all();
698 __button_press_menu
.popup(null, null,null,0, Gtk
.get_current_event_time());
702 // Commands specific to play_queue
703 if(view_mode
== ViewType
.PLAY_QUEUE
)
705 if(__key_press_event_callback_play_queue(event
)) return true;
707 else if (view_mode
== ViewType
.PLAYLIST
)
709 if(__key_press_event_callback_playlist(event
)) return true;
711 else if (view_mode
== ViewType
.SONG_LIST
)
713 if(__key_press_event_callback_song_list(event
)) return true;
721 // Hack to stop vala from destroying my menu.
722 private Gtk
.Menu __button_press_menu
= null;
723 private bool __button_press_event_callback(Gdk
.EventButton event
)
725 if(event
.button
== 3)
727 __button_press_menu
= new Gtk
.Menu();
728 right_mouse_menu(__button_press_menu
);
730 __button_press_menu
.show_all();
731 __button_press_menu
.popup(null, null,null, event
.button
, event
.time
);
736 private bool __button_release_event_callback(Gdk
.EventButton event
)
743 * Interaction on selected songs.
745 // Set priority on the selected songs.
746 private bool selected_songs_raise_priority()
748 if(server
.check_command_allowed("prioid") != MPD
.Server
.Command
.ALLOWED
) return false;
749 var selection
= this
.get_selection();
751 if(selection
.count_selected_rows() > 254) {
752 Gmpc
.Messages
.show(_("You can only queue 254 songs at the time."), Gmpc
.Messages
.Level
.WARNING
);
758 foreach(var path
in selection
.get_selected_rows(out model
))
761 if(model
.get_iter(out iter
, path
))
763 MPD
.Data
.Type row_type
;
766 Gmpc
.MpdData
.ColumnTypes
.COL_SONG_ID
, out song_id
,
767 Gmpc
.MpdData
.ColumnTypes
.ROW_TYPE
, out row_type
);
768 // Only act on songs.
769 if(row_type
!= MPD
.Data
.Type
.SONG
) continue;
772 MPD
.PlayQueue
.set_priority(server
, song_id
, priority
--);
775 model
.get(iter
, Gmpc
.MpdData
.ColumnTypes
.COL_PATH
, out song_path
);
776 song_id
= MPD
.PlayQueue
.add_song_get_id(server
,song_path
);
777 MPD
.PlayQueue
.set_priority(server
, song_id
, priority
--);
783 // Remove the set priority from the selected songs.
784 private bool selected_songs_remove_priority()
786 if(server
.check_command_allowed("prioid") != MPD
.Server
.Command
.ALLOWED
) return false;
787 var selection
= this
.get_selection();
790 foreach(var path
in selection
.get_selected_rows(out model
))
793 if(model
.get_iter(out iter
, path
))
796 model
.get(iter
,Gmpc
.MpdData
.ColumnTypes
.COL_SONG_ID
, out song_id
);
797 if ( song_id
>= 0 ) {
798 MPD
.PlayQueue
.set_priority(server
, song_id
, 0);
804 // Add the selected song
805 private bool selected_songs_add()
808 var selection
= this
.get_selection();
811 foreach(var path
in selection
.get_selected_rows(out model
))
814 if(model
.get_iter(out iter
, path
))
817 MPD
.Data
.Type row_type
;
819 Gmpc
.MpdData
.ColumnTypes
.ROW_TYPE
, out row_type
,
820 Gmpc
.MpdData
.ColumnTypes
.COL_PATH
, out song_path
);
821 if ( row_type
== MPD
.Data
.Type
.SONG
|| row_type
== MPD
.Data
.Type
.DIRECTORY
) {
822 MPD
.PlayQueue
.queue_add_song(server
, song_path
);
824 }else if (row_type
== MPD
.Data
.Type
.PLAYLIST
) {
825 MPD
.PlayQueue
.queue_load_playlist(server
, song_path
);
830 MPD
.PlayQueue
.queue_commit(server
);
836 // Play the selected song
837 private bool selected_songs_play()
839 var selection
= this
.get_selection();
841 foreach(var path
in selection
.get_selected_rows(out model
))
844 if(model
.get_iter(out iter
, path
))
846 if(view_mode
== ViewType
.PLAY_QUEUE
) {
848 model
.get(iter
, Gmpc
.MpdData
.ColumnTypes
.COL_SONG_ID
, out song_id
);
850 MPD
.Player
.play_id(server
, song_id
);
855 model
.get(iter
, Gmpc
.MpdData
.ColumnTypes
.COL_PATH
, out song_path
);
856 MpdInteraction
.play_path(song_path
);
861 return selection
.count_selected_rows() > 0;
863 // Remove the selected songs from the play queue.
864 private bool selected_songs_remove()
866 int deleted_rows
= 0;
867 var selection
= this
.get_selection();
870 var sel_rows
= selection
.get_selected_rows(out model
);
872 foreach(var path
in sel_rows
)
875 if(model
.get_iter(out iter
, path
))
877 if(view_mode
== ViewType
.PLAY_QUEUE
) {
879 model
.get(iter
,Gmpc
.MpdData
.ColumnTypes
.COL_SONG_ID
, out song_id
);
880 MPD
.PlayQueue
.queue_delete_id(server
, song_id
);
881 }else if ( view_mode
== ViewType
.PLAYLIST
) {
882 var indc
= path
.get_indices();
883 int song_pos
= indc
[0];
884 MPD
.Database
.playlist_list_delete(server
, playlist_name
, song_pos
);
886 error("Invalid state, cannot call this here.");
891 MPD
.PlayQueue
.queue_commit(server
);
892 if(deleted_rows
> 0) {
893 selection
.unselect_all();
898 // Show the Information of the first selected song.
899 private bool selected_songs_info()
901 var selection
= this
.get_selection();
903 foreach(var path
in selection
.get_selected_rows(out model
))
906 if(model
.get_iter(out iter
, path
))
908 unowned MPD
.Song? song
= null;
909 model
.get(iter
, Gmpc
.MpdData
.ColumnTypes
.COL_MPDSONG
, out song
);
911 Browser
.Metadata
.show();
912 Browser
.Metadata
.show_song(song
);
917 return selection
.count_selected_rows() > 0;
920 // Cut the selected songs in the play queue
921 private bool selected_songs_paste_queue_cut()
923 if(selected_songs_paste_queue_copy()){
924 selected_songs_remove();
928 // Copy the selected songs in the play queue
929 private bool selected_songs_paste_queue_copy()
931 var selection
= this
.get_selection();
932 // If nothing to copy , do nothing.
933 if(selection
.count_selected_rows() == 0) return false;
937 foreach(var path
in selection
.get_selected_rows(out model
))
940 if(model
.get_iter(out iter
, path
))
943 model
.get(iter
,Gmpc
.MpdData
.ColumnTypes
.COL_PATH
, out insert_path
);
944 paste_queue
.prepend(insert_path
);
947 paste_queue
.reverse();
952 private bool selected_songs_paste_before()
954 var selection
= this
.get_selection();
955 // If nothing selected.
956 if(selection
.count_selected_rows() == 0|| paste_queue
== null)
962 Gtk
.TreePath path
= selection
.get_selected_rows(out model
).last().data
;
963 if(model
.get_iter(out iter
, path
))
966 if( view_mode
== ViewType
.PLAY_QUEUE
) {
967 model
.get(iter
, Gmpc
.MpdData
.ColumnTypes
.COL_SONG_POS
, out songpos
);
970 paste_queue
.reverse();
971 foreach(var fpath
in paste_queue
)
973 int nsongid
= MPD
.PlayQueue
.add_song_get_id(server
,fpath
);
974 MPD
.PlayQueue
.song_move_id(server
, nsongid
, songpos
);
976 paste_queue
.reverse();
978 }else if (view_mode
== ViewType
.PLAYLIST
) {
979 int length
= this
.model
.iter_n_children(null);
980 var indc
= path
.get_indices();
982 paste_queue
.reverse();
983 foreach(var fpath
in paste_queue
)
985 MPD
.Database
.playlist_list_add(server
, playlist_name
, fpath
);
986 MPD
.Database
.playlist_move(server
, playlist_name
, length
,songpos
);
989 paste_queue
.reverse();
992 error("We should be able to be here.");
997 private bool selected_songs_paste_after()
999 var selection
= this
.get_selection();
1000 // If nothing selected.
1001 if(selection
.count_selected_rows() == 0|| paste_queue
== null)
1005 Gtk
.TreeModel model
;
1007 Gtk
.TreePath path
= selection
.get_selected_rows(out model
).last().data
;
1008 if(model
.get_iter(out iter
, path
))
1011 if(view_mode
== ViewType
.PLAY_QUEUE
) {
1012 model
.get(iter
, Gmpc
.MpdData
.ColumnTypes
.COL_SONG_POS
, out songpos
);
1014 paste_queue
.reverse();
1015 foreach(var fpath
in paste_queue
)
1017 int nsongid
= MPD
.PlayQueue
.add_song_get_id(server
,fpath
);
1018 MPD
.PlayQueue
.song_move_id(server
, nsongid
, songpos
);
1020 paste_queue
.reverse();
1023 else if (view_mode
== ViewType
.PLAYLIST
) {
1024 int length
= this
.model
.iter_n_children(null);
1025 var indc
= path
.get_indices();
1026 songpos
= indc
[0]+1;
1027 paste_queue
.reverse();
1028 foreach(var fpath
in paste_queue
)
1030 MPD
.Database
.playlist_list_add(server
, playlist_name
, fpath
);
1031 MPD
.Database
.playlist_move(server
, playlist_name
, length
,songpos
);
1034 paste_queue
.reverse();
1036 error("We should be able to be here.");
1043 private bool selected_songs_add_to_playlist(string playlist
)
1045 int songs_added
= 0;
1046 var selection
= this
.get_selection();
1047 // If nothing selected.
1048 if(selection
.count_selected_rows() == 0)
1052 Gtk
.TreeModel model
;
1053 foreach (var path
in selection
.get_selected_rows(out model
))
1056 if(model
.get_iter(out iter
, path
))
1058 string? song_path
= null;
1059 model
.get(iter
, Gmpc
.MpdData
.ColumnTypes
.COL_PATH
, out song_path
);
1060 if(song_path
!= null) {
1061 MPD
.Database
.playlist_list_add(server
, playlist
, song_path
);
1066 return (songs_added
> 0);
1072 private void move_cursor_down()
1075 Gtk
.TreeViewColumn? col
;
1076 this
.get_cursor(out path
, out col
);
1081 if(this
.model
.get_iter(out iter
, path
))
1083 this
.set_cursor(path
, col
, false);
1087 private void move_cursor_top()
1089 Gtk
.TreeViewColumn? col
;
1090 var rows
= this
.model
.iter_n_children(null);
1093 this
.get_cursor(null, out col
);
1094 path
= new Gtk
.TreePath
.from_indices(0);
1095 this
.set_cursor(path
, col
, false);
1098 private void move_cursor_bottom()
1100 Gtk
.TreeViewColumn? col
;
1101 var rows
= this
.model
.iter_n_children(null);
1104 this
.get_cursor(null, out col
);
1105 path
= new Gtk
.TreePath
.from_indices(rows
-1);
1106 this
.set_cursor(path
, col
, false);
1109 private void move_cursor_up()
1112 Gtk
.TreeViewColumn? col
;
1113 this
.get_cursor(out path
, out col
);
1118 this
.set_cursor(path
, col
, false);