diff --git a/components/MusicTable.py b/components/MusicTable.py index 10a0a58..20e1c0e 100644 --- a/components/MusicTable.py +++ b/components/MusicTable.py @@ -70,6 +70,7 @@ class MusicTable(QTableView): refreshMusicTableSignal = pyqtSignal() handleProgressSignal = pyqtSignal(str) getThreadPoolSignal = pyqtSignal() + searchBoxSignal = pyqtSignal() def __init__(self, parent=None, application_window=None): super().__init__(parent) @@ -91,6 +92,7 @@ class MusicTable(QTableView): self.proxymodel.setSourceModel(self.model2) self.setModel(self.proxymodel) self.setSortingEnabled(True) + self.search_string = None # Config cfg_file = ( @@ -582,6 +584,12 @@ class MusicTable(QTableView): # Delete key? shortcut = QShortcut(QKeySequence("Delete"), self) shortcut.activated.connect(self.delete_songs) + # Search box + shortcut = QShortcut(QKeySequence("Ctrl+F"), self) + shortcut.activated.connect(self.emit_search_box) + + def emit_search_box(self): + self.searchBoxSignal.emit() def confirm_reorganize_files(self) -> None: """ @@ -669,14 +677,27 @@ class MusicTable(QTableView): self.model2.clear() self.model2.setHorizontalHeaderLabels(self.headers.get_user_gui_headers()) fields = ", ".join(self.headers.user_fields) + search_clause = ( + "title LIKE %?% AND artist LIKE %?% and album LIKE %?%" + if self.search_string + else "" + ) + params = "" if playlist_id: # Load a playlist - # Fetch playlist data selected_playlist_id = playlist_id[0] try: with DBA.DBAccess() as db: + query = f"SELECT id, {fields} FROM song JOIN song_playlist sp ON id = sp.song_id WHERE sp.playlist_id = ?" + # fulltext search + if self.search_string: + params = 3 * [self.search_string] + if query.find("WHERE") == -1: + query = f"{query} WHERE {search_clause};" + else: + query = f"{query} AND {search_clause};" data = db.query( - f"SELECT id, {fields} FROM song JOIN song_playlist sp ON id = sp.song_id WHERE sp.playlist_id = ?", - (selected_playlist_id,), + query, + (selected_playlist_id, params), ) except Exception as e: error(f"load_music_table() | Unhandled exception: {e}") @@ -684,9 +705,17 @@ class MusicTable(QTableView): else: # Load the library try: with DBA.DBAccess() as db: + query = f"SELECT id, {fields} FROM song" + # fulltext search + if self.search_string: + params = 3 * [self.search_string] + if query.find("WHERE") == -1: + query = f"{query} WHERE {search_clause};" + else: + query = f"{query} AND {search_clause};" data = db.query( - f"SELECT id, {fields} FROM song;", - (), + query, + (params), ) except Exception as e: error(f"load_music_table() | Unhandled exception: {e}") @@ -915,6 +944,10 @@ class MusicTable(QTableView): real_index: QModelIndex = self.proxymodel.mapToSource(index) self.selected_song_qmodel_index: QModelIndex = real_index + def set_search_string(self, text: str): + """set the search string""" + self.search_string = text + def load_qapp(self, qapp) -> None: """Necessary for using members and methods of main application window""" self.qapp = qapp diff --git a/components/SearchLineEdit.py b/components/SearchLineEdit.py new file mode 100644 index 0000000..434b24b --- /dev/null +++ b/components/SearchLineEdit.py @@ -0,0 +1,34 @@ +from PyQt5.QtWidgets import QLineEdit + +""" +MusicTable.py holds a variable called self.search_string +MusicTable.py had a function called load_music_table(), which loads data + from the SQLite database to the QTableView. load_music_table() + checks for the self.search_string + +in main.py, on self.lineEditSearch.textChanged(), +this updates the self.search_string in MusicTable.py + +in MusicTable.py, when Ctrl+F is pressed, the line edit gets hidden or visible +""" + + +class SearchLineEdit(QLineEdit): + def __init__(self, parent=None): + super().__init__(parent) + self.setVisible(False) + + def toggle_visibility(self): + if self.isHidden(): + self.setHidden(False) + else: + self.setHidden(True) + self.setText(None) + + # def toggle_visibility(self): + # if self.is_hidden: + # self.button.setVisible(True) + # self.is_hidden = False + # else: + # self.button.setVisible(False) + # self.is_hidden = True diff --git a/components/__init__.py b/components/__init__.py index 460c842..5eb37b5 100644 --- a/components/__init__.py +++ b/components/__init__.py @@ -12,3 +12,4 @@ from .ExportPlaylistWindow import ExportPlaylistWindow from .QuestionBoxDetails import QuestionBoxDetails from .HeaderTags import HeaderTags from .MediaPlayer import MediaPlayer +from .SearchLineEdit import SearchLineEdit diff --git a/main.py b/main.py index d92e006..91ec300 100644 --- a/main.py +++ b/main.py @@ -18,6 +18,7 @@ from ui import Ui_MainWindow from PyQt5.QtWidgets import ( QFileDialog, QLabel, + QLineEdit, QMainWindow, QApplication, QGraphicsScene, @@ -261,13 +262,18 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow): # for drag & drop functionality self.tableView.viewport().installEventFilter(self) + # Search box + self.lineEditSearch: QLineEdit + ## CONNECTIONS + self.lineEditSearch.textChanged.connect(self.handle_search_box_text) # tableView self.tableView.playSignal.connect(self.play_audio_file) self.tableView.playPauseSignal.connect( self.on_play_clicked ) # Spacebar toggle play/pause signal self.tableView.handleProgressSignal.connect(self.handle_progress) + self.tableView.searchBoxSignal.connect(self.handle_search_box) self.tableView.playlistStatsSignal.connect( self.set_permanent_status_bar_message ) @@ -483,6 +489,15 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow): else: self.status_bar.showMessage(message) + def handle_search_box(self): + """show or hide the searchbox""" + self.lineEditSearch.toggle_visibility() + + def handle_search_box_text(self, text: str): + """when text changes, update the music table thingie""" + self.tableView.set_search_string(text) + self.tableView.load_music_table(text) + def play_audio_file(self, filepath=None) -> None: """ Start playback of filepath & moves playback slider diff --git a/ui.py b/ui.py index 9157209..d4b7711 100644 --- a/ui.py +++ b/ui.py @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'ui.ui' # -# Created by: PyQt5 UI code generator 5.15.10 +# Created by: PyQt5 UI code generator 5.15.11 # # WARNING: Any manual changes made to this file will be lost when pyuic5 is # run again. Do not edit this file unless you know what you are doing. @@ -24,6 +24,9 @@ class Ui_MainWindow(object): self.verticalLayout.setContentsMargins(-1, -1, 0, -1) self.verticalLayout.setSpacing(6) self.verticalLayout.setObjectName("verticalLayout") + self.lineEditSearch = SearchLineEdit(self.centralwidget) + self.lineEditSearch.setObjectName("lineEditSearch") + self.verticalLayout.addWidget(self.lineEditSearch) self.hLayoutHead = QtWidgets.QHBoxLayout() self.hLayoutHead.setSizeConstraint(QtWidgets.QLayout.SetFixedSize) self.hLayoutHead.setObjectName("hLayoutHead") @@ -57,13 +60,15 @@ class Ui_MainWindow(object): self.hLayoutMusicTable.setSizeConstraint(QtWidgets.QLayout.SetMaximumSize) self.hLayoutMusicTable.setContentsMargins(0, -1, 0, -1) self.hLayoutMusicTable.setObjectName("hLayoutMusicTable") + self.verticalLayout_2 = QtWidgets.QVBoxLayout() + self.verticalLayout_2.setObjectName("verticalLayout_2") self.playlistTreeView = PlaylistsPane(self.centralwidget) self.playlistTreeView.setObjectName("playlistTreeView") - self.hLayoutMusicTable.addWidget(self.playlistTreeView) + self.verticalLayout_2.addWidget(self.playlistTreeView) + self.hLayoutMusicTable.addLayout(self.verticalLayout_2) self.tableView = MusicTable(self.centralwidget) self.tableView.setObjectName("tableView") self.hLayoutMusicTable.addWidget(self.tableView) - self.hLayoutMusicTable.setStretch(0, 2) self.hLayoutMusicTable.setStretch(1, 10) self.verticalLayout.addLayout(self.hLayoutMusicTable) self.hLayoutCurrentSongDetails = QtWidgets.QHBoxLayout() @@ -185,7 +190,7 @@ class Ui_MainWindow(object): self.verticalLayout_3.setStretch(0, 20) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MainWindow) - self.menubar.setGeometry(QtCore.QRect(0, 0, 1152, 24)) + self.menubar.setGeometry(QtCore.QRect(0, 0, 1152, 21)) self.menubar.setObjectName("menubar") self.menuFile = QtWidgets.QMenu(self.menubar) self.menuFile.setObjectName("menuFile") @@ -252,5 +257,5 @@ class Ui_MainWindow(object): self.actionDeleteDatabase.setText(_translate("MainWindow", "Delete Database")) self.actionNewPlaylist.setText(_translate("MainWindow", "New playlist")) self.actionExportPlaylist.setText(_translate("MainWindow", "Export playlist")) -from components import AlbumArtGraphicsView, MusicTable, PlaylistsPane +from components import AlbumArtGraphicsView, MusicTable, PlaylistsPane, SearchLineEdit from pyqtgraph import PlotWidget diff --git a/ui.ui b/ui.ui deleted file mode 100644 index 3a82b2a..0000000 --- a/ui.ui +++ /dev/null @@ -1,420 +0,0 @@ - - - MainWindow - - - - 0 - 0 - 953 - 739 - - - - MainWindow - - - - - - - - - - 6 - - - 0 - - - - - QLayout::SetFixedSize - - - - - QLayout::SetFixedSize - - - - - - 0 - 0 - - - - - 200 - 200 - - - - - 200 - 200 - - - - - - - - - - - - - - - - - - - - - - QLayout::SetMaximumSize - - - 0 - - - 0 - - - - - - - - - - - - - 6 - - - - - - - - - - - - - - - - - - - - QLayout::SetMaximumSize - - - - - Qt::Horizontal - - - - - - - - - - Monospace - false - - - - 00:00 - - - - - - - - Monospace - false - - - - / - - - - - - - - Monospace - 75 - false - true - - - - 00:00 - - - - - - - - - - - 6 - - - - - - - 50 - - - - - - - -1 - - - 101 - - - 50 - - - Qt::Horizontal - - - QSlider::TicksAbove - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 28 - - - - - - - - - 28 - - - - - - - - - 28 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - 0 - - - 100 - - - 1 - - - 50 - - - Qt::Horizontal - - - false - - - QSlider::TicksAbove - - - - - - - - Monospace - - - - 1.00 - - - - - - - - - - - - - - - 0 - 0 - 953 - 24 - - - - - File - - - - - - - - Edit - - - - - - View - - - - - Quick-Actions - - - - - - - - - - - - - - - Preferences - - - Open preferences - - - - - Scan libraries - - - - - Delete Library - - - - - Sort Columns - - - - - Open file(s) - - - - - Delete Database - - - - - New playlist - - - - - Export playlist - - - - - - PlotWidget - QWidget -
pyqtgraph
- 1 -
- - MusicTable - QTableView -
components
-
- - AlbumArtGraphicsView - QGraphicsView -
components
-
- - PlaylistsPane - QTreeView -
components
-
-
- - -