Restore a few missing features

* Allow adding a new tag, or adding multiple values to an existing tag
* Add a "MusicBrainz Lookup" button to the toolbar
This commit is contained in:
Michael Wiencek
2012-01-30 00:48:01 -06:00
parent 0e38e82243
commit 2d4a4a8a4c
15 changed files with 594 additions and 250 deletions

View File

@@ -102,7 +102,7 @@ class Cluster(QtCore.QObject, Item):
def can_remove(self):
"""Return if this object can be removed."""
return True
return not self.special
def can_edit_tags(self):
"""Return if this object supports tag editing."""
@@ -118,6 +118,9 @@ class Cluster(QtCore.QObject, Item):
def can_refresh(self):
return False
def can_browser_lookup(self):
return not self.special
def column(self, column):
if column == 'title':
return '%s (%d)' % (self.metadata['album'], self.metadata['totaltracks'])
@@ -271,6 +274,12 @@ class UnmatchedFiles(Cluster):
def can_edit_tags(self):
return False
def can_analyze(self):
return len(self.files) > 0
def can_autotag(self):
return len(self.files) > 0
class ClusterList(list, Item):
"""A list of clusters."""
@@ -295,6 +304,9 @@ class ClusterList(list, Item):
def can_autotag(self):
return len(self) > 0
def can_browser_lookup(self):
return False
class ClusterDict(object):

View File

@@ -185,7 +185,6 @@ class File(LockableObject, Item):
self.orig_metadata['~length'] = format_time(length)
for k, v in temp_info.items():
self.orig_metadata[k] = v
self.metadata.changed = False
self.error = None
self.clear_pending()
return self, old_filename, new_filename

View File

@@ -38,7 +38,6 @@ class Metadata(object):
def __init__(self):
super(Metadata, self).__init__()
self._items = {}
self.changed = False
self.images = []
self.length = 0
@@ -197,7 +196,6 @@ class Metadata(object):
def __setitem__(self, name, value):
self.__set(name, value)
self.changed = True
def add(self, name, value):
if value or value == 0:
@@ -236,9 +234,6 @@ class Metadata(object):
def __delitem__(self, name):
del self._items[name]
def set_changed(self, changed=True):
self.changed = changed
def apply_func(self, func):
new = Metadata()
for key, values in self.rawitems():

View File

@@ -2,7 +2,7 @@
# Resource object code
#
# Created: Sat Dec 17 14:09:48 2011
# Created: Sun Jan 29 22:16:09 2012
# by: The Resource Compiler for PyQt (Qt v4.7.4)
#
# WARNING! All changes made in this file will be lost!
@@ -2228,6 +2228,155 @@ qt_resource_data = "\
\x3e\x60\xd9\x01\x60\x1b\x6e\xde\xfc\xbf\xe9\x22\x80\x57\x06\xfb\
\x74\xf5\xdb\x85\x7f\x01\xf6\xcb\xb9\xc0\xbf\x0a\x97\x37\x00\x00\
\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
\x00\x00\x09\x26\
\x89\
\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
\x00\x00\x16\x00\x00\x00\x16\x08\x06\x00\x00\x00\xc4\xb4\x6c\x3b\
\x00\x00\x03\x1e\x69\x43\x43\x50\x49\x43\x43\x20\x50\x72\x6f\x66\
\x69\x6c\x65\x00\x00\x78\x01\x85\x54\xdf\x6b\xd3\x50\x14\xfe\xda\
\x65\x9d\xb0\xe1\x8b\x3a\x67\x11\x09\x3e\x68\x91\x6e\x64\x53\x74\
\x43\x9c\xb6\x6b\x57\xba\xcd\x5a\xea\x36\xb7\x21\x48\x9b\xa6\x6d\
\x5c\x9a\xc6\x24\xed\x7e\xb0\x07\xd9\x8b\x6f\x3a\xc5\x77\xf1\x07\
\x3e\xf9\x07\x0c\xd9\x83\x6f\x7b\x92\x0d\xc6\x14\x61\xf8\xac\x88\
\x22\x4c\xf6\x22\xb3\x9e\x9b\x34\x4d\x27\x53\x03\xb9\xf7\xbb\xdf\
\xf9\xee\x39\x27\xe7\xe4\x5e\xa0\xf9\x71\x5a\xd3\x14\x2f\x0f\x14\
\x55\x53\x4f\xc5\xc2\xfc\xc4\xe4\x14\xdf\xf2\x01\x5e\x1c\x43\x2b\
\xfc\x68\x4d\x8b\x86\x16\x4a\x26\x47\x40\x0f\xd3\xb2\x79\xef\xb3\
\xf3\x0e\x1e\xc6\x6c\x74\xee\x6f\xdf\xab\xfe\x63\xd5\x9a\x95\x0c\
\x11\xf0\x1c\x20\xbe\x94\x35\xc4\x22\xe1\x59\xa0\x69\x5c\xd4\x74\
\x13\xe0\xd6\x89\xef\x9d\x31\x35\xc2\xcd\x4c\x73\x58\xa7\x04\x09\
\x1f\x67\x38\x6f\x63\x81\xe1\x8c\x8d\x23\x96\x66\x34\x35\x40\x9a\
\x09\xc2\x07\xc5\x42\x3a\x4b\xb8\x40\x38\x98\x69\xe0\xf3\x0d\xd8\
\xce\x81\x14\xe4\x27\x26\xa9\x92\x2e\x8b\x3c\xab\x45\x52\x2f\xe5\
\x64\x45\xb2\x0c\xf6\xf0\x1f\x73\x83\xf2\x5f\xb0\xa8\x94\xe9\x9b\
\xad\xe7\x10\x8d\x6d\x9a\x19\x4e\xd1\x7c\x8a\xde\x1f\x39\x7d\x70\
\x8c\xe6\x00\xd5\xc1\x3f\x5f\x18\xbd\x41\xb8\x9d\x70\x58\x36\xe3\
\xa3\x35\x7e\x42\xcd\x24\xae\x11\x26\xbd\xe7\xee\x74\x69\x98\xed\
\x65\x9a\x97\x59\x29\x12\x25\x1c\x24\xbc\x62\x54\xae\x33\x6c\x69\
\xe6\x0b\x03\x89\x9a\xe6\xd3\xed\xf4\x50\x92\xb0\x9f\x34\xbf\x34\
\x33\x59\xf3\xe3\xed\x50\x95\x04\xeb\x31\xc5\xf5\xf6\x4b\x46\xf4\
\xba\xbd\xd7\xdb\x91\x93\x07\xe3\x35\x3e\xa7\x29\xd6\x7f\x40\xfe\
\xbd\xf7\xf5\x72\x8a\xe5\x79\x92\xf0\xeb\xb4\x1e\x8d\xd5\xf4\x5b\
\x92\x3a\x56\xdb\xdb\xe4\xcd\xa6\x23\xc3\xc4\x77\x51\x3f\x03\x48\
\x42\x82\x8e\x1c\x64\x28\xe0\x91\x42\x0c\x61\x9a\x63\xc4\xaa\xf8\
\x4c\x16\x19\x22\x4a\xa4\xd2\x69\x74\x54\x79\xb2\x38\xd6\x3b\x28\
\x93\x96\xed\x1c\x47\x78\xc9\x5f\x0e\xb8\x5e\x16\xf5\x5b\xb2\xb8\
\xf6\xe0\xfb\x9e\xdd\x25\xd7\x8e\xbc\x15\x85\xc5\xb7\xa3\xd8\x51\
\xed\xb5\x81\xe9\xba\xb2\x13\x9a\x1b\x7f\x75\x61\xa5\xa3\x6e\xe1\
\x37\xb9\xe5\x9b\x1b\x6d\xab\x0b\x08\x51\xfe\x8a\xe5\xb1\x48\x5e\
\x65\xca\x4f\x82\x51\xd7\x75\x36\xe6\x90\x53\x97\xfc\x75\x0b\xcf\
\x32\x94\xee\x25\x76\x12\x58\x0c\xba\xac\xf0\x5e\xf8\x2a\x6c\x0a\
\x4f\x85\x17\xc2\x97\xbf\xd4\xc8\xce\xde\xad\x11\xcb\x80\x71\x2c\
\x3e\xab\x9e\x53\xcd\xc6\xec\x25\xd2\x4c\xd2\xeb\x64\xb8\xbf\x8a\
\xf5\x42\xc6\x18\xf9\x90\x31\x43\x5a\x9d\xbe\x24\x4d\x9c\x8a\x39\
\xf2\xda\x50\x0b\x27\x06\x77\x82\xeb\xe6\xe2\x5c\x2f\xd7\x07\x9e\
\xbb\xcc\x5d\xe1\xfa\xb9\x08\xad\x2e\x72\x23\x8e\xc2\x17\xf5\x45\
\x7c\x21\xf0\xbe\x33\xbe\x3e\x5f\xb7\x6f\x88\x61\xa7\xdb\xbe\xd3\
\x64\xeb\xa3\x31\x5a\xeb\xbb\xd3\x91\xba\xa2\xb1\x7a\x94\x8f\xdb\
\x27\xf6\x3d\x8e\xaa\x13\x19\xb2\xb1\xbe\xb1\x7e\x56\x08\x2b\xb4\
\xa2\x63\x6a\x4a\xb3\x74\x4f\x00\x03\x25\x6d\x4e\x97\xf3\x05\x93\
\xef\x11\x84\x0b\x7c\x88\xae\x2d\x89\x8f\xab\x62\x57\x90\x4f\x2b\
\x0a\x6f\x99\x0c\x5e\x97\x0c\x49\xaf\x48\xd9\x2e\xb0\x3b\x8f\xed\
\x03\xb6\x53\xd6\x5d\xe6\x69\x5f\x73\x39\xf3\x2a\x70\xe9\x1b\xfd\
\xc3\xeb\x2e\x37\x55\x06\x5e\x19\xc0\xd1\x73\x2e\x17\xa0\x33\x75\
\xe4\x09\xb0\x7c\x5e\x2c\xeb\x15\xdb\x1f\x3c\x9e\xb7\x80\x91\x3b\
\xdb\x63\xad\x3d\x6d\x61\xba\x8b\x3e\x56\xab\xdb\x74\x2e\x5b\x1e\
\x01\xbb\x0f\xab\xd5\x9f\xcf\xaa\xd5\xdd\xe7\xe4\x7f\x0b\x78\xa3\
\xfc\x06\xa9\x23\x0a\xd6\xc2\xa1\x5f\x32\x00\x00\x00\x09\x70\x48\
\x59\x73\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\x00\
\x00\x05\xae\x49\x44\x41\x54\x38\x11\x6d\x95\x5b\x6c\x14\x55\x18\
\xc7\xbf\x99\xd9\xd9\x76\x7b\xef\x96\xb6\xb4\xdd\xda\x0b\xb7\x4a\
\x29\xd1\x16\x22\x09\x18\x5a\x41\x0c\x22\x3c\x20\x4a\xa2\x81\xc8\
\x8b\x35\xe0\x83\x4f\x26\xbe\xd8\x16\x1f\x7c\xd0\x44\x89\x4f\x40\
\x14\x50\x8c\x5a\x49\x54\x88\x72\x69\xb5\x21\xa4\x09\x6d\x81\xde\
\xdc\x96\xde\xb7\xed\x6e\xf7\x3a\x9d\xdd\x99\xdd\xb9\xef\x1c\xbf\
\xd9\xd6\x4d\x51\x4e\xf2\x65\xce\x7c\xe7\xcc\xef\x7c\xdf\x77\xfe\
\xe7\x0c\x10\x42\xe0\x69\xd6\xde\xde\x63\x7b\x9a\x7f\xad\xaf\x93\
\x10\x06\xe0\x0d\x66\xad\xef\xdf\x3e\x65\x75\xd6\x36\x8a\xa2\x68\
\xf4\x51\xe8\x4b\x5a\x7e\x7c\x77\x96\x54\x1d\xab\xab\xdf\x5e\xe9\
\x2a\x2f\xcd\xb7\x53\x4a\x9c\x1f\xb8\x7a\x67\x7a\x02\x46\x26\x71\
\x5e\xea\xe3\x8e\x8e\x0e\x5b\x5b\x5b\x9b\xf1\x04\x67\x2d\x78\x15\
\x6a\xae\x02\xab\xbf\x38\x77\xf9\xdd\xca\xda\xea\x23\x65\x25\x85\
\x5b\x6a\x9e\xa9\xb0\x89\x92\x02\x7d\x6e\x2f\x04\x42\xcb\x9c\x6f\
\xc1\x7b\xff\xa7\x1b\xfd\x97\xfd\x8f\x2e\x5e\xb3\xe6\xff\x0f\x6e\
\x81\x57\xe1\x56\xa4\xa9\xfe\xe9\xd6\x8f\x8e\x5e\xbf\x7e\x67\x7e\
\x72\x3e\x4c\xa6\x42\x2a\x91\x0c\x1c\xc1\x36\xb3\x18\x24\xbf\xf6\
\x2d\x90\xab\xf7\xbc\xa4\x7b\x28\x40\x7e\xff\xb3\x9f\x7c\xf0\xe1\
\xe7\x57\x91\x5b\x84\xc3\xd0\xde\xde\x9e\x2e\x9f\x6d\x35\xba\x74\
\x49\xce\x9c\xf9\xf8\xe4\x6b\xc7\x0e\x5f\xa9\xad\xdf\x0e\xc4\xd4\
\x74\x55\x96\xc0\x17\x94\x99\x98\x20\x52\x51\x85\x00\x03\x26\xe4\
\xb2\x24\xe9\xcc\x48\x9a\x05\x9b\x2b\xed\xdb\xb6\x9c\x78\xbb\xc6\
\xe5\x74\x61\xb6\xaf\x23\x9c\x4b\x47\x6e\xad\xd4\xd3\xb3\xb2\x51\
\x00\x7b\x5f\x7c\x30\x30\x2c\xab\xe8\x9c\x8f\x28\x32\x1f\x13\xc8\
\xd4\x52\x8c\x4c\x86\x0d\x32\xea\x93\x49\xdf\x6c\x9c\xfc\x35\xec\
\x23\x43\x93\x5e\x32\x8b\xd1\x73\xbc\xa0\x4b\x09\x51\x9b\xf3\x2c\
\x90\xb3\x9f\x9c\xfb\xde\x62\x59\x66\x6d\x28\xda\xca\xae\xe2\x1b\
\xfb\xe3\xcf\x7f\x74\xe3\x80\xd5\x14\x4d\x91\xc8\xe3\xd9\x45\x32\
\x32\xcf\x93\x19\x9e\x90\x69\x2e\x49\xfa\x67\x45\xd2\x37\xc9\x11\
\x7f\x88\x23\x09\x49\x4e\x4d\x8c\x45\x79\xc3\xe3\x99\x23\xb7\xef\
\xf4\x90\x57\x0e\xbf\xf7\x26\x3a\x2d\x38\x63\x23\x9d\x9d\x96\x02\
\xe0\xc0\xc1\xf7\xf7\xef\x6c\xac\xdf\x67\xf5\x55\x45\xb6\xcd\xf8\
\x05\x30\x58\x27\x38\x1c\x0e\x30\x93\x26\x98\x26\x81\x24\x06\x93\
\x9f\x41\x81\x2f\x1c\x83\xbe\xf1\x00\x64\xdb\x29\xa8\x2c\xce\x61\
\x6c\x60\x68\x95\xae\x52\xfb\x81\xe6\xe7\x4e\x61\x49\xae\x21\x38\
\x49\x23\x27\x25\x93\xb7\x8e\xb7\xec\x73\x55\xba\x20\x9e\x90\x8d\
\xd1\xd9\x30\xc3\x9b\x39\x90\x95\x9d\x85\xc3\x04\x90\x09\x9a\x91\
\x04\x1d\xcd\x66\xa3\x61\xeb\x86\x72\x68\xac\x73\x01\x63\x77\x40\
\x80\x4b\x80\xaa\x6a\x8c\x20\x8a\x90\x9b\xe7\xd8\xe5\x74\x1e\xac\
\xb3\x82\xb3\xc0\x96\x56\xe9\x9a\xea\xb2\xad\x3e\x2e\x0e\x57\x7a\
\x66\xcc\xa9\x28\x03\x92\x4e\x40\x48\x68\xa0\xe9\x26\xa8\xba\x01\
\x7c\x5c\x85\x1c\x8c\xb0\xa6\x34\x17\x1c\x19\x76\xa8\x2c\xc9\x83\
\x96\xc6\x6a\xa8\x2e\xcb\x85\xc5\x00\x4f\x07\xc3\x3c\xf8\x97\x95\
\x82\x9d\xbb\x6b\x37\x59\xcc\x94\x2a\xf0\x99\xb9\x18\x14\x0b\x37\
\x36\xb0\xb0\x69\x7d\x0e\xb5\x20\x18\x90\xe4\x04\x10\xe2\x76\x28\
\xc8\x62\x81\xa6\x08\xc4\x12\x2a\x94\x96\x67\x81\x8d\x49\xc5\x82\
\x59\x60\x69\x0c\x1d\xcd\x00\x31\x2e\x03\xc7\xf1\xc4\xb7\xac\x51\
\x61\x99\x71\xae\x05\x9b\x13\x5e\x4e\xcf\x18\x0b\x81\xae\x88\xb0\
\xbd\xa2\x08\x4a\x8b\xf2\x60\xd8\xc3\x83\x7b\x3e\x06\x79\x0e\x1b\
\x88\x92\x06\x94\xa1\x40\x45\x01\x0b\x76\x1b\x05\x84\xa2\x21\x11\
\x4f\x20\x58\x83\xe2\x7c\x16\xfa\x06\xc3\xd4\x62\x44\x01\x57\x51\
\xa6\x96\x06\x63\xb1\x95\xf6\xcf\xbe\x5d\x44\x05\x40\x0c\x57\x7f\
\x09\x53\x2c\x75\xe6\x40\xbe\x83\x06\x6d\x28\x00\xee\xa5\x18\xe0\
\xee\x81\x3f\x1c\x85\xb9\x85\x00\x48\x92\x0c\x2f\x37\x3d\x03\xe5\
\x85\x2c\x88\x58\x5b\x21\x16\x23\xa1\xa8\x42\x59\x4a\xca\xd4\x64\
\xaf\x05\xb6\xf2\x4a\xa9\x22\xce\x85\xfb\x89\x14\x83\x75\xd9\x36\
\x26\x2b\x83\x4d\xdd\x01\x05\xb9\x59\x70\x74\x77\x0d\xec\xab\x2b\
\x80\x65\x5e\x80\xa8\x28\xc1\xfd\x69\x1e\xae\x0d\x47\x60\xc0\xbd\
\x08\xd1\x28\x0f\xa8\x63\x70\x4f\x2f\x25\xc7\xfd\x0a\x64\x33\xc9\
\xe9\x99\xae\x87\xe3\x29\x70\x6b\xeb\x85\x54\x9d\xbb\xbf\xfc\xee\
\xa6\xba\xec\x0f\x86\x05\x95\x1e\x1c\xf3\x18\x9a\x2a\x83\x2c\x2b\
\x40\xd3\xb8\x86\x9e\x00\x4f\x90\x87\x38\x66\x43\x61\xea\xf9\x74\
\x12\x4f\x23\x0f\x91\xc8\x32\xf0\xfc\x32\x08\x62\x1c\x0a\x33\xf1\
\x4c\xaa\xf2\x8d\x61\xb1\x37\x94\x02\x5f\xb8\xd0\x9a\xba\xc5\x86\
\x94\xa1\xc9\xa8\x77\xfa\x1b\xc6\x90\xe1\xfc\xad\x49\xa6\x7f\x70\
\xc2\x14\x62\xcb\x30\x37\xe7\x81\xde\xa1\x39\x88\x88\x6a\x0a\x10\
\x89\xc6\x21\x1c\x93\x52\xf5\x15\x84\x28\x78\x7d\x01\xcd\x1b\x96\
\x59\x4a\x11\x83\xbe\xbf\xdd\x5f\x5b\xd0\x96\x96\x0e\x9b\x75\x97\
\x12\x3c\xdf\x74\x73\x73\x33\x39\x72\x68\xef\x62\xdd\xe6\x86\x17\
\x98\x82\x0a\x57\x1e\xab\x99\x79\xac\x4c\xee\x0e\x4c\xd3\x3f\xf4\
\x73\xe0\x40\xfd\x26\xf0\x76\x53\x15\x0d\x6b\x9c\x00\x3d\x1e\x23\
\x65\xd9\x8a\x11\xe2\x13\xf6\xc7\x1e\x01\x42\xf3\xb3\x9f\x0e\x0d\
\xfe\x76\xeb\x2e\x45\x91\x9e\x4b\x6d\x46\xfa\xf2\xa9\xdb\xb3\x27\
\x77\xa2\xb7\x37\x1f\x17\xdc\x79\xf8\x54\xc7\xd9\xe3\xaf\xee\xda\
\x96\xcd\xaa\x70\xa9\x7b\xc1\xec\x8f\x50\xe6\x7a\xd6\xa4\x14\x5d\
\xc7\x52\xa8\x60\xea\x32\x14\xb0\x26\xf3\x7c\x55\x16\xf0\x5c\x14\
\x46\x47\xa6\xce\x8f\x3d\xfa\xe5\x62\x59\x4d\x4d\xc4\x3f\xc7\x04\
\x08\x99\x52\xd3\x60\x3c\x24\xb6\xda\xfa\xa6\xf2\x59\xf7\x43\x4b\
\x87\x75\xef\x9c\x3c\x7d\xc2\x51\x5c\xd5\xe2\xd7\xf3\x1d\x04\xf7\
\x57\x52\x10\x88\xf5\xa5\x89\x01\x2c\xfe\x03\x68\x94\x9e\xc0\x71\
\x9e\xb1\x91\xd1\x6b\x11\xef\xbd\xdb\xc5\xc5\xc5\x9c\x14\xa6\x96\
\x12\x10\x0a\x59\x55\x48\x83\xad\xda\x20\xdc\x5e\x5e\x5b\xbf\xde\
\x50\x7d\x85\x21\x5f\x74\x1d\xc0\x86\xc6\xfd\x87\xf6\xee\x60\x73\
\xf2\x37\xd2\x0c\x5b\x44\x4c\xc2\x24\x75\x5d\x52\x25\x71\x89\x0f\
\xfb\xdc\xc3\x0f\x6e\x0d\xe0\x67\x33\x25\x15\x15\x62\xc8\xa7\x05\
\x01\xc2\x61\x64\xae\xfc\x79\xb0\x63\x31\xd3\x0d\xe1\x94\xd3\xb9\
\x31\xb7\xa9\xa9\x26\xa7\xab\xab\x2b\x13\x07\x72\xd1\xac\x2c\xac\
\xa7\xa5\x20\x05\x0d\x85\x0d\x51\x34\xb9\xea\xd9\x26\x79\x7e\xfc\
\x61\x0c\x39\x12\xbe\xa7\xdb\x13\x11\xa7\xbd\xab\x9d\x1d\xad\xad\
\x6c\x49\x46\x06\x7d\xf3\xc6\x57\x14\x78\x56\xf4\x6e\x0d\x59\x1b\
\xed\x68\x68\x20\x39\x81\x80\xd1\xd9\xd9\x99\x8a\xf0\xbf\xdf\xfe\
\x03\x41\x9e\x9c\x5e\xe1\xf9\x56\x48\x00\x00\x00\x00\x49\x45\x4e\
\x44\xae\x42\x60\x82\
\x00\x00\x03\x54\
\x89\
\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
@@ -8923,6 +9072,11 @@ qt_resource_name = "\
\x00\x70\
\x00\x69\x00\x63\x00\x61\x00\x72\x00\x64\x00\x2d\x00\x73\x00\x75\x00\x62\x00\x6d\x00\x69\x00\x74\x00\x2e\x00\x70\x00\x6e\x00\x67\
\
\x00\x16\
\x08\x9b\xc7\x87\
\x00\x6c\
\x00\x6f\x00\x6f\x00\x6b\x00\x75\x00\x70\x00\x2d\x00\x6d\x00\x75\x00\x73\x00\x69\x00\x63\x00\x62\x00\x72\x00\x61\x00\x69\x00\x6e\
\x00\x7a\x00\x2e\x00\x70\x00\x6e\x00\x67\
\x00\x13\
\x06\x89\x11\xa7\
\x00\x70\
@@ -8958,8 +9112,8 @@ qt_resource_struct = "\
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x1a\x00\x00\x00\x02\
\x00\x00\x02\x2a\x00\x00\x00\x00\x00\x01\x00\x00\x57\x19\
\x00\x00\x02\x8c\x00\x02\x00\x00\x00\x0c\x00\x00\x00\x2e\
\x00\x00\x01\xce\x00\x02\x00\x00\x00\x0d\x00\x00\x00\x21\
\x00\x00\x02\x8c\x00\x02\x00\x00\x00\x0c\x00\x00\x00\x2f\
\x00\x00\x01\xce\x00\x02\x00\x00\x00\x0e\x00\x00\x00\x21\
\x00\x00\x00\x12\x00\x02\x00\x00\x00\x01\x00\x00\x00\x20\
\x00\x00\x00\xe0\x00\x02\x00\x00\x00\x01\x00\x00\x00\x1f\
\x00\x00\x00\xf0\x00\x02\x00\x00\x00\x01\x00\x00\x00\x1e\
@@ -8983,24 +9137,25 @@ qt_resource_struct = "\
\x00\x00\x01\xde\x00\x00\x00\x00\x00\x01\x00\x00\x55\x9d\
\x00\x00\x01\x6c\x00\x00\x00\x00\x00\x01\x00\x00\x52\x58\
\x00\x00\x01\x20\x00\x00\x00\x00\x00\x01\x00\x00\x50\xdf\
\x00\x00\x04\x42\x00\x00\x00\x00\x00\x01\x00\x00\xd1\xc6\
\x00\x00\x04\x42\x00\x00\x00\x00\x00\x01\x00\x01\xbd\x13\
\x00\x00\x04\x42\x00\x00\x00\x00\x00\x01\x00\x00\xb3\xe6\
\x00\x00\x04\x42\x00\x00\x00\x00\x00\x01\x00\x00\xc7\x79\
\x00\x00\x04\x42\x00\x00\x00\x00\x00\x01\x00\x02\x14\x50\
\x00\x00\x03\xcc\x00\x00\x00\x00\x00\x01\x00\x00\x91\xa6\
\x00\x00\x03\x60\x00\x00\x00\x00\x00\x01\x00\x00\x89\x8b\
\x00\x00\x05\xac\x00\x00\x00\x00\x00\x01\x00\x00\x9f\x5c\
\x00\x00\x05\xf8\x00\x00\x00\x00\x00\x01\x00\x00\xa7\x28\
\x00\x00\x04\x42\x00\x00\x00\x00\x00\x01\x00\x00\xda\xf0\
\x00\x00\x04\x42\x00\x00\x00\x00\x00\x01\x00\x01\xc6\x3d\
\x00\x00\x04\x42\x00\x00\x00\x00\x00\x01\x00\x00\xbd\x10\
\x00\x00\x04\x42\x00\x00\x00\x00\x00\x01\x00\x00\xd0\xa3\
\x00\x00\x04\x42\x00\x00\x00\x00\x00\x01\x00\x02\x1d\x7a\
\x00\x00\x03\xcc\x00\x00\x00\x00\x00\x01\x00\x00\x9a\xd0\
\x00\x00\x03\x60\x00\x00\x00\x00\x00\x01\x00\x00\x92\xb5\
\x00\x00\x05\xde\x00\x00\x00\x00\x00\x01\x00\x00\xa8\x86\
\x00\x00\x06\x2a\x00\x00\x00\x00\x00\x01\x00\x00\xb0\x52\
\x00\x00\x05\x00\x00\x00\x00\x00\x00\x01\x00\x00\x7f\xe4\
\x00\x00\x05\x5a\x00\x00\x00\x00\x00\x01\x00\x00\x8f\x5d\
\x00\x00\x04\x0e\x00\x00\x00\x00\x00\x01\x00\x00\xa3\x6c\
\x00\x00\x05\x28\x00\x00\x00\x00\x00\x01\x00\x00\x86\x33\
\x00\x00\x04\x0e\x00\x00\x00\x00\x00\x01\x00\x00\x9a\x42\
\x00\x00\x05\x82\x00\x00\x00\x00\x00\x01\x00\x00\x9c\x46\
\x00\x00\x03\xf4\x00\x00\x00\x00\x00\x01\x00\x00\x97\x1b\
\x00\x00\x04\x5c\x00\x00\x00\x00\x00\x01\x00\x00\xa9\xff\
\x00\x00\x05\x54\x00\x00\x00\x00\x00\x01\x00\x00\x8d\x78\
\x00\x00\x05\xd0\x00\x00\x00\x00\x00\x01\x00\x00\xa2\x31\
\x00\x00\x04\xb2\x00\x00\x00\x00\x00\x01\x00\x00\xaf\x64\
\x00\x00\x05\xb4\x00\x00\x00\x00\x00\x01\x00\x00\xa5\x70\
\x00\x00\x03\xf4\x00\x00\x00\x00\x00\x01\x00\x00\xa0\x45\
\x00\x00\x04\x5c\x00\x00\x00\x00\x00\x01\x00\x00\xb3\x29\
\x00\x00\x05\x86\x00\x00\x00\x00\x00\x01\x00\x00\x96\xa2\
\x00\x00\x06\x02\x00\x00\x00\x00\x00\x01\x00\x00\xab\x5b\
\x00\x00\x04\xb2\x00\x00\x00\x00\x00\x01\x00\x00\xb8\x8e\
\x00\x00\x03\xcc\x00\x00\x00\x00\x00\x01\x00\x00\x68\x62\
\x00\x00\x03\x60\x00\x00\x00\x00\x00\x01\x00\x00\x60\x89\
\x00\x00\x04\x0e\x00\x00\x00\x00\x00\x01\x00\x00\x6d\xff\

View File

@@ -88,7 +88,6 @@ from picard.webservice import XmlWebService
class Tagger(QtGui.QApplication):
file_state_changed = QtCore.pyqtSignal(int)
selected_metadata_changed = QtCore.pyqtSignal()
cluster_added = QtCore.pyqtSignal(Cluster)
cluster_removed = QtCore.pyqtSignal(Cluster)
album_added = QtCore.pyqtSignal(Album)

145
picard/ui/edittagdialog.py Normal file
View File

@@ -0,0 +1,145 @@
# -*- coding: utf-8 -*-
#
# Picard, the next-generation MusicBrainz tagger
# Copyright (C) 2011 Michael Wiencek
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
from PyQt4 import QtCore, QtGui
from picard.util.tags import TAG_NAMES
from picard.ui.ui_edittagdialog import Ui_EditTagDialog
class EditTagDialog(QtGui.QDialog):
def __init__(self, window, tag):
QtGui.QDialog.__init__(self, window)
self.ui = Ui_EditTagDialog()
self.ui.setupUi(self)
self.window = window
self.value_list = self.ui.value_list
self.metadata_box = window.metadata_box
self.tag = tag
self.modified_tags = {}
tag_names = self.ui.tag_names
tag_names.setCompleter(None)
tag_names.editTextChanged.connect(self.tag_changed)
self.default_tags = sorted(set(TAG_NAMES.keys() + self.metadata_box.tag_names))
tag_names.addItem("")
tag_names.addItems([tn for tn in self.default_tags if not tn.startswith("~")])
self.tag_changed(tag)
self.ui.edit_value.clicked.connect(self.edit_value)
self.ui.add_value.clicked.connect(self.add_value)
self.ui.remove_value.clicked.connect(self.remove_value)
self.value_list.itemChanged.connect(self.value_edited)
def edit_value(self):
item = self.value_list.currentItem()
if item:
self.value_list.editItem(item)
def add_value(self):
self._modified_tag().append("")
item = QtGui.QListWidgetItem()
item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsEditable)
self.value_list.addItem(item)
self.value_list.editItem(item)
def remove_value(self):
value_list = self.value_list
row = value_list.row(value_list.currentItem())
value_list.takeItem(row)
del self._modified_tag()[row]
def disable_all(self):
self.value_list.clear()
self.value_list.setEnabled(False)
self.ui.edit_value.setEnabled(False)
self.ui.add_value.setEnabled(False)
self.ui.remove_value.setEnabled(False)
def enable_all(self):
self.value_list.setEnabled(True)
self.ui.edit_value.setEnabled(True)
self.ui.add_value.setEnabled(True)
self.ui.remove_value.setEnabled(True)
def tag_changed(self, text):
tag_names = self.ui.tag_names
tag_names.editTextChanged.disconnect(self.tag_changed)
if self.value_list.count() == 0 and self.tag and self.tag not in self.default_tags:
tag_names.removeItem(tag_names.currentIndex())
row = tag_names.findText(text, QtCore.Qt.MatchFixedString)
if row == -1:
tag_names.addItem(text)
tag_names.setCurrentIndex(tag_names.count() - 1)
tag_names.model().sort(0)
else:
tag_names.setCurrentIndex(row)
self.tag = unicode(text)
if row == 0:
self.disable_all()
tag_names.editTextChanged.connect(self.tag_changed)
return
self.enable_all()
value_list = self.value_list
value_list.clear()
new_tags = self.metadata_box.new_tags
values = self.modified_tags.get(self.tag, [])
if not values:
different = new_tags.different_placeholder(self.tag)
if different:
item = QtGui.QListWidgetItem(different)
item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsEditable)
font = item.font()
font.setItalic(True)
item.setFont(font)
value_list.addItem(item)
else:
values = new_tags.get(self.tag, [""])[0]
for value in values:
if value:
item = QtGui.QListWidgetItem(value)
item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsEditable)
value_list.addItem(item)
value_list.setCurrentItem(value_list.item(0), QtGui.QItemSelectionModel.SelectCurrent)
tag_names.editTextChanged.connect(self.tag_changed)
def value_edited(self, item):
row = self.value_list.row(item)
self._modified_tag()[row] = unicode(item.text())
font = item.font()
font.setItalic(False)
item.setFont(font)
def _modified_tag(self):
return self.modified_tags.setdefault(self.tag,
list(self.metadata_box.new_tags.get(self.tag, [("")])[0]))
def accept(self):
self.window.ignore_selection_changes = True
for tag, values in self.modified_tags.items():
self.modified_tags[tag] = [v for v in values if v]
modified_tags = self.modified_tags.items()
for obj in self.metadata_box.objects:
for tag, values in modified_tags:
if values:
obj.metadata[tag] = values
else:
obj.metadata._items.pop(tag, None)
obj.update()
self.window.ignore_selection_changes = False
self.window.update_selection()
QtGui.QDialog.accept(self)

View File

@@ -45,3 +45,6 @@ class Item(object):
def can_view_info(self):
return False
def can_browser_lookup(self):
return True

View File

@@ -96,7 +96,7 @@ class MainPanel(QtGui.QSplitter):
self._ignore_selection_changes = False
self._selected_objects = set()
TreeItem.selected_metadata_changed = self.tagger.selected_metadata_changed
TreeItem.window = window
TreeItem.base_color = self.palette().base().color()
TreeItem.text_color = self.palette().text().color()
TrackItem.track_colors = {
@@ -551,7 +551,7 @@ class ClusterItem(TreeItem):
if self.obj.special and album and album.loaded:
album.item.update(update_tracks=False)
if self.isSelected():
TreeItem.selected_metadata_changed.emit()
TreeItem.window.update_selection()
def add_file(self, file):
self.add_files([file])
@@ -606,7 +606,7 @@ class AlbumItem(TreeItem):
for i, column in enumerate(MainPanel.columns):
self.setText(i, album.column(column[1]))
if self.isSelected():
TreeItem.selected_metadata_changed.emit()
TreeItem.window.update_selection()
class TrackItem(TreeItem):
@@ -650,7 +650,7 @@ class TrackItem(TreeItem):
self.setForeground(i, color)
self.setBackground(i, bgcolor)
if self.isSelected():
TreeItem.selected_metadata_changed.emit()
TreeItem.window.update_selection()
if update_album:
self.parent().update(update_tracks=False)
@@ -667,7 +667,7 @@ class FileItem(TreeItem):
self.setForeground(i, color)
self.setBackground(i, bgcolor)
if self.isSelected():
TreeItem.selected_metadata_changed.emit()
TreeItem.window.update_selection()
@staticmethod
def decide_file_icon(file):

View File

@@ -63,7 +63,7 @@ class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QMainWindow.__init__(self, parent)
self.selected_objects = []
self.tagger.selected_metadata_changed.connect(self.update_selection)
self.ignore_selection_changes = False
self.setupUi()
def setupUi(self):
@@ -301,6 +301,11 @@ class MainWindow(QtGui.QMainWindow):
self.remove_action.setEnabled(False)
self.connect(self.remove_action, QtCore.SIGNAL("triggered()"), self.remove)
self.browser_lookup_action = QtGui.QAction(icontheme.lookup('lookup-musicbrainz'), _(u"&MusicBrainz Lookup"), self)
self.browser_lookup_action.setStatusTip(_(u"Lookup selected item on MusicBrainz"))
self.browser_lookup_action.setEnabled(False)
self.browser_lookup_action.triggered.connect(self.browser_lookup)
self.show_file_browser_action = QtGui.QAction(_(u"File &Browser"), self)
self.show_file_browser_action.setCheckable(True)
if self.config.persist["view_file_browser"]:
@@ -484,6 +489,7 @@ class MainWindow(QtGui.QMainWindow):
toolbar.addAction(self.analyze_action)
toolbar.addAction(self.view_info_action)
toolbar.addAction(self.remove_action)
toolbar.addAction(self.browser_lookup_action)
self.search_toolbar = toolbar = self.addToolBar(_(u"&Search Bar"))
toolbar.setObjectName("search_toolbar")
search_panel = QtGui.QWidget(toolbar)
@@ -643,6 +649,9 @@ class MainWindow(QtGui.QMainWindow):
def refresh(self):
self.tagger.refresh(self.selected_objects)
def browser_lookup(self):
self.tagger.lookup(self.selected_objects[0].metadata)
def update_actions(self):
can_remove = False
can_save = False
@@ -650,6 +659,9 @@ class MainWindow(QtGui.QMainWindow):
can_refresh = False
can_autotag = False
can_view_info = False
can_browser_lookup = (
len(self.selected_objects) == 1 and
self.selected_objects[0].can_browser_lookup())
for obj in self.selected_objects:
if obj is None:
continue
@@ -674,9 +686,13 @@ class MainWindow(QtGui.QMainWindow):
self.analyze_action.setEnabled(can_analyze)
self.refresh_action.setEnabled(can_refresh)
self.autotag_action.setEnabled(can_autotag)
self.browser_lookup_action.setEnabled(can_browser_lookup)
self.cut_action.setEnabled(bool(self.selected_objects))
def update_selection(self, objects=None):
if self.ignore_selection_changes:
return
if objects is not None:
self.selected_objects = objects
else:

View File

@@ -24,44 +24,9 @@ from picard.cluster import Cluster
from picard.track import Track
from picard.file import File
from picard.config import TextOption
from picard.util import partial
from picard.util.tags import display_tag_name
from picard.ui.ui_edittagdialog import Ui_EditTagDialog
class EditTagDialog(QtGui.QDialog):
def __init__(self, parent, values):
QtGui.QDialog.__init__(self, parent)
self.ui = Ui_EditTagDialog()
self.ui.setupUi(self)
self.values = values
self.list = self.ui.value_list
for value in values[0]:
item = QtGui.QListWidgetItem(value)
item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsEditable)
self.list.addItem(item)
self.list.setCurrentItem(self.list.item(0), QtGui.QItemSelectionModel.SelectCurrent)
self.ui.add_value.clicked.connect(self.add_value)
self.ui.remove_value.clicked.connect(self.remove_value)
def add_value(self):
item = QtGui.QListWidgetItem()
item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsEditable)
self.list.addItem(item)
self.list.editItem(item)
def remove_value(self):
vals = self.list
vals.takeItem(vals.row(vals.currentItem()))
def accept(self):
values = []
for i in xrange(self.list.count()):
value = unicode(self.list.item(i).text())
if value:
values.append(value)
self.values[0] = tuple(values)
QtGui.QDialog.accept(self)
from picard.ui.edittagdialog import EditTagDialog
class TagCounter(dict):
@@ -69,30 +34,36 @@ class TagCounter(dict):
empty = [("",)]
def __init__(self):
self._counts = {}
self._different = set()
self.counts = {}
self.different = set()
self.objects = 0
def add(self, tag, values):
if tag not in self._different:
if tag not in self.different:
vals = self.setdefault(tag, set())
vals.add(tuple(sorted(values)))
if len(vals) > 1:
self._different.add(tag)
self.different.add(tag)
self[tag] = self.empty
self._counts[tag] = self._counts.get(tag, 0) + 1
def different(self, tag):
return tag in self._different
def count(self, tag):
return self._counts.get(tag, 0)
self.counts[tag] = self.counts.get(tag, 0) + 1
def clear(self):
dict.clear(self)
self._counts.clear()
self._different.clear()
self.counts.clear()
self.different.clear()
self.objects = 0
return self
def different_placeholder(self, tag):
count = self.counts.get(tag, 0)
missing = self.objects - count
if tag in self.different or (count > 0 and missing > 0):
if missing > 0:
return ungettext("(missing from %d item)", "(missing from %d items)", missing) % missing
else:
return _("(different across %d items)") % self.objects
return None
class MetadataBox(QtGui.QTableWidget):
@@ -120,7 +91,7 @@ class MetadataBox(QtGui.QTableWidget):
self.verticalHeader().setVisible(False)
self.setContentsMargins(0, 0, 0, 0)
self.setSelectionMode(QtGui.QAbstractItemView.SingleSelection)
self.setStyleSheet("border: none; font-size: 11px;")
self.setStyleSheet("border: none;")
self.itemChanged.connect(self.item_changed)
self._item_signals = True
self.colors = {
@@ -138,6 +109,8 @@ class MetadataBox(QtGui.QTableWidget):
self.updating = False
self.update_pending = False
self.selection_dirty = False
self.add_tag_action = QtGui.QAction(_(u"Add New Tag…"), parent)
self.add_tag_action.triggered.connect(partial(self.edit_tag, ""))
def edit(self, index, trigger, event):
if index.column() != 2:
@@ -149,17 +122,30 @@ class MetadataBox(QtGui.QTableWidget):
tag = self.tag_names[item.row()]
values = self.new_tags[tag]
if len(values) == 1 and len(values[0]) > 1:
dialog = EditTagDialog(self.parent, values)
if dialog.exec_():
self.set_item_value(item, values)
self._item_signals = False
self.set_row_colors(item.row())
self._item_signals = True
self.edit_tag(tag)
return False
else:
return QtGui.QTableWidget.edit(self, index, trigger, event)
return False
def contextMenuEvent(self, event):
item = self.itemAt(event.pos())
if not item:
return
menu = QtGui.QMenu(self)
tag = self.tag_names[item.row()]
if item.column() == 2 and tag != "~length":
edit_tag_action = QtGui.QAction(_(u"Edit “%s” Tag…") % tag, self.parent)
edit_tag_action.triggered.connect(partial(self.edit_tag, tag))
menu.addAction(edit_tag_action)
menu.addSeparator()
menu.addAction(self.add_tag_action)
menu.exec_(event.globalPos())
event.accept()
def edit_tag(self, tag):
EditTagDialog(self.parent, tag).exec_()
def update_selection(self):
self.selection_mutex.lock()
self.selection_dirty = True
@@ -210,7 +196,6 @@ class MetadataBox(QtGui.QTableWidget):
return None
orig_tags = self.orig_tags.clear()
new_tags = self.new_tags.clear()
orig_total = 0
for file in files:
for name, values in file.orig_metadata._items.iteritems():
@@ -219,20 +204,20 @@ class MetadataBox(QtGui.QTableWidget):
for name, values in file.metadata._items.iteritems():
if not name.startswith("~") or name == "~length":
new_tags.add(name, values)
orig_total += 1
orig_tags.objects += 1
new_total = orig_total
new_tags.objects = orig_tags.objects
for track in tracks:
if track.num_linked_files == 0:
for name, values in track.metadata._items.iteritems():
if not name.startswith("~") or name == "~length":
new_tags.add(name, values)
new_total += 1
new_tags.objects += 1
common_tags = MetadataBox.common_tags
all_tags = set(orig_tags.keys() + new_tags.keys())
self.tag_names = [t for t in common_tags if t in all_tags] + sorted(all_tags.difference(common_tags))
return (orig_total, new_total)
return True
def _update_items(self, result=None, error=None):
if result is None or error is not None:
@@ -246,14 +231,9 @@ class MetadataBox(QtGui.QTableWidget):
return
self._item_signals = False
orig_total, new_total = result
orig_tags = self.orig_tags
new_tags = self.new_tags
tag_names = self.tag_names
self.setRowCount(len(tag_names))
set_item_value = self.set_item_value
self.setRowCount(len(self.tag_names))
for i, name in enumerate(tag_names):
for i, name in enumerate(self.tag_names):
tag_item = self.item(i, 0)
if not tag_item:
tag_item = QtGui.QTableWidgetItem()
@@ -264,15 +244,12 @@ class MetadataBox(QtGui.QTableWidget):
self.setItem(i, 0, tag_item)
tag_item.setText(display_tag_name(name))
orig_values = orig_tags[name] = list(orig_tags.get(name, TagCounter.empty))
new_values = new_tags[name] = list(new_tags.get(name, TagCounter.empty))
orig_item = self.item(i, 1)
if not orig_item:
orig_item = QtGui.QTableWidgetItem()
orig_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
self.setItem(i, 1, orig_item)
set_item_value(orig_item, orig_values, orig_tags.different(name), orig_tags.count(name), orig_total)
self.set_item_value(orig_item, self.orig_tags, name)
new_item = self.item(i, 2)
if not new_item:
@@ -280,7 +257,7 @@ class MetadataBox(QtGui.QTableWidget):
self.setItem(i, 2, new_item)
if name == "~length":
new_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
set_item_value(new_item, new_values, new_tags.different(name), new_tags.count(name), new_total)
self.set_item_value(new_item, self.new_tags, name)
self.set_row_colors(i)
self._item_signals = True
@@ -288,14 +265,12 @@ class MetadataBox(QtGui.QTableWidget):
if self.update_pending:
self.update()
def set_item_value(self, item, values, different=False, count=0, total=0):
def set_item_value(self, item, tags, name):
values = tags[name] = list(tags.get(name, TagCounter.empty))
font = item.font()
missing = total - count
if different or (count > 0 and missing > 0):
if missing > 0:
item.setText(ungettext("(missing from %d item)", "(missing from %d items)", missing) % missing)
else:
item.setText(_("(different across %d items)") % total)
different = tags.different_placeholder(name)
if different:
item.setText(different)
font.setItalic(True)
else:
value = values[0]
@@ -307,29 +282,25 @@ class MetadataBox(QtGui.QTableWidget):
item.setFont(font)
def set_row_colors(self, row):
orig_item = self.item(row, 1)
new_item = self.item(row, 2)
tag = self.tag_names[row]
orig_values = self.orig_tags[tag]
new_values = self.new_tags[tag]
orig_blank = orig_values == TagCounter.empty and not self.orig_tags.different(tag)
new_blank = new_values == TagCounter.empty and not self.new_tags.different(tag)
orig_values, new_values = self.orig_tags[tag], self.new_tags[tag]
orig_blank = orig_values == TagCounter.empty and not tag in self.orig_tags.different
new_blank = new_values == TagCounter.empty and not tag in self.new_tags.different
if new_blank and not orig_blank:
orig_item.setForeground(self.colors["removed"])
self.item(row, 1).setForeground(self.colors["removed"])
elif orig_blank and not new_blank:
new_item.setForeground(self.colors["added"])
self.item(row, 2).setForeground(self.colors["added"])
elif not (orig_blank or new_blank) and orig_values != new_values:
orig_item.setForeground(self.colors["changed"])
new_item.setForeground(self.colors["changed"])
self.item(row, 1).setForeground(self.colors["changed"])
self.item(row, 2).setForeground(self.colors["changed"])
else:
orig_item.setForeground(self.colors["default"])
new_item.setForeground(self.colors["default"])
self.item(row, 1).setForeground(self.colors["default"])
self.item(row, 2).setForeground(self.colors["default"])
def item_changed(self, item):
if not self._item_signals:
return
self._item_signals = False
self.tagger.selected_metadata_changed.disconnect(self.parent.update_selection)
tag = self.tag_names[item.row()]
values = self.new_tags[tag]
if len(values) == 1 and len(values[0]) > 1:
@@ -337,15 +308,20 @@ class MetadataBox(QtGui.QTableWidget):
value = list(values[0])
else:
value = unicode(item.text())
new_values = self.new_tags[tag] = [(value,)]
self.new_tags[tag] = [(value,)]
self.new_tags.different.discard(tag)
font = item.font()
font.setItalic(False)
item.setFont(font)
self.set_row_colors(item.row())
self.parent.ignore_selection_changes = True
for obj in self.objects:
obj.metadata[tag] = value
if value:
obj.metadata._items[tag] = [value]
else:
obj.metadata._items.pop(tag, None)
obj.update()
self.tagger.selected_metadata_changed.connect(self.parent.update_selection)
self.parent.ignore_selection_changes = False
self._item_signals = True
def restore_state(self):

View File

@@ -2,36 +2,47 @@
# Form implementation generated from reading ui file 'ui/edittagdialog.ui'
#
# Created: Fri Dec 16 23:07:11 2011
# by: PyQt4 UI code generator 4.8.5
# Created: Mon Dec 19 04:18:13 2011
# by: PyQt4 UI code generator 4.7.3
#
# WARNING! All changes made in this file will be lost!
from PyQt4 import QtCore, QtGui
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
_fromUtf8 = lambda s: s
class Ui_EditTagDialog(object):
def setupUi(self, EditTagDialog):
EditTagDialog.setObjectName(_fromUtf8("EditTagDialog"))
EditTagDialog.setObjectName("EditTagDialog")
EditTagDialog.setWindowModality(QtCore.Qt.ApplicationModal)
EditTagDialog.resize(436, 240)
EditTagDialog.resize(400, 250)
EditTagDialog.setFocusPolicy(QtCore.Qt.StrongFocus)
EditTagDialog.setWindowTitle(_("Edit tag"))
EditTagDialog.setWindowTitle("")
EditTagDialog.setModal(True)
self.verticalLayout = QtGui.QVBoxLayout(EditTagDialog)
self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
self.verticalLayout_2 = QtGui.QVBoxLayout(EditTagDialog)
self.verticalLayout_2.setObjectName("verticalLayout_2")
self.tag_names = QtGui.QComboBox(EditTagDialog)
self.tag_names.setEditable(True)
self.tag_names.setObjectName("tag_names")
self.verticalLayout_2.addWidget(self.tag_names)
self.horizontalLayout = QtGui.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
self.value_list = QtGui.QListWidget(EditTagDialog)
self.value_list.setFocusPolicy(QtCore.Qt.StrongFocus)
self.value_list.setTabKeyNavigation(False)
self.value_list.setProperty("showDropIndicator", False)
self.value_list.setObjectName(_fromUtf8("value_list"))
self.verticalLayout.addWidget(self.value_list)
self.horizontalLayout = QtGui.QHBoxLayout()
self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout"))
self.value_list.setObjectName("value_list")
self.horizontalLayout.addWidget(self.value_list)
self.verticalLayout = QtGui.QVBoxLayout()
self.verticalLayout.setObjectName("verticalLayout")
self.edit_value = QtGui.QPushButton(EditTagDialog)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(100)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.edit_value.sizePolicy().hasHeightForWidth())
self.edit_value.setSizePolicy(sizePolicy)
self.edit_value.setMinimumSize(QtCore.QSize(100, 0))
self.edit_value.setAutoDefault(False)
self.edit_value.setObjectName("edit_value")
self.verticalLayout.addWidget(self.edit_value)
self.add_value = QtGui.QPushButton(EditTagDialog)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(100)
@@ -39,10 +50,9 @@ class Ui_EditTagDialog(object):
sizePolicy.setHeightForWidth(self.add_value.sizePolicy().hasHeightForWidth())
self.add_value.setSizePolicy(sizePolicy)
self.add_value.setMinimumSize(QtCore.QSize(100, 0))
self.add_value.setText(_("Add value"))
self.add_value.setAutoDefault(False)
self.add_value.setObjectName(_fromUtf8("add_value"))
self.horizontalLayout.addWidget(self.add_value)
self.add_value.setObjectName("add_value")
self.verticalLayout.addWidget(self.add_value)
self.remove_value = QtGui.QPushButton(EditTagDialog)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(120)
@@ -50,12 +60,13 @@ class Ui_EditTagDialog(object):
sizePolicy.setHeightForWidth(self.remove_value.sizePolicy().hasHeightForWidth())
self.remove_value.setSizePolicy(sizePolicy)
self.remove_value.setMinimumSize(QtCore.QSize(120, 0))
self.remove_value.setText(_("Remove value"))
self.remove_value.setAutoDefault(False)
self.remove_value.setObjectName(_fromUtf8("remove_value"))
self.horizontalLayout.addWidget(self.remove_value)
spacerItem = QtGui.QSpacerItem(33, 17, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem)
self.remove_value.setObjectName("remove_value")
self.verticalLayout.addWidget(self.remove_value)
spacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
self.verticalLayout.addItem(spacerItem)
self.horizontalLayout.addLayout(self.verticalLayout)
self.verticalLayout_2.addLayout(self.horizontalLayout)
self.buttonbox = QtGui.QDialogButtonBox(EditTagDialog)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(150)
@@ -65,15 +76,16 @@ class Ui_EditTagDialog(object):
self.buttonbox.setMinimumSize(QtCore.QSize(150, 0))
self.buttonbox.setOrientation(QtCore.Qt.Horizontal)
self.buttonbox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Save)
self.buttonbox.setObjectName(_fromUtf8("buttonbox"))
self.horizontalLayout.addWidget(self.buttonbox)
self.verticalLayout.addLayout(self.horizontalLayout)
self.buttonbox.setObjectName("buttonbox")
self.verticalLayout_2.addWidget(self.buttonbox)
self.retranslateUi(EditTagDialog)
QtCore.QObject.connect(self.buttonbox, QtCore.SIGNAL(_fromUtf8("accepted()")), EditTagDialog.accept)
QtCore.QObject.connect(self.buttonbox, QtCore.SIGNAL(_fromUtf8("rejected()")), EditTagDialog.reject)
QtCore.QObject.connect(self.buttonbox, QtCore.SIGNAL("accepted()"), EditTagDialog.accept)
QtCore.QObject.connect(self.buttonbox, QtCore.SIGNAL("rejected()"), EditTagDialog.reject)
QtCore.QMetaObject.connectSlotsByName(EditTagDialog)
def retranslateUi(self, EditTagDialog):
pass
self.edit_value.setText(QtGui.QApplication.translate("EditTagDialog", "Edit value", None, QtGui.QApplication.UnicodeUTF8))
self.add_value.setText(QtGui.QApplication.translate("EditTagDialog", "Add value", None, QtGui.QApplication.UnicodeUTF8))
self.remove_value.setText(QtGui.QApplication.translate("EditTagDialog", "Remove value", None, QtGui.QApplication.UnicodeUTF8))

View File

@@ -17,7 +17,7 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
tag_names = {
TAG_NAMES = {
'album': N_('Album'),
'artist': N_('Artist'),
'title': N_('Title'),
@@ -85,15 +85,16 @@ tag_names = {
def display_tag_name(name):
if ':' in name:
name, desc = name.split(':', 1)
name = _(tag_names.get(name + ':', name))
name = _(TAG_NAMES.get(name + ':', name))
return '%s [%s]' % (_(name), desc)
else:
new_name = tag_names.get(name)
new_name = TAG_NAMES.get(name)
if new_name is None:
new_name = tag_names.get(name + ':')
new_name = TAG_NAMES.get(name + ':')
if new_name is None:
return _(name)
else:
return '%s []' % (_(new_name),)
else:
return _(new_name)

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -21,6 +21,7 @@
<file>images/22x22/list-remove.png</file>
<file>images/22x22/system-search.png</file>
<file>images/22x22/picard-submit.png</file>
<file>images/22x22/lookup-musicbrainz.png</file>
<file>images/match-50.png</file>
<file>images/match-60.png</file>
<file>images/match-70.png</file>

View File

@@ -9,119 +9,149 @@
<rect>
<x>0</x>
<y>0</y>
<width>436</width>
<height>240</height>
<width>400</width>
<height>250</height>
</rect>
</property>
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="windowTitle">
<string>Edit tag</string>
<string/>
</property>
<property name="modal">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QListWidget" name="value_list">
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="tabKeyNavigation">
<bool>false</bool>
</property>
<property name="showDropIndicator" stdset="0">
<bool>false</bool>
<widget class="QComboBox" name="tag_names">
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="add_value">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>100</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
<widget class="QListWidget" name="value_list">
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
<property name="tabKeyNavigation">
<bool>false</bool>
</property>
<property name="text">
<string>Add value</string>
</property>
<property name="autoDefault">
<property name="showDropIndicator" stdset="0">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="remove_value">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>120</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>120</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Remove value</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>33</width>
<height>17</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonbox">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>150</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Save</set>
</property>
</widget>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QPushButton" name="edit_value">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>100</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Edit value</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="add_value">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>100</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Add value</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="remove_value">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>120</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>120</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Remove value</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonbox">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>150</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Save</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>