Merge lp:~serge-hallyn/ubuntu/precise/rhythmbox/rhythmbox-sort into lp:ubuntu/precise/rhythmbox
- Precise (12.04)
- rhythmbox-sort
- Merge into precise
Proposed by
Serge Hallyn
Status: | Work in progress |
---|---|
Proposed branch: | lp:~serge-hallyn/ubuntu/precise/rhythmbox/rhythmbox-sort |
Merge into: | lp:ubuntu/precise/rhythmbox |
Diff against target: |
886 lines (+836/-1) 6 files modified
.pc/applied-patches (+1/-0) .pc/lp30554.patch/sources/rb-browser-source.c (+807/-0) debian/changelog (+7/-0) debian/patches/lp30554.patch (+19/-0) debian/patches/series (+1/-0) sources/rb-browser-source.c (+1/-1) |
To merge this branch: | bzr merge lp:~serge-hallyn/ubuntu/precise/rhythmbox/rhythmbox-sort |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu branches | Pending | ||
Review via email: mp+95646@code.launchpad.net |
Commit message
Description of the change
This patch from Chris Wilson changes the order of columns in the library view, fixing an oldie-but-goodie bug #30554. Please apply.
To post a comment you must log in.
Unmerged revisions
- 202. By Serge Hallyn
-
[ Chris Wilson ]
lp30554.patch: fix sort order (LP: #30554)
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file '.pc/applied-patches' |
2 | --- .pc/applied-patches 2012-02-27 13:49:19 +0000 |
3 | +++ .pc/applied-patches 2012-03-02 19:11:17 +0000 |
4 | @@ -4,3 +4,4 @@ |
5 | 04_pause_button.patch |
6 | 05_hide_on_quit.patch |
7 | git_use_correct_mpris_name.patch |
8 | +lp30554.patch |
9 | |
10 | === added directory '.pc/lp30554.patch' |
11 | === added file '.pc/lp30554.patch/.timestamp' |
12 | === added directory '.pc/lp30554.patch/sources' |
13 | === added file '.pc/lp30554.patch/sources/rb-browser-source.c' |
14 | --- .pc/lp30554.patch/sources/rb-browser-source.c 1970-01-01 00:00:00 +0000 |
15 | +++ .pc/lp30554.patch/sources/rb-browser-source.c 2012-03-02 19:11:17 +0000 |
16 | @@ -0,0 +1,807 @@ |
17 | +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- |
18 | + * |
19 | + * Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org> |
20 | + * Copyright (C) 2003,2004 Colin Walters <walters@verbum.org> |
21 | + * |
22 | + * This program is free software; you can redistribute it and/or modify |
23 | + * it under the terms of the GNU General Public License as published by |
24 | + * the Free Software Foundation; either version 2 of the License, or |
25 | + * (at your option) any later version. |
26 | + * |
27 | + * The Rhythmbox authors hereby grant permission for non-GPL compatible |
28 | + * GStreamer plugins to be used and distributed together with GStreamer |
29 | + * and Rhythmbox. This permission is above and beyond the permissions granted |
30 | + * by the GPL license by which Rhythmbox is covered. If you modify this code |
31 | + * you may extend this exception to your version of the code, but you are not |
32 | + * obligated to do so. If you do not wish to do so, delete this exception |
33 | + * statement from your version. |
34 | + * |
35 | + * This program is distributed in the hope that it will be useful, |
36 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
37 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
38 | + * GNU General Public License for more details. |
39 | + * |
40 | + * You should have received a copy of the GNU General Public License |
41 | + * along with this program; if not, write to the Free Software |
42 | + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
43 | + * |
44 | + */ |
45 | + |
46 | +/** |
47 | + * SECTION:rb-browser-source |
48 | + * @short_description: base class for sources that include genre/artist/album browsers |
49 | + * |
50 | + * This class simplifies implementation of sources that include genre/artist/album browsers. |
51 | + * It also handles searching (using the search box) and a few other UI niceties. |
52 | + * |
53 | + * Instances of browser sources will use a query that will match all entries of |
54 | + * the entry type assigned to the source, so it's mostly suited for sources that |
55 | + * have an entry type of their own. |
56 | + */ |
57 | + |
58 | +#include "config.h" |
59 | + |
60 | +#include <string.h> |
61 | + |
62 | +#include <gtk/gtk.h> |
63 | +#include <glib/gi18n.h> |
64 | + |
65 | +#include "rb-source.h" |
66 | +#include "rb-library-source.h" |
67 | +#include "rb-source-search-basic.h" |
68 | + |
69 | +#include "rhythmdb-query-model.h" |
70 | +#include "rb-property-view.h" |
71 | +#include "rb-entry-view.h" |
72 | +#include "rb-library-browser.h" |
73 | +#include "rb-util.h" |
74 | +#include "rb-file-helpers.h" |
75 | +#include "rb-dialog.h" |
76 | +#include "rb-debug.h" |
77 | +#include "rb-song-info.h" |
78 | +#include "rb-search-entry.h" |
79 | +#include "rb-source-toolbar.h" |
80 | +#include "rb-shell-preferences.h" |
81 | + |
82 | +static void rb_browser_source_class_init (RBBrowserSourceClass *klass); |
83 | +static void rb_browser_source_init (RBBrowserSource *source); |
84 | +static void rb_browser_source_constructed (GObject *object); |
85 | +static void rb_browser_source_dispose (GObject *object); |
86 | +static void rb_browser_source_finalize (GObject *object); |
87 | +static void rb_browser_source_set_property (GObject *object, |
88 | + guint prop_id, |
89 | + const GValue *value, |
90 | + GParamSpec *pspec); |
91 | +static void rb_browser_source_get_property (GObject *object, |
92 | + guint prop_id, |
93 | + GValue *value, |
94 | + GParamSpec *pspec); |
95 | +static void rb_browser_source_cmd_choose_genre (GtkAction *action, RBSource *source); |
96 | +static void rb_browser_source_cmd_choose_artist (GtkAction *action, RBSource *source); |
97 | +static void rb_browser_source_cmd_choose_album (GtkAction *action, RBSource *source); |
98 | +static void songs_view_sort_order_changed_cb (GObject *object, GParamSpec *pspec, RBBrowserSource *source); |
99 | +static void rb_browser_source_browser_changed_cb (RBLibraryBrowser *entry, |
100 | + GParamSpec *param, |
101 | + RBBrowserSource *source); |
102 | + |
103 | +/* source methods */ |
104 | +static RBEntryView *impl_get_entry_view (RBSource *source); |
105 | +static GList *impl_get_property_views (RBSource *source); |
106 | +static void impl_delete (RBSource *source); |
107 | +static void impl_search (RBSource *source, RBSourceSearch *search, const char *cur_text, const char *new_text); |
108 | +static void impl_reset_filters (RBSource *source); |
109 | +static void impl_song_properties (RBSource *source); |
110 | +static void default_show_entry_popup (RBBrowserSource *source); |
111 | +static void default_pack_content (RBBrowserSource *source, GtkWidget *content); |
112 | + |
113 | +void rb_browser_source_browser_views_activated_cb (GtkWidget *widget, |
114 | + RBBrowserSource *source); |
115 | +static void songs_view_drag_data_received_cb (GtkWidget *widget, |
116 | + GdkDragContext *dc, |
117 | + gint x, gint y, |
118 | + GtkSelectionData *data, |
119 | + guint info, guint time, |
120 | + RBBrowserSource *source); |
121 | +static void rb_browser_source_do_query (RBBrowserSource *source, |
122 | + gboolean subset); |
123 | +static void rb_browser_source_populate (RBBrowserSource *source); |
124 | + |
125 | +struct RBBrowserSourcePrivate |
126 | +{ |
127 | + RhythmDB *db; |
128 | + |
129 | + RBLibraryBrowser *browser; |
130 | + RBEntryView *songs; |
131 | + RBSourceToolbar *toolbar; |
132 | + |
133 | + RhythmDBQueryModel *cached_all_query; |
134 | + RhythmDBQuery *search_query; |
135 | + RhythmDBPropType search_prop; |
136 | + gboolean populate; |
137 | + gboolean query_active; |
138 | + gboolean search_on_completion; |
139 | + RBSourceSearch *default_search; |
140 | + |
141 | + GtkActionGroup *action_group; |
142 | + GtkActionGroup *search_action_group; |
143 | + |
144 | + gboolean dispose_has_run; |
145 | +}; |
146 | + |
147 | +#define RB_BROWSER_SOURCE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_BROWSER_SOURCE, RBBrowserSourcePrivate)) |
148 | + |
149 | +static GtkActionEntry rb_browser_source_actions [] = |
150 | +{ |
151 | + { "BrowserSrcChooseGenre", NULL, N_("Browse This _Genre"), NULL, |
152 | + N_("Set the browser to view only this genre"), |
153 | + G_CALLBACK (rb_browser_source_cmd_choose_genre) }, |
154 | + { "BrowserSrcChooseArtist", NULL , N_("Browse This _Artist"), NULL, |
155 | + N_("Set the browser to view only this artist"), |
156 | + G_CALLBACK (rb_browser_source_cmd_choose_artist) }, |
157 | + { "BrowserSrcChooseAlbum", NULL, N_("Browse This A_lbum"), NULL, |
158 | + N_("Set the browser to view only this album"), |
159 | + G_CALLBACK (rb_browser_source_cmd_choose_album) } |
160 | +}; |
161 | + |
162 | +static GtkRadioActionEntry rb_browser_source_radio_actions [] = |
163 | +{ |
164 | + { "BrowserSourceSearchAll", NULL, N_("Search all fields"), NULL, NULL, RHYTHMDB_PROP_SEARCH_MATCH }, |
165 | + { "BrowserSourceSearchArtists", NULL, N_("Search artists"), NULL, NULL, RHYTHMDB_PROP_ARTIST_FOLDED }, |
166 | + { "BrowserSourceSearchAlbums", NULL, N_("Search albums"), NULL, NULL, RHYTHMDB_PROP_ALBUM_FOLDED }, |
167 | + { "BrowserSourceSearchTitles", NULL, N_("Search titles"), NULL, NULL, RHYTHMDB_PROP_TITLE_FOLDED } |
168 | +}; |
169 | + |
170 | +static const GtkTargetEntry songs_view_drag_types[] = { |
171 | + { "application/x-rhythmbox-entry", 0, 0 }, |
172 | + { "text/uri-list", 0, 1 } |
173 | +}; |
174 | + |
175 | +enum |
176 | +{ |
177 | + PROP_0, |
178 | + PROP_BASE_QUERY_MODEL, |
179 | + PROP_POPULATE, |
180 | + PROP_SHOW_BROWSER |
181 | +}; |
182 | + |
183 | +G_DEFINE_ABSTRACT_TYPE (RBBrowserSource, rb_browser_source, RB_TYPE_SOURCE) |
184 | + |
185 | +static void |
186 | +rb_browser_source_class_init (RBBrowserSourceClass *klass) |
187 | +{ |
188 | + GObjectClass *object_class = G_OBJECT_CLASS (klass); |
189 | + RBSourceClass *source_class = RB_SOURCE_CLASS (klass); |
190 | + |
191 | + object_class->dispose = rb_browser_source_dispose; |
192 | + object_class->finalize = rb_browser_source_finalize; |
193 | + object_class->constructed = rb_browser_source_constructed; |
194 | + |
195 | + object_class->set_property = rb_browser_source_set_property; |
196 | + object_class->get_property = rb_browser_source_get_property; |
197 | + |
198 | + source_class->impl_search = impl_search; |
199 | + source_class->impl_get_entry_view = impl_get_entry_view; |
200 | + source_class->impl_get_property_views = impl_get_property_views; |
201 | + source_class->impl_reset_filters = impl_reset_filters; |
202 | + source_class->impl_song_properties = impl_song_properties; |
203 | + source_class->impl_can_cut = (RBSourceFeatureFunc) rb_false_function; |
204 | + source_class->impl_can_copy = (RBSourceFeatureFunc) rb_true_function; |
205 | + source_class->impl_can_delete = (RBSourceFeatureFunc) rb_true_function; |
206 | + source_class->impl_can_add_to_queue = (RBSourceFeatureFunc) rb_true_function; |
207 | + source_class->impl_can_move_to_trash = (RBSourceFeatureFunc) rb_true_function; |
208 | + source_class->impl_delete = impl_delete; |
209 | + |
210 | + klass->pack_content = default_pack_content; |
211 | + klass->has_drop_support = (RBBrowserSourceFeatureFunc) rb_false_function; |
212 | + klass->show_entry_popup = default_show_entry_popup; |
213 | + |
214 | + g_object_class_override_property (object_class, |
215 | + PROP_BASE_QUERY_MODEL, |
216 | + "base-query-model"); |
217 | + |
218 | + g_object_class_install_property (object_class, |
219 | + PROP_POPULATE, |
220 | + g_param_spec_boolean ("populate", |
221 | + "populate", |
222 | + "whether to populate the source", |
223 | + TRUE, |
224 | + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); |
225 | + |
226 | + g_object_class_override_property (object_class, |
227 | + PROP_SHOW_BROWSER, |
228 | + "show-browser"); |
229 | + |
230 | + g_type_class_add_private (klass, sizeof (RBBrowserSourcePrivate)); |
231 | +} |
232 | + |
233 | +static void |
234 | +rb_browser_source_init (RBBrowserSource *source) |
235 | +{ |
236 | + source->priv = RB_BROWSER_SOURCE_GET_PRIVATE (source); |
237 | +} |
238 | + |
239 | +static void |
240 | +rb_browser_source_dispose (GObject *object) |
241 | +{ |
242 | + RBBrowserSource *source; |
243 | + source = RB_BROWSER_SOURCE (object); |
244 | + |
245 | + if (source->priv->dispose_has_run) { |
246 | + /* If dispose did already run, return. */ |
247 | + return; |
248 | + } |
249 | + /* Make sure dispose does not run twice. */ |
250 | + source->priv->dispose_has_run = TRUE; |
251 | + |
252 | + if (source->priv->db != NULL) { |
253 | + g_object_unref (source->priv->db); |
254 | + source->priv->db = NULL; |
255 | + } |
256 | + |
257 | + if (source->priv->search_query != NULL) { |
258 | + rhythmdb_query_free (source->priv->search_query); |
259 | + source->priv->search_query = NULL; |
260 | + } |
261 | + |
262 | + if (source->priv->cached_all_query != NULL) { |
263 | + g_object_unref (source->priv->cached_all_query); |
264 | + source->priv->cached_all_query = NULL; |
265 | + } |
266 | + |
267 | + if (source->priv->action_group != NULL) { |
268 | + g_object_unref (source->priv->action_group); |
269 | + source->priv->action_group = NULL; |
270 | + } |
271 | + |
272 | + if (source->priv->default_search != NULL) { |
273 | + g_object_unref (source->priv->default_search); |
274 | + source->priv->default_search = NULL; |
275 | + } |
276 | + |
277 | + G_OBJECT_CLASS (rb_browser_source_parent_class)->dispose (object); |
278 | +} |
279 | + |
280 | +static void |
281 | +rb_browser_source_finalize (GObject *object) |
282 | +{ |
283 | + RBBrowserSource *source; |
284 | + |
285 | + g_return_if_fail (object != NULL); |
286 | + g_return_if_fail (RB_IS_BROWSER_SOURCE (object)); |
287 | + |
288 | + source = RB_BROWSER_SOURCE (object); |
289 | + |
290 | + g_return_if_fail (source->priv != NULL); |
291 | + |
292 | + G_OBJECT_CLASS (rb_browser_source_parent_class)->finalize (object); |
293 | +} |
294 | + |
295 | +static void |
296 | +rb_browser_source_songs_show_popup_cb (RBEntryView *view, |
297 | + gboolean over_entry, |
298 | + RBBrowserSource *source) |
299 | +{ |
300 | + if (over_entry) { |
301 | + RBBrowserSourceClass *klass = RB_BROWSER_SOURCE_GET_CLASS (source); |
302 | + |
303 | + klass->show_entry_popup (source); |
304 | + } else { |
305 | + rb_display_page_show_popup (RB_DISPLAY_PAGE (source)); |
306 | + } |
307 | +} |
308 | + |
309 | +static void |
310 | +default_show_entry_popup (RBBrowserSource *source) |
311 | +{ |
312 | + _rb_display_page_show_popup (RB_DISPLAY_PAGE (source), "/BrowserSourceViewPopup"); |
313 | +} |
314 | + |
315 | +static void |
316 | +rb_browser_source_constructed (GObject *object) |
317 | +{ |
318 | + RBBrowserSource *source; |
319 | + RBBrowserSourceClass *klass; |
320 | + RBShell *shell; |
321 | + GObject *shell_player; |
322 | + GtkUIManager *ui_manager; |
323 | + RhythmDBEntryType *entry_type; |
324 | + GtkWidget *content; |
325 | + GtkWidget *paned; |
326 | + |
327 | + RB_CHAIN_GOBJECT_METHOD (rb_browser_source_parent_class, constructed, object); |
328 | + |
329 | + source = RB_BROWSER_SOURCE (object); |
330 | + |
331 | + g_object_get (source, |
332 | + "shell", &shell, |
333 | + "entry-type", &entry_type, |
334 | + NULL); |
335 | + g_object_get (shell, |
336 | + "db", &source->priv->db, |
337 | + "shell-player", &shell_player, |
338 | + "ui-manager", &ui_manager, |
339 | + NULL); |
340 | + |
341 | + source->priv->action_group = _rb_display_page_register_action_group (RB_DISPLAY_PAGE (source), |
342 | + "BrowserSourceActions", |
343 | + NULL, 0, NULL); |
344 | + _rb_action_group_add_display_page_actions (source->priv->action_group, |
345 | + G_OBJECT (shell), |
346 | + rb_browser_source_actions, |
347 | + G_N_ELEMENTS (rb_browser_source_actions)); |
348 | + |
349 | + /* only add the actions if we haven't already */ |
350 | + if (gtk_action_group_get_action (source->priv->action_group, |
351 | + rb_browser_source_radio_actions[0].name) == NULL) { |
352 | + gtk_action_group_add_radio_actions (source->priv->action_group, |
353 | + rb_browser_source_radio_actions, |
354 | + G_N_ELEMENTS (rb_browser_source_radio_actions), |
355 | + 0, |
356 | + NULL, |
357 | + NULL); |
358 | + |
359 | + rb_source_search_basic_create_for_actions (source->priv->action_group, |
360 | + rb_browser_source_radio_actions, |
361 | + G_N_ELEMENTS (rb_browser_source_radio_actions)); |
362 | + } |
363 | + g_object_unref (shell); |
364 | + |
365 | + source->priv->default_search = rb_source_search_basic_new (RHYTHMDB_PROP_SEARCH_MATCH); |
366 | + |
367 | + paned = gtk_vpaned_new (); |
368 | + |
369 | + source->priv->browser = rb_library_browser_new (source->priv->db, entry_type); |
370 | + gtk_widget_set_no_show_all (GTK_WIDGET (source->priv->browser), TRUE); |
371 | + gtk_paned_pack1 (GTK_PANED (paned), GTK_WIDGET (source->priv->browser), TRUE, FALSE); |
372 | + gtk_container_child_set (GTK_CONTAINER (paned), |
373 | + GTK_WIDGET (source->priv->browser), |
374 | + "resize", FALSE, |
375 | + NULL); |
376 | + g_signal_connect_object (G_OBJECT (source->priv->browser), "notify::output-model", |
377 | + G_CALLBACK (rb_browser_source_browser_changed_cb), |
378 | + source, 0); |
379 | + |
380 | + /* set up songs tree view */ |
381 | + source->priv->songs = rb_entry_view_new (source->priv->db, shell_player, |
382 | + TRUE, FALSE); |
383 | + |
384 | + rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_TRACK_NUMBER, FALSE); |
385 | + rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_TITLE, TRUE); |
386 | + rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_GENRE, FALSE); |
387 | + rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_ARTIST, FALSE); |
388 | + rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_ALBUM, FALSE); |
389 | + rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_YEAR, FALSE); |
390 | + rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_DURATION, FALSE); |
391 | + rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_QUALITY, FALSE); |
392 | + rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_PLAY_COUNT, FALSE); |
393 | + rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_BPM, FALSE); |
394 | + rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_COMMENT, FALSE); |
395 | + rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_LOCATION, FALSE); |
396 | + |
397 | + g_signal_connect_object (G_OBJECT (source->priv->songs), "show_popup", |
398 | + G_CALLBACK (rb_browser_source_songs_show_popup_cb), source, 0); |
399 | + g_signal_connect_object (source->priv->songs, |
400 | + "notify::sort-order", |
401 | + G_CALLBACK (songs_view_sort_order_changed_cb), |
402 | + source, 0); |
403 | + |
404 | + rb_source_bind_settings (RB_SOURCE (source), |
405 | + GTK_WIDGET (source->priv->songs), |
406 | + paned, |
407 | + GTK_WIDGET (source->priv->browser)); |
408 | + |
409 | + if (rb_browser_source_has_drop_support (source)) { |
410 | + gtk_drag_dest_set (GTK_WIDGET (source->priv->songs), |
411 | + GTK_DEST_DEFAULT_ALL, |
412 | + songs_view_drag_types, G_N_ELEMENTS (songs_view_drag_types), |
413 | + GDK_ACTION_COPY | GDK_ACTION_MOVE); /* really accept move actions? */ |
414 | + |
415 | + /* set up drag and drop for the song tree view. |
416 | + * we don't use RBEntryView's DnD support because it does too much. |
417 | + * we just want to be able to drop songs in to add them to the |
418 | + * library. |
419 | + */ |
420 | + g_signal_connect_object (G_OBJECT (source->priv->songs), |
421 | + "drag_data_received", |
422 | + G_CALLBACK (songs_view_drag_data_received_cb), |
423 | + source, 0); |
424 | + } |
425 | + |
426 | + gtk_paned_pack2 (GTK_PANED (paned), GTK_WIDGET (source->priv->songs), TRUE, FALSE); |
427 | + |
428 | + /* set up toolbar */ |
429 | + source->priv->toolbar = rb_source_toolbar_new (RB_SOURCE (source), ui_manager); |
430 | + rb_source_toolbar_add_search_entry (source->priv->toolbar, "/BrowserSourceSearchMenu", NULL); |
431 | + |
432 | + content = gtk_grid_new (); |
433 | + gtk_grid_set_column_spacing (GTK_GRID (content), 6); |
434 | + gtk_grid_set_row_spacing (GTK_GRID (content), 6); |
435 | + gtk_grid_attach (GTK_GRID (content), GTK_WIDGET (source->priv->toolbar), 0, 0, 1, 1); |
436 | + gtk_widget_set_vexpand (paned, TRUE); |
437 | + gtk_widget_set_hexpand (paned, TRUE); |
438 | + gtk_grid_attach (GTK_GRID (content), paned, 0, 1, 1, 1); |
439 | + |
440 | + klass = RB_BROWSER_SOURCE_GET_CLASS (source); |
441 | + klass->pack_content (source, content); |
442 | + |
443 | + gtk_widget_show_all (GTK_WIDGET (source)); |
444 | + |
445 | + /* use a throwaway model until the real one is ready */ |
446 | + rb_library_browser_set_model (source->priv->browser, |
447 | + rhythmdb_query_model_new_empty (source->priv->db), |
448 | + FALSE); |
449 | + |
450 | + source->priv->cached_all_query = rhythmdb_query_model_new_empty (source->priv->db); |
451 | + rb_browser_source_populate (source); |
452 | + |
453 | + g_object_unref (entry_type); |
454 | + g_object_unref (shell_player); |
455 | +} |
456 | + |
457 | +static void |
458 | +rb_browser_source_set_property (GObject *object, |
459 | + guint prop_id, |
460 | + const GValue *value, |
461 | + GParamSpec *pspec) |
462 | +{ |
463 | + RBBrowserSource *source = RB_BROWSER_SOURCE (object); |
464 | + |
465 | + switch (prop_id) { |
466 | + case PROP_POPULATE: |
467 | + source->priv->populate = g_value_get_boolean (value); |
468 | + |
469 | + /* if being set after construction, run the query now. otherwise the constructor will do it. */ |
470 | + if (source->priv->songs != NULL) { |
471 | + rb_browser_source_populate (source); |
472 | + } |
473 | + break; |
474 | + case PROP_SHOW_BROWSER: |
475 | + if (g_value_get_boolean (value)) { |
476 | + gtk_widget_show (GTK_WIDGET (source->priv->browser)); |
477 | + } else { |
478 | + gtk_widget_hide (GTK_WIDGET (source->priv->browser)); |
479 | + rb_library_browser_reset (source->priv->browser); |
480 | + } |
481 | + break; |
482 | + default: |
483 | + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
484 | + break; |
485 | + } |
486 | +} |
487 | + |
488 | +static void |
489 | +rb_browser_source_get_property (GObject *object, |
490 | + guint prop_id, |
491 | + GValue *value, |
492 | + GParamSpec *pspec) |
493 | +{ |
494 | + RBBrowserSource *source = RB_BROWSER_SOURCE (object); |
495 | + |
496 | + switch (prop_id) { |
497 | + case PROP_BASE_QUERY_MODEL: |
498 | + g_value_set_object (value, source->priv->cached_all_query); |
499 | + break; |
500 | + case PROP_POPULATE: |
501 | + g_value_set_boolean (value, source->priv->populate); |
502 | + break; |
503 | + case PROP_SHOW_BROWSER: |
504 | + g_value_set_boolean (value, gtk_widget_get_visible (GTK_WIDGET (source->priv->browser))); |
505 | + break; |
506 | + default: |
507 | + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
508 | + break; |
509 | + } |
510 | +} |
511 | + |
512 | +static void |
513 | +cached_all_query_complete_cb (RhythmDBQueryModel *model, RBBrowserSource *source) |
514 | +{ |
515 | + rb_library_browser_set_model (source->priv->browser, |
516 | + source->priv->cached_all_query, |
517 | + FALSE); |
518 | +} |
519 | + |
520 | +static void |
521 | +rb_browser_source_populate (RBBrowserSource *source) |
522 | +{ |
523 | + RhythmDBEntryType *entry_type; |
524 | + |
525 | + if (source->priv->populate == FALSE) |
526 | + return; |
527 | + |
528 | + /* only connect the model to the browser when it's complete. this avoids |
529 | + * thousands of row-added signals, which is ridiculously slow with a11y enabled. |
530 | + */ |
531 | + g_signal_connect_object (source->priv->cached_all_query, |
532 | + "complete", |
533 | + G_CALLBACK (cached_all_query_complete_cb), |
534 | + source, 0); |
535 | + |
536 | + g_object_get (source, "entry-type", &entry_type, NULL); |
537 | + rhythmdb_do_full_query_async (source->priv->db, |
538 | + RHYTHMDB_QUERY_RESULTS (source->priv->cached_all_query), |
539 | + RHYTHMDB_QUERY_PROP_EQUALS, RHYTHMDB_PROP_TYPE, entry_type, |
540 | + RHYTHMDB_QUERY_END); |
541 | + g_object_unref (entry_type); |
542 | +} |
543 | + |
544 | +static void |
545 | +browse_property (RBBrowserSource *source, RhythmDBPropType prop) |
546 | +{ |
547 | + GList *props; |
548 | + RBPropertyView *view; |
549 | + |
550 | + props = rb_source_gather_selected_properties (RB_SOURCE (source), prop); |
551 | + view = rb_library_browser_get_property_view (source->priv->browser, prop); |
552 | + if (view) { |
553 | + rb_property_view_set_selection (view, props); |
554 | + } |
555 | + |
556 | + rb_list_deep_free (props); |
557 | +} |
558 | + |
559 | +static void |
560 | +rb_browser_source_cmd_choose_genre (GtkAction *action, RBSource *source) |
561 | +{ |
562 | + rb_debug ("choosing genre"); |
563 | + |
564 | + if (RB_IS_BROWSER_SOURCE (source)) { |
565 | + browse_property (RB_BROWSER_SOURCE (source), RHYTHMDB_PROP_GENRE); |
566 | + } |
567 | +} |
568 | + |
569 | +static void |
570 | +rb_browser_source_cmd_choose_artist (GtkAction *action, RBSource *source) |
571 | +{ |
572 | + rb_debug ("choosing artist"); |
573 | + |
574 | + if (RB_IS_BROWSER_SOURCE (source)) { |
575 | + browse_property (RB_BROWSER_SOURCE (source), RHYTHMDB_PROP_ARTIST); |
576 | + } |
577 | +} |
578 | + |
579 | +static void |
580 | +rb_browser_source_cmd_choose_album (GtkAction *action, RBSource *source) |
581 | +{ |
582 | + rb_debug ("choosing album"); |
583 | + |
584 | + if (RB_IS_BROWSER_SOURCE (source)) { |
585 | + browse_property (RB_BROWSER_SOURCE (source), RHYTHMDB_PROP_ALBUM); |
586 | + } |
587 | +} |
588 | + |
589 | +static void |
590 | +songs_view_sort_order_changed_cb (GObject *object, GParamSpec *pspec, RBBrowserSource *source) |
591 | +{ |
592 | + rb_debug ("sort order changed"); |
593 | + rb_entry_view_resort_model (RB_ENTRY_VIEW (object)); |
594 | +} |
595 | + |
596 | +static void |
597 | +impl_search (RBSource *asource, RBSourceSearch *search, const char *cur_text, const char *new_text) |
598 | +{ |
599 | + RBBrowserSource *source = RB_BROWSER_SOURCE (asource); |
600 | + gboolean subset; |
601 | + |
602 | + if (search == NULL) { |
603 | + search = source->priv->default_search; |
604 | + } |
605 | + |
606 | + /* replace our search query */ |
607 | + if (source->priv->search_query != NULL) { |
608 | + rhythmdb_query_free (source->priv->search_query); |
609 | + source->priv->search_query = NULL; |
610 | + } |
611 | + source->priv->search_query = rb_source_search_create_query (search, source->priv->db, new_text); |
612 | + |
613 | + /* for subset searches, we have to wait until the query |
614 | + * has finished before we can refine the results. |
615 | + */ |
616 | + subset = rb_source_search_is_subset (search, cur_text, new_text); |
617 | + if (source->priv->query_active && subset) { |
618 | + rb_debug ("deferring search for \"%s\" until query completion", new_text ? new_text : "<NULL>"); |
619 | + source->priv->search_on_completion = TRUE; |
620 | + } else { |
621 | + rb_debug ("doing search for \"%s\"", new_text ? new_text : "<NULL>"); |
622 | + rb_browser_source_do_query (source, subset); |
623 | + } |
624 | +} |
625 | + |
626 | +static RBEntryView * |
627 | +impl_get_entry_view (RBSource *asource) |
628 | +{ |
629 | + RBBrowserSource *source = RB_BROWSER_SOURCE (asource); |
630 | + |
631 | + return source->priv->songs; |
632 | +} |
633 | + |
634 | +static GList * |
635 | +impl_get_property_views (RBSource *asource) |
636 | +{ |
637 | + GList *ret; |
638 | + RBBrowserSource *source = RB_BROWSER_SOURCE (asource); |
639 | + |
640 | + ret = rb_library_browser_get_property_views (source->priv->browser); |
641 | + return ret; |
642 | +} |
643 | + |
644 | +static void |
645 | +impl_reset_filters (RBSource *asource) |
646 | +{ |
647 | + RBBrowserSource *source = RB_BROWSER_SOURCE (asource); |
648 | + gboolean changed = FALSE; |
649 | + |
650 | + rb_debug ("Resetting search filters"); |
651 | + |
652 | + if (rb_library_browser_reset (source->priv->browser)) |
653 | + changed = TRUE; |
654 | + |
655 | + if (source->priv->search_query != NULL) { |
656 | + rhythmdb_query_free (source->priv->search_query); |
657 | + source->priv->search_query = NULL; |
658 | + changed = TRUE; |
659 | + } |
660 | + |
661 | + rb_source_toolbar_clear_search_entry (source->priv->toolbar); |
662 | + |
663 | + if (changed) |
664 | + rb_browser_source_do_query (source, FALSE); |
665 | +} |
666 | + |
667 | +static void |
668 | +impl_delete (RBSource *asource) |
669 | +{ |
670 | + RBBrowserSource *source = RB_BROWSER_SOURCE (asource); |
671 | + GList *sel, *tem; |
672 | + |
673 | + sel = rb_entry_view_get_selected_entries (source->priv->songs); |
674 | + for (tem = sel; tem != NULL; tem = tem->next) { |
675 | + rhythmdb_entry_delete (source->priv->db, tem->data); |
676 | + rhythmdb_commit (source->priv->db); |
677 | + } |
678 | + g_list_foreach (sel, (GFunc)rhythmdb_entry_unref, NULL); |
679 | + g_list_free (sel); |
680 | +} |
681 | + |
682 | +static void |
683 | +impl_song_properties (RBSource *asource) |
684 | +{ |
685 | + RBBrowserSource *source = RB_BROWSER_SOURCE (asource); |
686 | + GtkWidget *song_info = NULL; |
687 | + |
688 | + g_return_if_fail (source->priv->songs != NULL); |
689 | + |
690 | + song_info = rb_song_info_new (asource, NULL); |
691 | + |
692 | + g_return_if_fail (song_info != NULL); |
693 | + |
694 | + if (song_info) |
695 | + gtk_widget_show_all (song_info); |
696 | + else |
697 | + rb_debug ("failed to create dialog, or no selection!"); |
698 | +} |
699 | + |
700 | +/** |
701 | + * rb_browser_source_has_drop_support: |
702 | + * @source: a #RBBrowserSource |
703 | + * |
704 | + * This is a virtual method that should be implemented by subclasses. It returns %TRUE |
705 | + * if drag and drop target support for the source should be activated. |
706 | + * |
707 | + * Return value: %TRUE if drop support should be activated |
708 | + */ |
709 | +gboolean |
710 | +rb_browser_source_has_drop_support (RBBrowserSource *source) |
711 | +{ |
712 | + RBBrowserSourceClass *klass = RB_BROWSER_SOURCE_GET_CLASS (source); |
713 | + |
714 | + return klass->has_drop_support (source); |
715 | +} |
716 | + |
717 | +static void |
718 | +songs_view_drag_data_received_cb (GtkWidget *widget, |
719 | + GdkDragContext *dc, |
720 | + gint x, gint y, |
721 | + GtkSelectionData *selection_data, |
722 | + guint info, guint time, |
723 | + RBBrowserSource *source) |
724 | +{ |
725 | + rb_debug ("data dropped on the library source song view"); |
726 | + rb_display_page_receive_drag (RB_DISPLAY_PAGE (source), selection_data); |
727 | +} |
728 | + |
729 | +static void |
730 | +rb_browser_source_browser_changed_cb (RBLibraryBrowser *browser, |
731 | + GParamSpec *pspec, |
732 | + RBBrowserSource *source) |
733 | +{ |
734 | + RhythmDBQueryModel *query_model; |
735 | + |
736 | + g_object_get (browser, "output-model", &query_model, NULL); |
737 | + rb_entry_view_set_model (source->priv->songs, query_model); |
738 | + g_object_set (source, "query-model", query_model, NULL); |
739 | + g_object_unref (query_model); |
740 | + |
741 | + rb_source_notify_filter_changed (RB_SOURCE (source)); |
742 | +} |
743 | + |
744 | +static void |
745 | +rb_browser_source_query_complete_cb (RhythmDBQueryModel *query_model, |
746 | + RBBrowserSource *source) |
747 | +{ |
748 | + rb_library_browser_set_model (source->priv->browser, query_model, FALSE); |
749 | + |
750 | + source->priv->query_active = FALSE; |
751 | + if (source->priv->search_on_completion) { |
752 | + rb_debug ("performing deferred search"); |
753 | + source->priv->search_on_completion = FALSE; |
754 | + /* this is only done for subset queries */ |
755 | + rb_browser_source_do_query (source, TRUE); |
756 | + } |
757 | +} |
758 | + |
759 | +static void |
760 | +rb_browser_source_do_query (RBBrowserSource *source, gboolean subset) |
761 | +{ |
762 | + RhythmDBQueryModel *query_model; |
763 | + GPtrArray *query; |
764 | + RhythmDBEntryType *entry_type; |
765 | + |
766 | + /* use the cached 'all' query to optimise the no-search case */ |
767 | + if (source->priv->search_query == NULL) { |
768 | + rb_library_browser_set_model (source->priv->browser, |
769 | + source->priv->cached_all_query, |
770 | + FALSE); |
771 | + return; |
772 | + } |
773 | + |
774 | + g_object_get (source, "entry-type", &entry_type, NULL); |
775 | + query = rhythmdb_query_parse (source->priv->db, |
776 | + RHYTHMDB_QUERY_PROP_EQUALS, |
777 | + RHYTHMDB_PROP_TYPE, |
778 | + entry_type, |
779 | + RHYTHMDB_QUERY_SUBQUERY, |
780 | + source->priv->search_query, |
781 | + RHYTHMDB_QUERY_END); |
782 | + g_object_unref (entry_type); |
783 | + |
784 | + if (subset) { |
785 | + /* if we're appending text to an existing search string, the results will be a subset |
786 | + * of the existing results, so rather than doing a whole new query, we can copy the |
787 | + * results to a new query model with a more restrictive query. |
788 | + */ |
789 | + RhythmDBQueryModel *old; |
790 | + g_object_get (source->priv->browser, "input-model", &old, NULL); |
791 | + |
792 | + query_model = rhythmdb_query_model_new_empty (source->priv->db); |
793 | + g_object_set (query_model, "query", query, NULL); |
794 | + rhythmdb_query_model_copy_contents (query_model, old); |
795 | + g_object_unref (old); |
796 | + |
797 | + rb_library_browser_set_model (source->priv->browser, query_model, FALSE); |
798 | + g_object_unref (query_model); |
799 | + |
800 | + } else { |
801 | + /* otherwise build a query based on the search text, and feed it to the browser |
802 | + * when the query finishes. |
803 | + */ |
804 | + query_model = rhythmdb_query_model_new_empty (source->priv->db); |
805 | + source->priv->query_active = TRUE; |
806 | + source->priv->search_on_completion = FALSE; |
807 | + g_signal_connect_object (query_model, |
808 | + "complete", G_CALLBACK (rb_browser_source_query_complete_cb), |
809 | + source, 0); |
810 | + rhythmdb_do_full_query_async_parsed (source->priv->db, |
811 | + RHYTHMDB_QUERY_RESULTS (query_model), |
812 | + query); |
813 | + g_object_unref (query_model); |
814 | + } |
815 | + |
816 | + rhythmdb_query_free (query); |
817 | +} |
818 | + |
819 | +static void |
820 | +default_pack_content (RBBrowserSource *source, GtkWidget *content) |
821 | +{ |
822 | + gtk_container_add (GTK_CONTAINER (source), content); |
823 | +} |
824 | |
825 | === modified file 'debian/changelog' |
826 | --- debian/changelog 2012-02-27 13:49:19 +0000 |
827 | +++ debian/changelog 2012-03-02 19:11:17 +0000 |
828 | @@ -1,3 +1,10 @@ |
829 | +rhythmbox (2.95-0ubuntu4) precise; urgency=low |
830 | + |
831 | + [ Chris Wilson ] |
832 | + * lp30554.patch: fix sort order (LP: #30554) |
833 | + |
834 | + -- Serge Hallyn <serge.hallyn@ubuntu.com> Fri, 02 Mar 2012 12:45:52 -0600 |
835 | + |
836 | rhythmbox (2.95-0ubuntu3) precise; urgency=low |
837 | |
838 | * debian/patches/git_use_correct_mpris_name.patch: |
839 | |
840 | === added file 'debian/patches/lp30554.patch' |
841 | --- debian/patches/lp30554.patch 1970-01-01 00:00:00 +0000 |
842 | +++ debian/patches/lp30554.patch 2012-03-02 19:11:17 +0000 |
843 | @@ -0,0 +1,19 @@ |
844 | +Description: Fix the sort order to Title->Artist->Album->Genre |
845 | +Author: Chris Wilson <afrowildo@gmail.com> |
846 | +Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/rhythmbox/+bug/30554 |
847 | + |
848 | +Index: rhythmbox/sources/rb-browser-source.c |
849 | +=================================================================== |
850 | +--- rhythmbox.orig/sources/rb-browser-source.c 2012-03-02 12:39:51.167629000 -0600 |
851 | ++++ rhythmbox/sources/rb-browser-source.c 2012-03-02 12:44:05.939964998 -0600 |
852 | +@@ -367,9 +367,9 @@ |
853 | + |
854 | + rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_TRACK_NUMBER, FALSE); |
855 | + rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_TITLE, TRUE); |
856 | +- rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_GENRE, FALSE); |
857 | + rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_ARTIST, FALSE); |
858 | + rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_ALBUM, FALSE); |
859 | ++ rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_GENRE, FALSE); |
860 | + rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_YEAR, FALSE); |
861 | + rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_DURATION, FALSE); |
862 | + rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_QUALITY, FALSE); |
863 | |
864 | === modified file 'debian/patches/series' |
865 | --- debian/patches/series 2012-02-27 13:49:19 +0000 |
866 | +++ debian/patches/series 2012-03-02 19:11:17 +0000 |
867 | @@ -4,3 +4,4 @@ |
868 | 04_pause_button.patch |
869 | 05_hide_on_quit.patch |
870 | git_use_correct_mpris_name.patch |
871 | +lp30554.patch |
872 | |
873 | === modified file 'sources/rb-browser-source.c' |
874 | --- sources/rb-browser-source.c 2012-01-10 17:05:11 +0000 |
875 | +++ sources/rb-browser-source.c 2012-03-02 19:11:17 +0000 |
876 | @@ -367,9 +367,9 @@ |
877 | |
878 | rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_TRACK_NUMBER, FALSE); |
879 | rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_TITLE, TRUE); |
880 | - rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_GENRE, FALSE); |
881 | rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_ARTIST, FALSE); |
882 | rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_ALBUM, FALSE); |
883 | + rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_GENRE, FALSE); |
884 | rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_YEAR, FALSE); |
885 | rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_DURATION, FALSE); |
886 | rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_QUALITY, FALSE); |
Thank you for your work, setting to "work in progress" until the design is sorted as mentioned on the bug