From 8ac7014dfeea6f31cf5b7ec7325768b157da65bf Mon Sep 17 00:00:00 2001 From: Laurent Monin Date: Wed, 9 Apr 2014 12:08:02 +0200 Subject: [PATCH 01/11] Add `update_constants` command to setup.py It retrieves and parses attributes.pot and countries.pot files from transifex to extract various constants needed in Picard. It helps to keep those in sync with MusicBrainz website. It then generates: - picard/attributes.py containing cover art types, medium formats, and release group types - picard/countries.py containing countries `update_constants` command replaces `update_countries` --- .gitignore | 1 + .tx/config | 6 ++++ NEWS.txt | 2 +- po/attributes/.gitignore | 0 setup.py | 59 ++++++++++++++++++++++++++++++++++------ 5 files changed, 59 insertions(+), 9 deletions(-) create mode 100644 po/attributes/.gitignore diff --git a/.gitignore b/.gitignore index 20756da8a..4456c8063 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ locale *.exe .DS_Store po/countries/countries.pot +po/attributes/attributes.pot diff --git a/.tx/config b/.tx/config index c767707e5..405ed3983 100644 --- a/.tx/config +++ b/.tx/config @@ -12,3 +12,9 @@ file_filter = po/countries/.po source_file = po/countries/countries.pot source_lang = en type = PO + +[musicbrainz.attributes] +file_filter = po/attributes/.po +source_file = po/attributes/attributes.pot +source_lang = en +type = PO diff --git a/NEWS.txt b/NEWS.txt index 4395ea09c..c65e0c4c9 100644 --- a/NEWS.txt +++ b/NEWS.txt @@ -24,7 +24,6 @@ * Added "_artists_sort", "_albumartists", "_albumartists_sort" variables for scripts and plugins. * Made Picard use the country names also used on the MusicBrainz website (PICARD-205) * New setup.py command `get_po_files` (Retrieve po files from transifex) - * New setup.py command `update_countries` (Regenerate countries.py) * New setup.py command `regen_pot_file` (Regenerate po/picard.pot) * New Work tag (which for Classical music is often different from the track title) saved as ID3 TOAL tag. * New Composer Sort Order tag (variable %composersort%). @@ -38,6 +37,7 @@ * Show the ID3 version of the file in the Info... dialog (Ctrl-I) (PICARD-218) * Fixed a bug where Picard crashed if a MP3 file had malformed TRCK or TPOS tags (PICARD-112) * Add --files option to setup.py build_ui, used to force .ui to .py regeneration (PICARD-566) + * New setup.py command `update_constants` (Regenerate countries.py and attributes.py) diff --git a/po/attributes/.gitignore b/po/attributes/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/setup.py b/setup.py index 1236dc4ef..3cac6da50 100755 --- a/setup.py +++ b/setup.py @@ -424,8 +424,8 @@ def _get_option_name(obj): raise Exception("No such command class") -class picard_update_countries(Command): - description = "Regenerate countries.py" +class picard_update_constants(Command): + description = "Regenerate attributes.py and countries.py" user_options = [ ('skip-pull', None, "skip the tx pull steps"), ] @@ -443,22 +443,22 @@ class picard_update_countries(Command): from babel.messages import pofile - countries = dict() if not self.skip_pull: txpull_cmd = [ tx_executable, 'pull', '--force', - '--resource=musicbrainz.countries', + '--resource=musicbrainz.attributes,musicbrainz.countries', '--source', '--language=none', ] self.spawn(txpull_cmd) - potfile = os.path.join('po', 'countries', 'countries.pot') + countries = dict() + countries_potfile = os.path.join('po', 'countries', 'countries.pot') isocode_comment = u'iso.code:' - with open(potfile, 'rb') as f: - log.info('Parsing %s' % potfile) + with open(countries_potfile, 'rb') as f: + log.info('Parsing %s' % countries_potfile) po = pofile.read_po(f) for message in po: if not message.id or not isinstance(message.id, unicode): @@ -472,6 +472,28 @@ class picard_update_countries(Command): else: sys.exit('Failed to extract any country code/name !') + attributes = dict() + attributes_potfile = os.path.join('po', 'attributes', 'attributes.pot') + extract_attributes = ( + u'DB:cover_art_archive.art_type/name', + u'DB:medium_format/name', + u'DB:release_group_primary_type/name', + u'DB:release_group_secondary_type/name', + ) + with open(attributes_potfile, 'rb') as f: + log.info('Parsing %s' % attributes_potfile) + po = pofile.read_po(f) + for message in po: + if not message.id or not isinstance(message.id, unicode): + continue + for loc, pos in message.locations: + if loc in extract_attributes: + attributes[u"%s:%03d" % (loc,pos)] = message.id + if attributes: + self.attributes_py_file(attributes) + else: + sys.exit('Failed to extract any attribute !') + def countries_py_file(self, countries): header = (u"# -*- coding: utf-8 -*-\n" u"# Automatically generated - don't edit.\n" @@ -492,6 +514,26 @@ class picard_update_countries(Command): log.info("%s was rewritten (%d countries)" % (filename, len(countries))) + def attributes_py_file(self, attributes): + header = (u"# -*- coding: utf-8 -*-\n" + u"# Automatically generated - don't edit.\n" + u"# Use `python setup.py {option}` to update it.\n" + u"\n" + u"MB_ATTRIBUTES = {{\n") + line = u" u'{key}': u'{value}',\n" + footer = u"}}\n" + filename = os.path.join('picard', 'attributes.py') + with open(filename, 'w') as attributes_py: + def write_utf8(s, **kwargs): + attributes_py.write(s.format(**kwargs).encode('utf-8')) + + write_utf8(header, option=_get_option_name(self)) + for key, value in sorted(attributes.items(), key=lambda (k,v): k): + write_utf8(line, key=key, value=value.replace("'", "\\'")) + write_utf8(footer) + log.info("%s was rewritten (%d attributes)" % (filename, + len(attributes))) + def cflags_to_include_dirs(cflags): cflags = cflags.split() @@ -507,6 +549,7 @@ def _picard_get_locale_files(): path_domain = { 'po': 'picard', os.path.join('po', 'countries'): 'picard-countries', + os.path.join('po', 'attributes'): 'picard-attributes', } for path, domain in path_domain.iteritems(): for filepath in glob.glob(os.path.join(path, '*.po')): @@ -537,7 +580,7 @@ args2 = { 'clean_ui': picard_clean_ui, 'install': picard_install, 'install_locales': picard_install_locales, - 'update_countries': picard_update_countries, + 'update_constants': picard_update_constants, 'get_po_files': picard_get_po_files, 'regen_pot_file': picard_regen_pot_file, }, From 08fdb554141d4a91fe2d00239b66bdc00f053b58 Mon Sep 17 00:00:00 2001 From: Laurent Monin Date: Wed, 9 Apr 2014 12:10:18 +0200 Subject: [PATCH 02/11] Update picard/attributes.py and picard/countries.py New setup.py update_constants command was used. --- picard/attributes.py | 73 ++++++++++++++++++++++++++++++++++++++++++++ picard/countries.py | 2 +- 2 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 picard/attributes.py diff --git a/picard/attributes.py b/picard/attributes.py new file mode 100644 index 000000000..6a7419c70 --- /dev/null +++ b/picard/attributes.py @@ -0,0 +1,73 @@ +# -*- coding: utf-8 -*- +# Automatically generated - don't edit. +# Use `python setup.py update_constants` to update it. + +MB_ATTRIBUTES = { + u'DB:cover_art_archive.art_type/name:001': u'Front', + u'DB:cover_art_archive.art_type/name:002': u'Back', + u'DB:cover_art_archive.art_type/name:003': u'Booklet', + u'DB:cover_art_archive.art_type/name:004': u'Medium', + u'DB:cover_art_archive.art_type/name:005': u'Obi', + u'DB:cover_art_archive.art_type/name:006': u'Spine', + u'DB:cover_art_archive.art_type/name:007': u'Track', + u'DB:cover_art_archive.art_type/name:008': u'Other', + u'DB:cover_art_archive.art_type/name:009': u'Tray', + u'DB:cover_art_archive.art_type/name:010': u'Sticker', + u'DB:cover_art_archive.art_type/name:011': u'Poster', + u'DB:cover_art_archive.art_type/name:012': u'Liner', + u'DB:cover_art_archive.art_type/name:013': u'Watermark', + u'DB:medium_format/name:001': u'CD', + u'DB:medium_format/name:002': u'DVD', + u'DB:medium_format/name:003': u'SACD', + u'DB:medium_format/name:004': u'DualDisc', + u'DB:medium_format/name:005': u'LaserDisc', + u'DB:medium_format/name:006': u'MiniDisc', + u'DB:medium_format/name:007': u'Vinyl', + u'DB:medium_format/name:008': u'Cassette', + u'DB:medium_format/name:009': u'Cartridge', + u'DB:medium_format/name:010': u'Reel-to-reel', + u'DB:medium_format/name:011': u'DAT', + u'DB:medium_format/name:012': u'Digital Media', + u'DB:medium_format/name:013': u'Other', + u'DB:medium_format/name:014': u'Wax Cylinder', + u'DB:medium_format/name:015': u'Piano Roll', + u'DB:medium_format/name:016': u'DCC', + u'DB:medium_format/name:017': u'HD-DVD', + u'DB:medium_format/name:018': u'DVD-Audio', + u'DB:medium_format/name:019': u'DVD-Video', + u'DB:medium_format/name:020': u'Blu-ray', + u'DB:medium_format/name:021': u'VHS', + u'DB:medium_format/name:022': u'VCD', + u'DB:medium_format/name:023': u'SVCD', + u'DB:medium_format/name:024': u'Betamax', + u'DB:medium_format/name:025': u'HDCD', + u'DB:medium_format/name:026': u'USB Flash Drive', + u'DB:medium_format/name:027': u'slotMusic', + u'DB:medium_format/name:028': u'UMD', + u'DB:medium_format/name:029': u'7" Vinyl', + u'DB:medium_format/name:030': u'10" Vinyl', + u'DB:medium_format/name:031': u'12" Vinyl', + u'DB:medium_format/name:032': u'Videotape', + u'DB:medium_format/name:033': u'CD-R', + u'DB:medium_format/name:034': u'8cm CD', + u'DB:medium_format/name:035': u'Blu-spec CD', + u'DB:medium_format/name:036': u'SHM-CD', + u'DB:medium_format/name:037': u'HQCD', + u'DB:medium_format/name:038': u'Hybrid SACD', + u'DB:medium_format/name:039': u'CD+G', + u'DB:medium_format/name:040': u'8cm CD+G', + u'DB:release_group_primary_type/name:001': u'Album', + u'DB:release_group_primary_type/name:002': u'Single', + u'DB:release_group_primary_type/name:003': u'EP', + u'DB:release_group_primary_type/name:011': u'Other', + u'DB:release_group_primary_type/name:012': u'Broadcast', + u'DB:release_group_secondary_type/name:001': u'Compilation', + u'DB:release_group_secondary_type/name:002': u'Soundtrack', + u'DB:release_group_secondary_type/name:003': u'Spokenword', + u'DB:release_group_secondary_type/name:004': u'Interview', + u'DB:release_group_secondary_type/name:005': u'Audiobook', + u'DB:release_group_secondary_type/name:006': u'Live', + u'DB:release_group_secondary_type/name:007': u'Remix', + u'DB:release_group_secondary_type/name:008': u'DJ-mix', + u'DB:release_group_secondary_type/name:009': u'Mixtape/Street', +} diff --git a/picard/countries.py b/picard/countries.py index fa67a2835..64405ed41 100644 --- a/picard/countries.py +++ b/picard/countries.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # Automatically generated - don't edit. -# Use `python setup.py update_countries` to update it. +# Use `python setup.py update_constants` to update it. RELEASE_COUNTRIES = { u'AD': u'Andorra', From 490e24d24300c5152643ba45ed0a7c03331aacd2 Mon Sep 17 00:00:00 2001 From: Laurent Monin Date: Wed, 9 Apr 2014 12:13:52 +0200 Subject: [PATCH 03/11] Add ugettext_attr() function needed to translate attributes Since contexts are used in attributes.pot, and python gettext do not yet support contexts, a minor hack is used to make it work, this workaround is used in django and babel, see ugettext_ctxt(). --- picard/i18n.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/picard/i18n.py b/picard/i18n.py index 85161d0e5..755e440bc 100644 --- a/picard/i18n.py +++ b/picard/i18n.py @@ -72,6 +72,9 @@ def setup_gettext(localedir, ui_language=None, logger=None): logger("Loading gettext translation (picard-countries), localedir=%r", localedir) trans_countries = gettext.translation("picard-countries", localedir) _ugettext_countries = trans_countries.ugettext + logger("Loading gettext translation (picard-attributes), localedir=%r", localedir) + trans_attributes = gettext.translation("picard-attributes", localedir) + _ugettext_attributes = trans_attributes.ugettext except IOError as e: logger(e) __builtin__.__dict__['_'] = lambda a: a @@ -85,10 +88,38 @@ def setup_gettext(localedir, ui_language=None, logger=None): def _ugettext_countries(msg): return msg + def _ugettext_attributes(msg): + return msg + __builtin__.__dict__['ungettext'] = _ungettext __builtin__.__dict__['ugettext_countries'] = _ugettext_countries + __builtin__.__dict__['ugettext_attributes'] = _ugettext_attributes logger("_ = %r", _) logger("N_ = %r", N_) logger("ungettext = %r", ungettext) logger("ugettext_countries = %r", ugettext_countries) + logger("ugettext_attributes = %r", ugettext_attributes) + + +# Workaround for po files with msgctxt which isn't supported by current python +# gettext +# msgctxt are used within attributes.po, and ugettext is failing to translate +# strings due to that +# This workaround is a hack until we get proper msgctxt support +_CONTEXT_SEPARATOR = "\x04" +def ugettext_ctxt(ugettext_, message, context=None): + if context is None: + return ugettext_(message) + + msg_with_ctxt = u"%s%s%s" % (context, _CONTEXT_SEPARATOR, message) + translated = ugettext_(msg_with_ctxt) + if _CONTEXT_SEPARATOR in translated: + # no translation found, return original message + return message + return translated + + +def ugettext_attr(message, context=None): + """Translate MB attributes, depending on context""" + return ugettext_ctxt(ugettext_attributes, message, context) From a53164a5ee75252367a7f310b4abd81f1d6ccdff Mon Sep 17 00:00:00 2001 From: Laurent Monin Date: Wed, 9 Apr 2014 12:18:21 +0200 Subject: [PATCH 04/11] Build RELEASE_FORMATS and CAA_TYPES from MB_ATTRIBUTES --- picard/const.py | 41 +++++---------------------------------- picard/coverartarchive.py | 20 +++++++------------ 2 files changed, 12 insertions(+), 49 deletions(-) diff --git a/picard/const.py b/picard/const.py index efd9bc1e4..9ea72413b 100644 --- a/picard/const.py +++ b/picard/const.py @@ -63,42 +63,11 @@ PICARD_URLS = { VARIOUS_ARTISTS_ID = '89ad4ac3-39f7-470e-963a-56509c546377' # Release formats -RELEASE_FORMATS = { - u'CD': N_('CD'), - u'CD-R': N_('CD-R'), - u'HDCD': N_('HDCD'), - u'8cm CD': N_('8cm CD'), - u'Vinyl': N_('Vinyl'), - u'7" Vinyl': N_('7" Vinyl'), - u'10" Vinyl': N_('10" Vinyl'), - u'12" Vinyl': N_('12" Vinyl'), - u'Digital Media': N_('Digital Media'), - u'USB Flash Drive': N_('USB Flash Drive'), - u'slotMusic': N_('slotMusic'), - u'Cassette': N_('Cassette'), - u'DVD': N_('DVD'), - u'DVD-Audio': N_('DVD-Audio'), - u'DVD-Video': N_('DVD-Video'), - u'SACD': N_('SACD'), - u'DualDisc': N_('DualDisc'), - u'MiniDisc': N_('MiniDisc'), - u'Blu-ray': N_('Blu-ray'), - u'HD-DVD': N_('HD-DVD'), - u'Videotape': N_('Videotape'), - u'VHS': N_('VHS'), - u'Betamax': N_('Betamax'), - u'VCD': N_('VCD'), - u'SVCD': N_('SVCD'), - u'UMD': N_('UMD'), - u'Other': N_('Other'), - u'LaserDisc': N_('LaserDisc'), - u'Cartridge': N_('Cartridge'), - u'Reel-to-reel': N_('Reel-to-reel'), - u'DAT': N_('DAT'), - u'Wax Cylinder': N_('Wax Cylinder'), - u'Piano Roll': N_('Piano Roll'), - u'DCC': N_('DCC') -} +from picard.attributes import MB_ATTRIBUTES +RELEASE_FORMATS = {} +for k, v in MB_ATTRIBUTES.iteritems(): + if k.startswith(u'DB:medium_format/name:'): + RELEASE_FORMATS[v] = v # Release countries from picard.countries import RELEASE_COUNTRIES diff --git a/picard/coverartarchive.py b/picard/coverartarchive.py index 845932aa4..6721edfea 100644 --- a/picard/coverartarchive.py +++ b/picard/coverartarchive.py @@ -17,19 +17,13 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +from picard.attributes import MB_ATTRIBUTES # list of types from http://musicbrainz.org/doc/Cover_Art/Types # order of declaration is preserved in selection box -CAA_TYPES = [ - {'name': "front", 'title': N_("Front")}, - {'name': "back", 'title': N_("Back")}, - {'name': "booklet", 'title': N_("Booklet")}, - {'name': "medium", 'title': N_("Medium")}, - {'name': "tray", 'title': N_("Tray")}, - {'name': "obi", 'title': N_("Obi")}, - {'name': "spine", 'title': N_("Spine")}, - {'name': "track", 'title': N_("Track")}, - {'name': "sticker", 'title': N_("Sticker")}, - {'name': "other", 'title': N_("Other")}, - {'name': "unknown", 'title': N_("Unknown")}, # pseudo type, used for the no type case -] +CAA_TYPES = [] +for k, v in sorted(MB_ATTRIBUTES.items(), key=lambda (k,v): k): + if k.startswith(u'DB:cover_art_archive.art_type/name:'): + CAA_TYPES.append({'name': v.lower(), 'title': v}) + +CAA_TYPES.append({'name': "unknown", 'title': N_(u"Unknown")}) # pseudo type, used for the no type case From 175ed700b57b1e1cb13bbf91e8e8692caf496b7d Mon Sep 17 00:00:00 2001 From: Laurent Monin Date: Wed, 9 Apr 2014 12:18:59 +0200 Subject: [PATCH 05/11] Ensure proper translation of cover art types --- picard/ui/options/cover.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/picard/ui/options/cover.py b/picard/ui/options/cover.py index 83c4f9aa0..090e2e392 100644 --- a/picard/ui/options/cover.py +++ b/picard/ui/options/cover.py @@ -22,6 +22,7 @@ from picard import config from picard.ui.options import OptionsPage, register_options_page from picard.ui.ui_options_cover import Ui_CoverOptionsPage from picard.coverartarchive import CAA_TYPES +from picard.i18n import ugettext_attr class CAATypesSelector(object): @@ -39,7 +40,11 @@ class CAATypesSelector(object): def _add_item(self, typ, enabled=False): item = QtGui.QListWidgetItem(self.widget) - item.setText(typ['title']) + if typ['name'] == 'unknown': + title = _(typ['title']) + else: + title = ugettext_attr(typ['title'], u"cover_art_type") + item.setText(title) tooltip = u"CAA: %(name)s" % typ item.setToolTip(tooltip) if enabled: From e59fabda3f0a8d174ece36c60a061d8928439e16 Mon Sep 17 00:00:00 2001 From: Laurent Monin Date: Wed, 9 Apr 2014 12:20:12 +0200 Subject: [PATCH 06/11] Build RELEASE_PRIMARY_GROUPS and RELEASE_SECONDARY_GROUPS from MB_ATTRIBUTES --- picard/const.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/picard/const.py b/picard/const.py index 9ea72413b..e7f20e5e0 100644 --- a/picard/const.py +++ b/picard/const.py @@ -65,9 +65,15 @@ VARIOUS_ARTISTS_ID = '89ad4ac3-39f7-470e-963a-56509c546377' # Release formats from picard.attributes import MB_ATTRIBUTES RELEASE_FORMATS = {} +RELEASE_PRIMARY_GROUPS = {} +RELEASE_SECONDARY_GROUPS = {} for k, v in MB_ATTRIBUTES.iteritems(): if k.startswith(u'DB:medium_format/name:'): RELEASE_FORMATS[v] = v + elif k.startswith(u'DB:release_group_primary_type/name:'): + RELEASE_PRIMARY_GROUPS[v] = v + elif k.startswith(u'DB:release_group_secondary_type/name:'): + RELEASE_SECONDARY_GROUPS[v] = v # Release countries from picard.countries import RELEASE_COUNTRIES From 91cd68022e3c2fa2f56c4a8a987ced7a1abf7026 Mon Sep 17 00:00:00 2001 From: Laurent Monin Date: Wed, 9 Apr 2014 14:03:14 +0200 Subject: [PATCH 07/11] Build release type score sliders UI dynamically. --- picard/ui/options/releases.py | 115 ++++++++++++--- picard/ui/ui_options_releases.py | 119 ---------------- ui/options_releases.ui | 233 ------------------------------- 3 files changed, 96 insertions(+), 371 deletions(-) diff --git a/picard/ui/options/releases.py b/picard/ui/options/releases.py index 0b3726dab..e95808691 100644 --- a/picard/ui/options/releases.py +++ b/picard/ui/options/releases.py @@ -24,7 +24,65 @@ from picard import config from picard.util import load_release_type_scores, save_release_type_scores from picard.ui.options import OptionsPage, register_options_page from picard.ui.ui_options_releases import Ui_ReleasesOptionsPage -from picard.const import RELEASE_COUNTRIES, RELEASE_FORMATS +from picard.const import (RELEASE_COUNTRIES, + RELEASE_FORMATS, + RELEASE_PRIMARY_GROUPS, + RELEASE_SECONDARY_GROUPS) +from picard.i18n import ugettext_attr + + +_DEFAULT_SCORE = 0.5 +_release_type_scores = save_release_type_scores(dict([(g, _DEFAULT_SCORE) for g + in + RELEASE_PRIMARY_GROUPS.keys() + + + RELEASE_SECONDARY_GROUPS.keys()])) + + +class ReleaseTypeScore: + + def __init__(self, group, layout, label, cell): + row, column = cell #it uses 2 cells (r,c and r,c+1) + self.group = group + self.layout = layout + self.label = QtGui.QLabel(self.group) + self.label.setText(label) + self.layout.addWidget(self.label, row, column, 1, 1) + self.slider = QtGui.QSlider(self.group) + self.slider.setMaximum(100) + self.slider.setOrientation(QtCore.Qt.Horizontal) + self.layout.addWidget(self.slider, row, column + 1, 1, 1) + self.reset() + + def setValue(self, value): + self.slider.setValue(int(value * 100)) + + def value(self): + return float(self.slider.value()) / 100.0 + + def reset(self): + self.setValue(_DEFAULT_SCORE) + + +class RowColIter: + def __init__(self, max_cells, max_cols=6, step=2): + assert(max_cols % step == 0) + self.step = step + self.cols = max_cols + self.rows = int((max_cells - 1) / (self.cols / step)) + 1 + self.current = (-1, 0) + + def __iter__(self): + return self + + def next(self): + row, col = self.current + row += 1 + if row == self.rows: + col += self.step + row = 0 + self.current = (row, col) + return self.current class ReleasesOptionsPage(OptionsPage): @@ -36,29 +94,43 @@ class ReleasesOptionsPage(OptionsPage): ACTIVE = True options = [ - config.TextOption("setting", "release_type_scores", "Album 0.5 Single 0.5 EP 0.5 Compilation 0.5 Soundtrack 0.5 Spokenword 0.5 Interview 0.5 Audiobook 0.5 Live 0.5 Remix 0.5 Other 0.5"), + config.TextOption("setting", "release_type_scores", _release_type_scores), config.ListOption("setting", "preferred_release_countries", []), config.ListOption("setting", "preferred_release_formats", []), ] - _release_type_sliders = {} def __init__(self, parent=None): super(ReleasesOptionsPage, self).__init__(parent) self.ui = Ui_ReleasesOptionsPage() self.ui.setupUi(self) - self.ui.reset_preferred_types_btn.clicked.connect(self.reset_preferred_types) - self._release_type_sliders["Album"] = self.ui.prefer_album_score - self._release_type_sliders["Single"] = self.ui.prefer_single_score - self._release_type_sliders["EP"] = self.ui.prefer_ep_score - self._release_type_sliders["Compilation"] = self.ui.prefer_compilation_score - self._release_type_sliders["Soundtrack"] = self.ui.prefer_soundtrack_score - self._release_type_sliders["Spokenword"] = self.ui.prefer_spokenword_score - self._release_type_sliders["Interview"] = self.ui.prefer_interview_score - self._release_type_sliders["Audiobook"] = self.ui.prefer_audiobook_score - self._release_type_sliders["Live"] = self.ui.prefer_live_score - self._release_type_sliders["Remix"] = self.ui.prefer_remix_score - self._release_type_sliders["Other"] = self.ui.prefer_other_score + + self._release_type_sliders = {} + def add_slider(name, griditer, context): + label = ugettext_attr(name, context) + self._release_type_sliders[name] = \ + ReleaseTypeScore(self.ui.type_group, + self.ui.gridLayout, + label, + griditer.next()) + + griditer = RowColIter(len(RELEASE_PRIMARY_GROUPS) + + len(RELEASE_SECONDARY_GROUPS) + 1) # +1 for Reset button + for name in RELEASE_PRIMARY_GROUPS: + add_slider(name, griditer, context=u'release_group_primary_type') + for name in RELEASE_SECONDARY_GROUPS: + add_slider(name, griditer, context=u'release_group_secondary_type') + + self.reset_preferred_types_btn = QtGui.QPushButton(self.ui.type_group) + self.reset_preferred_types_btn.setText(_("Reset all")) + sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.reset_preferred_types_btn.sizePolicy().hasHeightForWidth()) + self.reset_preferred_types_btn.setSizePolicy(sizePolicy) + r, c = griditer.next() + self.ui.gridLayout.addWidget(self.reset_preferred_types_btn, r, c, 1, 2) + self.reset_preferred_types_btn.clicked.connect(self.reset_preferred_types) self.ui.add_countries.clicked.connect(self.add_preferred_countries) self.ui.remove_countries.clicked.connect(self.remove_preferred_countries) @@ -72,7 +144,8 @@ class ReleasesOptionsPage(OptionsPage): def load(self): scores = load_release_type_scores(config.setting["release_type_scores"]) for (release_type, release_type_slider) in self._release_type_sliders.iteritems(): - release_type_slider.setValue(int(scores.get(release_type, 0.5) * 100)) + release_type_slider.setValue(scores.get(release_type, + _DEFAULT_SCORE)) self._load_list_items("preferred_release_countries", RELEASE_COUNTRIES, self.ui.country_list, self.ui.preferred_country_list) @@ -82,7 +155,7 @@ class ReleasesOptionsPage(OptionsPage): def save(self): scores = {} for (release_type, release_type_slider) in self._release_type_sliders.iteritems(): - scores[release_type] = float(release_type_slider.value()) / 100.0 + scores[release_type] = release_type_slider.value() config.setting["release_type_scores"] = save_release_type_scores(scores) self._save_list_items("preferred_release_countries", self.ui.preferred_country_list) @@ -90,7 +163,7 @@ class ReleasesOptionsPage(OptionsPage): def reset_preferred_types(self): for release_type_slider in self._release_type_sliders.values(): - release_type_slider.setValue(50) + release_type_slider.reset() def add_preferred_countries(self): self._move_selected_items(self.ui.country_list, self.ui.preferred_country_list) @@ -114,7 +187,11 @@ class ReleasesOptionsPage(OptionsPage): def _load_list_items(self, setting, source, list1, list2): if setting == "preferred_release_countries": - source_list = [(c[0], ugettext_countries(c[1])) for c in source.items()] + source_list = [(c[0], ugettext_countries(c[1])) for c in + source.items()] + elif setting == "preferred_release_formats": + source_list = [(c[0], ugettext_attr(c[1], u"medium_format")) for c + in source.items()] else: source_list = [(c[0], _(c[1])) for c in source.items()] source_list.sort(key=itemgetter(1), cmp=strcoll) diff --git a/picard/ui/ui_options_releases.py b/picard/ui/ui_options_releases.py index caa8f85c4..650631cc3 100644 --- a/picard/ui/ui_options_releases.py +++ b/picard/ui/ui_options_releases.py @@ -21,113 +21,6 @@ class Ui_ReleasesOptionsPage(object): self.gridLayout = QtGui.QGridLayout(self.type_group) self.gridLayout.setVerticalSpacing(6) self.gridLayout.setObjectName(_fromUtf8("gridLayout")) - self.label = QtGui.QLabel(self.type_group) - self.label.setObjectName(_fromUtf8("label")) - self.gridLayout.addWidget(self.label, 0, 0, 1, 1) - self.prefer_album_score = QtGui.QSlider(self.type_group) - self.prefer_album_score.setMaximum(100) - self.prefer_album_score.setProperty("value", 50) - self.prefer_album_score.setOrientation(QtCore.Qt.Horizontal) - self.prefer_album_score.setObjectName(_fromUtf8("prefer_album_score")) - self.gridLayout.addWidget(self.prefer_album_score, 0, 1, 1, 1) - self.label_2 = QtGui.QLabel(self.type_group) - self.label_2.setObjectName(_fromUtf8("label_2")) - self.gridLayout.addWidget(self.label_2, 0, 2, 1, 1) - self.prefer_single_score = QtGui.QSlider(self.type_group) - self.prefer_single_score.setMaximum(100) - self.prefer_single_score.setProperty("value", 50) - self.prefer_single_score.setOrientation(QtCore.Qt.Horizontal) - self.prefer_single_score.setObjectName(_fromUtf8("prefer_single_score")) - self.gridLayout.addWidget(self.prefer_single_score, 0, 3, 1, 1) - self.label_3 = QtGui.QLabel(self.type_group) - self.label_3.setObjectName(_fromUtf8("label_3")) - self.gridLayout.addWidget(self.label_3, 0, 4, 1, 1) - self.prefer_ep_score = QtGui.QSlider(self.type_group) - self.prefer_ep_score.setMaximum(100) - self.prefer_ep_score.setProperty("value", 50) - self.prefer_ep_score.setOrientation(QtCore.Qt.Horizontal) - self.prefer_ep_score.setObjectName(_fromUtf8("prefer_ep_score")) - self.gridLayout.addWidget(self.prefer_ep_score, 0, 5, 1, 1) - self.label_7 = QtGui.QLabel(self.type_group) - self.label_7.setObjectName(_fromUtf8("label_7")) - self.gridLayout.addWidget(self.label_7, 1, 0, 1, 1) - self.prefer_compilation_score = QtGui.QSlider(self.type_group) - self.prefer_compilation_score.setMaximum(100) - self.prefer_compilation_score.setProperty("value", 50) - self.prefer_compilation_score.setOrientation(QtCore.Qt.Horizontal) - self.prefer_compilation_score.setObjectName(_fromUtf8("prefer_compilation_score")) - self.gridLayout.addWidget(self.prefer_compilation_score, 1, 1, 1, 1) - self.label_8 = QtGui.QLabel(self.type_group) - self.label_8.setObjectName(_fromUtf8("label_8")) - self.gridLayout.addWidget(self.label_8, 1, 2, 1, 1) - self.prefer_soundtrack_score = QtGui.QSlider(self.type_group) - self.prefer_soundtrack_score.setMaximum(100) - self.prefer_soundtrack_score.setProperty("value", 50) - self.prefer_soundtrack_score.setOrientation(QtCore.Qt.Horizontal) - self.prefer_soundtrack_score.setObjectName(_fromUtf8("prefer_soundtrack_score")) - self.gridLayout.addWidget(self.prefer_soundtrack_score, 1, 3, 1, 1) - self.label_9 = QtGui.QLabel(self.type_group) - self.label_9.setObjectName(_fromUtf8("label_9")) - self.gridLayout.addWidget(self.label_9, 1, 4, 1, 1) - self.prefer_spokenword_score = QtGui.QSlider(self.type_group) - self.prefer_spokenword_score.setMaximum(100) - self.prefer_spokenword_score.setProperty("value", 50) - self.prefer_spokenword_score.setOrientation(QtCore.Qt.Horizontal) - self.prefer_spokenword_score.setObjectName(_fromUtf8("prefer_spokenword_score")) - self.gridLayout.addWidget(self.prefer_spokenword_score, 1, 5, 1, 1) - self.label_10 = QtGui.QLabel(self.type_group) - self.label_10.setObjectName(_fromUtf8("label_10")) - self.gridLayout.addWidget(self.label_10, 2, 0, 1, 1) - self.prefer_interview_score = QtGui.QSlider(self.type_group) - self.prefer_interview_score.setMaximum(100) - self.prefer_interview_score.setProperty("value", 50) - self.prefer_interview_score.setOrientation(QtCore.Qt.Horizontal) - self.prefer_interview_score.setObjectName(_fromUtf8("prefer_interview_score")) - self.gridLayout.addWidget(self.prefer_interview_score, 2, 1, 1, 1) - self.label_11 = QtGui.QLabel(self.type_group) - self.label_11.setObjectName(_fromUtf8("label_11")) - self.gridLayout.addWidget(self.label_11, 2, 2, 1, 1) - self.prefer_audiobook_score = QtGui.QSlider(self.type_group) - self.prefer_audiobook_score.setMaximum(100) - self.prefer_audiobook_score.setProperty("value", 50) - self.prefer_audiobook_score.setOrientation(QtCore.Qt.Horizontal) - self.prefer_audiobook_score.setObjectName(_fromUtf8("prefer_audiobook_score")) - self.gridLayout.addWidget(self.prefer_audiobook_score, 2, 3, 1, 1) - self.label_12 = QtGui.QLabel(self.type_group) - self.label_12.setObjectName(_fromUtf8("label_12")) - self.gridLayout.addWidget(self.label_12, 2, 4, 1, 1) - self.prefer_live_score = QtGui.QSlider(self.type_group) - self.prefer_live_score.setMaximum(100) - self.prefer_live_score.setProperty("value", 50) - self.prefer_live_score.setOrientation(QtCore.Qt.Horizontal) - self.prefer_live_score.setObjectName(_fromUtf8("prefer_live_score")) - self.gridLayout.addWidget(self.prefer_live_score, 2, 5, 1, 1) - self.label_13 = QtGui.QLabel(self.type_group) - self.label_13.setObjectName(_fromUtf8("label_13")) - self.gridLayout.addWidget(self.label_13, 3, 0, 1, 1) - self.prefer_remix_score = QtGui.QSlider(self.type_group) - self.prefer_remix_score.setMaximum(100) - self.prefer_remix_score.setProperty("value", 50) - self.prefer_remix_score.setOrientation(QtCore.Qt.Horizontal) - self.prefer_remix_score.setObjectName(_fromUtf8("prefer_remix_score")) - self.gridLayout.addWidget(self.prefer_remix_score, 3, 1, 1, 1) - self.label_14 = QtGui.QLabel(self.type_group) - self.label_14.setObjectName(_fromUtf8("label_14")) - self.gridLayout.addWidget(self.label_14, 3, 2, 1, 1) - self.prefer_other_score = QtGui.QSlider(self.type_group) - self.prefer_other_score.setMaximum(100) - self.prefer_other_score.setSliderPosition(50) - self.prefer_other_score.setOrientation(QtCore.Qt.Horizontal) - self.prefer_other_score.setObjectName(_fromUtf8("prefer_other_score")) - self.gridLayout.addWidget(self.prefer_other_score, 3, 3, 1, 1) - self.reset_preferred_types_btn = QtGui.QPushButton(self.type_group) - sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.reset_preferred_types_btn.sizePolicy().hasHeightForWidth()) - self.reset_preferred_types_btn.setSizePolicy(sizePolicy) - self.reset_preferred_types_btn.setObjectName(_fromUtf8("reset_preferred_types_btn")) - self.gridLayout.addWidget(self.reset_preferred_types_btn, 4, 5, 1, 1) self.verticalLayout_3.addWidget(self.type_group) self.country_group = QtGui.QGroupBox(ReleasesOptionsPage) self.country_group.setObjectName(_fromUtf8("country_group")) @@ -209,18 +102,6 @@ class Ui_ReleasesOptionsPage(object): def retranslateUi(self, ReleasesOptionsPage): self.type_group.setTitle(_("Preferred release types")) - self.label.setText(_("Album")) - self.label_2.setText(_("Single")) - self.label_3.setText(_("EP")) - self.label_7.setText(_("Compilation")) - self.label_8.setText(_("Soundtrack")) - self.label_9.setText(_("Spokenword")) - self.label_10.setText(_("Interview")) - self.label_11.setText(_("Audiobook")) - self.label_12.setText(_("Live")) - self.label_13.setText(_("Remix")) - self.label_14.setText(_("Other")) - self.reset_preferred_types_btn.setText(_("Reset all")) self.country_group.setTitle(_("Preferred release countries")) self.add_countries.setText(_(">")) self.remove_countries.setText(_("<")) diff --git a/ui/options_releases.ui b/ui/options_releases.ui index f4a1de70f..2366b883e 100644 --- a/ui/options_releases.ui +++ b/ui/options_releases.ui @@ -20,239 +20,6 @@ 6 - - - - Album - - - - - - - 100 - - - 50 - - - Qt::Horizontal - - - - - - - Single - - - - - - - 100 - - - 50 - - - Qt::Horizontal - - - - - - - EP - - - - - - - 100 - - - 50 - - - Qt::Horizontal - - - - - - - Compilation - - - - - - - 100 - - - 50 - - - Qt::Horizontal - - - - - - - Soundtrack - - - - - - - 100 - - - 50 - - - Qt::Horizontal - - - - - - - Spokenword - - - - - - - 100 - - - 50 - - - Qt::Horizontal - - - - - - - Interview - - - - - - - 100 - - - 50 - - - Qt::Horizontal - - - - - - - Audiobook - - - - - - - 100 - - - 50 - - - Qt::Horizontal - - - - - - - Live - - - - - - - 100 - - - 50 - - - Qt::Horizontal - - - - - - - Remix - - - - - - - 100 - - - 50 - - - Qt::Horizontal - - - - - - - Other - - - - - - - 100 - - - 50 - - - Qt::Horizontal - - - - - - - - 0 - 0 - - - - Reset all - - - From a2a84ac8e68dd0ed13b7e0a8a4be40c24b2e6b20 Mon Sep 17 00:00:00 2001 From: Laurent Monin Date: Wed, 9 Apr 2014 14:09:10 +0200 Subject: [PATCH 08/11] Convert `release_type_scores` option to `ListOption` We had a space-separated list of name,value tuples ("Album 0.5 Other 0.4"), and two helper functions to load and save data in the correct format (`load_release_type_scores` and `save_release_type_scores`). Since option is converted to recently-introduced ListOption, data is now saved as a list of tuples, eventually converted to dict when needed. It simplifies code, and also prevents an issue if it comes we have a release group type with a space in its name. An upgrade hook was added to handle this change on Picard upgrade. --- picard/__init__.py | 2 +- picard/config_upgrade.py | 19 +++++++++++++++++++ picard/metadata.py | 3 +-- picard/ui/options/releases.py | 17 ++++++----------- picard/util/__init__.py | 16 ---------------- test/test_utils.py | 30 ------------------------------ 6 files changed, 27 insertions(+), 60 deletions(-) diff --git a/picard/__init__.py b/picard/__init__.py index 1f13df46f..8c0f42ada 100644 --- a/picard/__init__.py +++ b/picard/__init__.py @@ -22,7 +22,7 @@ import re PICARD_APP_NAME = "Picard" PICARD_ORG_NAME = "MusicBrainz" -PICARD_VERSION = (1, 3, 0, 'dev', 3) +PICARD_VERSION = (1, 3, 0, 'dev', 4) class VersionError(Exception): diff --git a/picard/config_upgrade.py b/picard/config_upgrade.py index 463999853..fac1f9184 100644 --- a/picard/config_upgrade.py +++ b/picard/config_upgrade.py @@ -118,10 +118,29 @@ def upgrade_to_v1_3_0_dev_3(): _s[opt] = _s.raw_value(opt).split(sep) +def upgrade_to_v1_3_0_dev_4(): + """Option "release_type_scores" is now a list of tuples + """ + def load_release_type_scores(setting): + scores = [] + values = setting.split() + for i in range(0, len(values), 2): + try: + score = float(values[i + 1]) + except IndexError: + score = 0.0 + scores.append((values[i], score)) + return scores + + opt = "release_type_scores" + _s[opt] = load_release_type_scores(_s.raw_value(opt)) + + def upgrade_config(): cfg = config._config cfg.register_upgrade_hook(upgrade_to_v1_0_0_final_0) cfg.register_upgrade_hook(upgrade_to_v1_3_0_dev_1) cfg.register_upgrade_hook(upgrade_to_v1_3_0_dev_2) cfg.register_upgrade_hook(upgrade_to_v1_3_0_dev_3) + cfg.register_upgrade_hook(upgrade_to_v1_3_0_dev_4) cfg.run_upgrade_hooks(log.debug) diff --git a/picard/metadata.py b/picard/metadata.py index e7af4d78f..c6bd757ab 100644 --- a/picard/metadata.py +++ b/picard/metadata.py @@ -32,7 +32,6 @@ from picard.plugin import ExtensionPoint from picard.similarity import similarity2 from picard.util import ( encode_filename, - load_release_type_scores, mimetype as mime, replace_non_ascii, replace_win32_incompat, @@ -288,7 +287,7 @@ class Metadata(dict): parts.append((score, weights["format"])) if "releasetype" in weights: - type_scores = load_release_type_scores(config.setting["release_type_scores"]) + type_scores = dict(config.setting["release_type_scores"]) if 'release_group' in release.children and 'type' in release.release_group[0].attribs: release_type = release.release_group[0].type score = type_scores.get(release_type, type_scores.get('Other', 0.5)) diff --git a/picard/ui/options/releases.py b/picard/ui/options/releases.py index e95808691..ca77576ce 100644 --- a/picard/ui/options/releases.py +++ b/picard/ui/options/releases.py @@ -21,7 +21,6 @@ from operator import itemgetter from locale import strcoll from PyQt4 import QtCore, QtGui from picard import config -from picard.util import load_release_type_scores, save_release_type_scores from picard.ui.options import OptionsPage, register_options_page from picard.ui.ui_options_releases import Ui_ReleasesOptionsPage from picard.const import (RELEASE_COUNTRIES, @@ -32,11 +31,7 @@ from picard.i18n import ugettext_attr _DEFAULT_SCORE = 0.5 -_release_type_scores = save_release_type_scores(dict([(g, _DEFAULT_SCORE) for g - in - RELEASE_PRIMARY_GROUPS.keys() - + - RELEASE_SECONDARY_GROUPS.keys()])) +_release_type_scores = [(g, _DEFAULT_SCORE) for g in RELEASE_PRIMARY_GROUPS.keys() + RELEASE_SECONDARY_GROUPS.keys()] class ReleaseTypeScore: @@ -94,7 +89,7 @@ class ReleasesOptionsPage(OptionsPage): ACTIVE = True options = [ - config.TextOption("setting", "release_type_scores", _release_type_scores), + config.ListOption("setting", "release_type_scores", _release_type_scores), config.ListOption("setting", "preferred_release_countries", []), config.ListOption("setting", "preferred_release_formats", []), ] @@ -142,7 +137,7 @@ class ReleasesOptionsPage(OptionsPage): self.ui.preferred_format_list.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection) def load(self): - scores = load_release_type_scores(config.setting["release_type_scores"]) + scores = dict(config.setting["release_type_scores"]) for (release_type, release_type_slider) in self._release_type_sliders.iteritems(): release_type_slider.setValue(scores.get(release_type, _DEFAULT_SCORE)) @@ -153,10 +148,10 @@ class ReleasesOptionsPage(OptionsPage): self.ui.format_list, self.ui.preferred_format_list) def save(self): - scores = {} + scores = [] for (release_type, release_type_slider) in self._release_type_sliders.iteritems(): - scores[release_type] = release_type_slider.value() - config.setting["release_type_scores"] = save_release_type_scores(scores) + scores.append((release_type, release_type_slider.value())) + config.setting["release_type_scores"] = scores self._save_list_items("preferred_release_countries", self.ui.preferred_country_list) self._save_list_items("preferred_release_formats", self.ui.preferred_format_list) diff --git a/picard/util/__init__.py b/picard/util/__init__.py index 5213f7a4a..f9545be73 100644 --- a/picard/util/__init__.py +++ b/picard/util/__init__.py @@ -267,22 +267,6 @@ def rot13(input): return u''.join(unichr(rot_13.encoding_map.get(ord(c), ord(c))) for c in input) -def load_release_type_scores(setting): - scores = {} - values = setting.split() - for i in range(0, len(values), 2): - try: - score = float(values[i + 1]) - except IndexError: - score = 0.0 - scores[values[i]] = score - return scores - - -def save_release_type_scores(scores): - return " ".join(["%s %.2f" % v for v in scores.iteritems()]) - - def parse_amazon_url(url): """Extract host and asin from an amazon url. It returns a dict with host and asin keys on success, None else diff --git a/test/test_utils.py b/test/test_utils.py index 13462a7a0..2b788f67c 100644 --- a/test/test_utils.py +++ b/test/test_utils.py @@ -92,36 +92,6 @@ class FormatTimeTest(unittest.TestCase): self.assertEqual("2:59", util.format_time(179499)) -class LoadReleaseTypeScoresTest(unittest.TestCase): - - def test_valid(self): - release_type_score_config = "Album 1.0 Single 0.5 EP 0.5 Compilation 0.5 Soundtrack 0.5 Spokenword 0.5 Interview 0.2 Audiobook 0.0 Live 0.5 Remix 0.4 Other 0.0" - release_type_scores = util.load_release_type_scores(release_type_score_config) - self.assertEqual(1.0, release_type_scores["Album"]) - self.assertEqual(0.5, release_type_scores["Single"]) - self.assertEqual(0.2, release_type_scores["Interview"]) - self.assertEqual(0.0, release_type_scores["Audiobook"]) - self.assertEqual(0.4, release_type_scores["Remix"]) - - def test_invalid(self): - release_type_score_config = "Album 1.0 Other" - release_type_scores = util.load_release_type_scores(release_type_score_config) - self.assertEqual(1.0, release_type_scores["Album"]) - self.assertEqual(0.0, release_type_scores["Other"]) - - -class SaveReleaseTypeScoresTest(unittest.TestCase): - - def test(self): - expected = "Album 1.00 Single 0.50 Other 0.00" - scores = {"Album": 1.0, "Single": 0.5, "Other": 0.0} - saved_scores = util.save_release_type_scores(scores) - self.assertTrue("Album 1.00" in saved_scores) - self.assertTrue("Single 0.50" in saved_scores) - self.assertTrue("Other 0.00" in saved_scores) - self.assertEqual(6, len(saved_scores.split())) - - class HiddenPathTest(unittest.TestCase): def test(self): From c2dc4df511005e8a179452d09034268c1a932095 Mon Sep 17 00:00:00 2001 From: Laurent Monin Date: Wed, 9 Apr 2014 14:26:06 +0200 Subject: [PATCH 09/11] Update NEWS.txt --- NEWS.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/NEWS.txt b/NEWS.txt index c65e0c4c9..ab3ce3930 100644 --- a/NEWS.txt +++ b/NEWS.txt @@ -38,6 +38,8 @@ * Fixed a bug where Picard crashed if a MP3 file had malformed TRCK or TPOS tags (PICARD-112) * Add --files option to setup.py build_ui, used to force .ui to .py regeneration (PICARD-566) * New setup.py command `update_constants` (Regenerate countries.py and attributes.py) + * Made Picard use release groups, medium formats and cover art types also used on the MusicBrainz website + * Use MusicBrainz Server translations for release groups, medium formats and cover art types From 68d424c2509ad67891540f80c43fb0fa3dc16a76 Mon Sep 17 00:00:00 2001 From: Laurent Monin Date: Thu, 10 Apr 2014 10:34:25 +0200 Subject: [PATCH 10/11] Make Cover Art Type selector use available space --- picard/ui/ui_options_cover.py | 3 +-- ui/options_cover.ui | 8 +------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/picard/ui/ui_options_cover.py b/picard/ui/ui_options_cover.py index 1da7c9db2..b82005bd0 100644 --- a/picard/ui/ui_options_cover.py +++ b/picard/ui/ui_options_cover.py @@ -83,12 +83,11 @@ class Ui_CoverOptionsPage(object): self.label_2.setObjectName(_fromUtf8("label_2")) self.verticalLayout_3.addWidget(self.label_2) self.caa_types_selector_1 = QtGui.QListWidget(self.gb_caa) - sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Preferred) + sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.caa_types_selector_1.sizePolicy().hasHeightForWidth()) self.caa_types_selector_1.setSizePolicy(sizePolicy) - self.caa_types_selector_1.setMaximumSize(QtCore.QSize(16777215, 80)) self.caa_types_selector_1.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded) self.caa_types_selector_1.setTabKeyNavigation(True) self.caa_types_selector_1.setProperty("showDropIndicator", False) diff --git a/ui/options_cover.ui b/ui/options_cover.ui index 457469153..5a0567326 100644 --- a/ui/options_cover.ui +++ b/ui/options_cover.ui @@ -162,17 +162,11 @@ - + 0 0 - - - 16777215 - 80 - - Qt::ScrollBarAsNeeded From cf529949899cf85b7e829a544091a328d0a1cd7b Mon Sep 17 00:00:00 2001 From: Laurent Monin Date: Thu, 10 Apr 2014 10:57:26 +0200 Subject: [PATCH 11/11] PEP8 fixes. --- picard/coverartarchive.py | 3 ++- picard/ui/options/releases.py | 15 ++++++++------- setup.py | 4 ++-- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/picard/coverartarchive.py b/picard/coverartarchive.py index 6721edfea..8ddeb3e51 100644 --- a/picard/coverartarchive.py +++ b/picard/coverartarchive.py @@ -26,4 +26,5 @@ for k, v in sorted(MB_ATTRIBUTES.items(), key=lambda (k,v): k): if k.startswith(u'DB:cover_art_archive.art_type/name:'): CAA_TYPES.append({'name': v.lower(), 'title': v}) -CAA_TYPES.append({'name': "unknown", 'title': N_(u"Unknown")}) # pseudo type, used for the no type case +# pseudo type, used for the no type case +CAA_TYPES.append({'name': "unknown", 'title': N_(u"Unknown")}) diff --git a/picard/ui/options/releases.py b/picard/ui/options/releases.py index ca77576ce..038242807 100644 --- a/picard/ui/options/releases.py +++ b/picard/ui/options/releases.py @@ -37,7 +37,7 @@ _release_type_scores = [(g, _DEFAULT_SCORE) for g in RELEASE_PRIMARY_GROUPS.keys class ReleaseTypeScore: def __init__(self, group, layout, label, cell): - row, column = cell #it uses 2 cells (r,c and r,c+1) + row, column = cell # it uses 2 cells (r,c and r,c+1) self.group = group self.layout = layout self.label = QtGui.QLabel(self.group) @@ -60,6 +60,7 @@ class ReleaseTypeScore: class RowColIter: + def __init__(self, max_cells, max_cols=6, step=2): assert(max_cols % step == 0) self.step = step @@ -94,23 +95,23 @@ class ReleasesOptionsPage(OptionsPage): config.ListOption("setting", "preferred_release_formats", []), ] - def __init__(self, parent=None): super(ReleasesOptionsPage, self).__init__(parent) self.ui = Ui_ReleasesOptionsPage() self.ui.setupUi(self) self._release_type_sliders = {} + def add_slider(name, griditer, context): label = ugettext_attr(name, context) self._release_type_sliders[name] = \ - ReleaseTypeScore(self.ui.type_group, - self.ui.gridLayout, - label, - griditer.next()) + ReleaseTypeScore(self.ui.type_group, + self.ui.gridLayout, + label, + griditer.next()) griditer = RowColIter(len(RELEASE_PRIMARY_GROUPS) + - len(RELEASE_SECONDARY_GROUPS) + 1) # +1 for Reset button + len(RELEASE_SECONDARY_GROUPS) + 1) # +1 for Reset button for name in RELEASE_PRIMARY_GROUPS: add_slider(name, griditer, context=u'release_group_primary_type') for name in RELEASE_SECONDARY_GROUPS: diff --git a/setup.py b/setup.py index 3cac6da50..f6751f389 100755 --- a/setup.py +++ b/setup.py @@ -488,7 +488,7 @@ class picard_update_constants(Command): continue for loc, pos in message.locations: if loc in extract_attributes: - attributes[u"%s:%03d" % (loc,pos)] = message.id + attributes[u"%s:%03d" % (loc, pos)] = message.id if attributes: self.attributes_py_file(attributes) else: @@ -532,7 +532,7 @@ class picard_update_constants(Command): write_utf8(line, key=key, value=value.replace("'", "\\'")) write_utf8(footer) log.info("%s was rewritten (%d attributes)" % (filename, - len(attributes))) + len(attributes))) def cflags_to_include_dirs(cflags):