diff --git a/app/log.py b/app/log.py index df8f3dc..85ee68e 100644 --- a/app/log.py +++ b/app/log.py @@ -85,7 +85,7 @@ def log_uncaught_exceptions(ex_cls, ex, tb): print("\033[1;31;47m") logging.critical(''.join(traceback.format_tb(tb))) print("\033[1;37;40m") - stackprinter.show(style="darkbg2") + stackprinter.show(style="lightbg") msg = stackprinter.format(ex) send_mail(Config.ERRORS_TO, Config.ERRORS_FROM, "Exception from musicmuster", msg) diff --git a/app/models.py b/app/models.py index 66adeee..7ecfccc 100644 --- a/app/models.py +++ b/app/models.py @@ -251,7 +251,7 @@ class Playlists(Base): id: int = Column(Integer, primary_key=True, autoincrement=True) name: str = Column(String(32), nullable=False, unique=True) last_used = Column(DateTime, default=None, nullable=True) - loaded = Column(Boolean, default=True, nullable=False) + tab = Column(Integer, default=False, nullable=True, unique=True) is_template = Column(Boolean, default=False, nullable=False) rows = relationship( "PlaylistRows", @@ -287,7 +287,7 @@ class Playlists(Base): def close(self, session: Session) -> None: """Mark playlist as unloaded""" - self.loaded = False + self.tab = None @classmethod def create_playlist_from_template(cls, @@ -310,7 +310,7 @@ class Playlists(Base): session.execute( select(cls) .filter(cls.is_template.is_(False)) - .order_by(cls.loaded.desc(), cls.last_used.desc()) + .order_by(cls.tab.desc(), cls.last_used.desc()) ) .scalars() .all() @@ -338,7 +338,7 @@ class Playlists(Base): session.execute( select(cls) .filter( - cls.loaded.is_(False), + cls.tab.is_(None), cls.is_template.is_(False) ) .order_by(cls.last_used.desc()) @@ -350,25 +350,45 @@ class Playlists(Base): @classmethod def get_open(cls, session: Session) -> List[Optional["Playlists"]]: """ - Return a list of playlists marked "loaded", ordered by loaded date. + Return a list of loaded playlists ordered by tab order. """ return ( session.execute( select(cls) - .where(cls.loaded.is_(True)) - .order_by(cls.last_used.desc()) + .where(cls.tab.is_not(None)) + .order_by(cls.tab) ) .scalars() .all() ) - def mark_open(self, session: Session) -> None: + def mark_open(self, session: Session, tab_index: int) -> None: """Mark playlist as loaded and used now""" - self.loaded = True + self.tab = tab_index self.last_used = datetime.now() + @staticmethod + def move_tab(session: Session, frm: int, to: int) -> None: + """Move tabs""" + + row_frm = session.execute( + select(Playlists) + .filter_by(tab=frm) + ).scalar_one() + + row_to = session.execute( + select(Playlists) + .filter_by(tab=to) + ).scalar_one() + + row_frm.tab = None + row_to.tab = None + session.commit() + row_to.tab = frm + row_frm.tab = to + @staticmethod def save_as_template(session: Session, playlist_id: int, template_name: str) -> None: diff --git a/app/musicmuster.py b/app/musicmuster.py index f19e82e..cc5864f 100755 --- a/app/musicmuster.py +++ b/app/musicmuster.py @@ -343,6 +343,11 @@ class Window(QMainWindow, Ui_MainWindow): if record.f_int != splitter_bottom: record.update(session, {'f_int': splitter_bottom}) + # Save current tab + record = Settings.get_int_settings(session, "active_tab") + record.update(session, + {'f_int': self.tabPlaylist.currentIndex()}) + event.accept() def close_playlist_tab(self) -> None: @@ -419,6 +424,8 @@ class Window(QMainWindow, Ui_MainWindow): self.tabPlaylist.currentChanged.connect( lambda: self.tabPlaylist.currentWidget().tab_visible()) self.tabPlaylist.tabCloseRequested.connect(self.close_tab) + self.tabBar = self.tabPlaylist.tabBar() + self.tabBar.tabMoved.connect(self.move_tab) self.txtSearch.returnPressed.connect(self.search_playlist_return) self.timer.timeout.connect(self.tick) @@ -442,10 +449,10 @@ class Window(QMainWindow, Ui_MainWindow): self.create_playlist_tab(session, playlist) def create_playlist_tab(self, session: Session, - playlist: Playlists) -> None: + playlist: Playlists) -> int: """ Take the passed playlist database object, create a playlist tab and - add tab to display. + add tab to display. Return index number of tab. """ playlist_tab = PlaylistTab( @@ -453,6 +460,8 @@ class Window(QMainWindow, Ui_MainWindow): idx = self.tabPlaylist.addTab(playlist_tab, playlist.name) self.tabPlaylist.setCurrentIndex(idx) + return idx + def cut_rows(self) -> None: """ Cut rows ready for pasting. @@ -759,8 +768,11 @@ class Window(QMainWindow, Ui_MainWindow): with Session() as session: for playlist in Playlists.get_open(session): - self.create_playlist_tab(session, playlist) - playlist.mark_open(session) + _ = self.create_playlist_tab(session, playlist) + # Set active tab + record = Settings.get_int_settings(session, "active_tab") + if record and record.f_int is not None: + self.tabPlaylist.setCurrentIndex(record.f_int) def move_playlist_rows(self, session: Session, playlistrows: List[PlaylistRows]) -> None: @@ -832,6 +844,12 @@ class Window(QMainWindow, Ui_MainWindow): self.visible_playlist_tab().get_selected_playlistrows(session) ) + def move_tab(self, frm: int, to: int) -> None: + """Handle tabs being moved""" + + with Session() as session: + Playlists.move_tab(session, frm, to) + def move_unplayed(self) -> None: """ Move unplayed rows to another playlist @@ -862,8 +880,8 @@ class Window(QMainWindow, Ui_MainWindow): return playlist = Playlists.create_playlist_from_template( session, template, playlist_name) - playlist.mark_open(session) - self.create_playlist_tab(session, playlist) + tab_index = self.create_playlist_tab(session, playlist) + playlist.mark_open(session, tab_index) def open_playlist(self): """Open existing playlist""" @@ -875,8 +893,8 @@ class Window(QMainWindow, Ui_MainWindow): dlg.exec() playlist = dlg.playlist if playlist: - playlist.mark_open(session) - self.create_playlist_tab(session, playlist) + tab_index = self.create_playlist_tab(session, playlist) + playlist.mark_open(session, tab_index) def paste_rows(self) -> None: """ diff --git a/migrations/versions/4a7b4ab3354f_record_tab_number_for_open_playlists.py b/migrations/versions/4a7b4ab3354f_record_tab_number_for_open_playlists.py new file mode 100644 index 0000000..de573c0 --- /dev/null +++ b/migrations/versions/4a7b4ab3354f_record_tab_number_for_open_playlists.py @@ -0,0 +1,32 @@ +"""Record tab number for open playlists + +Revision ID: 4a7b4ab3354f +Revises: 6730f03317df +Create Date: 2022-12-20 15:38:28.318280 + +""" +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import mysql + +# revision identifiers, used by Alembic. +revision = '4a7b4ab3354f' +down_revision = '6730f03317df' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('playlists', sa.Column('tab', sa.Integer(), nullable=True)) + op.create_unique_constraint(None, 'playlists', ['tab']) + op.drop_column('playlists', 'loaded') + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('playlists', sa.Column('loaded', mysql.TINYINT(display_width=1), autoincrement=False, nullable=False)) + op.drop_constraint(None, 'playlists', type_='unique') + op.drop_column('playlists', 'tab') + # ### end Alembic commands ###