Add sort selection
This commit is contained in:
parent
ee391e42e7
commit
8e2edb6af3
115
app/playlists.py
115
app/playlists.py
@ -270,13 +270,22 @@ class PlaylistTab(QTableWidget):
|
|||||||
self.hide_or_show_played_tracks()
|
self.hide_or_show_played_tracks()
|
||||||
|
|
||||||
def _add_context_menu(
|
def _add_context_menu(
|
||||||
self, text: str, action: Callable, disabled: bool = False
|
self,
|
||||||
) -> QAction:
|
text: str,
|
||||||
|
action: Callable,
|
||||||
|
disabled: bool = False,
|
||||||
|
parent_menu: Optional[QMenu] = None,
|
||||||
|
) -> Optional[QAction]:
|
||||||
"""
|
"""
|
||||||
Add item to self.menu
|
Add item to self.menu
|
||||||
"""
|
"""
|
||||||
|
|
||||||
menu_item = self.menu.addAction(text)
|
if parent_menu is None:
|
||||||
|
parent_menu = self.menu
|
||||||
|
|
||||||
|
menu_item = parent_menu.addAction(text)
|
||||||
|
if not menu_item:
|
||||||
|
return None
|
||||||
menu_item.setDisabled(disabled)
|
menu_item.setDisabled(disabled)
|
||||||
menu_item.triggered.connect(action)
|
menu_item.triggered.connect(action)
|
||||||
|
|
||||||
@ -1073,6 +1082,30 @@ class PlaylistTab(QTableWidget):
|
|||||||
# ----------------------
|
# ----------------------
|
||||||
self.menu.addSeparator()
|
self.menu.addSeparator()
|
||||||
|
|
||||||
|
# Sort
|
||||||
|
sort_menu = self.menu.addMenu("Sort")
|
||||||
|
self._add_context_menu(
|
||||||
|
"by title", lambda: self._sort_selection(TITLE), parent_menu=sort_menu
|
||||||
|
)
|
||||||
|
self._add_context_menu(
|
||||||
|
"by artist", lambda: self._sort_selection(ARTIST), parent_menu=sort_menu
|
||||||
|
)
|
||||||
|
self._add_context_menu(
|
||||||
|
"by duration", lambda: self._sort_selection(DURATION), parent_menu=sort_menu
|
||||||
|
)
|
||||||
|
self._add_context_menu(
|
||||||
|
"by last played",
|
||||||
|
lambda: self._sort_selection(LASTPLAYED),
|
||||||
|
parent_menu=sort_menu,
|
||||||
|
)
|
||||||
|
if sort_menu:
|
||||||
|
sort_menu.setEnabled(self._sortable())
|
||||||
|
|
||||||
|
# Build submenu
|
||||||
|
|
||||||
|
# ----------------------
|
||||||
|
self.menu.addSeparator()
|
||||||
|
|
||||||
# Info
|
# Info
|
||||||
if track_row:
|
if track_row:
|
||||||
self._add_context_menu("Info", lambda: self._info_row(track_id))
|
self._add_context_menu("Info", lambda: self._info_row(track_id))
|
||||||
@ -2184,6 +2217,82 @@ class PlaylistTab(QTableWidget):
|
|||||||
|
|
||||||
return item
|
return item
|
||||||
|
|
||||||
|
def _sortable(self) -> bool:
|
||||||
|
"""
|
||||||
|
Return True if the selection is sortable. That means:
|
||||||
|
- at least two rows selected
|
||||||
|
- selected rows are contiguous
|
||||||
|
- selected rows do not include any header rows
|
||||||
|
"""
|
||||||
|
|
||||||
|
selectionModel = self.selectionModel()
|
||||||
|
if not selectionModel:
|
||||||
|
return False
|
||||||
|
source_rows = selectionModel.selectedRows()
|
||||||
|
sorted_source_rows = sorted([a.row() for a in source_rows])
|
||||||
|
if len(sorted_source_rows) < 2:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if sorted_source_rows != list(
|
||||||
|
range(min(sorted_source_rows), max(sorted_source_rows) + 1)
|
||||||
|
):
|
||||||
|
return False
|
||||||
|
|
||||||
|
for row in sorted_source_rows:
|
||||||
|
if self._get_row_track_id(row) == 0:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _sort_selection(self, sort_column: int) -> None:
|
||||||
|
"""
|
||||||
|
Algorithm:
|
||||||
|
- check row selection is contiguous; return if not
|
||||||
|
- copy (row-number, sort-field) to a list
|
||||||
|
- sort the list by sort-field
|
||||||
|
- create a new row after the selection
|
||||||
|
- iterate the list and move items to new row
|
||||||
|
- create another new row and repeat until all rows moved
|
||||||
|
- delete old rows
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Check selection is contiguous
|
||||||
|
selectionModel = self.selectionModel()
|
||||||
|
if not selectionModel:
|
||||||
|
return
|
||||||
|
source_rows = selectionModel.selectedRows()
|
||||||
|
if not self._sortable():
|
||||||
|
return
|
||||||
|
|
||||||
|
# Copy (row-number, sort-field) to a list
|
||||||
|
sorted_rows = []
|
||||||
|
for index in source_rows:
|
||||||
|
sort_item = self.item(index.row(), sort_column)
|
||||||
|
if sort_item:
|
||||||
|
sorted_rows.append((index.row(), sort_item.text()))
|
||||||
|
print(f"{sort_item.text()=}")
|
||||||
|
|
||||||
|
# Sort the list
|
||||||
|
sorted_rows.sort(key=lambda row: row[1])
|
||||||
|
|
||||||
|
# Move rows
|
||||||
|
source_row_numbers = [a[0] for a in sorted_rows]
|
||||||
|
next_row = max(source_row_numbers) + 1
|
||||||
|
for source_row_number in source_row_numbers:
|
||||||
|
self.insertRow(next_row)
|
||||||
|
for column in range(self.columnCount()):
|
||||||
|
self.setItem(next_row, column, self.takeItem(source_row_number, column))
|
||||||
|
next_row += 1
|
||||||
|
|
||||||
|
# Remove source rows
|
||||||
|
for i in reversed(source_rows):
|
||||||
|
self.removeRow(i.row())
|
||||||
|
|
||||||
|
# Save playlist
|
||||||
|
# with Session() as session:
|
||||||
|
# self.save_playlist(session)
|
||||||
|
# self._update_start_end_times(session)
|
||||||
|
|
||||||
def _track_time_between_rows(
|
def _track_time_between_rows(
|
||||||
self, session: scoped_session, from_plr: PlaylistRows, to_plr: PlaylistRows
|
self, session: scoped_session, from_plr: PlaylistRows, to_plr: PlaylistRows
|
||||||
) -> int:
|
) -> int:
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user