"""Round 57: click an already-selected playlist to rename it. Clicking the selected playlist in the sidebar opens inline rename (Qt's SelectedClicked trigger), and renaming an existing playlist opens the editor with nothing selected and the cursor at the end rather than Qt's select-all. A brand-new playlist still selects all, so typing replaces "untitled playlist". """ from PyQt6.QtCore import Qt from PyQt6.QtTest import QTest from PyQt6.QtWidgets import ( QAbstractItemDelegate, QAbstractItemView, QApplication, QLineEdit, ) from lintunes.models import Library, Track from lintunes.library_manager import LibraryManager from lintunes.gui.sidebar import PlaylistTree SelectedClicked = QAbstractItemView.EditTrigger.SelectedClicked def _tree(qapp, tmp_path): library = Library(tracks={1: Track(track_id=1, name="One")}) manager = LibraryManager(library, tmp_path) tree = PlaylistTree(manager) playlist = manager.create_playlist("Road Trip") tree.resize(200, 300) tree.show() item = tree._find_item(playlist.persistent_id) tree.setCurrentItem(item) return tree, manager, playlist, item def _editor(tree, item): editor = tree.indexWidget(tree.indexFromItem(item, 0)) assert isinstance(editor, QLineEdit) return editor def test_selected_click_is_an_edit_trigger(qapp, tmp_path): tree, *_ = _tree(qapp, tmp_path) assert tree.editTriggers() & SelectedClicked # Qt's defaults survive alongside it. assert tree.editTriggers() & QAbstractItemView.EditTrigger.DoubleClicked assert tree.editTriggers() & QAbstractItemView.EditTrigger.EditKeyPressed def test_click_rename_puts_cursor_at_end(qapp, tmp_path): tree, _, _, item = _tree(qapp, tmp_path) center = tree.visualItemRect(item).center() # The row is already current; a real click on it arms Qt's delayed # editing, which opens the editor once the double-click interval passes. QTest.mouseClick(tree.viewport(), Qt.MouseButton.LeftButton, pos=center) QTest.qWait(QApplication.doubleClickInterval() + 100) editor = _editor(tree, item) assert editor.text() == "Road Trip" assert not editor.hasSelectedText() assert editor.cursorPosition() == len("Road Trip") def test_context_menu_rename_puts_cursor_at_end(qapp, tmp_path): tree, _, _, item = _tree(qapp, tmp_path) tree.editItem(item, 0) editor = _editor(tree, item) assert not editor.hasSelectedText() assert editor.cursorPosition() == len("Road Trip") def test_new_playlist_still_selects_all(qapp, tmp_path): tree, manager, _, _ = _tree(qapp, tmp_path) tree.create_playlist_interactive() item = tree.currentItem() editor = _editor(tree, item) assert editor.selectedText() == "untitled playlist" # The select-all is one-shot: the next rename is back to cursor-at-end. tree.closeEditor(editor, QAbstractItemDelegate.EndEditHint.NoHint) tree.editItem(item, 0) assert not _editor(tree, item).hasSelectedText() def test_non_matching_trigger_does_not_consume_select_all(qapp, tmp_path): tree, _, _, item = _tree(qapp, tmp_path) tree._select_all_next_edit = True tree.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers) assert not tree.edit(tree.indexFromItem(item, 0), SelectedClicked, None) assert tree._select_all_next_edit def test_committing_the_edit_renames(qapp, tmp_path): tree, manager, playlist, item = _tree(qapp, tmp_path) tree.editItem(item, 0) editor = _editor(tree, item) editor.insert(" 2026") tree.commitData(editor) assert manager.library.playlists[playlist.persistent_id].name == \ "Road Trip 2026" def test_first_click_only_selects(qapp, tmp_path): tree, manager, _, _ = _tree(qapp, tmp_path) other = manager.create_playlist("Other") item = tree._find_item(other.persistent_id) QTest.mouseClick(tree.viewport(), Qt.MouseButton.LeftButton, pos=tree.visualItemRect(item).center()) QTest.qWait(QApplication.doubleClickInterval() + 100) assert tree.currentItem() is item assert tree.indexWidget(tree.indexFromItem(item, 0)) is None