stay on selected song after sort feature

This commit is contained in:
billypom on debian 2025-04-14 18:04:16 -04:00
parent 1970235224
commit b219d0109e
3 changed files with 76 additions and 20 deletions

View File

@ -1,6 +1,9 @@
from collections.abc import Iterable
from PyQt5.QtWidgets import ( from PyQt5.QtWidgets import (
QDialog, QDialog,
QPlainTextEdit, QPlainTextEdit,
QTableWidget,
QTableWidgetItem,
QVBoxLayout, QVBoxLayout,
) )
from pprint import pformat from pprint import pformat
@ -8,16 +11,45 @@ from logging import debug
class DebugWindow(QDialog): class DebugWindow(QDialog):
def __init__(self, text: str): def __init__(self, data):
"""
Shows a dialog window
data can be str, list or dict
"""
super(DebugWindow, self).__init__() super(DebugWindow, self).__init__()
self.setWindowTitle("debug") self.setWindowTitle("debug")
self.setMinimumSize(400, 400) self.setMinimumSize(400, 400)
self.text: str = text self.data = data
layout = QVBoxLayout() layout = QVBoxLayout()
# Labels & input fields # Labels & input fields
# debug(pformat(self.text)) # debug(pformat(self.text))
self.input_field = QPlainTextEdit(pformat(self.text)) if isinstance(self.data, str):
self.input_field = QPlainTextEdit(pformat(self.data))
layout.addWidget(self.input_field)
elif isinstance(self.data, list):
table = QTableWidget()
table.setRowCount(len(data))
table.setColumnCount(len(data[0]))
for ri, row_data in enumerate(data):
for ci, item in enumerate(row_data):
table.setItem(ri, ci, QTableWidgetItem(str(item)))
layout.addWidget(table)
elif isinstance(self.data, dict):
# FIXME: i wanna grow....woah
try:
table = QTableWidget()
rows = max(len(value) for value in data.keys())
table.setRowCount(rows)
table.setColumnCount(len(data))
table.setHorizontalHeaderLabels(data.keys())
for ci, (key, values) in enumerate(data.items()):
for ri, value in enumerate(values):
table.setItem(ri, ci, QTableWidgetItem(str(value)))
layout.addWidget(table)
except Exception as e:
data = str(self.data)
self.input_field = QPlainTextEdit(pformat(data + "\n\n" + str(e)))
layout.addWidget(self.input_field) layout.addWidget(self.input_field)
self.setLayout(layout) self.setLayout(layout)

View File

@ -128,6 +128,7 @@ class MusicTable(QTableView):
self.database_columns = str(self.config["table"]["columns"]).split(",") self.database_columns = str(self.config["table"]["columns"]).split(",")
self.vertical_scroll_position = 0 self.vertical_scroll_position = 0
self.selected_song_filepath = "" self.selected_song_filepath = ""
self.selected_song_qmodel_index: QModelIndex
self.current_song_filepath = "" self.current_song_filepath = ""
self.current_song_db_id = None self.current_song_db_id = None
self.current_song_qmodel_index: QModelIndex self.current_song_qmodel_index: QModelIndex
@ -356,10 +357,16 @@ class MusicTable(QTableView):
def on_sort(self): def on_sort(self):
debug("on_sort") debug("on_sort")
search_col_num = self.table_headers.index("path") search_col_num = self.table_headers.index("path")
qmodel_index = self.find_qmodel_index_by_value( selected_qmodel_index = self.find_qmodel_index_by_value(
self.model2, search_col_num, self.selected_song_filepath
)
current_qmodel_index = self.find_qmodel_index_by_value(
self.model2, search_col_num, self.current_song_filepath self.model2, search_col_num, self.current_song_filepath
) )
self.set_qmodel_index(qmodel_index) # Update the 2 QModelIndexes that we track
self.set_selected_song_qmodel_index(selected_qmodel_index)
self.set_current_song_qmodel_index(current_qmodel_index)
self.jump_to_selected_song()
self.jump_to_current_song() self.jump_to_current_song()
# ```python # ```python
@ -377,8 +384,8 @@ class MusicTable(QTableView):
When a cell is clicked, do some stuff :) When a cell is clicked, do some stuff :)
- this func also runs when double click happens, fyi - this func also runs when double click happens, fyi
""" """
debug("on_cell_clicked")
self.set_selected_song_filepath() self.set_selected_song_filepath()
self.set_selected_song_qmodel_index()
self.viewport().update() # type: ignore self.viewport().update() # type: ignore
def on_header_resized(self, logicalIndex, oldSize, newSize): def on_header_resized(self, logicalIndex, oldSize, newSize):
@ -409,7 +416,7 @@ class MusicTable(QTableView):
def on_cell_data_changed(self, topLeft: QModelIndex, bottomRight: QModelIndex): def on_cell_data_changed(self, topLeft: QModelIndex, bottomRight: QModelIndex):
"""Handles updating ID3 tags when data changes in a cell""" """Handles updating ID3 tags when data changes in a cell"""
if isinstance(self.model2, QStandardItemModel): if isinstance(self.model2, QStandardItemModel):
debug("on_cell_data_changed | doing the normal stuff") debug("on_cell_data_changed")
# get the ID of the row that was edited # get the ID of the row that was edited
id_index = self.model2.index(topLeft.row(), 0) # ID is column 0, always id_index = self.model2.index(topLeft.row(), 0) # ID is column 0, always
# get the db song_id from the row # get the db song_id from the row
@ -451,6 +458,7 @@ class MusicTable(QTableView):
# FIXME: # FIXME:
# TODO: make this prettier, show a table in a window instead of raw text probably # TODO: make this prettier, show a table in a window instead of raw text probably
_, details = args[0][:2] _, details = args[0][:2]
details = dict(tuple(details)[0])
if details: if details:
window = DebugWindow(details) window = DebugWindow(details)
window.exec_() window.exec_()
@ -496,7 +504,6 @@ class MusicTable(QTableView):
def delete_songs(self): def delete_songs(self):
"""Asks to delete the currently selected songs from the db and music table (not the filesystem)""" """Asks to delete the currently selected songs from the db and music table (not the filesystem)"""
# FIXME: need to get indexes based on the proxy model
selected_filepaths = self.get_selected_songs_filepaths() selected_filepaths = self.get_selected_songs_filepaths()
formatted_selected_filepaths = "\n".join(selected_filepaths) formatted_selected_filepaths = "\n".join(selected_filepaths)
question_dialog = QuestionBoxDetails( question_dialog = QuestionBoxDetails(
@ -537,6 +544,15 @@ class MusicTable(QTableView):
window.refreshMusicTableSignal.connect(self.load_music_table) window.refreshMusicTableSignal.connect(self.load_music_table)
window.exec_() # Display the preferences window modally window.exec_() # Display the preferences window modally
def jump_to_selected_song(self):
"""Moves screen to the selected song, and selects the row"""
debug("jump_to_selected_song")
# get the proxy model index
proxy_index = self.proxymodel.mapFromSource(self.selected_song_qmodel_index)
self.scrollTo(proxy_index)
self.selectRow(proxy_index.row())
def jump_to_current_song(self): def jump_to_current_song(self):
"""Moves screen to the currently playing song, and selects the row""" """Moves screen to the currently playing song, and selects the row"""
debug("jump_to_current_song") debug("jump_to_current_song")
@ -564,7 +580,7 @@ class MusicTable(QTableView):
def show_id3_tags_debug_menu(self): def show_id3_tags_debug_menu(self):
"""Shows ID3 tags for a specific .mp3 file""" """Shows ID3 tags for a specific .mp3 file"""
if self.get_selected_song_filepath() is not None: if self.get_selected_song_filepath() is not None:
window = DebugWindow(str(self.get_selected_song_metadata())) window = DebugWindow(dict(self.get_selected_song_metadata()))
window.exec_() window.exec_()
def show_lyrics_menu(self): def show_lyrics_menu(self):
@ -809,7 +825,7 @@ class MusicTable(QTableView):
def get_selected_songs_filepaths(self) -> list[str]: def get_selected_songs_filepaths(self) -> list[str]:
""" """
Returns a list of the filepaths for the currently selected songs, based on the proxy model Returns a list of the filepaths for the currently selected songs, based on the proxy model
(things could be sorted differently) (because things could be sorted differently)
""" """
selected_rows = self.get_selected_rows() selected_rows = self.get_selected_rows()
filepaths = [] filepaths = []
@ -861,10 +877,7 @@ class MusicTable(QTableView):
Sets the current song filepath to the value in column 'path' with current selected row index Sets the current song filepath to the value in column 'path' with current selected row index
also stores the QModelIndex for some useful navigation stuff also stores the QModelIndex for some useful navigation stuff
""" """
# map proxy (sortable) model to the original model (used for interactions) self.set_current_song_qmodel_index()
source_index = self.proxymodel.mapToSource(self.currentIndex())
# set the proxy model index
self.set_current_song_qmodel_index(source_index)
# update the filepath # update the filepath
self.current_song_filepath: str = ( self.current_song_filepath: str = (
self.current_song_qmodel_index.siblingAtColumn( self.current_song_qmodel_index.siblingAtColumn(
@ -872,9 +885,20 @@ class MusicTable(QTableView):
).data() ).data()
) )
def set_current_song_qmodel_index(self, index: QModelIndex): def set_current_song_qmodel_index(self, index = None):
if index is None:
# map proxy (sortable) model to the original model (used for interactions)
index = self.proxymodel.mapToSource(self.currentIndex())
# set the proxy model index
self.current_song_qmodel_index: QModelIndex = index self.current_song_qmodel_index: QModelIndex = index
def set_selected_song_qmodel_index(self, index = None):
if index is None:
# map proxy (sortable) model to the original model (used for interactions)
index = self.proxymodel.mapToSource(self.currentIndex())
# set the proxy model index
self.selected_song_qmodel_index: QModelIndex = index
def load_qapp(self, qapp) -> None: def load_qapp(self, qapp) -> None:
"""Necessary for using members and methods of main application window""" """Necessary for using members and methods of main application window"""
self.qapp = qapp self.qapp = qapp

View File

@ -30,14 +30,14 @@ class QuestionBoxDetails(QDialog):
layout.addWidget(label) layout.addWidget(label)
self.text_field = QPlainTextEdit(self.details) self.text_field = QPlainTextEdit(self.details)
layout.addWidget(self.text_field) layout.addWidget(self.text_field)
# cancel
cancel_button = QPushButton("cancel")
cancel_button.clicked.connect(self.cancel)
h_layout.addWidget(cancel_button)
# ok # ok
ok_button = QPushButton("ok") ok_button = QPushButton("ok")
ok_button.clicked.connect(self.ok) ok_button.clicked.connect(self.ok)
h_layout.addWidget(ok_button) h_layout.addWidget(ok_button)
# cancel
cancel_button = QPushButton("cancel")
cancel_button.clicked.connect(self.cancel)
h_layout.addWidget(cancel_button)
layout.addLayout(h_layout) layout.addLayout(h_layout)
self.setLayout(layout) self.setLayout(layout)