Commit 5178637d authored by Jean Felder's avatar Jean Felder Committed by Marinus Schraal

playlistsview: Restore drag and drop operation

parent a95a1a72
......@@ -6,11 +6,29 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<signal name="notify::selected" handler="_on_selection_changed"/>
<signal name="drag_data_received" handler="_on_drag_data_received"/>
<child>
<object class="GtkBox" id="box1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">3</property>
<child>
<object class="GtkEventBox" id="_dnd_eventbox">
<property name="visible">False</property>
<signal name="drag-begin" handler="_on_drag_begin"/>
<signal name="drag-end" handler="_on_drag_end"/>
<signal name="drag_data_get" handler="_on_drag_data_get"/>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="icon-name">open-menu-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="box3">
<property name="width_request">48</property>
......@@ -61,7 +79,7 @@
</child>
</object>
<packing>
<property name="position">0</property>
<property name="position">1</property>
</packing>
</child>
<child>
......@@ -103,7 +121,7 @@
</child>
</object>
<packing>
<property name="position">1</property>
<property name="position">2</property>
</packing>
</child>
<child>
......@@ -127,7 +145,7 @@
</child>
</object>
<packing>
<property name="position">2</property>
<property name="position">3</property>
</packing>
</child>
<child>
......
......@@ -549,6 +549,50 @@ class Playlist(GObject.GObject):
self._tracker.update_blank_async(
query, GLib.PRIORITY_LOW, None, _requery_media, coresong)
def reorder(self, previous_position, new_position):
"""Changes the order of a songs in the playlist.
:param int previous_position: preivous song position
:param int new_position: new song position
"""
def _position_changed_cb(conn, res, position):
# FIXME: Check for failure.
conn.update_finish(res)
coresong = self._model.get_item(previous_position)
self._model.remove(previous_position)
self._model.insert(new_position, coresong)
main_query = """
INSERT OR REPLACE {
?entry
nfo:listPosition %(position)s
}
WHERE {
?playlist a nmm:Playlist ;
a nfo:MediaList ;
nfo:hasMediaFileListEntry ?entry .
FILTER (
tracker:id(?playlist) = %(playlist_id)s &&
tracker:id(?entry) = %(song_id)s
)
}
""".replace("\n", " ").strip()
first_pos = min(previous_position, new_position)
last_pos = max(previous_position, new_position)
for position in range(first_pos, last_pos + 1):
coresong = self._model.get_item(position)
query = main_query % {
"playlist_id": self.props.pl_id,
"song_id": coresong.props.media.get_id(),
"position": position
}
self._tracker.update_async(
query, GLib.PRIORITY_LOW, None, _position_changed_cb,
position)
class SmartPlaylist(Playlist):
"""Base class for smart playlists"""
......
......@@ -230,7 +230,8 @@ class PlaylistsView(BaseView):
if self.rename_active:
self._pl_ctrls.disable_rename_playlist()
self._view.bind_model(playlist.props.model, self._create_song_widget)
self._view.bind_model(
playlist.props.model, self._create_song_widget, playlist)
self._current_playlist = playlist
self._pl_ctrls.props.playlist_name = playlist_name
......@@ -243,11 +244,14 @@ class PlaylistsView(BaseView):
def _on_song_count_changed(self, playlist, value):
self._update_songs_count(playlist.props.count)
def _create_song_widget(self, coresong):
song_widget = SongWidget(coresong)
def _create_song_widget(self, coresong, playlist):
can_dnd = not playlist.props.is_smart
song_widget = SongWidget(coresong, can_dnd)
song_widget.props.show_song_number = False
song_widget.connect('button-release-event', self._song_activated)
if can_dnd is True:
song_widget.connect("widget_moved", self._on_song_widget_moved)
return song_widget
......@@ -300,6 +304,11 @@ class PlaylistsView(BaseView):
# self.player.stop()
# self._window.set_player_visible(False)
def _on_song_widget_moved(self, target, source_position):
target_position = target.get_parent().get_index()
current_playlist = self._sidebar.get_selected_row().playlist
current_playlist.reorder(source_position, target_position)
@log
def _populate(self, data=None):
"""Populate sidebar.
......
......@@ -139,8 +139,6 @@ class DiscBox(Gtk.Box):
song_widget.connect('button-release-event', self._song_activated)
song_widget.show_all()
return song_widget
@log
......
......@@ -53,6 +53,7 @@ class SongWidget(Gtk.EventBox):
__gsignals__ = {
'selection-changed': (GObject.SignalFlags.RUN_FIRST, None, ()),
"widget-moved": (GObject.SignalFlags.RUN_FIRST, None, (int,))
}
coresong = GObject.Property(type=CoreSong, default=None)
......@@ -63,6 +64,7 @@ class SongWidget(Gtk.EventBox):
_playlists = Playlists.get_default()
_dnd_eventbox = Gtk.Template.Child()
_select_button = Gtk.Template.Child()
_number_label = Gtk.Template.Child()
_title_label = Gtk.Template.Child()
......@@ -82,7 +84,12 @@ class SongWidget(Gtk.EventBox):
return '<SongWidget>'
@log
def __init__(self, coresong):
def __init__(self, coresong, can_dnd=False):
"""Instanciates a SongWidget
:param Corsong coresong: song associated with the widget
:param bool can_dnd: allow drag and drop operations
"""
super().__init__()
self.props.coresong = coresong
......@@ -134,11 +141,60 @@ class SongWidget(Gtk.EventBox):
self._number_label.props.no_show_all = True
if can_dnd is True:
self._dnd_eventbox.props.visible = True
self._drag_widget = None
entries = [
Gtk.TargetEntry.new(
"GTK_EVENT_BOX", Gtk.TargetFlags.SAME_APP, 0)
]
self._dnd_eventbox.drag_source_set(
Gdk.ModifierType.BUTTON1_MASK, entries,
Gdk.DragAction.MOVE)
self.drag_dest_set(
Gtk.DestDefaults.ALL, entries, Gdk.DragAction.MOVE)
@Gtk.Template.Callback()
@log
def _on_selection_changed(self, klass, value):
self.emit('selection-changed')
@Gtk.Template.Callback()
def _on_drag_begin(self, klass, context):
gdk_window = self.get_window()
_, x, y, _ = gdk_window.get_device_position(context.get_device())
allocation = self.get_allocation()
self._drag_widget = Gtk.ListBox()
self._drag_widget.set_size_request(allocation.width, allocation.height)
drag_row = SongWidget(self.props.coresong)
self._drag_widget.add(drag_row)
self._drag_widget.drag_highlight_row(drag_row.get_parent())
self._drag_widget.show_all()
Gtk.drag_set_icon_widget(context, self._drag_widget, x, y)
@Gtk.Template.Callback()
def _on_drag_end(self, klass, context):
self._drag_widget = None
@Gtk.Template.Callback()
def _on_drag_data_get(self, klass, context, selection_data, info, time_):
row_position = self.get_parent().get_index()
selection_data.set(
Gdk.Atom.intern("row_position", False), 0,
bytes(str(row_position), encoding="UTF8"))
@Gtk.Template.Callback()
def _on_drag_data_received(
self, klass, context, x, y, selection_data, info, time_):
source_position = int(str(selection_data.get_data(), "UTF-8"))
target_position = self.get_parent().get_index()
if source_position == target_position:
return
self.emit("widget-moved", source_position)
@Gtk.Template.Callback()
@log
def _on_star_toggle(self, widget, event):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment