Much improved search now working
This commit is contained in:
parent
b7c0fa94dd
commit
ebdb0d0a82
@ -16,7 +16,7 @@ from PyQt5.QtWidgets import (
|
|||||||
QFileDialog,
|
QFileDialog,
|
||||||
QInputDialog,
|
QInputDialog,
|
||||||
QLabel,
|
QLabel,
|
||||||
# QLineEdit,
|
QLineEdit,
|
||||||
QListWidgetItem,
|
QListWidgetItem,
|
||||||
QMainWindow,
|
QMainWindow,
|
||||||
# QMessageBox,
|
# QMessageBox,
|
||||||
@ -77,9 +77,9 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
self.set_main_window_size()
|
self.set_main_window_size()
|
||||||
self.lblSumPlaytime = QLabel("")
|
self.lblSumPlaytime = QLabel("")
|
||||||
self.statusbar.addPermanentWidget(self.lblSumPlaytime)
|
self.statusbar.addPermanentWidget(self.lblSumPlaytime)
|
||||||
# self.txtSearch = QLineEdit()
|
self.txtSearch = QLineEdit()
|
||||||
# self.statusbar.addWidget(self.txtSearch)
|
self.statusbar.addWidget(self.txtSearch)
|
||||||
# self.txtSearch.setHidden(True)
|
self.txtSearch.setHidden(True)
|
||||||
self.hide_played_tracks = False
|
self.hide_played_tracks = False
|
||||||
|
|
||||||
self.visible_playlist_tab: Callable[[], PlaylistTab] = \
|
self.visible_playlist_tab: Callable[[], PlaylistTab] = \
|
||||||
@ -101,8 +101,12 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
def clear_selection(self) -> None:
|
def clear_selection(self) -> None:
|
||||||
""" Clear selected row"""
|
""" Clear selected row"""
|
||||||
|
|
||||||
|
# Unselect any selected rows
|
||||||
if self.visible_playlist_tab():
|
if self.visible_playlist_tab():
|
||||||
self.visible_playlist_tab().clear_selection()
|
self.visible_playlist_tab().clear_selection()
|
||||||
|
# Clear the search bar
|
||||||
|
self.search_playlist_clear()
|
||||||
|
|
||||||
|
|
||||||
def closeEvent(self, event: QEvent) -> None:
|
def closeEvent(self, event: QEvent) -> None:
|
||||||
"""Handle attempt to close main window"""
|
"""Handle attempt to close main window"""
|
||||||
@ -148,6 +152,10 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
event.accept()
|
event.accept()
|
||||||
|
|
||||||
def connect_signals_slots(self) -> None:
|
def connect_signals_slots(self) -> None:
|
||||||
|
self.actionFind_next.triggered.connect(
|
||||||
|
lambda: self.tabPlaylist.currentWidget().search_next())
|
||||||
|
self.actionFind_previous.triggered.connect(
|
||||||
|
lambda: self.tabPlaylist.currentWidget().search_previous())
|
||||||
self.actionInsertSectionHeader.triggered.connect(self.insert_header)
|
self.actionInsertSectionHeader.triggered.connect(self.insert_header)
|
||||||
self.action_Clear_selection.triggered.connect(self.clear_selection)
|
self.action_Clear_selection.triggered.connect(self.clear_selection)
|
||||||
self.actionClosePlaylist.triggered.connect(self.close_playlist_tab)
|
self.actionClosePlaylist.triggered.connect(self.close_playlist_tab)
|
||||||
@ -162,7 +170,7 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
self.actionNewPlaylist.triggered.connect(self.create_playlist)
|
self.actionNewPlaylist.triggered.connect(self.create_playlist)
|
||||||
self.actionOpenPlaylist.triggered.connect(self.open_playlist)
|
self.actionOpenPlaylist.triggered.connect(self.open_playlist)
|
||||||
self.actionPlay_next.triggered.connect(self.play_next)
|
self.actionPlay_next.triggered.connect(self.play_next)
|
||||||
# self.actionSearch.triggered.connect(self.search_playlist)
|
self.actionSearch.triggered.connect(self.search_playlist)
|
||||||
self.actionInsertTrack.triggered.connect(self.insert_track)
|
self.actionInsertTrack.triggered.connect(self.insert_track)
|
||||||
self.actionSelect_next_track.triggered.connect(self.select_next_row)
|
self.actionSelect_next_track.triggered.connect(self.select_next_row)
|
||||||
# self.actionSelect_played_tracks.triggered.connect(self.select_played)
|
# self.actionSelect_played_tracks.triggered.connect(self.select_played)
|
||||||
@ -179,9 +187,8 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
self.btnFade.clicked.connect(self.fade)
|
self.btnFade.clicked.connect(self.fade)
|
||||||
self.btnStop.clicked.connect(self.stop)
|
self.btnStop.clicked.connect(self.stop)
|
||||||
self.tabPlaylist.tabCloseRequested.connect(self.close_tab)
|
self.tabPlaylist.tabCloseRequested.connect(self.close_tab)
|
||||||
# self.txtSearch.returnPressed.connect(self.search_playlist_return)
|
self.txtSearch.returnPressed.connect(self.search_playlist_return)
|
||||||
# self.txtSearch.textChanged.connect(self.search_playlist_update)
|
|
||||||
#
|
|
||||||
self.timer.timeout.connect(self.tick)
|
self.timer.timeout.connect(self.tick)
|
||||||
|
|
||||||
def close_playlist_tab(self) -> None:
|
def close_playlist_tab(self) -> None:
|
||||||
@ -623,26 +630,35 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
with Session() as session:
|
with Session() as session:
|
||||||
dlg = DbDialog(self, session)
|
dlg = DbDialog(self, session)
|
||||||
dlg.exec()
|
dlg.exec()
|
||||||
#
|
|
||||||
# def search_playlist(self):
|
def search_playlist(self) -> None:
|
||||||
# """Show text box to search playlist"""
|
"""Show text box to search playlist"""
|
||||||
#
|
|
||||||
# self.disable_play_next_controls()
|
# Disable play controls so that 'return' in search box doesn't
|
||||||
# self.txtSearch.setHidden(False)
|
# play next track
|
||||||
# self.txtSearch.setFocus()
|
self.disable_play_next_controls()
|
||||||
#
|
self.txtSearch.setHidden(False)
|
||||||
# def search_playlist_return(self):
|
self.txtSearch.setFocus()
|
||||||
# """Close off search box when return pressed"""
|
|
||||||
#
|
def search_playlist_clear(self) -> None:
|
||||||
# self.txtSearch.setText("")
|
"""Tidy up and reset search bar"""
|
||||||
# self.txtSearch.setHidden(True)
|
|
||||||
# self.enable_play_next_controls()
|
# Clear the search text
|
||||||
# self.visible_playlist_tab().set_filter("")
|
self.visible_playlist_tab().search("")
|
||||||
#
|
# Clean up search bar
|
||||||
# def search_playlist_update(self):
|
self.txtSearch.setText("")
|
||||||
# """Update search when search string changes"""
|
self.txtSearch.setHidden(True)
|
||||||
#
|
|
||||||
# self.visible_playlist_tab().set_filter(self.txtSearch.text())
|
def search_playlist_return(self) -> None:
|
||||||
|
"""Initiate search when return pressed"""
|
||||||
|
|
||||||
|
self.visible_playlist_tab().search(self.txtSearch.text())
|
||||||
|
self.enable_play_next_controls()
|
||||||
|
|
||||||
|
# def search_playlist_update(self):
|
||||||
|
# """Update search when search string changes"""
|
||||||
|
|
||||||
|
# self.visible_playlist_tab().set_filter(self.txtSearch.text())
|
||||||
|
|
||||||
def open_playlist(self):
|
def open_playlist(self):
|
||||||
with Session() as session:
|
with Session() as session:
|
||||||
|
|||||||
326
app/playlists.py
326
app/playlists.py
@ -146,7 +146,7 @@ class PlaylistTab(QTableWidget):
|
|||||||
|
|
||||||
self.itemSelectionChanged.connect(self._select_event)
|
self.itemSelectionChanged.connect(self._select_event)
|
||||||
|
|
||||||
self.row_filter: Optional[str] = None
|
self.search_text: str = ""
|
||||||
self.edit_cell_type = None
|
self.edit_cell_type = None
|
||||||
self.selecting_in_progress = False
|
self.selecting_in_progress = False
|
||||||
# Connect signals
|
# Connect signals
|
||||||
@ -775,78 +775,109 @@ class PlaylistTab(QTableWidget):
|
|||||||
session.commit()
|
session.commit()
|
||||||
PlaylistRows.delete_higher_rows(session, self.playlist_id, row)
|
PlaylistRows.delete_higher_rows(session, self.playlist_id, row)
|
||||||
|
|
||||||
# def save_playlist(self, session) -> None:
|
def search(self, text: str) -> None:
|
||||||
# """
|
"""Set search text and find first match"""
|
||||||
# Save playlist to database.
|
|
||||||
#
|
self.search_text = text
|
||||||
# For notes: check the database entry is correct and update it if
|
if not text:
|
||||||
# necessary. Playlists:Note is one:many, so each note may only appear
|
# Search string has been reset
|
||||||
# in one playlist.
|
return
|
||||||
#
|
self.search_next()
|
||||||
# For tracks: erase the playlist tracks and recreate. This is much
|
|
||||||
# simpler than trying to implement any Playlists:Tracks many:many
|
def search_next(self) -> None:
|
||||||
# changes.
|
"""
|
||||||
# """
|
Select next row containg self.search_string. Start from
|
||||||
#
|
top selected row if there is one, else from top.
|
||||||
# playlist = Playlists.get_by_id(session, self.playlist_id)
|
|
||||||
#
|
Wrap at last row.
|
||||||
# # Notes first
|
"""
|
||||||
# # Create dictionaries indexed by note_id
|
|
||||||
# playlist_notes: Dict[int, Notes] = {}
|
if not self.search_text:
|
||||||
# database_notes: Dict[int, Notes] = {}
|
return
|
||||||
# notes_rows: List[int] = self._get_notes_rows()
|
|
||||||
#
|
selected_row = self._get_selected_row()
|
||||||
# # PlaylistTab
|
if selected_row and selected_row < self.rowCount() - 1:
|
||||||
# for row in notes_rows:
|
starting_row = selected_row + 1
|
||||||
# note: Notes = self._get_row_notes_object(row, session)
|
else:
|
||||||
# session.add(note)
|
starting_row = 0
|
||||||
# playlist_notes[note.id] = note
|
|
||||||
# if row != note.row:
|
wrapped = False
|
||||||
# log.debug(f"Updating: {playlist.name=}, {row=}, {note.row=}")
|
match_row = None
|
||||||
# note.update(session=session, row=row)
|
row = starting_row
|
||||||
#
|
needle = self.search_text.lower()
|
||||||
# # Database
|
while True:
|
||||||
# for note in playlist.notes:
|
# Check for match in title, artist or notes
|
||||||
# database_notes[note.id] = note
|
title = self._get_row_title(row)
|
||||||
#
|
if title and needle in title.lower():
|
||||||
# # We don't need to check for notes to add to the database as
|
match_row = row
|
||||||
# # they can't exist in the playlist without being in the database
|
break
|
||||||
# # and pointing at this playlist.
|
artist = self._get_row_title(row)
|
||||||
#
|
if artist and needle in artist.lower():
|
||||||
# # Notes to remove from database
|
match_row = row
|
||||||
# for note_id in set(database_notes.keys()) - set(playlist_notes.keys()):
|
break
|
||||||
# log.debug(
|
note = self._get_row_note(row)
|
||||||
# "_save_playlist(): "
|
if note and needle in note.lower():
|
||||||
# f"Delete {note_id=} from {self=} in database"
|
match_row = row
|
||||||
# )
|
break
|
||||||
# database_notes[note_id].delete_note(session)
|
row += 1
|
||||||
#
|
if wrapped and row >= starting_row:
|
||||||
# # Note rows to update in playlist database
|
break
|
||||||
# for note_id in set(playlist_notes.keys()) & set(database_notes.keys()):
|
if row >= self.rowCount():
|
||||||
# if playlist_notes[note_id].row != database_notes[note_id].row:
|
row = 0
|
||||||
# log.debug(
|
wrapped = True
|
||||||
# f"_save_playlist(): Update notes row in database "
|
|
||||||
# f"from {database_notes[note_id]=} "
|
if match_row:
|
||||||
# f"to {playlist_notes[note_id]=}"
|
self.selectRow(row)
|
||||||
# )
|
|
||||||
# database_notes[note_id].update(
|
def search_previous(self) -> None:
|
||||||
# session, row=playlist_notes[note_id].row)
|
"""
|
||||||
#
|
Select previous row containg self.search_string. Start from
|
||||||
# # Tracks
|
top selected row if there is one, else from top.
|
||||||
# # Remove all tracks from this playlist
|
|
||||||
# playlist.remove_all_tracks(session)
|
Wrap at last row.
|
||||||
# # Iterate on-screen playlist and add tracks back in
|
"""
|
||||||
# for row in range(self.rowCount()):
|
|
||||||
# if row in notes_rows:
|
if not self.search_text:
|
||||||
# continue
|
return
|
||||||
# track_id: int = self.item(
|
|
||||||
# row, FIXUP.COL_USERDATA).data(self.CONTENT_OBJECT)
|
selected_row = self._get_selected_row()
|
||||||
# playlist.add_track(session, track_id, row)
|
if selected_row and selected_row > 0:
|
||||||
# session.commit()
|
starting_row = selected_row - 1
|
||||||
|
else:
|
||||||
|
starting_row = self.rowCount() - 1
|
||||||
|
|
||||||
|
wrapped = False
|
||||||
|
match_row = None
|
||||||
|
row = starting_row
|
||||||
|
needle = self.search_text.lower()
|
||||||
|
while True:
|
||||||
|
# Check for match in title, artist or notes
|
||||||
|
title = self._get_row_title(row)
|
||||||
|
if title and needle in title.lower():
|
||||||
|
match_row = row
|
||||||
|
break
|
||||||
|
artist = self._get_row_title(row)
|
||||||
|
if artist and needle in artist.lower():
|
||||||
|
match_row = row
|
||||||
|
break
|
||||||
|
note = self._get_row_note(row)
|
||||||
|
if note and needle in note.lower():
|
||||||
|
match_row = row
|
||||||
|
break
|
||||||
|
row -= 1
|
||||||
|
if wrapped and row <= starting_row:
|
||||||
|
break
|
||||||
|
if row < 0:
|
||||||
|
row = self.rowCount() - 1
|
||||||
|
wrapped = True
|
||||||
|
|
||||||
|
if match_row:
|
||||||
|
self.selectRow(row)
|
||||||
|
|
||||||
def select_next_row(self) -> None:
|
def select_next_row(self) -> None:
|
||||||
"""
|
"""
|
||||||
Select next or first row. Don't select section headers.
|
Select next or first row. Don't select section headers.
|
||||||
|
|
||||||
Wrap at last row.
|
Wrap at last row.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -938,13 +969,12 @@ class PlaylistTab(QTableWidget):
|
|||||||
# finally:
|
# finally:
|
||||||
# self.selecting_in_progress = False
|
# self.selecting_in_progress = False
|
||||||
# self._select_event()
|
# self._select_event()
|
||||||
#
|
|
||||||
# def set_filter(self, text: Optional[str]) -> None:
|
def set_searchtext(self, text: Optional[str]) -> None:
|
||||||
# """Filter rows to only show those containing text"""
|
"""Set the search text and find first match"""
|
||||||
#
|
|
||||||
# self.row_filter = text
|
self.search_text = text
|
||||||
# with Session() as session:
|
self._find_next_match()
|
||||||
# self.update_display(session)
|
|
||||||
|
|
||||||
def set_selected_as_next(self) -> None:
|
def set_selected_as_next(self) -> None:
|
||||||
"""Sets the select track as next to play"""
|
"""Sets the select track as next to play"""
|
||||||
@ -980,10 +1010,6 @@ class PlaylistTab(QTableWidget):
|
|||||||
]
|
]
|
||||||
unreadable: List[int] = self._get_unreadable_track_rows()
|
unreadable: List[int] = self._get_unreadable_track_rows()
|
||||||
|
|
||||||
if self.row_filter:
|
|
||||||
filter_text = self.row_filter.lower()
|
|
||||||
else:
|
|
||||||
filter_text = None
|
|
||||||
next_start_time = None
|
next_start_time = None
|
||||||
section_start_plr = None
|
section_start_plr = None
|
||||||
section_time = 0
|
section_time = 0
|
||||||
@ -1023,22 +1049,6 @@ class PlaylistTab(QTableWidget):
|
|||||||
if section_start_plr is not None:
|
if section_start_plr is not None:
|
||||||
section_time += track.duration
|
section_time += track.duration
|
||||||
|
|
||||||
# If filtering, only show matching tracks
|
|
||||||
if filter_text:
|
|
||||||
try:
|
|
||||||
if (track.title
|
|
||||||
and filter_text not in track.title.lower()
|
|
||||||
and track.artist
|
|
||||||
and filter_text not in track.artist.lower()):
|
|
||||||
self.hideRow(row)
|
|
||||||
continue
|
|
||||||
else:
|
|
||||||
self.showRow(row)
|
|
||||||
except TypeError:
|
|
||||||
print(f"TypeError: {track=}")
|
|
||||||
else:
|
|
||||||
self.showRow(row)
|
|
||||||
|
|
||||||
# Colour any note
|
# Colour any note
|
||||||
if note_text:
|
if note_text:
|
||||||
(self.item(row, columns['row_notes'].idx)
|
(self.item(row, columns['row_notes'].idx)
|
||||||
@ -1119,14 +1129,6 @@ class PlaylistTab(QTableWidget):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
# No track associated, so this row is a section header
|
# No track associated, so this row is a section header
|
||||||
if filter_text:
|
|
||||||
if filter_text not in note_text.lower():
|
|
||||||
self.hideRow(row)
|
|
||||||
continue
|
|
||||||
else:
|
|
||||||
self.showRow(row)
|
|
||||||
else:
|
|
||||||
self.showRow(row)
|
|
||||||
# Does the note have a start time?
|
# Does the note have a start time?
|
||||||
row_time = self._get_note_text_time(note_text)
|
row_time = self._get_note_text_time(note_text)
|
||||||
if row_time:
|
if row_time:
|
||||||
@ -1264,11 +1266,18 @@ class PlaylistTab(QTableWidget):
|
|||||||
return (index.row() + 1 if self._is_below(event.pos(), index)
|
return (index.row() + 1 if self._is_below(event.pos(), index)
|
||||||
else index.row())
|
else index.row())
|
||||||
|
|
||||||
# def _get_notes_rows(self) -> List[int]:
|
def _find_next_match(self) -> None:
|
||||||
# """Return rows marked as notes, or None"""
|
"""
|
||||||
#
|
Find next match of search_text. Start at first highlighted row
|
||||||
# return self._meta_search(RowMeta.NOTE, one=False)
|
if there is one, else from top of playlist.
|
||||||
#
|
"""
|
||||||
|
|
||||||
|
start_row = self._get_selected_row()
|
||||||
|
if start_row is None:
|
||||||
|
start_row = 0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def _find_next_track_row(self, session: Session,
|
def _find_next_track_row(self, session: Session,
|
||||||
starting_row: int = None) -> Optional[int]:
|
starting_row: int = None) -> Optional[int]:
|
||||||
@ -1340,6 +1349,16 @@ class PlaylistTab(QTableWidget):
|
|||||||
|
|
||||||
return playlistrow_id
|
return playlistrow_id
|
||||||
|
|
||||||
|
def _get_row_artist(self, row: int) -> Optional[str]:
|
||||||
|
"""Return artist on this row or None if none"""
|
||||||
|
|
||||||
|
track_id = self._get_row_track_id(row)
|
||||||
|
if not track_id:
|
||||||
|
return None
|
||||||
|
|
||||||
|
item_artist = self.item(row, columns['artist'].idx)
|
||||||
|
return item_artist.text()
|
||||||
|
|
||||||
def _get_row_duration(self, row: int) -> int:
|
def _get_row_duration(self, row: int) -> int:
|
||||||
"""Return duration associated with this row"""
|
"""Return duration associated with this row"""
|
||||||
|
|
||||||
@ -1350,46 +1369,15 @@ class PlaylistTab(QTableWidget):
|
|||||||
else:
|
else:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def _get_row_track_id(self, row: int) -> int:
|
def _get_row_note(self, row: int) -> Optional[str]:
|
||||||
"""Return the track_id associated with this row or None"""
|
"""Return note on this row or None if none"""
|
||||||
|
|
||||||
track_id = (self.item(row, columns['userdata'].idx)
|
track_id = self._get_row_track_id(row)
|
||||||
.data(self.ROW_TRACK_ID))
|
if track_id:
|
||||||
|
item_note = self.item(row, columns['row_notes'].idx)
|
||||||
return track_id
|
else:
|
||||||
|
item_note = self.item(row, 1)
|
||||||
#
|
return item_note.text()
|
||||||
# def _get_row_end_time(self, row) -> Optional[datetime]:
|
|
||||||
# """
|
|
||||||
# Return row end time as string
|
|
||||||
# """
|
|
||||||
#
|
|
||||||
# try:
|
|
||||||
# if self.item(row, FIXUP.COL_END_TIME):
|
|
||||||
# return datetime.strptime(self.item(
|
|
||||||
# row, FIXUP.COL_END_TIME).text(),
|
|
||||||
# Config.NOTE_TIME_FORMAT
|
|
||||||
# )
|
|
||||||
# else:
|
|
||||||
# return None
|
|
||||||
# except ValueError:
|
|
||||||
# return None
|
|
||||||
#
|
|
||||||
# def _get_row_notes_object(self, row: int, session: Session) \
|
|
||||||
# -> Optional[Notes]:
|
|
||||||
# """Return note associated with this row"""
|
|
||||||
#
|
|
||||||
# note_id = self.item(row, FIXUP.COL_USERDATA).data(self.CONTENT_OBJECT)
|
|
||||||
# note = Notes.get_by_id(session, note_id)
|
|
||||||
# return note
|
|
||||||
#
|
|
||||||
# def _get_unplayed_track_rows(self) -> Optional[List[int]]:
|
|
||||||
# """Return rows marked as unplayed, or None"""
|
|
||||||
#
|
|
||||||
# unplayed_rows: Set[int] = set(self._meta_notset(RowMeta.PLAYED))
|
|
||||||
# notes_rows: Set[int] = set(self._get_notes_rows())
|
|
||||||
#
|
|
||||||
# return list(unplayed_rows - notes_rows)
|
|
||||||
|
|
||||||
def _get_row_start_time(self, row: int) -> Optional[datetime]:
|
def _get_row_start_time(self, row: int) -> Optional[datetime]:
|
||||||
try:
|
try:
|
||||||
@ -1403,6 +1391,35 @@ class PlaylistTab(QTableWidget):
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def _get_row_title(self, row: int) -> Optional[str]:
|
||||||
|
"""Return title on this row or None if none"""
|
||||||
|
|
||||||
|
track_id = self._get_row_track_id(row)
|
||||||
|
if not track_id:
|
||||||
|
return None
|
||||||
|
|
||||||
|
item_title = self.item(row, columns['title'].idx)
|
||||||
|
return item_title.text()
|
||||||
|
|
||||||
|
def _get_row_track_id(self, row: int) -> int:
|
||||||
|
"""Return the track_id associated with this row or None"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
track_id = (self.item(row, columns['userdata'].idx)
|
||||||
|
.data(self.ROW_TRACK_ID))
|
||||||
|
except AttributeError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return track_id
|
||||||
|
|
||||||
|
# def _get_unplayed_track_rows(self) -> Optional[List[int]]:
|
||||||
|
# """Return rows marked as unplayed, or None"""
|
||||||
|
#
|
||||||
|
# unplayed_rows: Set[int] = set(self._meta_notset(RowMeta.PLAYED))
|
||||||
|
# notes_rows: Set[int] = set(self._get_notes_rows())
|
||||||
|
#
|
||||||
|
# return list(unplayed_rows - notes_rows)
|
||||||
|
|
||||||
def _get_selected_row(self) -> Optional[int]:
|
def _get_selected_row(self) -> Optional[int]:
|
||||||
"""Return row number of first selected row, or None if none selected"""
|
"""Return row number of first selected row, or None if none selected"""
|
||||||
|
|
||||||
@ -1410,19 +1427,6 @@ class PlaylistTab(QTableWidget):
|
|||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
return self.selectionModel().selectedRows()[0].row()
|
return self.selectionModel().selectedRows()[0].row()
|
||||||
#
|
|
||||||
# def _get_row_track_object(self, row: int, session: Session) \
|
|
||||||
# -> Optional[Tracks]:
|
|
||||||
# """Return track associated with this row"""
|
|
||||||
#
|
|
||||||
# track_id = self.item(row, FIXUP.COL_USERDATA).data(self.CONTENT_OBJECT)
|
|
||||||
# track = Tracks.get_by_id(session, track_id)
|
|
||||||
# return track
|
|
||||||
#
|
|
||||||
# def _get_track_rows(self) -> List[int]:
|
|
||||||
# """Return rows marked as tracks, or None"""
|
|
||||||
#
|
|
||||||
# return self._meta_notset(RowMeta.NOTE)
|
|
||||||
|
|
||||||
def _get_unreadable_track_rows(self) -> List[int]:
|
def _get_unreadable_track_rows(self) -> List[int]:
|
||||||
"""Return rows marked as unreadable, or None"""
|
"""Return rows marked as unreadable, or None"""
|
||||||
|
|||||||
@ -784,17 +784,26 @@ border: 1px solid rgb(85, 87, 83);</string>
|
|||||||
<addaction name="actionInsertTrack"/>
|
<addaction name="actionInsertTrack"/>
|
||||||
<addaction name="actionRemove"/>
|
<addaction name="actionRemove"/>
|
||||||
<addaction name="actionImport"/>
|
<addaction name="actionImport"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
<addaction name="actionSetNext"/>
|
<addaction name="actionSetNext"/>
|
||||||
<addaction name="action_Clear_selection"/>
|
<addaction name="action_Clear_selection"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionEnable_controls"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="menuSearc_h">
|
||||||
|
<property name="title">
|
||||||
|
<string>Searc&h</string>
|
||||||
|
</property>
|
||||||
<addaction name="actionSearch"/>
|
<addaction name="actionSearch"/>
|
||||||
|
<addaction name="actionFind_next"/>
|
||||||
|
<addaction name="actionFind_previous"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
<addaction name="actionSelect_next_track"/>
|
<addaction name="actionSelect_next_track"/>
|
||||||
<addaction name="actionSelect_previous_track"/>
|
<addaction name="actionSelect_previous_track"/>
|
||||||
<addaction name="separator"/>
|
|
||||||
<addaction name="actionEnable_controls"/>
|
|
||||||
</widget>
|
</widget>
|
||||||
<addaction name="menuFile"/>
|
<addaction name="menuFile"/>
|
||||||
<addaction name="menuPlaylist"/>
|
<addaction name="menuPlaylist"/>
|
||||||
|
<addaction name="menuSearc_h"/>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QStatusBar" name="statusbar">
|
<widget class="QStatusBar" name="statusbar">
|
||||||
<property name="enabled">
|
<property name="enabled">
|
||||||
@ -1043,6 +1052,22 @@ border: 1px solid rgb(85, 87, 83);</string>
|
|||||||
<string>&Remove track</string>
|
<string>&Remove track</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="actionFind_next">
|
||||||
|
<property name="text">
|
||||||
|
<string>Find next</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>N</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionFind_previous">
|
||||||
|
<property name="text">
|
||||||
|
<string>Find previous</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>P</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
<customwidget>
|
<customwidget>
|
||||||
|
|||||||
@ -350,6 +350,8 @@ class Ui_MainWindow(object):
|
|||||||
self.menuFile.setObjectName("menuFile")
|
self.menuFile.setObjectName("menuFile")
|
||||||
self.menuPlaylist = QtWidgets.QMenu(self.menubar)
|
self.menuPlaylist = QtWidgets.QMenu(self.menubar)
|
||||||
self.menuPlaylist.setObjectName("menuPlaylist")
|
self.menuPlaylist.setObjectName("menuPlaylist")
|
||||||
|
self.menuSearc_h = QtWidgets.QMenu(self.menubar)
|
||||||
|
self.menuSearc_h.setObjectName("menuSearc_h")
|
||||||
MainWindow.setMenuBar(self.menubar)
|
MainWindow.setMenuBar(self.menubar)
|
||||||
self.statusbar = QtWidgets.QStatusBar(MainWindow)
|
self.statusbar = QtWidgets.QStatusBar(MainWindow)
|
||||||
self.statusbar.setEnabled(True)
|
self.statusbar.setEnabled(True)
|
||||||
@ -444,6 +446,10 @@ class Ui_MainWindow(object):
|
|||||||
self.actionInsertSectionHeader.setObjectName("actionInsertSectionHeader")
|
self.actionInsertSectionHeader.setObjectName("actionInsertSectionHeader")
|
||||||
self.actionRemove = QtWidgets.QAction(MainWindow)
|
self.actionRemove = QtWidgets.QAction(MainWindow)
|
||||||
self.actionRemove.setObjectName("actionRemove")
|
self.actionRemove.setObjectName("actionRemove")
|
||||||
|
self.actionFind_next = QtWidgets.QAction(MainWindow)
|
||||||
|
self.actionFind_next.setObjectName("actionFind_next")
|
||||||
|
self.actionFind_previous = QtWidgets.QAction(MainWindow)
|
||||||
|
self.actionFind_previous.setObjectName("actionFind_previous")
|
||||||
self.menuFile.addAction(self.actionNewPlaylist)
|
self.menuFile.addAction(self.actionNewPlaylist)
|
||||||
self.menuFile.addAction(self.actionOpenPlaylist)
|
self.menuFile.addAction(self.actionOpenPlaylist)
|
||||||
self.menuFile.addAction(self.actionClosePlaylist)
|
self.menuFile.addAction(self.actionClosePlaylist)
|
||||||
@ -468,16 +474,20 @@ class Ui_MainWindow(object):
|
|||||||
self.menuPlaylist.addAction(self.actionInsertTrack)
|
self.menuPlaylist.addAction(self.actionInsertTrack)
|
||||||
self.menuPlaylist.addAction(self.actionRemove)
|
self.menuPlaylist.addAction(self.actionRemove)
|
||||||
self.menuPlaylist.addAction(self.actionImport)
|
self.menuPlaylist.addAction(self.actionImport)
|
||||||
|
self.menuPlaylist.addSeparator()
|
||||||
self.menuPlaylist.addAction(self.actionSetNext)
|
self.menuPlaylist.addAction(self.actionSetNext)
|
||||||
self.menuPlaylist.addAction(self.action_Clear_selection)
|
self.menuPlaylist.addAction(self.action_Clear_selection)
|
||||||
self.menuPlaylist.addSeparator()
|
self.menuPlaylist.addSeparator()
|
||||||
self.menuPlaylist.addAction(self.actionSearch)
|
|
||||||
self.menuPlaylist.addAction(self.actionSelect_next_track)
|
|
||||||
self.menuPlaylist.addAction(self.actionSelect_previous_track)
|
|
||||||
self.menuPlaylist.addSeparator()
|
|
||||||
self.menuPlaylist.addAction(self.actionEnable_controls)
|
self.menuPlaylist.addAction(self.actionEnable_controls)
|
||||||
|
self.menuSearc_h.addAction(self.actionSearch)
|
||||||
|
self.menuSearc_h.addAction(self.actionFind_next)
|
||||||
|
self.menuSearc_h.addAction(self.actionFind_previous)
|
||||||
|
self.menuSearc_h.addSeparator()
|
||||||
|
self.menuSearc_h.addAction(self.actionSelect_next_track)
|
||||||
|
self.menuSearc_h.addAction(self.actionSelect_previous_track)
|
||||||
self.menubar.addAction(self.menuFile.menuAction())
|
self.menubar.addAction(self.menuFile.menuAction())
|
||||||
self.menubar.addAction(self.menuPlaylist.menuAction())
|
self.menubar.addAction(self.menuPlaylist.menuAction())
|
||||||
|
self.menubar.addAction(self.menuSearc_h.menuAction())
|
||||||
|
|
||||||
self.retranslateUi(MainWindow)
|
self.retranslateUi(MainWindow)
|
||||||
self.tabPlaylist.setCurrentIndex(-1)
|
self.tabPlaylist.setCurrentIndex(-1)
|
||||||
@ -514,6 +524,7 @@ class Ui_MainWindow(object):
|
|||||||
self.btnHidePlayed.setText(_translate("MainWindow", "Hide played"))
|
self.btnHidePlayed.setText(_translate("MainWindow", "Hide played"))
|
||||||
self.menuFile.setTitle(_translate("MainWindow", "P&laylists"))
|
self.menuFile.setTitle(_translate("MainWindow", "P&laylists"))
|
||||||
self.menuPlaylist.setTitle(_translate("MainWindow", "Sho&wtime"))
|
self.menuPlaylist.setTitle(_translate("MainWindow", "Sho&wtime"))
|
||||||
|
self.menuSearc_h.setTitle(_translate("MainWindow", "Searc&h"))
|
||||||
self.actionPlay_next.setText(_translate("MainWindow", "&Play next"))
|
self.actionPlay_next.setText(_translate("MainWindow", "&Play next"))
|
||||||
self.actionPlay_next.setShortcut(_translate("MainWindow", "Return"))
|
self.actionPlay_next.setShortcut(_translate("MainWindow", "Return"))
|
||||||
self.actionSkipToNext.setText(_translate("MainWindow", "Skip to &next"))
|
self.actionSkipToNext.setText(_translate("MainWindow", "Skip to &next"))
|
||||||
@ -560,5 +571,9 @@ class Ui_MainWindow(object):
|
|||||||
self.actionInsertSectionHeader.setText(_translate("MainWindow", "Insert §ion header..."))
|
self.actionInsertSectionHeader.setText(_translate("MainWindow", "Insert §ion header..."))
|
||||||
self.actionInsertSectionHeader.setShortcut(_translate("MainWindow", "Ctrl+H"))
|
self.actionInsertSectionHeader.setShortcut(_translate("MainWindow", "Ctrl+H"))
|
||||||
self.actionRemove.setText(_translate("MainWindow", "&Remove track"))
|
self.actionRemove.setText(_translate("MainWindow", "&Remove track"))
|
||||||
|
self.actionFind_next.setText(_translate("MainWindow", "Find next"))
|
||||||
|
self.actionFind_next.setShortcut(_translate("MainWindow", "N"))
|
||||||
|
self.actionFind_previous.setText(_translate("MainWindow", "Find previous"))
|
||||||
|
self.actionFind_previous.setShortcut(_translate("MainWindow", "P"))
|
||||||
from infotabs import InfoTabs
|
from infotabs import InfoTabs
|
||||||
import icons_rc
|
import icons_rc
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user