예제 #1
0
    def __init__(self, all_button=True):
        Gtk.Box.__init__(self)
        self.init_template()

        self.parent_row = None
        self.all_func = None
        self.update_func = None
        # Prevents the update function from being called, make
        # sure you do that manually after the batch update
        self.batch_update = False

        self.pixbuf = None
        self.info = CoverImage(None, None, None, None)
        self.default_type = 3
        self.mime_info = {
            'image/jpeg': {
                # Title for display
                'title': _('JPEG image'),
                # Type and options for GDK Pixbuf saving
                'type': 'jpeg',
                'options': {
                    'quality': '90'
                }
            },
            'image/png': {
                'title': _('PNG image'),
                'type': 'png',
                'options': {}
            },
            'image/': {
                'title': _('Image'),
                # Store unknown images as JPEG
                'type': 'jpeg',
                'options': {
                    'quality': '90'
                }
            },
            # TODO: Handle linked images
            '-->': {
                'title': _('Linked image')
            }
        }

        self.button.drag_dest_set(Gtk.DestDefaults.ALL, [],
                                  Gdk.DragAction.COPY)
        self.button.drag_dest_add_uri_targets()

        self.type_selection.connect('scroll-event', dummy_scroll_handler)

        self.all_button = None
        if all_button:
            self.all_button = AllButton(self)
            self.pack_start(self.all_button, False, False, 0)
예제 #2
0
 def _get_tag(self, raw, t):
     if not raw.tags: return []
     if t not in self.tag_mapping.itervalues():
         t = "TXXX:" + t
     field = raw.tags.getall(t)
     if len(field) <= 0:
         return []
     ret = []
     if t in ('TDRC', 'TDOR'): # values are ID3TimeStamps
         for value in field:
             ret.extend([unicode(x) for x in value.text])
     elif t == 'USLT': # Lyrics are stored in plain old strings
         for value in field:
             ret.append(unicode(value.text))
     elif t == 'WOAR': # URLS are stored in url not text
         for value in field:
             ret.extend([unicode(value.url.replace('\n','').replace('\r',''))])
     elif t == 'APIC':
         ret = [CoverImage(type=f.type, desc=f.desc, mime=f.mime, data=f.data) for f in field]
     elif t == 'COMM': # Newlines within comments are allowed, keep them
         for item in field:
             ret.extend([value for value in item.text])
     else:
         for value in field:
             try:
                 ret.extend([unicode(x.replace('\n','').replace('\r','')) \
                     for x in value.text])
             except:
                 pass
     return ret
예제 #3
0
    def __init__(self, all_button=True):
        gtk.HBox.__init__(self, homogeneous=False, spacing=5)

        self.parent_row = None
        self.all_func = None
        self.update_func = None
        # Prevents the update function from being called, make 
        # sure you do that manually after the batch update
        self.batch_update = False

        self.pixbuf = None
        self.info = CoverImage(None, None, None, None)
        self.default_type = 3
        self.mime_info = {
            'image/jpeg': {
                # Title for display
                'title': _('JPEG image'),
                # Type and options for GDK Pixbuf saving
                'type': 'jpeg',
                'options': {'quality': '90'}
            },
            'image/png': {
                'title': _('PNG image'),
                'type': 'png',
                'options': {}
            },
            'image/': {
                'title': _('Image'),
                # Store unknown images as JPEG
                'type': 'jpeg',
                'options': {'quality': '90'}
            },
            # TODO: Handle linked images
            '-->': {
                'title': _('Linked image')
            }
        }

        builder = gtk.Builder()
        builder.add_from_file(xdg.get_data_path('ui', 'trackproperties_dialog_cover_row.ui'))
        builder.connect_signals(self)
        cover_row = builder.get_object('cover_row')
        cover_row.reparent(self)

        button = builder.get_object('button')
        button.drag_dest_set(gtk.DEST_DEFAULT_ALL, [], gtk.gdk.ACTION_COPY)
        button.drag_dest_add_uri_targets()

        self.image = builder.get_object('image')
        self.info_label = builder.get_object('info_label')
        self.type_model = builder.get_object('type_model')
        self.type_selection = builder.get_object('type_selection')
        self.type_selection.set_sensitive(False)
        self.description_entry = builder.get_object('description_entry')
        self.description_entry.set_sensitive(False)

        self.all_button = None
        if all_button:
            self.all_button = AllButton(self)
            self.pack_start(self.all_button, expand=False, fill=False)
예제 #4
0
    def _get_tag(self, raw, tag):
        if tag == '__cover':
            return [
                CoverImage(type=p.type, desc=p.desc, mime=p.mime, data=p.data)
                for p in raw.pictures
            ]

        return CaseInsensitveBaseFormat._get_tag(self, raw, tag)
예제 #5
0
파일: ogg.py 프로젝트: remcohaszing/exaile
 def _get_tag(self, raw, tag):
     value = CaseInsensitveBaseFormat._get_tag(self, raw, tag)
     if value and tag == 'metadata_block_picture':
         new_value = []
         for v in value:
             picture = Picture(base64.b64decode(v))
             new_value.append(CoverImage(type=picture.type, desc=picture.desc, mime=picture.mime, data=picture.data))
         value = new_value
     return value
예제 #6
0
 def read_tags(self, tags):
     if "cover" in tags:
         tags[tags.index("cover")] = "metadata_block_picture"
     td = super(OggFormat, self).read_tags(tags)
     if 'metadata_block_picture' in td:
         td['cover'] = []
         for d in td["metadata_block_picture"]:
             picture = mutagen.flac.Picture(base64.standard_b64decode(d))
             td['cover'] += [
                 CoverImage(type=picture.type,
                            desc=picture.desc,
                            mime=picture.mime,
                            data=picture.data)
             ]
     return td
예제 #7
0
    def __init__(self, all_button=True):
        Gtk.Box.__init__(self)
        self.init_template()

        self.parent_row = None
        self.all_func = None
        self.update_func = None
        # Prevents the update function from being called, make 
        # sure you do that manually after the batch update
        self.batch_update = False

        self.pixbuf = None
        self.info = CoverImage(None, None, None, None)
        self.default_type = 3
        self.mime_info = {
            'image/jpeg': {
                # Title for display
                'title': _('JPEG image'),
                # Type and options for GDK Pixbuf saving
                'type': 'jpeg',
                'options': {'quality': '90'}
            },
            'image/png': {
                'title': _('PNG image'),
                'type': 'png',
                'options': {}
            },
            'image/': {
                'title': _('Image'),
                # Store unknown images as JPEG
                'type': 'jpeg',
                'options': {'quality': '90'}
            },
            # TODO: Handle linked images
            '-->': {
                'title': _('Linked image')
            }
        }

        self.button.drag_dest_set(Gtk.DestDefaults.ALL, [], Gdk.DragAction.COPY)
        self.button.drag_dest_add_uri_targets()

        self.type_selection.connect('scroll-event', dummy_scroll_handler)

        self.all_button = None
        if all_button:
            self.all_button = AllButton(self)
            self.pack_start(self.all_button, False, False, 0)
예제 #8
0
 def _get_tag(self, f, name):
     if not f.has_key(name):
         return []
     elif name == 'covr':
         ret = []
         for value in f[name]:
             if value.imageformat == mp4.MP4Cover.FORMAT_PNG:
                 mime = 'image/png'
             else:
                 mime = 'image/jpeg'
             ret.append(
                 CoverImage(type=None, desc=None, mime=mime, data=value))
         return ret
     elif name in ['trkn', 'disk']:
         ret = []
         for value in f[name]:
             ret.append("%d/%d" % (value[0], value[1]))
         return ret
     else:
         return [t for t in f[name]]
예제 #9
0
파일: _id3.py 프로젝트: unkie/exaile
 def _get_tag(self, raw, t):
     if not raw.tags:
         return []
     if t not in self.tag_mapping.values():
         t = "TXXX:" + t
     field = raw.tags.getall(t)
     if len(field) <= 0:
         return []
     ret = []
     if t in ('TDRC', 'TDOR'):  # values are ID3TimeStamps, need str conversion
         for value in field:
             ret.extend([str(x) for x in value.text])
     elif t == 'USLT':  # Lyrics are stored in a single str object
         for value in field:
             ret.append(value.text)
     elif (
         t == 'WOAR'
     ):  # URLs are stored in url field instead of text field (as a single str object)
         for value in field:
             ret.append(value.url.replace('\n', '').replace('\r', ''))
     elif t == 'APIC':
         ret = [
             CoverImage(type=f.type, desc=f.desc, mime=f.mime, data=f.data)
             for f in field
         ]
     elif t == 'COMM':  # Newlines within comments are allowed, keep them
         for item in field:
             ret.extend([value for value in item.text])
     else:
         for value in field:
             try:
                 ret.extend(
                     [x.replace('\n', '').replace('\r', '') for x in value.text]
                 )
             except Exception:
                 pass
     return ret
예제 #10
0
class TagImageField(Gtk.HBox):
    def __init__(self, all_button=True):
        Gtk.HBox.__init__(self, homogeneous=False, spacing=5)

        self.parent_row = None
        self.all_func = None
        self.update_func = None
        # Prevents the update function from being called, make 
        # sure you do that manually after the batch update
        self.batch_update = False

        self.pixbuf = None
        self.info = CoverImage(None, None, None, None)
        self.default_type = 3
        self.mime_info = {
            'image/jpeg': {
                # Title for display
                'title': _('JPEG image'),
                # Type and options for GDK Pixbuf saving
                'type': 'jpeg',
                'options': {'quality': '90'}
            },
            'image/png': {
                'title': _('PNG image'),
                'type': 'png',
                'options': {}
            },
            'image/': {
                'title': _('Image'),
                # Store unknown images as JPEG
                'type': 'jpeg',
                'options': {'quality': '90'}
            },
            # TODO: Handle linked images
            '-->': {
                'title': _('Linked image')
            }
        }

        builder = Gtk.Builder()
        builder.add_from_file(xdg.get_data_path('ui', 'trackproperties_dialog_cover_row.ui'))
        builder.connect_signals(self)
        cover_row = builder.get_object('cover_row')
        cover_row.reparent(self)

        button = builder.get_object('button')
        button.drag_dest_set(Gtk.DestDefaults.ALL, [], Gdk.DragAction.COPY)
        button.drag_dest_add_uri_targets()

        self.image = builder.get_object('image')
        self.info_label = builder.get_object('info_label')
        self.type_model = builder.get_object('type_model')
        self.type_selection = builder.get_object('type_selection')
        self.type_selection.set_sensitive(False)
        self.type_selection.connect('scroll-event', dummy_scroll_handler)
        self.description_entry = builder.get_object('description_entry')
        self.description_entry.set_sensitive(False)

        self.all_button = None
        if all_button:
            self.all_button = AllButton(self)
            self.pack_start(self.all_button, False, False, 0)

    def grab_focus(self):
        """
            Gives focus to the internal widget
        """
        self.image.grab_focus()

    def register_parent_row(self, parent_row):
        self.parent_row = parent_row

    def register_update_func(self, func):
        self.update_func = func

    def register_all_func(self, function):
        self.all_func = function

    def set_value(self, val, all_vals=None, doupdate=True):
        if doupdate:
            if val:
                loader = GdkPixbuf.PixbufLoader()

                try:
                    loader.write(val.data)
                    loader.close()
                except GLib.GError:
                    pass
                else:
                    self.batch_update = True
                    self.set_pixbuf(loader.get_pixbuf(), val.mime)
                    
                    # some file types do not support multiple cover types
                    if val.type is not None:
                        self.type_selection.set_active(val.type)
                        self.type_selection.set_sensitive(True)
                    else:
                        self.type_selection.set_active(-1)
                        self.type_selection.set_sensitive(False)
                        
                    if val.desc is not None:
                        self.description_entry.set_text(val.desc)
                        self.description_entry.set_sensitive(True)
                    else:
                        self.description_entry.set_text('')
                        self.description_entry.set_sensitive(False)
                    
                    self.batch_update = False
            else:
                self.batch_update = True
                self.set_pixbuf(None)
                self.type_selection.set_active(-1)
                self.type_selection.set_sensitive(False)
                self.description_entry.set_text('')
                self.description_entry.set_sensitive(False)
                self.batch_update = False
                self.call_update_func()

        if not None in (all_vals, self.all_button):
            self.all_button.set_active(all(val == v for v in all_vals))

    def get_value(self):
        if not self.pixbuf:
            return None

        mime = self.mime_info[self.info.mime]
        # Retrieve proper image data
        writer = io.BytesIO()
        self.pixbuf.save_to_callback(writer.write, mime['type'], mime['options'])
        # Move to the beginning of the buffer to allow read operations
        writer.seek(0)

        return self.info._replace(data=writer.read())

    def call_update_func(self):
        """
            Wrapper around the update function
        """
        if not self.update_func or self.batch_update:
            return

        self.update_func(self, self.parent_row.tag, self.parent_row.multi_id, self.get_value)

    def set_pixbuf(self, pixbuf, mime=None):
        """
            Updates the displayed cover image and info values
        """
        self.pixbuf = pixbuf

        if pixbuf is None:
            self.image.set_from_icon_name('list-add', Gtk.IconSize.DIALOG)
            self.info_label.set_markup('')
        else:
            self.image.set_from_pixbuf(pixbuf.scale_simple(
                100, 100, GdkPixbuf.InterpType.BILINEAR))

            width, height = pixbuf.get_width(), pixbuf.get_height()
            if mime is None:
                # TRANSLATORS: do not translate 'width' and 'height'
                markup = _('{width}x{height} pixels').format(width=width, height=height)
            else:
                # TRANSLATORS: do not translate 'format', 'width', and 'height'
                markup = _('{format} ({width}x{height} pixels)').format(
                    format=self.mime_info.get(mime, self.mime_info['image/'])['title'],
                    width=width, height=height
                )
            self.info_label.set_markup(markup)

            self.info = self.info._replace(mime=mime)

    def on_button_clicked(self, button):
        """
            Allows setting the cover image using a file selection dialog
        """
        dialog = dialogs.FileOperationDialog(
            title=_('Select image to set as cover'),
            parent=self.get_toplevel(),
            buttons=(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
                     Gtk.STOCK_OK, Gtk.ResponseType.OK)
        )
        dialog.set_select_multiple(False)
        filefilter = Gtk.FileFilter()
        # Not using Gtk.FileFilter.add_pixbuf_formats since
        # not all image formats are supported in tags
        filefilter.set_name(_('Supported image formats'))
        filefilter.add_pattern('*.[jJ][pP][gG]')
        filefilter.add_pattern('*.[jJ][pP][eE][gG]')
        filefilter.add_pattern('*.[pP][nN][gG]')
        dialog.add_filter(filefilter)

        if dialog.run() == Gtk.ResponseType.OK:
            filename = dialog.get_filename()

            try:
                pixbuf = GdkPixbuf.Pixbuf.new_from_file(filename)
                info = GdkPixbuf.Pixbuf.get_file_info(filename)[0]
            except TypeError:
                pass
            else:
                self.batch_update = True
                self.set_pixbuf(pixbuf, info['mime_types'][0])
                self.type_selection.set_active(self.default_type)
                self.type_selection.set_sensitive(True)
                self.description_entry.set_text(os.path.basename(filename).rsplit('.', 1)[0])
                self.description_entry.set_sensitive(True)
                self.batch_update = False
                self.call_update_func()

        dialog.destroy()

    def on_button_drag_data_received(self, widget, context, x, y, selection, info, time):
        """
            Allows setting the cover image via drag and drop
        """
        if selection.target.name() == 'text/uri-list':
            filename = Gio.File.new_for_uri(selection.get_uris()[0]).get_path()

            try:
                pixbuf = GdkPixbuf.Pixbuf.new_from_file(filename)
                info = GdkPixbuf.Pixbuf.get_file_info(filename)[0]
            except TypeError:
                pass
            else:
                self.batch_update = True
                self.set_pixbuf(pixbuf, info['mime_types'][0])
                self.type_selection.set_active(self.default_type)
                self.description_entry.set_sensitive(True)
                self.description_entry.set_text(os.path.basename(filename).rsplit('.', 1)[0])
                self.description_entry.set_sensitive(True)
                self.batch_update = False
                self.call_update_func()

    def on_type_selection_changed(self, combobox):
        """
            Notifies about changes in the cover type
        """
        self.info = self.info._replace(type=self.type_model[combobox.get_active()][0])
        self.call_update_func()

    def on_description_entry_changed(self, entry):
        """
            Notifies about changes in the cover description
        """
        self.info = self.info._replace(desc=entry.get_text())
        self.call_update_func()
예제 #11
0
파일: flac.py 프로젝트: mexicarne/exaile
 def read_tags(self, tags):
     td = super(FlacFormat, self).read_tags(tags)
     if 'cover' in tags:
         td['cover'] = [CoverImage(type=p.type, desc=p.desc, mime=p.mime, data=p.data) \
             for p in self.mutagen.pictures]
     return td
예제 #12
0
    def __init__(self, all_button=True):
        gtk.HBox.__init__(self, homogeneous=False, spacing=5)

        self.parent_row = None
        self.all_func = None
        self.update_func = None
        # Prevents the update function from being called, make
        # sure you do that manually after the batch update
        self.batch_update = False

        self.pixbuf = None
        self.info = CoverImage(None, None, None, None)
        self.default_type = 3
        self.mime_info = {
            'image/jpeg': {
                # Title for display
                'title': _('JPEG image'),
                # Type and options for GDK Pixbuf saving
                'type': 'jpeg',
                'options': {
                    'quality': '90'
                }
            },
            'image/png': {
                'title': _('PNG image'),
                'type': 'png',
                'options': {}
            },
            'image/': {
                'title': _('Image'),
                # Store unknown images as JPEG
                'type': 'jpeg',
                'options': {
                    'quality': '90'
                }
            },
            # TODO: Handle linked images
            '-->': {
                'title': _('Linked image')
            }
        }

        builder = gtk.Builder()
        builder.add_from_file(
            xdg.get_data_path('ui', 'trackproperties_dialog_cover_row.ui'))
        builder.connect_signals(self)
        cover_row = builder.get_object('cover_row')
        cover_row.reparent(self)

        button = builder.get_object('button')
        button.drag_dest_set(gtk.DEST_DEFAULT_ALL, [], gtk.gdk.ACTION_COPY)
        button.drag_dest_add_uri_targets()

        self.image = builder.get_object('image')
        self.info_label = builder.get_object('info_label')
        self.type_model = builder.get_object('type_model')
        self.type_selection = builder.get_object('type_selection')
        self.type_selection.set_sensitive(False)
        self.description_entry = builder.get_object('description_entry')
        self.description_entry.set_sensitive(False)

        self.all_button = None
        if all_button:
            self.all_button = AllButton(self)
            self.pack_start(self.all_button, expand=False, fill=False)
예제 #13
0
class TagImageField(gtk.HBox):
    def __init__(self, all_button=True):
        gtk.HBox.__init__(self, homogeneous=False, spacing=5)

        self.parent_row = None
        self.all_func = None
        self.update_func = None
        # Prevents the update function from being called, make
        # sure you do that manually after the batch update
        self.batch_update = False

        self.pixbuf = None
        self.info = CoverImage(None, None, None, None)
        self.default_type = 3
        self.mime_info = {
            'image/jpeg': {
                # Title for display
                'title': _('JPEG image'),
                # Type and options for GDK Pixbuf saving
                'type': 'jpeg',
                'options': {
                    'quality': '90'
                }
            },
            'image/png': {
                'title': _('PNG image'),
                'type': 'png',
                'options': {}
            },
            'image/': {
                'title': _('Image'),
                # Store unknown images as JPEG
                'type': 'jpeg',
                'options': {
                    'quality': '90'
                }
            },
            # TODO: Handle linked images
            '-->': {
                'title': _('Linked image')
            }
        }

        builder = gtk.Builder()
        builder.add_from_file(
            xdg.get_data_path('ui', 'trackproperties_dialog_cover_row.ui'))
        builder.connect_signals(self)
        cover_row = builder.get_object('cover_row')
        cover_row.reparent(self)

        button = builder.get_object('button')
        button.drag_dest_set(gtk.DEST_DEFAULT_ALL, [], gtk.gdk.ACTION_COPY)
        button.drag_dest_add_uri_targets()

        self.image = builder.get_object('image')
        self.info_label = builder.get_object('info_label')
        self.type_model = builder.get_object('type_model')
        self.type_selection = builder.get_object('type_selection')
        self.type_selection.set_sensitive(False)
        self.description_entry = builder.get_object('description_entry')
        self.description_entry.set_sensitive(False)

        self.all_button = None
        if all_button:
            self.all_button = AllButton(self)
            self.pack_start(self.all_button, expand=False, fill=False)

    def grab_focus(self):
        """
            Gives focus to the internal widget
        """
        self.image.grab_focus()

    def register_parent_row(self, parent_row):
        self.parent_row = parent_row

    def register_update_func(self, func):
        self.update_func = func

    def register_all_func(self, function):
        self.all_func = function

    def set_value(self, val, all_vals=None, doupdate=True):
        if doupdate:
            if val:
                loader = gtk.gdk.PixbufLoader()

                try:
                    loader.write(val.data)
                    loader.close()
                except glib.GError:
                    pass
                else:
                    self.batch_update = True
                    self.set_pixbuf(loader.get_pixbuf(), val.mime)

                    # some file types do not support multiple cover types
                    if val.type is not None:
                        self.type_selection.set_active(val.type)
                        self.type_selection.set_sensitive(True)
                    else:
                        self.type_selection.set_active(-1)
                        self.type_selection.set_sensitive(False)

                    if val.desc is not None:
                        self.description_entry.set_text(val.desc)
                        self.description_entry.set_sensitive(True)
                    else:
                        self.description_entry.set_text('')
                        self.description_entry.set_sensitive(False)

                    self.batch_update = False
            else:
                self.batch_update = True
                self.set_pixbuf(None)
                self.type_selection.set_active(-1)
                self.type_selection.set_sensitive(False)
                self.description_entry.set_text('')
                self.description_entry.set_sensitive(False)
                self.batch_update = False
                self.call_update_func()

        if not None in (all_vals, self.all_button):
            self.all_button.set_active(all(val == v for v in all_vals))

    def get_value(self):
        if not self.pixbuf:
            return None

        mime = self.mime_info[self.info.mime]
        # Retrieve proper image data
        writer = io.BytesIO()
        self.pixbuf.save_to_callback(writer.write, mime['type'],
                                     mime['options'])
        # Move to the beginning of the buffer to allow read operations
        writer.seek(0)

        return self.info._replace(data=writer.read())

    def call_update_func(self):
        """
            Wrapper around the update function
        """
        if not self.update_func or self.batch_update:
            return

        self.update_func(self, self.parent_row.tag, self.parent_row.multi_id,
                         self.get_value)

    def set_pixbuf(self, pixbuf, mime=None):
        """
            Updates the displayed cover image and info values
        """
        self.pixbuf = pixbuf

        if pixbuf is None:
            self.image.set_from_stock(gtk.STOCK_ADD, gtk.ICON_SIZE_DIALOG)
            self.info_label.set_markup('')
        else:
            self.image.set_from_pixbuf(
                pixbuf.scale_simple(100, 100, gtk.gdk.INTERP_BILINEAR))

            width, height = pixbuf.get_width(), pixbuf.get_height()
            if mime is None:
                # TRANSLATORS: do not translate 'width' and 'height'
                markup = _('{width}x{height} pixels').format(width=width,
                                                             height=height)
            else:
                # TRANSLATORS: do not translate 'format', 'width', and 'height'
                markup = _('{format} ({width}x{height} pixels)').format(
                    format=self.mime_info.get(
                        mime, self.mime_info['image/'])['title'],
                    width=width,
                    height=height)
            self.info_label.set_markup(markup)

            self.info = self.info._replace(mime=mime)

    def on_button_clicked(self, button):
        """
            Allows setting the cover image using a file selection dialog
        """
        dialog = dialogs.FileOperationDialog(
            title=_('Select image to set as cover'),
            parent=self.get_toplevel(),
            buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OK,
                     gtk.RESPONSE_OK))
        dialog.set_select_multiple(False)
        filefilter = gtk.FileFilter()
        # Not using gtk.FileFilter.add_pixbuf_formats since
        # not all image formats are supported in tags
        filefilter.set_name(_('Supported image formats'))
        filefilter.add_pattern('*.[jJ][pP][gG]')
        filefilter.add_pattern('*.[jJ][pP][eE][gG]')
        filefilter.add_pattern('*.[pP][nN][gG]')
        dialog.add_filter(filefilter)

        if dialog.run() == gtk.RESPONSE_OK:
            filename = dialog.get_filename()

            try:
                pixbuf = gtk.gdk.pixbuf_new_from_file(filename)
                info = gtk.gdk.pixbuf_get_file_info(filename)[0]
            except TypeError:
                pass
            else:
                self.batch_update = True
                self.set_pixbuf(pixbuf, info['mime_types'][0])
                self.type_selection.set_active(self.default_type)
                self.type_selection.set_sensitive(True)
                self.description_entry.set_text(
                    os.path.basename(filename).rsplit('.', 1)[0])
                self.description_entry.set_sensitive(True)
                self.batch_update = False
                self.call_update_func()

        dialog.destroy()

    def on_button_drag_data_received(self, widget, context, x, y, selection,
                                     info, time):
        """
            Allows setting the cover image via drag and drop
        """
        if selection.target == 'text/uri-list':
            filename = gio.File(selection.get_uris()[0]).get_path()

            try:
                pixbuf = gtk.gdk.pixbuf_new_from_file(filename)
                info = gtk.gdk.pixbuf_get_file_info(filename)[0]
            except TypeError:
                pass
            else:
                self.batch_update = True
                self.set_pixbuf(pixbuf, info['mime_types'][0])
                self.type_selection.set_active(self.default_type)
                self.description_entry.set_sensitive(True)
                self.description_entry.set_text(
                    os.path.basename(filename).rsplit('.', 1)[0])
                self.description_entry.set_sensitive(True)
                self.batch_update = False
                self.call_update_func()

    def on_type_selection_changed(self, combobox):
        """
            Notifies about changes in the cover type
        """
        self.info = self.info._replace(
            type=self.type_model[combobox.get_active()][0])
        self.call_update_func()

    def on_description_entry_changed(self, entry):
        """
            Notifies about changes in the cover description
        """
        self.info = self.info._replace(desc=entry.get_text())
        self.call_update_func()
예제 #14
0
class TagImageField(Gtk.Box):

    __gtype_name__ = 'TagImageField'

    button, image, type_model, description_entry, type_selection, \
        info_label = GtkTemplate.Child.widgets(6)

    def __init__(self, all_button=True):
        Gtk.Box.__init__(self)
        self.init_template()

        self.parent_row = None
        self.all_func = None
        self.update_func = None
        # Prevents the update function from being called, make
        # sure you do that manually after the batch update
        self.batch_update = False

        self.pixbuf = None
        self.info = CoverImage(None, None, None, None)
        self.default_type = 3
        self.mime_info = {
            'image/jpeg': {
                # Title for display
                'title': _('JPEG image'),
                # Type and options for GDK Pixbuf saving
                'type': 'jpeg',
                'options': {
                    'quality': '90'
                }
            },
            'image/png': {
                'title': _('PNG image'),
                'type': 'png',
                'options': {}
            },
            'image/': {
                'title': _('Image'),
                # Store unknown images as JPEG
                'type': 'jpeg',
                'options': {
                    'quality': '90'
                }
            },
            # TODO: Handle linked images
            '-->': {
                'title': _('Linked image')
            }
        }

        self.button.drag_dest_set(Gtk.DestDefaults.ALL, [],
                                  Gdk.DragAction.COPY)
        self.button.drag_dest_add_uri_targets()

        self.type_selection.connect('scroll-event', dummy_scroll_handler)

        self.all_button = None
        if all_button:
            self.all_button = AllButton(self)
            self.pack_start(self.all_button, False, False, 0)

    def grab_focus(self):
        """
            Gives focus to the internal widget
        """
        self.image.grab_focus()

    def register_parent_row(self, parent_row):
        self.parent_row = parent_row

    def register_update_func(self, func):
        self.update_func = func

    def register_all_func(self, function):
        self.all_func = function

    def set_value(self, val, all_vals=None, doupdate=True):
        if doupdate:
            if val:
                loader = GdkPixbuf.PixbufLoader()

                try:
                    loader.write(val.data)
                    loader.close()
                except GLib.GError:
                    pass
                else:
                    self.batch_update = True
                    self.set_pixbuf(loader.get_pixbuf(), val.mime)

                    # some file types do not support multiple cover types
                    if val.type is not None:
                        self.type_selection.set_active(val.type)
                        self.type_selection.set_sensitive(True)
                    else:
                        self.type_selection.set_active(-1)
                        self.type_selection.set_sensitive(False)

                    if val.desc is not None:
                        self.description_entry.set_text(val.desc)
                        self.description_entry.set_sensitive(True)
                    else:
                        self.description_entry.set_text('')
                        self.description_entry.set_sensitive(False)

                    self.batch_update = False
            else:
                self.batch_update = True
                self.set_pixbuf(None)
                self.type_selection.set_active(-1)
                self.type_selection.set_sensitive(False)
                self.description_entry.set_text('')
                self.description_entry.set_sensitive(False)
                self.batch_update = False
                self.call_update_func()

        if not None in (all_vals, self.all_button):
            self.all_button.set_active(all(val == v for v in all_vals))

    def get_value(self):
        if not self.pixbuf:
            return None

        mime = self.mime_info[self.info.mime]
        # Retrieve proper image data
        writer = io.BytesIO()

        def gdk_pixbuf_save_func(buf, count, user_data):
            if writer.write(buf) == count:
                return True
            return False

        # workaround for some undocumented changes in GdkPixbuf API
        # see https://bugzilla.gnome.org/show_bug.cgi?id=670372
        # see https://github.com/mypaint/mypaint/issues/236
        try:
            save_to_callback_function = self.pixbuf.save_to_callbackv
        except AttributeError:
            save_to_callback_function = self.pixbuf.save_to_callback
        save_to_callback_function(gdk_pixbuf_save_func, None, mime['type'], \
                mime['options'].keys(), mime['options'].values())

        # Move to the beginning of the buffer to allow read operations
        writer.seek(0)

        return self.info._replace(data=writer.read())

    def call_update_func(self):
        """
            Wrapper around the update function
        """
        if not self.update_func or self.batch_update:
            return

        self.update_func(self, self.parent_row.tag, self.parent_row.multi_id,
                         self.get_value)

    def set_pixbuf(self, pixbuf, mime=None):
        """
            Updates the displayed cover image and info values
        """
        self.pixbuf = pixbuf

        if pixbuf is None:
            self.image.set_from_icon_name('list-add', Gtk.IconSize.DIALOG)
            self.info_label.set_markup('')
        else:
            self.image.set_from_pixbuf(
                pixbuf.scale_simple(100, 100, GdkPixbuf.InterpType.BILINEAR))

            width, height = pixbuf.get_width(), pixbuf.get_height()
            if mime is None:
                # TRANSLATORS: do not translate 'width' and 'height'
                markup = _('{width}x{height} pixels').format(width=width,
                                                             height=height)
            else:
                # TRANSLATORS: do not translate 'format', 'width', and 'height'
                markup = _('{format} ({width}x{height} pixels)').format(
                    format=self.mime_info.get(
                        mime, self.mime_info['image/'])['title'],
                    width=width,
                    height=height)
            self.info_label.set_markup(markup)

            self.info = self.info._replace(mime=mime)

    def _on_button_clicked(self, button):
        """
            Allows setting the cover image using a file selection dialog
        """
        dialog = dialogs.FileOperationDialog(
            title=_('Select image to set as cover'),
            parent=self.get_toplevel(),
            buttons=(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OK,
                     Gtk.ResponseType.OK))
        dialog.set_select_multiple(False)
        filefilter = Gtk.FileFilter()
        # Not using Gtk.FileFilter.add_pixbuf_formats since
        # not all image formats are supported in tags
        filefilter.set_name(_('Supported image formats'))
        filefilter.add_pattern('*.[jJ][pP][gG]')
        filefilter.add_pattern('*.[jJ][pP][eE][gG]')
        filefilter.add_pattern('*.[pP][nN][gG]')
        dialog.add_filter(filefilter)

        if dialog.run() == Gtk.ResponseType.OK:
            filename = dialog.get_filename()

            try:
                pixbuf = GdkPixbuf.Pixbuf.new_from_file(filename)
                info = GdkPixbuf.Pixbuf.get_file_info(filename)[0]
            except TypeError:
                pass
            else:
                self.batch_update = True
                self.set_pixbuf(pixbuf, info.get_mime_types()[0])
                self.type_selection.set_active(self.default_type)
                self.type_selection.set_sensitive(True)
                self.description_entry.set_text(
                    os.path.basename(filename).rsplit('.', 1)[0])
                self.description_entry.set_sensitive(True)
                self.batch_update = False
                self.call_update_func()

        dialog.destroy()

    def _on_button_drag_data_received(self, widget, context, x, y, selection,
                                      info, time):
        """
            Allows setting the cover image via drag and drop
        """
        if selection.target.name() == 'text/uri-list':
            filename = Gio.File.new_for_uri(selection.get_uris()[0]).get_path()

            try:
                pixbuf = GdkPixbuf.Pixbuf.new_from_file(filename)
                info = GdkPixbuf.Pixbuf.get_file_info(filename)[0]
            except TypeError:
                pass
            else:
                self.batch_update = True
                self.set_pixbuf(pixbuf, info['mime_types'][0])
                self.type_selection.set_active(self.default_type)
                self.description_entry.set_sensitive(True)
                self.description_entry.set_text(
                    os.path.basename(filename).rsplit('.', 1)[0])
                self.description_entry.set_sensitive(True)
                self.batch_update = False
                self.call_update_func()

    def _on_type_selection_changed(self, combobox):
        """
            Notifies about changes in the cover type
        """
        self.info = self.info._replace(
            type=self.type_model[combobox.get_active()][0])
        self.call_update_func()

    def _on_description_entry_changed(self, entry):
        """
            Notifies about changes in the cover description
        """
        self.info = self.info._replace(desc=entry.get_text())
        self.call_update_func()