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 __playlist_name
= value
;
138 error("Cannot set playlist name on non-playlist view.");
144 * The name of the treeview.
145 * This is used to store the column layout.
147 public string uid
{get; set; default="default";}
151 * Construction function.
153 public DataView(string name
, ViewType mode
= ViewType
.SONG_LIST
)
155 log(log_domain
, LogLevelFlags
.LEVEL_INFO
, "Constructing dataview: "+name
);
156 this
.view_mode
= mode
;
158 // Connect row activated signal.
159 this
.row_activated
.connect(__row_activated
);
160 this
.key_press_event
.connect(__key_press_event_callback
);
161 this
.button_press_event
.connect(__button_press_event_callback
);
162 this
.button_release_event
.connect(__button_release_event_callback
);
163 // When it getst he destroy signal.
164 this
.destroy
.connect(column_store_state
);
166 this
.set_rules_hint(true);
167 this
.set_enable_search(false);
169 this
.get_selection().set_mode(Gtk
.SelectionMode
.MULTIPLE
);
170 this
.set_fixed_height_mode(true);
175 // Update the sorting when it changed.
176 this
.notify
["model"].connect((source
) => {
177 // Only the SONG_LIST is sortable.
178 if(this
.model is Gtk
.TreeSortable
&& view_mode
== ViewType
.SONG_LIST
) {
179 int sort_column
= config
.get_int_with_default(uid
,
180 "sort-column", Gmpc
.MpdData
.ColumnTypes
.COL_ICON_ID
);
181 Gtk
.SortType sort_order
= (Gtk
.SortType
)config
.get_int_with_default(uid
,
182 "sort-order",(int)Gtk
.SortType
.ASCENDING
);
184 (this
.model as Gtk
.TreeSortable
).set_sort_column_id(
185 sort_column
, sort_order
198 /** small wrapper.. */
199 private void playlist_editor_add_new(Gtk
.Widget menu
)
201 string playlist
= menu
.get_data("playlist");
202 selected_songs_add_to_playlist(playlist
);
205 public void right_mouse_menu(Gtk
.Menu menu
)
207 int selected_rows
= this
.get_selection().count_selected_rows();
208 if(selected_rows
== 1) {
210 var path
= this
.get_selection().get_selected_rows(out model
).first().data
;
212 if(model
.get_iter(out iter
, path
))
214 MPD
.Data
.Type row_type
;
215 model
.get(iter
, Gmpc
.MpdData
.ColumnTypes
.ROW_TYPE
, out row_type
);
216 if(row_type
== MPD
.Data
.Type
.SONG
) {
217 var item
= new Gtk
.ImageMenuItem
.from_stock(Gtk
.Stock
.MEDIA_PLAY
,null);
218 item
.activate
.connect((source
)=>{
219 selected_songs_play();
223 item
= new Gtk
.ImageMenuItem
.from_stock(Gtk
.Stock
.INFO
, null);
224 item
.activate
.connect((source
)=>{
225 selected_songs_info();
232 if(view_mode
== ViewType
.PLAY_QUEUE
|| view_mode
== ViewType
.PLAYLIST
)
234 if(selected_rows
> 0) {
235 var item
= new Gtk
.ImageMenuItem
.from_stock(Gtk
.Stock
.REMOVE
,null);
236 item
.activate
.connect((source
)=>{
237 selected_songs_remove();
242 var item
= new Gtk
.ImageMenuItem
.from_stock(Gtk
.Stock
.ADD
,null);
243 item
.activate
.connect((source
)=>{
244 selected_songs_add();
247 item
= new Gtk
.ImageMenuItem
.with_label(_("Replace"));
248 item
.activate
.connect((source
)=>{
249 MPD
.PlayQueue
.clear(server
);
250 selected_songs_add();
254 if(server
.check_command_allowed("prioid") == MPD
.Server
.Command
.ALLOWED
)
256 menu
.append( new Gtk
.SeparatorMenuItem());
257 var item
= new Gtk
.MenuItem
.with_label(_("Queue"));
258 item
.activate
.connect((source
)=>{ selected_songs_raise_priority();});
261 if(view_mode
== ViewType
.PLAY_QUEUE
) {
262 item
= new Gtk
.MenuItem
.with_label(_("Dequeue"));
263 item
.activate
.connect((source
)=>{ selected_songs_remove_priority();});
268 if(selected_rows
> 0)
271 item
= new Gtk
.SeparatorMenuItem();
273 if(view_mode
== ViewType
.PLAY_QUEUE
) {
274 item
= new Gtk
.ImageMenuItem
.from_stock(Gtk
.Stock
.CUT
, null);
275 item
.activate
.connect((source
)=>{ selected_songs_paste_queue_cut();});
279 item
= new Gtk
.ImageMenuItem
.from_stock(Gtk
.Stock
.COPY
, null);
280 item
.activate
.connect((source
)=>{ selected_songs_paste_queue_copy();});
283 if(view_mode
== ViewType
.PLAY_QUEUE
&& paste_queue
!= null) {
284 item
= new Gtk
.ImageMenuItem
.with_label(_("Paste before"));
285 (item as Gtk
.ImageMenuItem
).set_image(new Image
.from_stock(Gtk
.Stock
.PASTE
, Gtk
.IconSize
.MENU
));
286 item
.activate
.connect((source
)=>{ selected_songs_paste_before();});
289 item
= new Gtk
.ImageMenuItem
.with_label(_("Paste after"));
290 (item as Gtk
.ImageMenuItem
).set_image(new Image
.from_stock(Gtk
.Stock
.PASTE
, Gtk
.IconSize
.MENU
));
291 item
.activate
.connect((source
)=>{ selected_songs_paste_after();});
295 // Add to playlist integration.
298 if(selected_rows
== 1)
301 var list
= get_selection().get_selected_rows(out model
);
302 var path
= list
.first().data
;
304 if(model
.get_iter(out iter
, path
))
306 unowned MPD
.Song? song
;
307 model
.get(iter
, MpdData
.ColumnTypes
.COL_MPDSONG
, out song
);
309 MpdInteraction
.submenu_for_song(menu
, song
);
314 // Tool menu integration.
315 bool initial
= false;
316 var item
= new Gtk
.MenuItem
.with_label(_("Tools"));
317 var smenu
= new Gtk
.Menu();
318 item
.set_submenu(smenu
);
319 for(int i
= 0; i
< Gmpc
.num_plugins
; i
++){
320 if(plugins
[i
].get_enabled() &&
321 plugins
[i
].browser_song_list_option_menu(this
,smenu
) > 0){
322 stdout
.printf("adding entry\n");
327 menu
.append(new Gtk
.SeparatorMenuItem());
331 Gmpc
.Browser
.PlaylistEditor
.right_mouse(menu
, playlist_editor_add_new
);
335 item
= new Gtk
.MenuItem
.with_label(_("Edit Columns"));
336 smenu
= new Gtk
.Menu();
337 item
.set_submenu(smenu
);
338 generate_column_selection_menu(smenu
);
340 // item.activate.connect((source)=>{ column_show_selection_menu();});
345 * Internal functions.
349 * Store the position, visibility and width of the columns
351 private void column_store_state()
353 // Save the position of the columns
354 var columns
= get_columns();
356 foreach(var column
in columns
)
358 int col_index
= column
.get_data("index");
359 int width
= column
.get_width();
360 config
.set_int(uid
+"-colpos", gmpc_data_view_col_names
[col_index
], index
);
361 config
.set_bool(uid
+"-colshow", gmpc_data_view_col_names
[col_index
], column
.visible
);
362 // Only store width if bigger then 0.
364 config
.set_int(uid
+"-colsize",gmpc_data_view_col_names
[col_index
], width
);
369 if(this
.model is Gtk
.TreeSortable
) {
372 if((this
.model as Gtk
.TreeSortable
).get_sort_column_id(out sort_column
, out sort_order
)) {
373 config
.set_int(uid
, "sort-column", sort_column
);
374 config
.set_int(uid
, "sort-order", sort_order
);
378 // Hack to make vala not destroy the menu directly.
380 private void generate_column_selection_menu(Gtk
.Menu menu
)
382 foreach(var col
in tree_columns
)
384 int index
= col
.get_data("index");
385 // Do not show the icon id in the selection list.
386 if(gmpc_data_view_col_ids
[index
] == MpdData
.ColumnTypes
.COL_ICON_ID
) continue;
387 var item
= new Gtk
.CheckMenuItem
.with_label(FixGtk
.gettext(gmpc_data_view_col_names
[index
]));
389 item
.set_active(true);
391 // On activation toggle the state.
392 item
.activate
.connect((source
) => {
393 col
.visible
= (source as Gtk
.CheckMenuItem
).get_active();
400 private Gtk
.Menu column_selection_menu
= null;
401 private void column_show_selection_menu()
403 column_selection_menu
= new Gtk
.Menu();
404 generate_column_selection_menu(column_selection_menu
);
405 column_selection_menu
.show_all();
406 column_selection_menu
.popup(null, null, null, 0, Gtk
.get_current_event_time());
409 * Populate the treeview with the right columns.
410 * The treeview should have a name now.
412 private void column_populate()
414 for(int i
= 0; i
< NUM_COLS
; i
++)
416 Gtk
.TreeViewColumn col
= new Gtk
.TreeViewColumn();
417 col
.set_data("index", i
);
418 if(gmpc_data_view_col_ids
[i
] == Gmpc
.MpdData
.ColumnTypes
.COL_ICON_ID
)
423 var renderer
= new Gtk
.CellRendererPixbuf();
424 renderer
.xalign
= 0.0f
;
426 col
.pack_start(renderer
, true);
427 col
.set_attributes(renderer
, "icon-name", Gmpc
.MpdData
.ColumnTypes
.COL_ICON_ID
);
428 col
.set_resizable(false);
429 col
.set_fixed_width(20);
430 col
.clickable
= true;
435 col
.set_title(FixGtk
.gettext(gmpc_data_view_col_names
[i
]));
436 var renderer
= new Gtk
.CellRendererText();
437 renderer
.ellipsize
= Pango
.EllipsizeMode
.END
;
439 if(view_mode
== ViewType
.PLAY_QUEUE
) {
440 renderer
.weight_set
= true;
441 renderer
.style_set
= true;
442 col
.set_cell_data_func(renderer
, highlight_row_current_song_playing
);
444 col
.pack_start(renderer
, true);
445 col
.set_attributes(renderer
, "text", gmpc_data_view_col_ids
[i
]);
446 col
.set_resizable(true);
448 int width
= config
.get_int_with_default(uid
+"-colsize",
449 gmpc_data_view_col_names
[i
], default_column_width
);
450 // Do not set to size 0, then revert back to 200.
451 col
.set_fixed_width(width
>0?width
:default_column_width
);
453 col
.set_sizing(Gtk
.TreeViewColumnSizing
.FIXED
);
454 col
.set_reorderable(true);
457 if(view_mode
== ViewType
.SONG_LIST
) {
458 col
.set_sort_indicator(true);
459 col
.set_sort_column_id(gmpc_data_view_col_ids
[i
]);
463 int pos
= config
.get_int_with_default(uid
+"-colpos",
464 gmpc_data_view_col_names
[i
], gmpc_data_view_col_position
[i
]);
465 this
.tree_columns
[pos
] = col
;
468 // Add the columns (in right order)
469 for(int i
= 0; i
< NUM_COLS
; i
++) {
470 int index
= this
.tree_columns
[i
].get_data("index");
471 this
.insert_column(this
.tree_columns
[i
], i
);
472 this
.tree_columns
[i
].set_visible(config
.get_bool_with_default(uid
+"-colshow",
473 gmpc_data_view_col_names
[index
], gmpc_data_view_col_enabled
[index
]));
482 * Function handles the row-activate signal.
484 private void __row_activated (Gtk
.TreePath path
, Gtk
.TreeViewColumn col
)
486 Gtk
.TreeModel? model
= this
.get_model();
489 MPD
.Data
.Type row_type
;
491 if(!model
.get_iter(out iter
, path
)) return;
493 model
.get(iter
, Gmpc
.MpdData
.ColumnTypes
.ROW_TYPE
, out row_type
);
494 if(view_mode
== ViewType
.PLAY_QUEUE
) {
495 /* If we are play-queue, play the selected song. */
497 model
.get(iter
, Gmpc
.MpdData
.ColumnTypes
.COL_SONG_ID
, out song_id
);
498 MPD
.Player
.play_id(Gmpc
.server
, song_id
);
501 model
.get(iter
, Gmpc
.MpdData
.ColumnTypes
.COL_PATH
, out song_path
);
502 if(row_type
== MPD
.Data
.Type
.SONG
) {
503 /* If we are a song browser, add the path and play it. */
504 MpdInteraction
.play_path(song_path
);
505 } else if (row_type
== MPD
.Data
.Type
.PLAYLIST
) {
506 MPD
.PlayQueue
.queue_load_playlist(server
, song_path
);
507 MPD
.PlayQueue
.queue_commit(server
);
513 * Check if current row is playing.
515 private void highlight_row_current_song_playing(
517 Gtk
.CellRenderer renderer
,
521 // The current song we make bold.
522 if(model is Gmpc
.MpdData
.ModelPlaylist
&&
523 (model as Gmpc
.MpdData
.ModelPlaylist
).is_current_song(iter
)){
524 (renderer as Gtk
.CellRendererText
).weight
= Pango
.Weight
.BOLD
;
526 (renderer as Gtk
.CellRendererText
).weight
= Pango
.Weight
.NORMAL
;
529 // A prioritized song we make italic.
531 model
.get(iter
, Gmpc
.MpdData
.ColumnTypes
.COL_SONG_PRIORITY
, out prio
);
533 (renderer as Gtk
.CellRendererText
).style
= Pango
.Style
.ITALIC
;
535 (renderer as Gtk
.CellRendererText
).style
= Pango
.Style
.NORMAL
;
541 * Handle keyboard input.
543 private bool __key_press_event_callback_song_list(Gdk
.EventKey event
)
545 if(event
.keyval
== Gdk
.Key_i
)
547 return selected_songs_add();
549 else if (event
.keyval
== Gdk
.Key_r
)
551 // If there are songs selected, clear the play queue,
552 // and add selection.
553 if(this
.get_selection().count_selected_rows() > 0) {
554 MPD
.PlayQueue
.clear(server
);
555 return selected_songs_add();
560 private bool __key_press_event_callback_play_queue(Gdk
.EventKey event
)
562 if (event
.keyval
== Gdk
.Key_Q
)
565 return selected_songs_remove_priority();
567 else 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 // Detach model (for some reason keeping it attached
587 // Makes thing break, work-around for now)
589 var model
= get_model();
592 MPD
.PlayQueue
.clear(server
);
600 private bool __key_press_event_callback(Gdk
.EventKey event
)
602 if(event
.keyval
== Gdk
.Key_j
)
607 else if (event
.keyval
== Gdk
.Key_k
)
612 else if(event
.keyval
== Gdk
.Key_y
)
614 // Copy data to clipboard
615 return selected_songs_paste_queue_copy();
617 else if (event
.keyval
== Gdk
.Key_o
)
619 return selected_songs_info();
621 else if (event
.keyval
== Gdk
.Key_Escape
)
625 else if (event
.keyval
== Gdk
.Key_m
)
628 column_show_selection_menu();
631 else if (event
.keyval
== Gdk
.Key_q
)
634 return selected_songs_raise_priority();
636 else if (event
.keyval
== Gdk
.Key_Menu
)
638 __button_press_menu
= new Gtk
.Menu();
640 right_mouse_menu(__button_press_menu
);
645 __button_press_menu
.show_all();
646 __button_press_menu
.popup(null, null,null,0, Gtk
.get_current_event_time());
650 // Commands specific to play_queue
651 if(view_mode
== ViewType
.PLAY_QUEUE
)
653 if(__key_press_event_callback_play_queue(event
)) return true;
657 if(__key_press_event_callback_song_list(event
)) return true;
665 // Hack to stop vala from destroying my menu.
666 private Gtk
.Menu __button_press_menu
= null;
667 private bool __button_press_event_callback(Gdk
.EventButton event
)
669 if(event
.button
== 3)
671 __button_press_menu
= new Gtk
.Menu();
672 right_mouse_menu(__button_press_menu
);
674 __button_press_menu
.show_all();
675 __button_press_menu
.popup(null, null,null, event
.button
, event
.time
);
680 private bool __button_release_event_callback(Gdk
.EventButton event
)
687 * Interaction on selected songs.
689 // Set priority on the selected songs.
690 private bool selected_songs_raise_priority()
692 if(server
.check_command_allowed("prioid") != MPD
.Server
.Command
.ALLOWED
) return false;
693 var selection
= this
.get_selection();
695 if(selection
.count_selected_rows() > 254) {
696 Gmpc
.Messages
.show(_("You can only queue 254 songs at the time."), Gmpc
.Messages
.Level
.WARNING
);
702 foreach(var path
in selection
.get_selected_rows(out model
))
705 if(model
.get_iter(out iter
, path
))
707 MPD
.Data
.Type row_type
;
710 Gmpc
.MpdData
.ColumnTypes
.COL_SONG_ID
, out song_id
,
711 Gmpc
.MpdData
.ColumnTypes
.ROW_TYPE
, out row_type
);
712 // Only act on songs.
713 if(row_type
!= MPD
.Data
.Type
.SONG
) continue;
716 MPD
.PlayQueue
.set_priority(server
, song_id
, priority
--);
719 model
.get(iter
, Gmpc
.MpdData
.ColumnTypes
.COL_PATH
, out song_path
);
720 song_id
= MPD
.PlayQueue
.add_song_get_id(server
,song_path
);
721 MPD
.PlayQueue
.set_priority(server
, song_id
, priority
--);
727 // Remove the set priority from the selected songs.
728 private bool selected_songs_remove_priority()
730 if(server
.check_command_allowed("prioid") != MPD
.Server
.Command
.ALLOWED
) return false;
731 var selection
= this
.get_selection();
734 foreach(var path
in selection
.get_selected_rows(out model
))
737 if(model
.get_iter(out iter
, path
))
740 model
.get(iter
,Gmpc
.MpdData
.ColumnTypes
.COL_SONG_ID
, out song_id
);
741 if ( song_id
>= 0 ) {
742 MPD
.PlayQueue
.set_priority(server
, song_id
, 0);
748 // Add the selected song
749 private bool selected_songs_add()
752 var selection
= this
.get_selection();
755 foreach(var path
in selection
.get_selected_rows(out model
))
758 if(model
.get_iter(out iter
, path
))
761 MPD
.Data
.Type row_type
;
763 Gmpc
.MpdData
.ColumnTypes
.ROW_TYPE
, out row_type
,
764 Gmpc
.MpdData
.ColumnTypes
.COL_PATH
, out song_path
);
765 if ( row_type
== MPD
.Data
.Type
.SONG
|| row_type
== MPD
.Data
.Type
.DIRECTORY
) {
766 MPD
.PlayQueue
.queue_add_song(server
, song_path
);
768 }else if (row_type
== MPD
.Data
.Type
.PLAYLIST
) {
769 MPD
.PlayQueue
.queue_load_playlist(server
, song_path
);
774 MPD
.PlayQueue
.queue_commit(server
);
780 // Play the selected song
781 private bool selected_songs_play()
783 var selection
= this
.get_selection();
785 foreach(var path
in selection
.get_selected_rows(out model
))
788 if(model
.get_iter(out iter
, path
))
790 if(view_mode
== ViewType
.PLAY_QUEUE
) {
792 model
.get(iter
, Gmpc
.MpdData
.ColumnTypes
.COL_SONG_ID
, out song_id
);
794 MPD
.Player
.play_id(server
, song_id
);
799 model
.get(iter
, Gmpc
.MpdData
.ColumnTypes
.COL_PATH
, out song_path
);
800 MpdInteraction
.play_path(song_path
);
805 return selection
.count_selected_rows() > 0;
807 // Remove the selected songs from the play queue.
808 private bool selected_songs_remove()
810 int deleted_rows
= 0;
811 var selection
= this
.get_selection();
814 foreach(var path
in selection
.get_selected_rows(out model
))
817 if(model
.get_iter(out iter
, path
))
820 model
.get(iter
,Gmpc
.MpdData
.ColumnTypes
.COL_SONG_ID
, out song_id
);
821 MPD
.PlayQueue
.queue_delete_id(server
, song_id
);
825 MPD
.PlayQueue
.queue_commit(server
);
826 if(deleted_rows
> 0) {
827 selection
.unselect_all();
832 // Show the Information of the first selected song.
833 private bool selected_songs_info()
835 var selection
= this
.get_selection();
837 foreach(var path
in selection
.get_selected_rows(out model
))
840 if(model
.get_iter(out iter
, path
))
842 unowned MPD
.Song? song
= null;
843 model
.get(iter
, Gmpc
.MpdData
.ColumnTypes
.COL_MPDSONG
, out song
);
845 Browser
.Metadata
.show();
846 Browser
.Metadata
.show_song(song
);
851 return selection
.count_selected_rows() > 0;
854 // Cut the selected songs in the play queue
855 private bool selected_songs_paste_queue_cut()
857 if(selected_songs_paste_queue_copy()){
858 selected_songs_remove();
862 // Copy the selected songs in the play queue
863 private bool selected_songs_paste_queue_copy()
865 var selection
= this
.get_selection();
866 // If nothing to copy , do nothing.
867 if(selection
.count_selected_rows() == 0) return false;
871 foreach(var path
in selection
.get_selected_rows(out model
))
874 if(model
.get_iter(out iter
, path
))
877 model
.get(iter
,Gmpc
.MpdData
.ColumnTypes
.COL_PATH
, out insert_path
);
878 paste_queue
.prepend(insert_path
);
881 paste_queue
.reverse();
886 private bool selected_songs_paste_before()
888 var selection
= this
.get_selection();
889 // If nothing selected.
890 if(selection
.count_selected_rows() == 0|| paste_queue
== null)
896 Gtk
.TreePath path
= selection
.get_selected_rows(out model
).last().data
;
897 if(model
.get_iter(out iter
, path
))
900 model
.get(iter
, Gmpc
.MpdData
.ColumnTypes
.COL_SONG_POS
, out songpos
);
903 paste_queue
.reverse();
904 foreach(var fpath
in paste_queue
)
906 int nsongid
= MPD
.PlayQueue
.add_song_get_id(server
,fpath
);
907 MPD
.PlayQueue
.song_move_id(server
, nsongid
, songpos
);
909 paste_queue
.reverse();
914 private bool selected_songs_paste_after()
916 var selection
= this
.get_selection();
917 // If nothing selected.
918 if(selection
.count_selected_rows() == 0|| paste_queue
== null)
924 Gtk
.TreePath path
= selection
.get_selected_rows(out model
).last().data
;
925 if(model
.get_iter(out iter
, path
))
928 model
.get(iter
, Gmpc
.MpdData
.ColumnTypes
.COL_SONG_POS
, out songpos
);
930 paste_queue
.reverse();
931 foreach(var fpath
in paste_queue
)
933 int nsongid
= MPD
.PlayQueue
.add_song_get_id(server
,fpath
);
934 MPD
.PlayQueue
.song_move_id(server
, nsongid
, songpos
);
936 paste_queue
.reverse();
942 private bool selected_songs_add_to_playlist(string playlist
)
945 var selection
= this
.get_selection();
946 // If nothing selected.
947 if(selection
.count_selected_rows() == 0)
952 foreach (var path
in selection
.get_selected_rows(out model
))
955 if(model
.get_iter(out iter
, path
))
957 string? song_path
= null;
958 model
.get(iter
, Gmpc
.MpdData
.ColumnTypes
.COL_PATH
, out song_path
);
959 if(song_path
!= null) {
960 MPD
.Database
.playlist_list_add(server
, playlist
, song_path
);
965 return (songs_added
> 0);
971 private void move_cursor_down()
974 Gtk
.TreeViewColumn? col
;
975 this
.get_cursor(out path
, out col
);
980 if(this
.model
.get_iter(out iter
, path
))
982 this
.set_cursor(path
, col
, false);
986 private void move_cursor_up()
989 Gtk
.TreeViewColumn? col
;
990 this
.get_cursor(out path
, out col
);
995 this
.set_cursor(path
, col
, false);