mirror of
https://github.com/fergalmoran/picard.git
synced 2026-01-08 01:26:28 +00:00
Save options to first enabled profile:
- Save to first enabled profile, with "User base settings" as fallback - Display note if any profiles are enabled - Highlight options for all enabled profiles - Add tooltip to options showing which profile will be updated - Update tests to remove deleted functionality
This commit is contained in:
@@ -46,10 +46,7 @@ from picard import (
|
||||
PICARD_VERSION,
|
||||
log,
|
||||
)
|
||||
from picard.profile import (
|
||||
USER_SETTINGS_PROFILE_ID,
|
||||
UserProfileGroups,
|
||||
)
|
||||
from picard.profile import UserProfileGroups
|
||||
from picard.version import Version
|
||||
|
||||
|
||||
@@ -152,21 +149,14 @@ class SettingConfigSection(ConfigSection):
|
||||
self.__prefix = self.__name + '/'
|
||||
self._memoization = defaultdict(Memovar)
|
||||
self.init_profile_options()
|
||||
self._selected_profile = None
|
||||
|
||||
def _get_active_profile_ids(self):
|
||||
if self._selected_profile is not None:
|
||||
if self._selected_profile == USER_SETTINGS_PROFILE_ID:
|
||||
return
|
||||
# Act as if the selected profile is the only active profile.
|
||||
yield self._selected_profile
|
||||
else:
|
||||
profiles = self.__qt_config.profiles[self.PROFILES_KEY]
|
||||
if profiles is None:
|
||||
return
|
||||
for profile in profiles:
|
||||
if profile['enabled']:
|
||||
yield profile["id"]
|
||||
profiles = self.__qt_config.profiles[self.PROFILES_KEY]
|
||||
if profiles is None:
|
||||
return
|
||||
for profile in profiles:
|
||||
if profile['enabled']:
|
||||
yield profile["id"]
|
||||
|
||||
def _get_active_profile_settings(self):
|
||||
for id in self._get_active_profile_ids():
|
||||
@@ -197,10 +187,9 @@ class SettingConfigSection(ConfigSection):
|
||||
if name in settings:
|
||||
self._save_profile_setting(id, name, value)
|
||||
return
|
||||
if self._selected_profile is None or self._selected_profile == USER_SETTINGS_PROFILE_ID:
|
||||
key = self.key(name)
|
||||
self.__qt_config.setValue(key, value)
|
||||
self._memoization[key].dirty = True
|
||||
key = self.key(name)
|
||||
self.__qt_config.setValue(key, value)
|
||||
self._memoization[key].dirty = True
|
||||
|
||||
def _save_profile_setting(self, profile_id, name, value):
|
||||
profile_settings = self.__qt_config.profiles[self.SETTINGS_KEY]
|
||||
@@ -209,9 +198,6 @@ class SettingConfigSection(ConfigSection):
|
||||
self.__qt_config.setValue(key, profile_settings)
|
||||
self._memoization[key].dirty = True
|
||||
|
||||
def set_profile(self, profile_id=None):
|
||||
self._selected_profile = profile_id
|
||||
|
||||
|
||||
class Config(QtCore.QSettings):
|
||||
|
||||
|
||||
@@ -27,9 +27,6 @@ from collections import (
|
||||
from picard import i18n # noqa: F401,E402 # pylint: disable=unused-import
|
||||
|
||||
|
||||
USER_SETTINGS_PROFILE_ID = 'user_settings'
|
||||
|
||||
|
||||
SettingDesc = namedtuple('SettingDesc', ('name', 'title', 'fields'))
|
||||
|
||||
|
||||
|
||||
@@ -45,10 +45,7 @@ from picard.config import (
|
||||
TextOption,
|
||||
get_config,
|
||||
)
|
||||
from picard.profile import (
|
||||
USER_SETTINGS_PROFILE_ID,
|
||||
UserProfileGroups,
|
||||
)
|
||||
from picard.profile import UserProfileGroups
|
||||
from picard.util import (
|
||||
restore_method,
|
||||
webbrowser2,
|
||||
@@ -193,19 +190,9 @@ class OptionsDialog(PicardDialog, SingletonDialog):
|
||||
self.first_enter = True
|
||||
self.installEventFilter(self)
|
||||
|
||||
self.USER_SETTINGS_TITLE = _("User base settings")
|
||||
|
||||
if config.profiles[SettingConfigSection.PROFILES_KEY]:
|
||||
self.ui.profile_frame.show()
|
||||
self.ui.save_to_profile.clear()
|
||||
self.ui.save_to_profile.addItem(self.USER_SETTINGS_TITLE, USER_SETTINGS_PROFILE_ID)
|
||||
index = 0
|
||||
for idx, item in enumerate(config.profiles[SettingConfigSection.PROFILES_KEY], start=1):
|
||||
self.ui.save_to_profile.addItem(item["title"], item["id"])
|
||||
if not index and item["enabled"]:
|
||||
index = idx
|
||||
self.ui.save_to_profile.currentIndexChanged.connect(self.switch_profile)
|
||||
self.ui.save_to_profile.setCurrentIndex(index)
|
||||
self.highlight_enabled_profile_options()
|
||||
else:
|
||||
self.ui.profile_frame.hide()
|
||||
|
||||
@@ -237,39 +224,31 @@ class OptionsDialog(PicardDialog, SingletonDialog):
|
||||
profile_dialog.activateWindow()
|
||||
|
||||
def _get_profile_title_from_id(self, profile_id):
|
||||
if profile_id == USER_SETTINGS_PROFILE_ID:
|
||||
return self.USER_SETTINGS_TITLE
|
||||
config = get_config()
|
||||
for item in config.profiles[SettingConfigSection.PROFILES_KEY]:
|
||||
if item["id"] == profile_id:
|
||||
return item["title"]
|
||||
return _('Unknown profile')
|
||||
|
||||
def switch_profile(self, index):
|
||||
def highlight_enabled_profile_options(self):
|
||||
config = get_config()
|
||||
if not config.profiles[SettingConfigSection.PROFILES_KEY]:
|
||||
return
|
||||
|
||||
self.ui.notice_text.hide()
|
||||
|
||||
HighlightColors = namedtuple('HighlightColors', ('fg', 'bg'))
|
||||
HIGHLIGHT_FMT = "#%s { color: %s; background-color: %s; }"
|
||||
if theme.is_dark_theme:
|
||||
option_colors = HighlightColors('#FFFFFF', '#000080')
|
||||
profile_colors = HighlightColors('#FFFFFF', '#300000')
|
||||
else:
|
||||
option_colors = HighlightColors('#000000', '#F9F906')
|
||||
profile_colors = HighlightColors('#000000', '#FFA500')
|
||||
|
||||
# Highlight profile selector if profile selected.
|
||||
if self.ui.save_to_profile.currentIndex():
|
||||
self.ui.save_to_profile.setStyleSheet(HIGHLIGHT_FMT % ('save_to_profile', profile_colors.fg, profile_colors.bg))
|
||||
else:
|
||||
self.ui.save_to_profile.setStyleSheet("")
|
||||
self.ui.notice_text.setStyleSheet(HIGHLIGHT_FMT % ("notice_text", option_colors.fg, option_colors.bg))
|
||||
self.ui.notice_text.setText(_("Highlighted options will be saved to a profile."))
|
||||
self.ui.notice_text.setToolTip(_("Hover your cursor over a highlighted option to see which profile will be updated."))
|
||||
|
||||
profile_id = self.ui.save_to_profile.currentData()
|
||||
profile_title = self._get_profile_title_from_id(profile_id)
|
||||
config = get_config()
|
||||
config.setting.set_profile(profile_id)
|
||||
settings = config.profiles[SettingConfigSection.SETTINGS_KEY]
|
||||
if profile_id in settings:
|
||||
profile_settings = settings[profile_id]
|
||||
else:
|
||||
profile_settings = {}
|
||||
|
||||
for page in self.pages:
|
||||
page.load()
|
||||
@@ -281,17 +260,24 @@ class OptionsDialog(PicardDialog, SingletonDialog):
|
||||
obj = getattr(page.ui, opt_field)
|
||||
except AttributeError:
|
||||
continue
|
||||
if opt.name in profile_settings:
|
||||
style = HIGHLIGHT_FMT % (opt_field, option_colors.fg, option_colors.bg)
|
||||
tooltip = _("This option is managed by profile: %s") % profile_title
|
||||
else:
|
||||
style = ""
|
||||
tooltip = ""
|
||||
try:
|
||||
obj.setStyleSheet(style)
|
||||
obj.setToolTip(tooltip)
|
||||
except AttributeError:
|
||||
pass
|
||||
for item in config.profiles[SettingConfigSection.PROFILES_KEY]:
|
||||
if item["enabled"]:
|
||||
profile_id = item["id"]
|
||||
profile_title = item["title"]
|
||||
if profile_id in settings:
|
||||
profile_settings = settings[profile_id]
|
||||
else:
|
||||
profile_settings = {}
|
||||
if opt.name in profile_settings:
|
||||
style = HIGHLIGHT_FMT % (opt_field, option_colors.fg, option_colors.bg)
|
||||
tooltip = _("This option will be saved to profile: %s") % profile_title
|
||||
try:
|
||||
obj.setStyleSheet(style)
|
||||
obj.setToolTip(tooltip)
|
||||
except AttributeError:
|
||||
pass
|
||||
self.ui.notice_text.show()
|
||||
break
|
||||
|
||||
def eventFilter(self, object, event):
|
||||
"""Process selected events.
|
||||
@@ -333,17 +319,6 @@ class OptionsDialog(PicardDialog, SingletonDialog):
|
||||
return url
|
||||
|
||||
def accept(self):
|
||||
profile_id = self.ui.save_to_profile.currentData()
|
||||
if profile_id and profile_id != USER_SETTINGS_PROFILE_ID:
|
||||
profile_name = self._get_profile_title_from_id(profile_id)
|
||||
message_box = QtWidgets.QMessageBox(self)
|
||||
message_box.setIcon(QtWidgets.QMessageBox.Warning)
|
||||
message_box.setWindowModality(QtCore.Qt.WindowModal)
|
||||
message_box.setWindowTitle(_("Save to Profile"))
|
||||
message_box.setText(_("Changes will only be saved to the profile: \"%s\"\n\nDo you want to continue?") % profile_name)
|
||||
message_box.setStandardButtons(QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.Cancel)
|
||||
if message_box.exec_() != QtWidgets.QMessageBox.Yes:
|
||||
return
|
||||
for page in self.pages:
|
||||
try:
|
||||
page.check()
|
||||
@@ -361,18 +336,8 @@ class OptionsDialog(PicardDialog, SingletonDialog):
|
||||
log.exception('Failed saving options page %r', page)
|
||||
self._show_page_error(page, e)
|
||||
return
|
||||
self.reset_profile()
|
||||
super().accept()
|
||||
|
||||
def reject(self):
|
||||
self.reset_profile()
|
||||
super().reject()
|
||||
|
||||
@staticmethod
|
||||
def reset_profile():
|
||||
config = get_config()
|
||||
config.setting.set_profile()
|
||||
|
||||
def _show_page_error(self, page, error):
|
||||
if not isinstance(error, OptionsCheckError):
|
||||
error = OptionsCheckError(_('Unexpected error'), str(error))
|
||||
@@ -462,7 +427,7 @@ class AttachedProfilesDialog(PicardDialog):
|
||||
window_title = _("Profiles Attached to Options in %s Section") % group_title
|
||||
self.setWindowTitle(window_title)
|
||||
|
||||
for name, title in group_options:
|
||||
for name, title, object_name in group_options:
|
||||
option_item = QtGui.QStandardItem(_(title))
|
||||
option_item.setEditable(False)
|
||||
row = [option_item]
|
||||
|
||||
@@ -39,25 +39,24 @@ class Ui_Dialog(object):
|
||||
self.profile_frame.setLineWidth(0)
|
||||
self.profile_frame.setObjectName("profile_frame")
|
||||
self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.profile_frame)
|
||||
self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0)
|
||||
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
|
||||
self.notice_text = QtWidgets.QLabel(self.profile_frame)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.notice_text.sizePolicy().hasHeightForWidth())
|
||||
self.notice_text.setSizePolicy(sizePolicy)
|
||||
font = QtGui.QFont()
|
||||
font.setPointSize(10)
|
||||
font.setBold(False)
|
||||
font.setWeight(50)
|
||||
self.notice_text.setFont(font)
|
||||
self.notice_text.setText("")
|
||||
self.notice_text.setObjectName("notice_text")
|
||||
self.horizontalLayout_2.addWidget(self.notice_text)
|
||||
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
|
||||
self.horizontalLayout_2.addItem(spacerItem)
|
||||
self.label = QtWidgets.QLabel(self.profile_frame)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.label.sizePolicy().hasHeightForWidth())
|
||||
self.label.setSizePolicy(sizePolicy)
|
||||
self.label.setObjectName("label")
|
||||
self.horizontalLayout_2.addWidget(self.label)
|
||||
self.save_to_profile = QtWidgets.QComboBox(self.profile_frame)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.save_to_profile.sizePolicy().hasHeightForWidth())
|
||||
self.save_to_profile.setSizePolicy(sizePolicy)
|
||||
self.save_to_profile.setObjectName("save_to_profile")
|
||||
self.horizontalLayout_2.addWidget(self.save_to_profile)
|
||||
self.profiles_buttonbox = QtWidgets.QDialogButtonBox(self.profile_frame)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
@@ -80,4 +79,3 @@ class Ui_Dialog(object):
|
||||
def retranslateUi(self, Dialog):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
Dialog.setWindowTitle(_("Options"))
|
||||
self.label.setText(_("Save settings to:"))
|
||||
|
||||
@@ -199,108 +199,6 @@ class TestUserProfiles(TestPicardProfilesCommon):
|
||||
self.assertEqual(self.config.setting[self.test_setting_1], False)
|
||||
self.assertEqual(self.config.setting[self.test_setting_2], 99)
|
||||
|
||||
# Test retrieval with profiles disabled and specific profile set
|
||||
self.config.profiles[self.PROFILES_KEY] = self.get_profiles(enabled=False)
|
||||
self.config.setting.set_profile("test_key_0")
|
||||
self.assertEqual(self.config.setting[self.test_setting_0], "def")
|
||||
self.assertEqual(self.config.setting[self.test_setting_1], True)
|
||||
self.assertEqual(self.config.setting[self.test_setting_2], 86)
|
||||
|
||||
# Test setting with profiles disabled and specific profile set
|
||||
self.config.setting[self.test_setting_0] = "jkl"
|
||||
|
||||
# Stack:
|
||||
# setting_0 setting_1 setting_2
|
||||
# --------- --------- ---------
|
||||
# test_key_0: jkl n/a n/a
|
||||
# test_key_1: n/a False n/a
|
||||
# test_key_2: n/a n/a 99
|
||||
# user_settings: ghi True 86
|
||||
|
||||
self.assertEqual(self.config.setting[self.test_setting_0], "jkl")
|
||||
self.assertEqual(self.config.setting[self.test_setting_1], True)
|
||||
self.assertEqual(self.config.setting[self.test_setting_2], 86)
|
||||
|
||||
# Test retrieval with profiles disabled and no specific profile set
|
||||
self.config.profiles[self.PROFILES_KEY] = self.get_profiles(enabled=False)
|
||||
self.config.setting.set_profile()
|
||||
self.assertEqual(self.config.setting[self.test_setting_0], "ghi")
|
||||
self.assertEqual(self.config.setting[self.test_setting_1], True)
|
||||
self.assertEqual(self.config.setting[self.test_setting_2], 86)
|
||||
|
||||
# Test retrieval with profiles enabled and no specific profile set
|
||||
self.config.profiles[self.PROFILES_KEY] = self.get_profiles(enabled=True)
|
||||
self.config.setting.set_profile()
|
||||
self.assertEqual(self.config.setting[self.test_setting_0], "jkl")
|
||||
self.assertEqual(self.config.setting[self.test_setting_1], False)
|
||||
self.assertEqual(self.config.setting[self.test_setting_2], 99)
|
||||
|
||||
# Test save with profiles disabled and specific profile set
|
||||
self.config.profiles[self.PROFILES_KEY] = self.get_profiles(enabled=False)
|
||||
self.config.setting.set_profile("test_key_2")
|
||||
self.config.setting[self.test_setting_0] = "xyz"
|
||||
self.config.setting[self.test_setting_2] = 1
|
||||
|
||||
# Stack:
|
||||
# setting_0 setting_1 setting_2
|
||||
# --------- --------- ---------
|
||||
# test_key_0: jkl n/a n/a
|
||||
# test_key_1: n/a False n/a
|
||||
# test_key_2: n/a n/a 1
|
||||
# user_settings: ghi True 86
|
||||
|
||||
self.assertEqual(self.config.setting[self.test_setting_0], "ghi")
|
||||
self.assertEqual(self.config.setting[self.test_setting_1], True)
|
||||
self.assertEqual(self.config.setting[self.test_setting_2], 1)
|
||||
self.config.setting.set_profile()
|
||||
self.assertEqual(self.config.setting[self.test_setting_0], "ghi")
|
||||
self.assertEqual(self.config.setting[self.test_setting_1], True)
|
||||
self.assertEqual(self.config.setting[self.test_setting_2], 86)
|
||||
|
||||
# Test save with profiles enabled and specific profile set
|
||||
self.config.profiles[self.PROFILES_KEY] = self.get_profiles(enabled=True)
|
||||
self.config.setting.set_profile("test_key_2")
|
||||
self.config.setting[self.test_setting_0] = "xyz"
|
||||
self.config.setting[self.test_setting_2] = 2
|
||||
|
||||
# Stack:
|
||||
# setting_0 setting_1 setting_2
|
||||
# --------- --------- ---------
|
||||
# test_key_0: jkl n/a n/a
|
||||
# test_key_1: n/a False n/a
|
||||
# test_key_2: n/a n/a 2
|
||||
# user_settings: ghi True 86
|
||||
|
||||
self.assertEqual(self.config.setting[self.test_setting_0], "ghi")
|
||||
self.assertEqual(self.config.setting[self.test_setting_1], True)
|
||||
self.assertEqual(self.config.setting[self.test_setting_2], 2)
|
||||
self.config.setting.set_profile()
|
||||
self.assertEqual(self.config.setting[self.test_setting_0], "jkl")
|
||||
self.assertEqual(self.config.setting[self.test_setting_1], False)
|
||||
self.assertEqual(self.config.setting[self.test_setting_2], 2)
|
||||
|
||||
# Test save with profiles enabled and "user_settings" profile set
|
||||
self.config.profiles[self.PROFILES_KEY] = self.get_profiles(enabled=True)
|
||||
self.config.setting.set_profile("user_settings")
|
||||
self.config.setting[self.test_setting_0] = "xyz"
|
||||
self.config.setting[self.test_setting_2] = 3
|
||||
|
||||
# Stack:
|
||||
# setting_0 setting_1 setting_2
|
||||
# --------- --------- ---------
|
||||
# test_key_0: jkl n/a n/a
|
||||
# test_key_1: n/a False n/a
|
||||
# test_key_2: n/a n/a 2
|
||||
# user_settings: xyz True 3
|
||||
|
||||
self.assertEqual(self.config.setting[self.test_setting_0], "xyz")
|
||||
self.assertEqual(self.config.setting[self.test_setting_1], True)
|
||||
self.assertEqual(self.config.setting[self.test_setting_2], 3)
|
||||
self.config.setting.set_profile()
|
||||
self.assertEqual(self.config.setting[self.test_setting_0], "jkl")
|
||||
self.assertEqual(self.config.setting[self.test_setting_1], False)
|
||||
self.assertEqual(self.config.setting[self.test_setting_2], 2)
|
||||
|
||||
def test_config_option_rename(self):
|
||||
from picard.config_upgrade import rename_option
|
||||
self.config.setting[self.test_setting_0] = "abc"
|
||||
|
||||
@@ -69,6 +69,38 @@
|
||||
<number>0</number>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="notice_text">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>10</pointsize>
|
||||
<weight>50</weight>
|
||||
<bold>false</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
@@ -82,29 +114,6 @@
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Save settings to:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="save_to_profile">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="profiles_buttonbox">
|
||||
<property name="sizePolicy">
|
||||
|
||||
Reference in New Issue
Block a user