Merge lp:~serge-hallyn/ubuntu/precise/rhythmbox/rhythmbox-sort into lp:ubuntu/precise/rhythmbox

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
Reviewer Review Type Date Requested Status
Ubuntu branches Pending
Review via email: mp+95646@code.launchpad.net

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.
Revision history for this message
Sebastien Bacher (seb128) wrote :

Thank you for your work, setting to "work in progress" until the design is sorted as mentioned on the bug

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);

Subscribers

People subscribed via source and target branches

to all changes: