New dataview updates
[gmpc.git] / src / Widgets / gmpc-data-view.vala
blob30453d5f77c533b949d313d53fa2169835b46357
1 using Gmpc;
3 using Gtk;
5 const string log_domain = "Gmpc.DataView";
7 /** The Default column width. */
8 const int default_column_width = 200;
10 /**
11 * List of columns.
12 * * List of column ids to show.
13 * * Name of each column
14 * * Default set of enabled columns.
16 const int NUM_COLS = 20;
17 const int[] gmpc_data_view_col_ids = {
18 Gmpc.MpdData.ColumnTypes.MARKUP,
19 Gmpc.MpdData.ColumnTypes.SONG_ARTIST, /* album name */
20 Gmpc.MpdData.ColumnTypes.SONG_ALBUM, /* album name */
21 Gmpc.MpdData.ColumnTypes.SONG_TITLE, /* song title */
22 Gmpc.MpdData.ColumnTypes.SONG_TITLEFILE, /* song title */
23 Gmpc.MpdData.ColumnTypes.SONG_GENRE, /* song genre */
24 Gmpc.MpdData.ColumnTypes.SONG_TRACK, /* song track */
25 Gmpc.MpdData.ColumnTypes.SONG_NAME, /* stream name */
26 Gmpc.MpdData.ColumnTypes.SONG_COMPOSER, /* composer name */
27 Gmpc.MpdData.ColumnTypes.SONG_PERFORMER, /* performer */
28 Gmpc.MpdData.ColumnTypes.SONG_DATE, /* date */
29 Gmpc.MpdData.ColumnTypes.SONG_LENGTH_FORMAT, /* length formatted */
30 Gmpc.MpdData.ColumnTypes.SONG_DISC, /* disc */
31 Gmpc.MpdData.ColumnTypes.SONG_COMMENT, /* comment */
32 Gmpc.MpdData.ColumnTypes.ICON_ID, /* icon id */
33 Gmpc.MpdData.ColumnTypes.SONG_POS,
34 Gmpc.MpdData.ColumnTypes.SONG_ALBUMARTIST,
35 Gmpc.MpdData.ColumnTypes.PATH_EXTENSION, /* Extension */
36 Gmpc.MpdData.ColumnTypes.PATH_DIRECTORY, /* Directory */
37 Gmpc.MpdData.ColumnTypes.SONG_PRIORITY
39 const string[] gmpc_data_view_col_names = {
40 N_("Markup"),
41 N_("Artist"),
42 N_("Album"),
43 N_("Title"),
44 N_("File"),
45 N_("Genre"),
46 N_("Track"),
47 N_("Name"),
48 N_("Composer"),
49 N_("Performer"),
50 N_("Date"),
51 N_("Duration"),
52 N_("Disc"),
53 N_("Comment"),
54 N_("Icon Id"),
55 N_("Position"),
56 N_("AlbumArtist"),
57 N_("Extension"),
58 N_("Directory"),
59 N_("Priority")
62 const bool[] gmpc_data_view_col_enabled = {
63 false,//"Markup",
64 true, //"Artist",
65 true,//"Album",
66 true,//"Title",
67 false,//"File",
68 false,//"Genre",
69 false,//"Track",
70 false,//"Name",
71 false,//"Composer",
72 false,//"Performer",
73 false,//"Date",
74 false,//"Duration",
75 false,//"Disc",
76 false,//"Comment",
77 true,//"Icon Id"
78 false,//"Position"
79 false,//"AlbumArtist"
80 false,//Extension
81 false,//Directory
82 false//Priority
86 const int[] gmpc_data_view_col_position = {
87 14,//"Markup",
88 3, //"Artist",
89 2,//"Album",
90 1,//"Title",
91 4,//"File",
92 5,//"Genre",
93 6,//"Track",
94 7,//"Name",
95 8,//"Composer",
96 9,//"Performer",
97 10,//"Date",
98 11,//"Duration",
99 12,//"Disc",
100 13,//"Comment",
101 0,//"Icon Id"
102 15, // "Position"
103 18, // "AlbumArtist"
104 16,// Extension
105 17, // Directory
109 public class Gmpc.DataView : Gtk.TreeView
111 private Gtk.TreeViewColumn[] tree_columns = new Gtk.TreeViewColumn[NUM_COLS];
113 * If we are a play-queue we should treat the content.
114 * slightly different.
115 * e.g. add-replace will be play-crop
117 public bool is_play_queue {get; set; default=false;}
120 * The name of the treeview.
121 * This is used to store the column layout.
123 public string uid {get; set; default="default";}
127 * Construction function.
129 public DataView(string name)
131 log(log_domain, LogLevelFlags.LEVEL_INFO, "Constructing dataview: "+name);
133 this.uid = name;
134 // Connect row activated signal.
135 this.row_activated.connect(__row_activated);
136 this.key_release_event.connect(__key_release_event_callback);
137 // When it getst he destroy signal.
138 this.destroy.connect(store_columns);
140 this.set_rules_hint(true);
142 this.get_selection().set_mode(Gtk.SelectionMode.MULTIPLE);
143 this.set_fixed_height_mode(true);
144 // Create the view.
145 populate();
149 * Store the position, visibility and width of the columns
151 private void store_columns()
153 // Save the position of the columns
154 var columns = get_columns();
155 int index = 0;
156 foreach(var column in columns)
158 int id = column.get_data("id");
159 int width = column.get_width();
160 config.set_int(uid+"-colpos", gmpc_data_view_col_names[id], index);
161 config.set_bool(uid+"-colshow", gmpc_data_view_col_names[id], column.visible);
162 // Only store width if bigger then 0.
163 if(width > 0 ) {
164 config.set_int(uid+"-colsize",gmpc_data_view_col_names[id], width);
166 index++;
171 * Deconstructor.
173 ~DataView()
179 * Populate the treeview with the right columns.
180 * The treeview should have a name now.
182 private void populate()
184 for(int i = 0; i < NUM_COLS; i++)
186 Gtk.TreeViewColumn col = new Gtk.TreeViewColumn();
187 col.set_data("id", i);
188 if(gmpc_data_view_col_ids[i] == Gmpc.MpdData.ColumnTypes.ICON_ID)
191 * Picture.
193 var renderer = new Gtk.CellRendererPixbuf();
194 renderer.xalign = 0.0f;
195 // Set up column
196 col.pack_start(renderer, true);
197 col.set_attributes(renderer, "icon-name", Gmpc.MpdData.ColumnTypes.ICON_ID);
198 col.set_resizable(false);
199 col.set_fixed_width(20);
200 } else {
202 * Text column
204 col.set_title(gmpc_data_view_col_names[i]);
205 var renderer = new Gtk.CellRendererText();
206 renderer.ellipsize = Pango.EllipsizeMode.END;
207 renderer.weight_set = true;
208 // Set up column
209 col.pack_start(renderer, true);
210 col.set_attributes(renderer, "text", gmpc_data_view_col_ids[i]);
211 col.set_resizable(true);
212 if(is_play_queue) {
213 // TODO fix this.
214 // col.set_cell_data_func(renderer, (Gtk.CellLayoutDataFunc)highlight_row_current_song_playing);
217 int width = config.get_int_with_default(uid+"-colsize",gmpc_data_view_col_names[i], default_column_width);
218 // Do not set to size 0, then revert back to 200.
219 col.set_fixed_width(width>0?width:default_column_width);
221 col.set_sizing(Gtk.TreeViewColumnSizing.FIXED);
222 col.set_reorderable(true);
224 // Fixed width.
225 int pos = config.get_int_with_default(uid+"-colpos", gmpc_data_view_col_names[i], gmpc_data_view_col_position[i]);
226 this.tree_columns[pos] = col;
228 // Add the columns (in right order)
229 for(int i = 0; i < NUM_COLS; i++) {
230 int id = this.tree_columns[i].get_data("id");
231 this.insert_column(this.tree_columns[i], i);
232 this.tree_columns[i].set_visible(config.get_bool_with_default(uid+"-colshow", gmpc_data_view_col_names[id], gmpc_data_view_col_enabled[id]));
239 * Internal functions.
243 * Function handles the row-activate signal.
245 private void __row_activated (Gtk.TreePath path, Gtk.TreeViewColumn col)
247 Gtk.TreeModel? model = this.get_model();
248 if(model != null)
250 Gtk.TreeIter iter;
251 if(!model.get_iter(out iter, path)) return;
252 if(is_play_queue) {
253 /* If we are play-queue, play the selected song. */
254 int song_id;
255 model.get(iter, Gmpc.MpdData.ColumnTypes.SONG_ID, out song_id);
256 MPD.Player.play_id(Gmpc.server, song_id);
257 } else {
258 /* If we are a song browser, add the path and play it. */
259 string song_path;
260 model.get(iter, Gmpc.MpdData.ColumnTypes.PATH, out song_path);
261 MpdInteraction.play_path(song_path);
266 * Check if current row is playing.
267 * TODO
269 private void highlight_row_current_song_playing(Gtk.TreeViewColumn col, Gtk.CellRenderer renderer, Gtk.TreeModel model, Gtk.TreeIter iter)
271 (renderer as Gtk.CellRendererText).weight = Pango.Weight.BOLD;
276 * Handle keyboard input.
278 private bool __key_release_event_callback(Gdk.EventKey event)
280 if(event.keyval == Gdk.Key_y)
282 // Copy data to clipboard
285 else if (event.keyval == Gdk.Key_c)
287 // Cut (if available) into clipboard
289 else if (event.keyval == Gdk.Key_P)
291 // Paste before
293 else if (event.keyval == Gdk.Key_p)
295 // Paste after
297 else if (event.keyval == Gdk.Key_Escape)
302 // Commands specific to play_queue
303 if(is_play_queue)
305 if (event.keyval == Gdk.Key_Q)
307 // remove priority.
308 return selected_songs_remove_priority();
310 else if (event.keyval == Gdk.Key_q)
312 // Raise priority.
313 return selected_songs_raise_priority();
315 else if (event.keyval == Gdk.Key_d)
317 return selected_songs_remove();
320 else
322 if(event.keyval == Gdk.Key_i)
324 // Insert
327 return false;
331 * Interaction on selected songs.
333 // Set priority on the selected songs.
334 private bool selected_songs_raise_priority()
336 if(server.check_command_allowed("prioid") != MPD.Server.Command.ALLOWED) return false;
337 var selection = this.get_selection();
339 if(selection.count_selected_rows() > 254) {
340 Gmpc.Messages.show(_("You can only queue 254 songs at the time."), Gmpc.Messages.Level.WARNING);
341 return false;
344 int priority = 255;
345 Gtk.TreeModel model;
346 foreach(var path in selection.get_selected_rows(out model))
348 Gtk.TreeIter iter;
349 if(model.get_iter(out iter, path))
351 int song_id;
352 model.get(iter,Gmpc.MpdData.ColumnTypes.SONG_ID, out song_id);
353 MPD.PlayQueue.set_priority(server, song_id, priority--);
356 return true;
358 // Remove the set priority from the selected songs.
359 private bool selected_songs_remove_priority()
361 if(server.check_command_allowed("prioid") != MPD.Server.Command.ALLOWED) return false;
362 var selection = this.get_selection();
364 Gtk.TreeModel model;
365 foreach(var path in selection.get_selected_rows(out model))
367 Gtk.TreeIter iter;
368 if(model.get_iter(out iter, path))
370 int song_id;
371 model.get(iter,Gmpc.MpdData.ColumnTypes.SONG_ID, out song_id);
372 MPD.PlayQueue.set_priority(server, song_id, 0);
375 return true;
377 // Remove the selected songs from the play queue.
378 private bool selected_songs_remove()
380 int deleted_rows = 0;
381 var selection = this.get_selection();
383 Gtk.TreeModel model;
384 foreach(var path in selection.get_selected_rows(out model))
386 Gtk.TreeIter iter;
387 if(model.get_iter(out iter, path))
389 int song_id;
390 model.get(iter,Gmpc.MpdData.ColumnTypes.SONG_ID, out song_id);
391 MPD.PlayQueue.queue_delete_id(server, song_id);
392 deleted_rows++;
395 MPD.PlayQueue.queue_commit(server);
396 return (deleted_rows > 0);