updated sample config. reorganized MusicTable into logical sections
This commit is contained in:
parent
eaddcf8961
commit
29182d5ca6
@ -2,7 +2,10 @@ from mutagen.id3 import ID3
|
|||||||
from json import load as jsonload
|
from json import load as jsonload
|
||||||
import DBA
|
import DBA
|
||||||
from PyQt5.QtGui import (
|
from PyQt5.QtGui import (
|
||||||
|
QColor,
|
||||||
QDragMoveEvent,
|
QDragMoveEvent,
|
||||||
|
QPainter,
|
||||||
|
QPen,
|
||||||
QStandardItem,
|
QStandardItem,
|
||||||
QStandardItemModel,
|
QStandardItemModel,
|
||||||
QKeySequence,
|
QKeySequence,
|
||||||
@ -64,7 +67,6 @@ class MusicTable(QTableView):
|
|||||||
|
|
||||||
def __init__(self, parent=None, application_window=None):
|
def __init__(self, parent=None, application_window=None):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
print(f"QTableView Model: {self.model()}")
|
|
||||||
# why do i need this?
|
# why do i need this?
|
||||||
self.application_window = application_window
|
self.application_window = application_window
|
||||||
|
|
||||||
@ -125,7 +127,7 @@ class MusicTable(QTableView):
|
|||||||
self.songChanged = None
|
self.songChanged = None
|
||||||
self.selected_song_filepath = ""
|
self.selected_song_filepath = ""
|
||||||
self.current_song_filepath = ""
|
self.current_song_filepath = ""
|
||||||
self.current_item = None # track where cursor was last
|
self.current_index = None # track where cursor was last
|
||||||
|
|
||||||
# Properties
|
# Properties
|
||||||
self.setAcceptDrops(True)
|
self.setAcceptDrops(True)
|
||||||
@ -147,13 +149,13 @@ class MusicTable(QTableView):
|
|||||||
self.vertical_header.setVisible(False)
|
self.vertical_header.setVisible(False)
|
||||||
|
|
||||||
# CONNECTIONS
|
# CONNECTIONS
|
||||||
self.clicked.connect(self.set_selected_song_filepath)
|
self.clicked.connect(self.on_cell_clicked)
|
||||||
# self.doubleClicked.connect(self.set_current_song_filepath)
|
# self.doubleClicked.connect(self.set_current_song_filepath)
|
||||||
# self.enterKey.connect(self.set_current_song_filepath)
|
# self.enterKey.connect(self.set_current_song_filepath)
|
||||||
self.deleteKey.connect(self.delete_songs)
|
self.deleteKey.connect(self.delete_songs)
|
||||||
self.model2.dataChanged.connect(self.on_cell_data_changed) # editing cells
|
self.model2.dataChanged.connect(self.on_cell_data_changed) # editing cells
|
||||||
self.model2.layoutChanged.connect(self.restore_scroll_position)
|
self.model2.layoutChanged.connect(self.restore_scroll_position)
|
||||||
self.horizontal_header.sectionResized.connect(self.header_was_resized)
|
self.horizontal_header.sectionResized.connect(self.on_header_resized)
|
||||||
# Final actions
|
# Final actions
|
||||||
self.load_music_table()
|
self.load_music_table()
|
||||||
self.setup_keyboard_shortcuts()
|
self.setup_keyboard_shortcuts()
|
||||||
@ -161,12 +163,259 @@ class MusicTable(QTableView):
|
|||||||
# Load the column widths from last save
|
# Load the column widths from last save
|
||||||
# NOTE: Constructor can't call member function i guess?
|
# NOTE: Constructor can't call member function i guess?
|
||||||
# otherwise i would just use `self.load_header_widths()`
|
# otherwise i would just use `self.load_header_widths()`
|
||||||
table_view_column_widths = str(self.config["table"]["column_widths"]).split(",")
|
# table_view_column_widths = str(self.config["table"]["column_widths"]).split(",")
|
||||||
if not isinstance(table_view_column_widths[0], int) or not isinstance(
|
# if not isinstance(table_view_column_widths[0], int) or not isinstance(
|
||||||
table_view_column_widths, list
|
# table_view_column_widths, list
|
||||||
):
|
# ):
|
||||||
for i in range(self.model2.columnCount() - 1):
|
# for i in range(self.model2.columnCount() - 1):
|
||||||
self.setColumnWidth(i, int(table_view_column_widths[i]))
|
# self.setColumnWidth(i, int(table_view_column_widths[i]))
|
||||||
|
self.load_header_widths()
|
||||||
|
|
||||||
|
# _________________
|
||||||
|
# | |
|
||||||
|
# | |
|
||||||
|
# | Built-in Events |
|
||||||
|
# | |
|
||||||
|
# |_________________|
|
||||||
|
|
||||||
|
def resizeEvent(self, e: typing.Optional[QResizeEvent]) -> None:
|
||||||
|
"""Do something when the QTableView is resized"""
|
||||||
|
if e is None:
|
||||||
|
raise Exception
|
||||||
|
super().resizeEvent(e)
|
||||||
|
|
||||||
|
def paintEvent(self, e):
|
||||||
|
"""Override paint event to highlight the current cell"""
|
||||||
|
# First do the default painting
|
||||||
|
super().paintEvent(e)
|
||||||
|
|
||||||
|
# Check if we have a current cell
|
||||||
|
if self.current_index and self.current_index.isValid():
|
||||||
|
# Get the visual rect for the current cell
|
||||||
|
rect = self.visualRect(self.current_index)
|
||||||
|
|
||||||
|
# Create a painter for custom drawing
|
||||||
|
painter = QPainter(self.viewport())
|
||||||
|
|
||||||
|
# Draw a border around the current cell
|
||||||
|
pen = QPen(QColor("#4a90e2"), 2) # Blue, 2px width
|
||||||
|
|
||||||
|
painter.setPen(pen)
|
||||||
|
painter.drawRect(rect.adjusted(1, 1, -1, -1))
|
||||||
|
painter.end()
|
||||||
|
|
||||||
|
def contextMenuEvent(self, a0):
|
||||||
|
"""Right-click context menu for rows in Music Table"""
|
||||||
|
menu = QMenu(self)
|
||||||
|
add_to_playlist_action = QAction("Add to playlist", self)
|
||||||
|
add_to_playlist_action.triggered.connect(self.add_selected_files_to_playlist)
|
||||||
|
menu.addAction(add_to_playlist_action)
|
||||||
|
# edit metadata
|
||||||
|
edit_metadata_action = QAction("Edit metadata", self)
|
||||||
|
edit_metadata_action.triggered.connect(self.edit_selected_files_metadata)
|
||||||
|
menu.addAction(edit_metadata_action)
|
||||||
|
# edit lyrics
|
||||||
|
lyrics_menu = QAction("Lyrics (View/Edit)", self)
|
||||||
|
lyrics_menu.triggered.connect(self.show_lyrics_menu)
|
||||||
|
menu.addAction(lyrics_menu)
|
||||||
|
# open in file explorer
|
||||||
|
open_containing_folder_action = QAction("Open in system file manager", self)
|
||||||
|
open_containing_folder_action.triggered.connect(self.open_directory)
|
||||||
|
menu.addAction(open_containing_folder_action)
|
||||||
|
# view id3 tags (debug)
|
||||||
|
view_id3_tags_debug = QAction("View ID3 tags (debug)", self)
|
||||||
|
view_id3_tags_debug.triggered.connect(self.show_id3_tags_debug_menu)
|
||||||
|
menu.addAction(view_id3_tags_debug)
|
||||||
|
# delete song
|
||||||
|
delete_action = QAction("Delete", self)
|
||||||
|
delete_action.triggered.connect(self.delete_songs)
|
||||||
|
menu.addAction(delete_action)
|
||||||
|
# show
|
||||||
|
self.set_selected_song_filepath()
|
||||||
|
if a0 is not None:
|
||||||
|
menu.exec_(a0.globalPos())
|
||||||
|
|
||||||
|
def dragEnterEvent(self, e: QDragEnterEvent | None):
|
||||||
|
if e is None:
|
||||||
|
return
|
||||||
|
data = e.mimeData()
|
||||||
|
if data and data.hasUrls():
|
||||||
|
e.accept()
|
||||||
|
else:
|
||||||
|
e.ignore()
|
||||||
|
|
||||||
|
def dragMoveEvent(self, e: QDragMoveEvent | None):
|
||||||
|
if e is None:
|
||||||
|
return
|
||||||
|
data = e.mimeData()
|
||||||
|
if data and data.hasUrls():
|
||||||
|
e.accept()
|
||||||
|
else:
|
||||||
|
e.ignore()
|
||||||
|
|
||||||
|
def dropEvent(self, e: QDropEvent | None):
|
||||||
|
if e is None:
|
||||||
|
return
|
||||||
|
data = e.mimeData()
|
||||||
|
debug(f"dropEvent data: {data}")
|
||||||
|
if data and data.hasUrls():
|
||||||
|
directories = []
|
||||||
|
files = []
|
||||||
|
for url in data.urls():
|
||||||
|
if url.isLocalFile():
|
||||||
|
path = url.toLocalFile()
|
||||||
|
if os.path.isdir(path):
|
||||||
|
# append 1 directory
|
||||||
|
directories.append(path)
|
||||||
|
else:
|
||||||
|
# append 1 file
|
||||||
|
files.append(path)
|
||||||
|
e.accept()
|
||||||
|
debug(f"directories: {directories}")
|
||||||
|
debug(f"files: {files}")
|
||||||
|
if directories:
|
||||||
|
worker = Worker(self.get_audio_files_recursively, directories)
|
||||||
|
worker.signals.signal_progress.connect(self.handle_progress)
|
||||||
|
# worker.signals.signal_progress.connect(self.qapp.handle_progress)
|
||||||
|
worker.signals.signal_result.connect(self.on_recursive_search_finished)
|
||||||
|
worker.signals.signal_finished.connect(self.load_music_table)
|
||||||
|
if self.qapp:
|
||||||
|
threadpool = self.qapp.threadpool
|
||||||
|
threadpool.start(worker)
|
||||||
|
if files:
|
||||||
|
self.add_files(files)
|
||||||
|
else:
|
||||||
|
e.ignore()
|
||||||
|
|
||||||
|
def keyPressEvent(self, e):
|
||||||
|
"""Press a key. Do a thing"""
|
||||||
|
if not e:
|
||||||
|
return
|
||||||
|
|
||||||
|
key = e.key()
|
||||||
|
if key == Qt.Key.Key_Space: # Spacebar to play/pause
|
||||||
|
self.toggle_play_pause()
|
||||||
|
|
||||||
|
elif key == Qt.Key.Key_Right:
|
||||||
|
current_index = self.currentIndex()
|
||||||
|
new_index = self.model2.index(
|
||||||
|
current_index.row(), current_index.column() + 1
|
||||||
|
)
|
||||||
|
if new_index.isValid():
|
||||||
|
self.setCurrentIndex(new_index)
|
||||||
|
super().keyPressEvent(e)
|
||||||
|
|
||||||
|
elif key == Qt.Key.Key_Left:
|
||||||
|
current_index = self.currentIndex()
|
||||||
|
new_index = self.model2.index(
|
||||||
|
current_index.row(), current_index.column() - 1
|
||||||
|
)
|
||||||
|
if new_index.isValid():
|
||||||
|
self.setCurrentIndex(new_index)
|
||||||
|
super().keyPressEvent(e)
|
||||||
|
|
||||||
|
elif key == Qt.Key.Key_Up:
|
||||||
|
current_index = self.currentIndex()
|
||||||
|
new_index = self.model2.index(
|
||||||
|
current_index.row() - 1, current_index.column()
|
||||||
|
)
|
||||||
|
if new_index.isValid():
|
||||||
|
self.setCurrentIndex(new_index)
|
||||||
|
super().keyPressEvent(e)
|
||||||
|
|
||||||
|
elif key == Qt.Key.Key_Down:
|
||||||
|
current_index = self.currentIndex()
|
||||||
|
new_index = self.model2.index(
|
||||||
|
current_index.row() + 1, current_index.column()
|
||||||
|
)
|
||||||
|
if new_index.isValid():
|
||||||
|
self.setCurrentIndex(new_index)
|
||||||
|
super().keyPressEvent(e)
|
||||||
|
|
||||||
|
elif key in (Qt.Key.Key_Return, Qt.Key.Key_Enter):
|
||||||
|
if self.state() != QAbstractItemView.EditingState:
|
||||||
|
self.enterKey.emit() # Enter key detected
|
||||||
|
else:
|
||||||
|
super().keyPressEvent(e)
|
||||||
|
else: # Default behavior
|
||||||
|
super().keyPressEvent(e)
|
||||||
|
|
||||||
|
# ____________________
|
||||||
|
# | |
|
||||||
|
# | |
|
||||||
|
# | On action handlers |
|
||||||
|
# | |
|
||||||
|
# |____________________|
|
||||||
|
|
||||||
|
def on_cell_clicked(self, index):
|
||||||
|
"""
|
||||||
|
When a cell is clicked, do some stuff :)
|
||||||
|
"""
|
||||||
|
if index == self.current_index:
|
||||||
|
print("nope")
|
||||||
|
return
|
||||||
|
self.current_index = index
|
||||||
|
self.set_selected_song_filepath()
|
||||||
|
self.viewport().update() # type: ignore
|
||||||
|
|
||||||
|
def on_header_resized(self, logicalIndex, oldSize, newSize):
|
||||||
|
"""Handles keeping headers inside the viewport"""
|
||||||
|
# https://stackoverflow.com/questions/46775438/how-to-limit-qheaderview-size-when-resizing-sections
|
||||||
|
col_count = self.model2.columnCount()
|
||||||
|
qtableview_width = self.size().width()
|
||||||
|
sum_of_cols = self.horizontal_header.length()
|
||||||
|
# debug(f'qtable_width: {qtableview_width}')
|
||||||
|
# debug(f'sum of cols: {sum_of_cols}')
|
||||||
|
|
||||||
|
if sum_of_cols != qtableview_width:
|
||||||
|
# if not the last header
|
||||||
|
if logicalIndex < (col_count):
|
||||||
|
next_header_size = self.horizontal_header.sectionSize(logicalIndex + 1)
|
||||||
|
# If it should shrink
|
||||||
|
if next_header_size > (sum_of_cols - qtableview_width):
|
||||||
|
# shrink it
|
||||||
|
self.horizontal_header.resizeSection(
|
||||||
|
logicalIndex + 1,
|
||||||
|
next_header_size - (sum_of_cols - qtableview_width),
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# block the resize
|
||||||
|
self.horizontal_header.resizeSection(logicalIndex, oldSize)
|
||||||
|
|
||||||
|
def on_cell_data_changed(self, topLeft: QModelIndex, bottomRight: QModelIndex):
|
||||||
|
"""Handles updating ID3 tags when data changes in a cell"""
|
||||||
|
if isinstance(self.model2, QStandardItemModel):
|
||||||
|
debug("on_cell_data_changed | doing the normal stuff")
|
||||||
|
# get the ID of the row that was edited
|
||||||
|
id_index = self.model2.index(topLeft.row(), 0) # ID is column 0, always
|
||||||
|
# get the db song_id from the row
|
||||||
|
song_id = self.model2.data(id_index, Qt.ItemDataRole.UserRole)
|
||||||
|
# get the filepath through a series of steps...
|
||||||
|
# NOTE: filepath is always the last column
|
||||||
|
filepath_column_idx = self.model2.columnCount() - 1
|
||||||
|
filepath_index = self.model2.index(topLeft.row(), filepath_column_idx)
|
||||||
|
filepath = self.model2.data(filepath_index)
|
||||||
|
# update the ID3 information
|
||||||
|
user_input_data = topLeft.data()
|
||||||
|
edited_column_name = self.database_columns[topLeft.column()]
|
||||||
|
debug(f"on_cell_data_changed | edited column name: {edited_column_name}")
|
||||||
|
response = set_id3_tag(filepath, edited_column_name, user_input_data)
|
||||||
|
if response:
|
||||||
|
# Update the library with new metadata
|
||||||
|
update_song_in_database(song_id, edited_column_name, user_input_data)
|
||||||
|
return
|
||||||
|
|
||||||
|
def on_recursive_search_finished(self, result):
|
||||||
|
"""file search completion handler"""
|
||||||
|
if result:
|
||||||
|
self.add_files(result)
|
||||||
|
|
||||||
|
# ____________________
|
||||||
|
# | |
|
||||||
|
# | |
|
||||||
|
# | Verbs |
|
||||||
|
# | |
|
||||||
|
# |____________________|
|
||||||
|
|
||||||
def load_header_widths(self):
|
def load_header_widths(self):
|
||||||
"""
|
"""
|
||||||
@ -219,67 +468,6 @@ class MusicTable(QTableView):
|
|||||||
self.connect_layout_changed()
|
self.connect_layout_changed()
|
||||||
# self.model2.layoutChanged.emit()
|
# self.model2.layoutChanged.emit()
|
||||||
|
|
||||||
def resizeEvent(self, e: typing.Optional[QResizeEvent]) -> None:
|
|
||||||
"""Do something when the QTableView is resized"""
|
|
||||||
if e is None:
|
|
||||||
raise Exception
|
|
||||||
super().resizeEvent(e)
|
|
||||||
|
|
||||||
def header_was_resized(self, logicalIndex, oldSize, newSize):
|
|
||||||
"""Handles keeping headers inside the viewport"""
|
|
||||||
# https://stackoverflow.com/questions/46775438/how-to-limit-qheaderview-size-when-resizing-sections
|
|
||||||
col_count = self.model2.columnCount()
|
|
||||||
qtableview_width = self.size().width()
|
|
||||||
sum_of_cols = self.horizontal_header.length()
|
|
||||||
# debug(f'qtable_width: {qtableview_width}')
|
|
||||||
# debug(f'sum of cols: {sum_of_cols}')
|
|
||||||
|
|
||||||
if sum_of_cols != qtableview_width:
|
|
||||||
# if not the last header
|
|
||||||
if logicalIndex < (col_count):
|
|
||||||
next_header_size = self.horizontal_header.sectionSize(logicalIndex + 1)
|
|
||||||
# If it should shrink
|
|
||||||
if next_header_size > (sum_of_cols - qtableview_width):
|
|
||||||
# shrink it
|
|
||||||
self.horizontal_header.resizeSection(
|
|
||||||
logicalIndex + 1,
|
|
||||||
next_header_size - (sum_of_cols - qtableview_width),
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
# block the resize
|
|
||||||
self.horizontal_header.resizeSection(logicalIndex, oldSize)
|
|
||||||
|
|
||||||
def contextMenuEvent(self, a0):
|
|
||||||
"""Right-click context menu for rows in Music Table"""
|
|
||||||
menu = QMenu(self)
|
|
||||||
add_to_playlist_action = QAction("Add to playlist", self)
|
|
||||||
add_to_playlist_action.triggered.connect(self.add_selected_files_to_playlist)
|
|
||||||
menu.addAction(add_to_playlist_action)
|
|
||||||
# edit metadata
|
|
||||||
edit_metadata_action = QAction("Edit metadata", self)
|
|
||||||
edit_metadata_action.triggered.connect(self.edit_selected_files_metadata)
|
|
||||||
menu.addAction(edit_metadata_action)
|
|
||||||
# edit lyrics
|
|
||||||
lyrics_menu = QAction("Lyrics (View/Edit)", self)
|
|
||||||
lyrics_menu.triggered.connect(self.show_lyrics_menu)
|
|
||||||
menu.addAction(lyrics_menu)
|
|
||||||
# open in file explorer
|
|
||||||
open_containing_folder_action = QAction("Open in system file manager", self)
|
|
||||||
open_containing_folder_action.triggered.connect(self.open_directory)
|
|
||||||
menu.addAction(open_containing_folder_action)
|
|
||||||
# view id3 tags (debug)
|
|
||||||
view_id3_tags_debug = QAction("View ID3 tags (debug)", self)
|
|
||||||
view_id3_tags_debug.triggered.connect(self.show_id3_tags_debug_menu)
|
|
||||||
menu.addAction(view_id3_tags_debug)
|
|
||||||
# delete song
|
|
||||||
delete_action = QAction("Delete", self)
|
|
||||||
delete_action.triggered.connect(self.delete_songs)
|
|
||||||
menu.addAction(delete_action)
|
|
||||||
# show
|
|
||||||
self.set_selected_song_filepath()
|
|
||||||
if a0 is not None:
|
|
||||||
menu.exec_(a0.globalPos())
|
|
||||||
|
|
||||||
def disconnect_data_changed(self):
|
def disconnect_data_changed(self):
|
||||||
"""Disconnects the dataChanged signal from QTableView.model"""
|
"""Disconnects the dataChanged signal from QTableView.model"""
|
||||||
try:
|
try:
|
||||||
@ -394,94 +582,6 @@ class MusicTable(QTableView):
|
|||||||
lyrics_window = LyricsWindow(selected_song_filepath, lyrics)
|
lyrics_window = LyricsWindow(selected_song_filepath, lyrics)
|
||||||
lyrics_window.exec_()
|
lyrics_window.exec_()
|
||||||
|
|
||||||
def dragEnterEvent(self, e: QDragEnterEvent | None):
|
|
||||||
if e is None:
|
|
||||||
return
|
|
||||||
data = e.mimeData()
|
|
||||||
if data and data.hasUrls():
|
|
||||||
e.accept()
|
|
||||||
else:
|
|
||||||
e.ignore()
|
|
||||||
|
|
||||||
def dragMoveEvent(self, e: QDragMoveEvent | None):
|
|
||||||
if e is None:
|
|
||||||
return
|
|
||||||
data = e.mimeData()
|
|
||||||
if data and data.hasUrls():
|
|
||||||
e.accept()
|
|
||||||
else:
|
|
||||||
e.ignore()
|
|
||||||
|
|
||||||
def dropEvent(self, e: QDropEvent | None):
|
|
||||||
if e is None:
|
|
||||||
return
|
|
||||||
data = e.mimeData()
|
|
||||||
debug(f"dropEvent data: {data}")
|
|
||||||
if data and data.hasUrls():
|
|
||||||
directories = []
|
|
||||||
files = []
|
|
||||||
for url in data.urls():
|
|
||||||
if url.isLocalFile():
|
|
||||||
path = url.toLocalFile()
|
|
||||||
if os.path.isdir(path):
|
|
||||||
# append 1 directory
|
|
||||||
directories.append(path)
|
|
||||||
else:
|
|
||||||
# append 1 file
|
|
||||||
files.append(path)
|
|
||||||
e.accept()
|
|
||||||
debug(f"directories: {directories}")
|
|
||||||
debug(f"files: {files}")
|
|
||||||
if directories:
|
|
||||||
worker = Worker(self.get_audio_files_recursively, directories)
|
|
||||||
worker.signals.signal_progress.connect(self.handle_progress)
|
|
||||||
# worker.signals.signal_progress.connect(self.qapp.handle_progress)
|
|
||||||
worker.signals.signal_result.connect(self.on_recursive_search_finished)
|
|
||||||
worker.signals.signal_finished.connect(self.load_music_table)
|
|
||||||
if self.qapp:
|
|
||||||
threadpool = self.qapp.threadpool
|
|
||||||
threadpool.start(worker)
|
|
||||||
if files:
|
|
||||||
self.add_files(files)
|
|
||||||
else:
|
|
||||||
e.ignore()
|
|
||||||
|
|
||||||
def on_recursive_search_finished(self, result):
|
|
||||||
"""file search completion handler"""
|
|
||||||
if result:
|
|
||||||
self.add_files(result)
|
|
||||||
|
|
||||||
def keyPressEvent(self, e):
|
|
||||||
"""Press a key. Do a thing"""
|
|
||||||
if not e:
|
|
||||||
return
|
|
||||||
key = e.key()
|
|
||||||
if key == Qt.Key.Key_Space: # Spacebar to play/pause
|
|
||||||
self.toggle_play_pause()
|
|
||||||
elif key == Qt.Key.Key_Up: # Arrow key navigation
|
|
||||||
current_index = self.currentIndex()
|
|
||||||
new_index = self.model2.index(
|
|
||||||
current_index.row() - 1, current_index.column()
|
|
||||||
)
|
|
||||||
if new_index.isValid():
|
|
||||||
self.setCurrentIndex(new_index)
|
|
||||||
super().keyPressEvent(e)
|
|
||||||
elif key == Qt.Key.Key_Down: # Arrow key navigation
|
|
||||||
current_index = self.currentIndex()
|
|
||||||
new_index = self.model2.index(
|
|
||||||
current_index.row() + 1, current_index.column()
|
|
||||||
)
|
|
||||||
if new_index.isValid():
|
|
||||||
self.setCurrentIndex(new_index)
|
|
||||||
super().keyPressEvent(e)
|
|
||||||
elif key in (Qt.Key.Key_Return, Qt.Key.Key_Enter):
|
|
||||||
if self.state() != QAbstractItemView.EditingState:
|
|
||||||
self.enterKey.emit() # Enter key detected
|
|
||||||
else:
|
|
||||||
super().keyPressEvent(e)
|
|
||||||
else: # Default behavior
|
|
||||||
super().keyPressEvent(e)
|
|
||||||
|
|
||||||
def setup_keyboard_shortcuts(self):
|
def setup_keyboard_shortcuts(self):
|
||||||
"""Setup shortcuts here"""
|
"""Setup shortcuts here"""
|
||||||
shortcut = QShortcut(QKeySequence("Ctrl+Shift+R"), self)
|
shortcut = QShortcut(QKeySequence("Ctrl+Shift+R"), self)
|
||||||
@ -490,30 +590,6 @@ class MusicTable(QTableView):
|
|||||||
shortcut = QShortcut(QKeySequence("Delete"), self)
|
shortcut = QShortcut(QKeySequence("Delete"), self)
|
||||||
shortcut.activated.connect(self.delete_songs)
|
shortcut.activated.connect(self.delete_songs)
|
||||||
|
|
||||||
def on_cell_data_changed(self, topLeft: QModelIndex, bottomRight: QModelIndex):
|
|
||||||
"""Handles updating ID3 tags when data changes in a cell"""
|
|
||||||
if isinstance(self.model2, QStandardItemModel):
|
|
||||||
debug("on_cell_data_changed | doing the normal stuff")
|
|
||||||
# get the ID of the row that was edited
|
|
||||||
id_index = self.model2.index(topLeft.row(), 0) # ID is column 0, always
|
|
||||||
# get the db song_id from the row
|
|
||||||
song_id = self.model2.data(id_index, Qt.ItemDataRole.UserRole)
|
|
||||||
# get the filepath through a series of steps...
|
|
||||||
# NOTE: filepath is always the last column
|
|
||||||
filepath_column_idx = self.model2.columnCount() - 1
|
|
||||||
filepath_index = self.model2.index(topLeft.row(), filepath_column_idx)
|
|
||||||
filepath = self.model2.data(filepath_index)
|
|
||||||
# update the ID3 information
|
|
||||||
user_input_data = topLeft.data()
|
|
||||||
edited_column_name = self.database_columns[topLeft.column()]
|
|
||||||
debug(f"edited column name: {edited_column_name}")
|
|
||||||
response = set_id3_tag(filepath, edited_column_name, user_input_data)
|
|
||||||
if response:
|
|
||||||
# Update the library with new metadata
|
|
||||||
update_song_in_database(song_id, edited_column_name, user_input_data)
|
|
||||||
return
|
|
||||||
debug("")
|
|
||||||
|
|
||||||
def handle_progress(self, data):
|
def handle_progress(self, data):
|
||||||
"""Emits data to main"""
|
"""Emits data to main"""
|
||||||
self.handleProgressSignal.emit(data)
|
self.handleProgressSignal.emit(data)
|
||||||
|
|||||||
@ -12,6 +12,7 @@ playlist_relative_path = /relative/suffix/for/playlist/items
|
|||||||
[settings]
|
[settings]
|
||||||
# Which file types are scanned
|
# Which file types are scanned
|
||||||
extensions = mp3,wav,ogg,flac
|
extensions = mp3,wav,ogg,flac
|
||||||
|
volume = 100
|
||||||
|
|
||||||
[table]
|
[table]
|
||||||
# Music table options
|
# Music table options
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user