Skip to content

Commit

Permalink
Fix mutli-selection-dnd from the search view to the play list
Browse files Browse the repository at this point in the history
* Add a mutli-selection capable TreeView class.
* Extract the SearchView class from the UserInterface Class.
  • Loading branch information
swenner committed Jul 4, 2010
1 parent e288872 commit 0655b65
Show file tree
Hide file tree
Showing 5 changed files with 193 additions and 68 deletions.
41 changes: 16 additions & 25 deletions data/main.ui
Expand Up @@ -203,26 +203,26 @@
<child>
<object class="GtkImageMenuItem" id="open_menu_item">
<property name="visible">True</property>
<property name="use_action_appearance">True</property>
<property name="related_action">open_action</property>
<property name="use_action_appearance">True</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="save_menu_item">
<property name="visible">True</property>
<property name="use_action_appearance">True</property>
<property name="related_action">save_action</property>
<property name="use_action_appearance">True</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="save_as_menu_item">
<property name="visible">True</property>
<property name="use_action_appearance">True</property>
<property name="related_action">save_as_action</property>
<property name="use_action_appearance">True</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
</object>
Expand All @@ -235,8 +235,8 @@
<child>
<object class="GtkImageMenuItem" id="properties_menu_item">
<property name="visible">True</property>
<property name="use_action_appearance">True</property>
<property name="related_action">properties_action</property>
<property name="use_action_appearance">True</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
</object>
Expand All @@ -249,8 +249,8 @@
<child>
<object class="GtkImageMenuItem" id="quit_menu_item">
<property name="visible">True</property>
<property name="use_action_appearance">True</property>
<property name="related_action">quit_action</property>
<property name="use_action_appearance">True</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
</object>
Expand All @@ -270,26 +270,26 @@
<child>
<object class="GtkImageMenuItem" id="cut_menu_item">
<property name="visible">True</property>
<property name="use_action_appearance">True</property>
<property name="related_action">cut_action</property>
<property name="use_action_appearance">True</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="copy_menu_item">
<property name="visible">True</property>
<property name="use_action_appearance">True</property>
<property name="related_action">copy_action</property>
<property name="use_action_appearance">True</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="paste_menu_item">
<property name="visible">True</property>
<property name="use_action_appearance">True</property>
<property name="related_action">paste_action</property>
<property name="use_action_appearance">True</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
</object>
Expand All @@ -302,17 +302,17 @@
<child>
<object class="GtkImageMenuItem" id="select_all_menu_item">
<property name="visible">True</property>
<property name="use_action_appearance">True</property>
<property name="related_action">select_all_action</property>
<property name="use_action_appearance">True</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="deselect_all_menu_item">
<property name="visible">True</property>
<property name="use_action_appearance">True</property>
<property name="related_action">deselect_all_action</property>
<property name="use_action_appearance">True</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
</object>
Expand All @@ -325,26 +325,26 @@
<child>
<object class="GtkImageMenuItem" id="add_menu_item">
<property name="visible">True</property>
<property name="use_action_appearance">True</property>
<property name="related_action">add_action</property>
<property name="use_action_appearance">True</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="remove_menu_item">
<property name="visible">True</property>
<property name="use_action_appearance">True</property>
<property name="related_action">remove_action</property>
<property name="use_action_appearance">True</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="clear_menu_item">
<property name="visible">True</property>
<property name="use_action_appearance">True</property>
<property name="related_action">clear_action</property>
<property name="use_action_appearance">True</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
</object>
Expand All @@ -357,8 +357,8 @@
<child>
<object class="GtkImageMenuItem" id="preferences_menu_item">
<property name="visible">True</property>
<property name="use_action_appearance">True</property>
<property name="related_action">preferences_action</property>
<property name="use_action_appearance">True</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
</object>
Expand Down Expand Up @@ -397,8 +397,8 @@
<child>
<object class="GtkImageMenuItem" id="about_menu_item">
<property name="visible">True</property>
<property name="use_action_appearance">True</property>
<property name="related_action">about_action</property>
<property name="use_action_appearance">True</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
</object>
Expand Down Expand Up @@ -618,16 +618,7 @@
<property name="hscrollbar_policy">never</property>
<property name="vscrollbar_policy">automatic</property>
<child>
<object class="GtkTreeView" id="search_view">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="model">search_store</property>
<property name="headers_clickable">False</property>
<property name="rules_hint">True</property>
<property name="search_column">2</property>
<property name="fixed_height_mode">True</property>
<property name="show_expanders">False</property>
</object>
<placeholder/>
</child>
</object>
<packing>
Expand Down
2 changes: 2 additions & 0 deletions src/Makefile.am
Expand Up @@ -24,6 +24,8 @@ hum_gtk_SOURCES = \
hum_track.vala \
hum_query_engine.vala \
hum_gui.vala \
hum_multi_selection_tree_view.vala \
hum_search_view.vala \
$(NULL)

hum_gtk_LDADD = \
Expand Down
60 changes: 17 additions & 43 deletions src/hum_gui.vala
Expand Up @@ -99,13 +99,12 @@ namespace Hum
public Gtk.Entry search_entry;
public Gtk.Button search_button;
public Gtk.VPaned view_separator;
public Gtk.TreeView search_view;
public Hum.SearchView search_view;
public Gtk.TreeView playlist_view;
public Gtk.ListStore search_store;
public Gtk.ListStore playlist_store;
public Gtk.CellRendererText text_renderer;
public Gtk.CellRendererPixbuf pixbuf_renderer;
public Gtk.TreeSelection search_select;
public Gtk.TreeSelection playlist_select;

private Gtk.TreeIter current_iter;
Expand Down Expand Up @@ -214,7 +213,13 @@ namespace Hum
this.playlist_store = (Gtk.ListStore) builder.get_object ("playlist_store");
this.search_store = (Gtk.ListStore) builder.get_object ("search_store");
this.playlist_view = (Gtk.TreeView) builder.get_object ("playlist_view");
this.search_view = (Gtk.TreeView) builder.get_object ("search_view");

// Setup the search results list view.
this.search_view = new Hum.SearchView ();
this.search_view.set_model (this.search_store);
Gtk.ScrolledWindow scrolledwindow1 = (Gtk.ScrolledWindow) builder.get_object ("scrolledwindow1");
scrolledwindow1.add (this.search_view);

this.text_renderer = (Gtk.CellRendererText) builder.get_object ("text_renderer");
this.pixbuf_renderer = (Gtk.CellRendererPixbuf) builder.get_object ("pixbuf_renderer");

Expand All @@ -226,8 +231,6 @@ namespace Hum
set_up_interface ();

// Set the selection mode.
this.search_select = this.search_view.get_selection ();
this.search_select.set_mode (Gtk.SelectionMode.MULTIPLE);
this.playlist_select = this.playlist_view.get_selection ();
this.playlist_select.set_mode (Gtk.SelectionMode.SINGLE);

Expand Down Expand Up @@ -295,7 +298,9 @@ namespace Hum
this.properties_action.activate.connect (show_properties_dialog);

this.playlist_select.changed.connect (handle_playlist_select_changed);
this.search_select.changed.connect (handle_search_select_changed);

Gtk.TreeSelection search_select = this.search_view.get_selection ();
search_select.changed.connect (handle_search_select_changed);

this.play_button.clicked.connect (handle_play_clicked);
this.pause_button.clicked.connect (handle_pause_clicked);
Expand All @@ -310,7 +315,6 @@ namespace Hum
this.search_entry.icon_release.connect (handle_search_cleared);

this.search_view.row_activated.connect (handle_search_view_selected);
this.search_view.drag_data_get.connect (handle_drag_data_get);
this.playlist_view.row_activated.connect (handle_playlist_view_selected);
this.playlist_view.key_press_event.connect (handle_playlist_view_key_pressed);
this.playlist_view.drag_data_received.connect (handle_drag_data_received);
Expand Down Expand Up @@ -1066,36 +1070,6 @@ namespace Hum
return true;
}

// Deal with an DND source data request.
// FIXME: The data that this method adds to the selection goes missing later
// on, in the method below.
public void handle_drag_data_get (Gtk.Widget widget, Gdk.DragContext context,
Gtk.SelectionData selection_data,
uint info, uint time)
{
GLib.List<Gtk.TreePath> rows;
string[] uris;
int i = 0;

rows = this.search_select.get_selected_rows (null);
uris = new string[this.search_select.count_selected_rows ()];

foreach (Gtk.TreePath path in rows)
{
Gtk.TreeIter iter;
GLib.Value text;

this.search_store.get_iter (out iter, path);
this.search_store.get_value (iter, Columns.URI, out text);
uris[i] = text.get_string ();
debug ("Setting selection_data to %s", uris[i]);

++i;
}

selection_data.set_uris (uris);
}

// Handle a DND drop event.
public void handle_drag_data_received (Gdk.DragContext context, int x, int y,
Gtk.SelectionData selection_data,
Expand Down Expand Up @@ -1136,21 +1110,21 @@ namespace Hum
// Signal that the drag has successfully completed.
Gtk.drag_finish (context, true, false, time);
break;
// FIXME: The URIs that I stuck into selection_data in
// handle_drag_data_get() are missing! Where did they go? No clue.
// Drag from the the SearchView to the Playlist.
case "SEARCH_RESULT":
Gtk.TreeModel search_model = (Gtk.TreeModel) this.search_store;
GLib.List<Gtk.TreePath> rows;
Gtk.TreeModel search_model;
Gtk.TreeSelection search_select = this.search_view.get_selection ();

rows = this.search_select.get_selected_rows (out search_model);
rows = search_select.get_selected_rows (out search_model);

foreach (Gtk.TreePath search_path in rows)
{
Gtk.TreeIter search_iter;
GLib.Value uri;

this.search_store.get_iter (out search_iter, search_path);
this.search_store.get_value (search_iter, Columns.URI, out uri);
search_model.get_iter (out search_iter, search_path);
search_model.get_value (search_iter, Columns.URI, out uri);
this.player.AddTrack (uri.get_string (), playlist_position);
}

Expand Down
95 changes: 95 additions & 0 deletions src/hum_multi_selection_tree_view.vala
@@ -0,0 +1,95 @@
/*
* hum_multi_selection_tree_view.vala
*
* This file is part of Hum, the low calorie music manager.
*
* Copyright (C) 2010 by Simon Wenner <simon@wenner.ch>
*
* Hum is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Hum is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Hum; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/

using Gtk;

namespace Hum
{
public class MultiSelectionTreeView : Gtk.TreeView
{
private Gtk.TreePath? blocked_selection_path = null;

public MultiSelectionTreeView ()
{
/* Allow multiple selections */
Gtk.TreeSelection selection = this.get_selection ();
selection.set_mode (Gtk.SelectionMode.MULTIPLE);

this.button_press_event.connect (on_button_press_event);
this.button_release_event.connect (on_button_release_event);
}

private bool on_button_press_event (Gdk.EventButton event)
{
/* Left mouse click */
if (event.button == 1)
return block_selection (event);

/* not handled */
return false;
}

private bool block_selection (Gdk.EventButton event)
{
/* Here we intercept mouse clicks on selected items, so that we can
drag multiple items without the click selecting only one item. */
Gtk.TreePath? path;
bool valid = this.get_path_at_pos ((int)event.x, (int)event.y, out path, null, null, null);
Gtk.TreeSelection selection = this.get_selection ();
if (valid &&
event.type == Gdk.EventType.BUTTON_PRESS &&
! (bool)(event.state & (Gdk.ModifierType.CONTROL_MASK | Gdk.ModifierType.SHIFT_MASK)) &&
selection.path_is_selected (path))
{
/* Disable the selection */
selection.set_select_function ((sel, mod, path, cursel) => { return false; });
this.blocked_selection_path = path;
}

/* not handled */
return false;
}

private bool on_button_release_event (Gdk.EventButton event)
{
/* re-enable selection */
Gtk.TreeSelection selection = this.get_selection ();
selection.set_select_function ((sel, mod, path, cursel) => { return true; });

Gtk.TreePath? path;
Gtk.TreeViewColumn? column;
bool valid = this.get_path_at_pos ((int)event.x, (int)event.y, out path, out column, null, null);
if (valid &&
this.blocked_selection_path != null &&
path.compare (this.blocked_selection_path) == 0 && // equal paths
!(event.x == 0.0 && event.y == 0.0)) // a strange case
{
this.set_cursor (path, column, false);
}
this.blocked_selection_path = null;

/* not handled */
return false;
}
}
}

0 comments on commit 0655b65

Please sign in to comment.