Skip to content

Commit

Permalink
Merge pull request #2463 from zas/itemviews_headers
Browse files Browse the repository at this point in the history
Itemviews headers refactoring
  • Loading branch information
zas committed May 11, 2024
2 parents a40a133 + f0d379a commit 92de44e
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 33 deletions.
2 changes: 1 addition & 1 deletion picard/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
PICARD_DISPLAY_NAME = "MusicBrainz Picard"
PICARD_APP_ID = "org.musicbrainz.Picard"
PICARD_DESKTOP_NAME = PICARD_APP_ID + ".desktop"
PICARD_VERSION = Version(3, 0, 0, 'dev', 3)
PICARD_VERSION = Version(3, 0, 0, 'dev', 4)


# optional build version
Expand Down
8 changes: 8 additions & 0 deletions picard/config_upgrade.py
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,14 @@ def upgrade_to_v3_0_0dev3(config):
rename_option(config, old_opt, new_opt, BoolOption, False)


def upgrade_to_v3_0_0dev4(config):
"""Reset "file/album_view_header_state" if there were saved while locked."""
if config.persist['album_view_header_locked']:
config.persist.remove('album_view_header_state')
if config.persist['file_view_header_locked']:
config.persist.remove('file_view_header_state')


def rename_option(config, old_opt, new_opt, option_type, default):
_s = config.setting
if old_opt in _s:
Expand Down
73 changes: 46 additions & 27 deletions picard/ui/itemviews.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@
ICON_SIZE = QtCore.QSize(COLUMN_ICON_SIZE+COLUMN_ICON_BORDER,
COLUMN_ICON_SIZE+COLUMN_ICON_BORDER)

DEFAULT_SECTION_SIZE = 100


def get_match_color(similarity, basecolor):
c1 = (basecolor.red(), basecolor.green(), basecolor.blue())
Expand Down Expand Up @@ -327,7 +329,7 @@ def __init__(self, parent=None):
# XXX it would be nice to be able to go to the 'no sort' mode, but the
# internal model that QTreeWidget uses doesn't support it
self.setSortIndicator(-1, QtCore.Qt.SortOrder.AscendingOrder)
self.setDefaultSectionSize(100)
self.setDefaultSectionSize(DEFAULT_SECTION_SIZE)

def show_column(self, column, show):
if column == 0: # The first column is fixed
Expand Down Expand Up @@ -396,24 +398,25 @@ def on_sort_indicator_changed(self, index, order):

def lock(self, is_locked):
super().lock(is_locked)
column_index = MainPanel.FINGERPRINT_COLUMN
if not self.is_locked and self.count() > column_index:
self.setSectionResizeMode(column_index, QtWidgets.QHeaderView.ResizeMode.Fixed)

def __str__(self):
name = getattr(self.parent(), 'NAME', str(self.parent().__class__.__name__))
return f"{name}'s header"


class BaseTreeView(QtWidgets.QTreeWidget):

def __init__(self, window, parent=None):
super().__init__(parent)
self.setAccessibleName(_(self.NAME))
self.setAccessibleDescription(_(self.DESCRIPTION))
self.tagger = QtCore.QCoreApplication.instance()
self.setHeader(ConfigurableColumnsHeader(self))
self.window = window
self.panel = parent
# Should multiple files dropped be assigned to tracks sequentially?
self._move_to_multi_tracks = True
self.setHeaderLabels([_(h) if n != '~fingerprint' else ''
for h, n in MainPanel.columns])
self.restore_state()

self._init_header()

self.setAcceptDrops(True)
self.setDragEnabled(True)
Expand Down Expand Up @@ -649,28 +652,42 @@ def _add_other_versions():
@restore_method
def restore_state(self):
config = get_config()
self._restore_state(config.persist[self.header_state])
self.header().lock(config.persist[self.header_locked])
self.restore_default_columns()

header_state = config.persist[self.header_state]
header = self.header()
if header_state and header.restoreState(header_state):
log.debug("Restoring state of %s" % header)
for i in range(0, self.columnCount()):
header.show_column(i, not self.isColumnHidden(i))

header.lock(config.persist[self.header_locked])

def save_state(self):
config = get_config()
config.persist[self.header_state] = self.header().saveState()
config.persist[self.header_locked] = self.header().is_locked
header = self.header()
if header.prelock_state is not None:
state = header.prelock_state
else:
state = header.saveState()
log.debug("Saving state of %s" % header)
config.persist[self.header_state] = state
config.persist[self.header_locked] = header.is_locked

def restore_default_columns(self):
self._restore_state(None)
labels = [_(h) if n != '~fingerprint' else '' for h, n in MainPanel.columns]
self.setHeaderLabels(labels)

def _restore_state(self, header_state):
header = self.header()
if header_state:
header.restoreState(header_state)
for i in range(0, self.columnCount()):
header.show_column(i, not self.isColumnHidden(i))
else:
header.update_visible_columns([0, 1, 2])
for i, size in enumerate([250, 50, 100]):
header.resizeSection(i, size)
self.sortByColumn(-1, QtCore.Qt.SortOrder.AscendingOrder)
header.update_visible_columns([0, 1, 2])
for i, size in enumerate([250, 50, 100]):
header.resizeSection(i, size)
self.sortByColumn(-1, QtCore.Qt.SortOrder.AscendingOrder)

def _init_header(self):
header = ConfigurableColumnsHeader(self)
self.setHeader(header)
self.restore_state()

def supportedDropActions(self):
return QtCore.Qt.DropAction.CopyAction | QtCore.Qt.DropAction.MoveAction
Expand Down Expand Up @@ -832,13 +849,14 @@ def default_drop_target(self):

class FileTreeView(BaseTreeView):

NAME = N_("file view")
DESCRIPTION = N_("Contains unmatched files and clusters")

header_state = 'file_view_header_state'
header_locked = 'file_view_header_locked'

def __init__(self, window, parent=None):
super().__init__(window, parent)
self.setAccessibleName(_("file view"))
self.setAccessibleDescription(_("Contains unmatched files and clusters"))
self.unmatched_files = ClusterItem(self.tagger.unclustered_files, False, self)
self.unmatched_files.update()
self.unmatched_files.setExpanded(True)
Expand Down Expand Up @@ -867,13 +885,14 @@ def default_drop_target(self):

class AlbumTreeView(BaseTreeView):

NAME = N_("album view")
DESCRIPTION = N_("Contains albums and matched files")

header_state = 'album_view_header_state'
header_locked = 'album_view_header_locked'

def __init__(self, window, parent=None):
super().__init__(window, parent)
self.setAccessibleName(_("album view"))
self.setAccessibleDescription(_("Contains albums and matched files"))
self.tagger.album_added.connect(self.add_album)
self.tagger.album_removed.connect(self.remove_album)

Expand Down
13 changes: 8 additions & 5 deletions picard/ui/widgets/tristatesortheaderview.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class TristateSortHeaderView(QtWidgets.QHeaderView):

def __init__(self, orientation, parent=None):
super().__init__(orientation, parent)
self.prelock_state = None

# Remember if resize / move event just happened
self._section_moved_or_resized = False
Expand Down Expand Up @@ -83,10 +84,12 @@ def mouseReleaseEvent(self, event):

def lock(self, is_locked):
self.is_locked = is_locked
self.setSectionsClickable(not is_locked)
self.setSectionsMovable(not is_locked)
if is_locked:
resize_mode = QtWidgets.QHeaderView.ResizeMode.Fixed
self.prelock_state = self.saveState()
self.setSectionResizeMode(QtWidgets.QHeaderView.ResizeMode.Fixed)
else:
resize_mode = QtWidgets.QHeaderView.ResizeMode.Interactive
self.setSectionResizeMode(resize_mode)
if self.prelock_state is not None:
self.restoreState(self.prelock_state)
self.prelock_state = None
self.setSectionsClickable(not is_locked)
self.setSectionsMovable(not is_locked)
22 changes: 22 additions & 0 deletions test/test_config_upgrade.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
upgrade_to_v2_7_0dev5,
upgrade_to_v2_8_0dev2,
upgrade_to_v3_0_0dev3,
upgrade_to_v3_0_0dev4,
)
from picard.const.defaults import (
DEFAULT_FILE_NAMING_FORMAT,
Expand Down Expand Up @@ -519,3 +520,24 @@ def test_upgrade_to_v3_0_0dev3(self):
upgrade_to_v3_0_0dev3(self.config)
self.assertNotIn('toolbar_multiselect', self.config.setting)
self.assertTrue(self.config.setting['allow_multi_dirs_selection'])

def test_upgrade_to_v3_0_0dev4(self):
Option('persist', 'album_view_header_state', QByteArray())
Option('persist', 'file_view_header_state', QByteArray())
BoolOption('persist', 'album_view_header_locked', False)
BoolOption('persist', 'file_view_header_locked', False)

self.config.persist['album_view_header_state'] = b'foo'
self.config.persist['file_view_header_state'] = b'bar'

# test not locked, states shouldn't be modified
upgrade_to_v3_0_0dev4(self.config)
self.assertEqual(b'foo', self.config.persist['album_view_header_state'])
self.assertEqual(b'bar', self.config.persist['file_view_header_state'])

# test locked, states should be removed
self.config.persist['album_view_header_locked'] = True
self.config.persist['file_view_header_locked'] = True
upgrade_to_v3_0_0dev4(self.config)
self.assertEqual(b'', self.config.persist['album_view_header_state'])
self.assertEqual(b'', self.config.persist['file_view_header_state'])

0 comments on commit 92de44e

Please sign in to comment.