def _window_response(self, window, response): if response == gtk.RESPONSE_CLOSE: self.last_tab = self.prefsnotebook.get_current_page() #XXX: These two are probably never triggered if self.config.show_lyrics and self.config.lyrics_location != consts.LYRICS_LOCATION_HOME: if not os.path.isdir(misc.file_from_utf8(self.config.musicdir[self.config.profile_num])): ui.show_msg(self.window, _("To save lyrics to the music file's directory, you must specify a valid music directory."), _("Music Dir Verification"), 'musicdirVerificationError', gtk.BUTTONS_CLOSE) # Set music_dir entry focused: self.prefsnotebook.set_current_page(0) self.direntry.grab_focus() return if self.config.show_covers and self.config.art_location != consts.ART_LOCATION_HOMECOVERS: if not os.path.isdir(misc.file_from_utf8(self.config.musicdir[self.config.profile_num])): ui.show_msg(self.window, _("To save artwork to the music file's directory, you must specify a valid music directory."), _("Music Dir Verification"), 'musicdirVerificationError', gtk.BUTTONS_CLOSE) # Set music_dir entry focused: self.prefsnotebook.set_current_page(0) self.direntry.grab_focus() return if not self.using_mpd_env_vars: if self.prev_host != self.config.host[self.config.profile_num] or self.prev_port != self.config.port[self.config.profile_num] or self.prev_password != self.config.password[self.config.profile_num]: # Try to connect if mpd connection info has been updated: ui.change_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH)) self.reconnect() self.settings_save() self.populate_profiles_for_menu() ui.change_cursor(None) window.destroy()
def download_progress(self, dest_filename_curr, i): # This populates Main.imagelist for the remote image window if os.path.exists(dest_filename_curr): pix = gtk.gdk.pixbuf_new_from_file(dest_filename_curr) pix = pix.scale_simple(148, 148, gtk.gdk.INTERP_HYPER) pix = self.artwork_apply_composite_case(pix, 148, 148) pix = img.pixbuf_add_border(pix) if self.stop_art_update: del pix return False # don't continue to next image self.imagelist_append([i+1, pix]) del pix self.remotefilelist_append(dest_filename_curr) if i == 0: self.allow_art_search() ui.change_cursor(None) # XXX indented twice more? return True # continue to next image
def artwork_download_img_to_file(self, artist, album, dest_filename, all_images=False): # Returns False if no images found if not artist and not album: self.downloading_image = False return False self.downloading_image = True # Amazon currently doesn't support utf8 and suggests latin1 encoding instead: artist = urllib.quote(artist.encode('latin1', 'replace')) album = urllib.quote(album.encode('latin1', 'replace')) # Try searching urls from most specific (artist, title) to least specific (artist only) urls = [AMAZON_URI % (AMAZON_KEY, artist) + "&Title=" + album, AMAZON_URI % (AMAZON_KEY, artist) + "&Keywords=" + album, AMAZON_URI % (AMAZON_KEY, artist)] for url in urls: request = urllib2.Request(url) opener = urllib2.build_opener() try: body = opener.open(request).read() xml = ElementTree.fromstring(body) largeimgs = xml.getiterator(AMAZON_NS + "LargeImage") except: largeimgs = None if largeimgs: break elif url == urls[-1]: self.downloading_image = False return False imgs = misc.iunique(url.text for img in largeimgs for url in img.getiterator(AMAZON_NS + "URL")) imglist = list(imgs) if not all_images: urllib.urlretrieve(imglist[0], dest_filename) self.downloading_image = False return True else: try: imgfound = False for i in range(len(imglist)): dest_filename_curr = dest_filename.replace("<imagenum>", str(i+1)) urllib.urlretrieve(imglist[i], dest_filename_curr) # This populates Main.imagelist for the remote image window if os.path.exists(dest_filename_curr): pix = gtk.gdk.pixbuf_new_from_file(dest_filename_curr) pix = pix.scale_simple(148, 148, gtk.gdk.INTERP_HYPER) pix = self.artwork_apply_composite_case(pix, 148, 148) pix = img.pixbuf_add_border(pix) if self.stop_art_update: del pix self.downloading_image = False return imgfound self.imagelist_append([i+1, pix]) del pix imgfound = True self.remotefilelist_append(dest_filename_curr) if i == 0: self.allow_art_search() ui.change_cursor(None) except: pass self.downloading_image = False return imgfound
def current_update(self, prevstatus_playlist, new_playlist_length): if self.connected(): if self.sonata_loaded(): playlistposition = self.current.get_visible_rect()[1] self.current.freeze_child_notify() if not self.current_update_skip: if not self.filterbox_visible: self.current.set_model(None) if prevstatus_playlist: changed_songs = mpdh.call(self.client, "plchanges", prevstatus_playlist) else: changed_songs = mpdh.call(self.client, "plchanges", 0) self.current_songs = [] newlen = int(new_playlist_length) currlen = len(self.currentdata) for track in changed_songs: pos = int(mpdh.get(track, "pos")) items = [] for part in self.columnformat: items += [self.parse_formatting(part, track, True)] if pos < currlen: # Update attributes for item: i = self.currentdata.get_iter((pos,)) trackid = int(mpdh.get(track, "id")) if trackid != self.currentdata.get_value(i, 0): self.currentdata.set_value(i, 0, trackid) for index in range(len(items)): if items[index] != self.currentdata.get_value(i, index + 1): self.currentdata.set_value(i, index + 1, items[index]) self.current_songs[pos] = track else: # Add new item: self.currentdata.append([int(mpdh.get(track, "id"))] + items) self.current_songs.append(track) if newlen == 0: self.currentdata.clear() self.current_songs = [] else: # Remove excess songs: for i in range(currlen - newlen): it = self.currentdata.get_iter((currlen - 1 - i,)) self.currentdata.remove(it) self.current_songs = self.current_songs[:newlen] if not self.filterbox_visible: self.current.set_model(self.currentdata) self.current_update_skip = False # Update statusbar time: self.total_time = 0 for track in self.current_songs: try: self.total_time = self.total_time + int(mpdh.get(track, "time")) except: pass if "pos" in self.songinfo(): currsong = int(mpdh.get(self.songinfo(), "pos")) self.boldrow(currsong) self.prev_boldrow = currsong if self.filterbox_visible: # Refresh filtered results: self.prevtodo = ( "RETAIN_POS_AND_SEL" ) # Hacky, but this ensures we retain the self.current position/selection self.plpos = playlistposition self.searchfilter_feed_loop(self.filterpattern) elif self.sonata_loaded(): self.playlist_retain_view(self.current, playlistposition) self.current.thaw_child_notify() self.header_update_column_indicators() self.update_statusbar() ui.change_cursor(None)
def on_link_leave(self, _widget, _event): ui.change_cursor(None)
def on_link_enter(self, widget, _event): if widget.get_children()[0].get_use_markup(): ui.change_cursor(gtk.gdk.Cursor(gtk.gdk.HAND2))
def current_update(self, prevstatus_playlist, new_playlist_length): if self.connected(): if self.sonata_loaded(): playlistposition = self.current.get_visible_rect()[1] self.current.freeze_child_notify() if not self.current_update_skip: if not self.filterbox_visible: self.current.set_model(None) if prevstatus_playlist: changed_songs = mpdh.call(self.client, 'plchanges', prevstatus_playlist) else: changed_songs = mpdh.call(self.client, 'plchanges', 0) self.current_songs = [] newlen = int(new_playlist_length) currlen = len(self.currentdata) for track in changed_songs: pos = int(mpdh.get(track, 'pos')) items = [] for part in self.columnformat: items += [self.parse_formatting(part, track, True)] if pos < currlen: # Update attributes for item: i = self.currentdata.get_iter((pos, )) trackid = int(mpdh.get(track, 'id')) if trackid != self.currentdata.get_value(i, 0): self.currentdata.set_value(i, 0, trackid) for index in range(len(items)): if items[index] != self.currentdata.get_value( i, index + 1): self.currentdata.set_value( i, index + 1, items[index]) self.current_songs[pos] = track else: # Add new item: self.currentdata.append([int(mpdh.get(track, 'id'))] + items) self.current_songs.append(track) if newlen == 0: self.currentdata.clear() self.current_songs = [] else: # Remove excess songs: for i in range(currlen - newlen): it = self.currentdata.get_iter((currlen - 1 - i, )) self.currentdata.remove(it) self.current_songs = self.current_songs[:newlen] if not self.filterbox_visible: self.current.set_model(self.currentdata) self.current_update_skip = False # Update statusbar time: self.total_time = 0 for track in self.current_songs: try: self.total_time = self.total_time + int( mpdh.get(track, 'time')) except: pass if 'pos' in self.songinfo(): currsong = int(mpdh.get(self.songinfo(), 'pos')) self.boldrow(currsong) self.prev_boldrow = currsong if self.filterbox_visible: # Refresh filtered results: self.prevtodo = "RETAIN_POS_AND_SEL" # Hacky, but this ensures we retain the self.current position/selection self.plpos = playlistposition self.searchfilter_feed_loop(self.filterpattern) elif self.sonata_loaded(): self.playlist_retain_view(self.current, playlistposition) self.current.thaw_child_notify() self.header_update_column_indicators() self.update_statusbar() ui.change_cursor(None)
def artwork_download_img_to_file(self, artist, album, dest_filename, all_images=False): # Returns False if no images found if not artist and not album: self.downloading_image = False return False self.downloading_image = True # Amazon currently doesn't support utf8 and suggests latin1 encoding instead: artist = urllib.quote(artist.encode('latin1', 'replace')) album = urllib.quote(album.encode('latin1', 'replace')) # Try searching urls from most specific (artist, title) to least specific (artist only) urls = [ AMAZON_URI % (AMAZON_KEY, artist) + "&Title=" + album, AMAZON_URI % (AMAZON_KEY, artist) + "&Keywords=" + album, AMAZON_URI % (AMAZON_KEY, artist) ] for url in urls: request = urllib2.Request(url) opener = urllib2.build_opener() try: body = opener.open(request).read() xml = ElementTree.fromstring(body) largeimgs = xml.getiterator(AMAZON_NS + "LargeImage") except: largeimgs = None if largeimgs: break elif url == urls[-1]: self.downloading_image = False return False imgs = misc.iunique(url.text for img in largeimgs for url in img.getiterator(AMAZON_NS + "URL")) # Prevent duplicate images in remote art window: imglist = list(set(list(imgs))) if not all_images: urllib.urlretrieve(imglist[0], dest_filename) self.downloading_image = False return True else: try: imgfound = False for i, image in enumerate(imglist): dest_filename_curr = dest_filename.replace( "<imagenum>", str(i + 1)) urllib.urlretrieve(image, dest_filename_curr) # This populates Main.imagelist for the remote image window if os.path.exists(dest_filename_curr): pix = gtk.gdk.pixbuf_new_from_file(dest_filename_curr) pix = pix.scale_simple(148, 148, gtk.gdk.INTERP_HYPER) pix = self.artwork_apply_composite_case(pix, 148, 148) pix = img.pixbuf_add_border(pix) if self.stop_art_update: del pix self.downloading_image = False return imgfound self.imagelist_append([i + 1, pix]) del pix imgfound = True self.remotefilelist_append(dest_filename_curr) if i == 0: self.allow_art_search() ui.change_cursor(None) except: pass self.downloading_image = False return imgfound
def on_tags_edit(self, files, temp_mpdpaths, music_dir): """Display the editing dialog""" # Try loading module global tagpy if tagpy is None: try: import tagpy except ImportError: ui.show_msg( self.window, _("Taglib and/or tagpy not found, tag editing support disabled." ), _("Edit Tags"), 'editTagsError', gtk.BUTTONS_CLOSE, response_cb=ui.dialog_destroy) ui.change_cursor(None) return # Set default tag encoding to utf8.. fixes some reported bugs. import tagpy.id3v2 as id3v2 id3v2.FrameFactory.instance().setDefaultTextEncoding( tagpy.StringType.UTF8) # Make sure tagpy is at least 0.91 if hasattr(tagpy.Tag.title, '__call__'): ui.show_msg( self.window, _("Tagpy version < 0.91. Please upgrade to a newer version, tag editing support disabled." ), _("Edit Tags"), 'editTagsError', gtk.BUTTONS_CLOSE, response_cb=ui.dialog_destroy) ui.change_cursor(None) return if not os.path.isdir(misc.file_from_utf8(music_dir)): ui.show_msg( self.window, _("The path") + " " + music_dir + " " + _("does not exist. Please specify a valid music directory in preferences." ), _("Edit Tags"), 'editTagsError', gtk.BUTTONS_CLOSE, response_cb=ui.dialog_destroy) ui.change_cursor(None) return # XXX file list was created here if len(files) == 0: ui.change_cursor(None) return # Initialize: self.tagnum = -1 tags = [{ 'title': '', 'artist': '', 'album': '', 'year': '', 'track': '', 'genre': '', 'comment': '', 'title-changed': False, 'artist-changed': False, 'album-changed': False, 'year-changed': False, 'track-changed': False, 'genre-changed': False, 'comment-changed': False, 'fullpath': misc.file_from_utf8(filename), 'mpdpath': path } for filename, path in zip(files, temp_mpdpaths)] if not os.path.exists(tags[0]['fullpath']): ui.change_cursor(None) ui.show_msg( self.window, _("File ") + "\"" + tags[0]['fullpath'] + "\"" + _(" not found. Please specify a valid music directory in preferences." ), _("Edit Tags"), 'editTagsError', gtk.BUTTONS_CLOSE, response_cb=ui.dialog_destroy) return if not self.tags_next_tag(tags): ui.change_cursor(None) ui.show_msg(self.window, _("No music files with editable tags found."), _("Edit Tags"), 'editTagsError', gtk.BUTTONS_CLOSE, response_cb=ui.dialog_destroy) return editwindow = ui.dialog(parent=self.window, flags=gtk.DIALOG_MODAL, role='editTags', resizable=False, separator=False) editwindow.set_size_request(375, -1) table = gtk.Table(9, 2, False) table.set_row_spacings(2) self.filelabel = ui.label(select=True, wrap=True) filehbox = gtk.HBox() sonataicon = ui.image(stock='sonata', stocksize=gtk.ICON_SIZE_DND, x=1) expandbutton = ui.button(" ") self.set_expandbutton_state(expandbutton) expandvbox = gtk.VBox() expandvbox.pack_start(ui.label(), True, True) expandvbox.pack_start(expandbutton, False, False) expandvbox.pack_start(ui.label(), True, True) expandbutton.connect('clicked', self.toggle_path) blanklabel = ui.label(w=5, h=12) filehbox.pack_start(sonataicon, False, False, 2) filehbox.pack_start(self.filelabel, True, True, 2) filehbox.pack_start(expandvbox, False, False, 2) filehbox.pack_start(blanklabel, False, False, 2) titlelabel, titleentry, titlebutton, titlehbox = self._create_label_entry_button_hbox( _("Title")) artistlabel, artistentry, artistbutton, artisthbox = self._create_label_entry_button_hbox( _("Artist")) albumlabel, albumentry, albumbutton, albumhbox = self._create_label_entry_button_hbox( _("Album")) yearlabel, yearentry, yearbutton, yearhbox = self._create_label_entry_button_hbox( _("Year")) yearentry.set_size_request(50, -1) tracklabel, trackentry, trackbutton, trackhbox = self._create_label_entry_button_hbox( " " + _("Track"), True) trackentry.set_size_request(50, -1) yearandtrackhbox = gtk.HBox() yearandtrackhbox.pack_start(yearhbox, True, True, 0) yearandtrackhbox.pack_start(trackhbox, True, True, 0) yearentry.connect("insert_text", self.tags_win_entry_constraint, True) trackentry.connect("insert_text", self.tags_win_entry_constraint, False) genrelabel = ui.label(text=_("Genre") + ":", x=1) genrecombo = ui.comboentry(items=self.tags_win_genres(), wrap=2) genreentry = genrecombo.get_child() genrehbox = gtk.HBox() genrebutton = ui.button() genrebuttonvbox = self.tags_win_create_apply_all_button( genrebutton, genreentry) genrehbox.pack_start(genrelabel, False, False, 2) genrehbox.pack_start(genrecombo, True, True, 2) genrehbox.pack_start(genrebuttonvbox, False, False, 2) commentlabel, commententry, commentbutton, commenthbox = self._create_label_entry_button_hbox( _("Comment")) ui.set_widths_equal([ titlelabel, artistlabel, albumlabel, yearlabel, genrelabel, commentlabel, sonataicon ]) genrecombo.set_size_request(-1, titleentry.size_request()[1]) tablewidgets = [ ui.label(), filehbox, ui.label(), titlehbox, artisthbox, albumhbox, yearandtrackhbox, genrehbox, commenthbox, ui.label() ] for i, widget in enumerate(tablewidgets): table.attach(widget, 1, 2, i + 1, i + 2, gtk.FILL | gtk.EXPAND, gtk.FILL | gtk.EXPAND, 2, 0) editwindow.vbox.pack_start(table) saveall_button = None if len(files) > 1: # Only show save all button if more than one song being edited. saveall_button = ui.button(text=_("Save _All")) editwindow.action_area.pack_start(saveall_button) editwindow.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT) editwindow.add_button(gtk.STOCK_SAVE, gtk.RESPONSE_ACCEPT) editwindow.connect('delete_event', self.tags_win_hide, tags) entries = [ titleentry, artistentry, albumentry, yearentry, trackentry, genreentry, commententry ] buttons = [ titlebutton, artistbutton, albumbutton, yearbutton, trackbutton, genrebutton, commentbutton ] entries_names = [ "title", "artist", "album", "year", "track", "genre", "comment" ] editwindow.connect('response', self.tags_win_response, tags, entries, entries_names) if saveall_button: saveall_button.connect('clicked', self.tags_win_save_all, editwindow, tags, entries, entries_names) for button, name, entry in zip(buttons, entries_names, entries): entry.connect('changed', self.tags_win_entry_changed) button.connect('clicked', self.tags_win_apply_all, name, tags, entry) self.tags_win_update(editwindow, tags, entries, entries_names) ui.change_cursor(None) self.filelabel.set_size_request( editwindow.size_request()[0] - titlelabel.size_request()[0] - 70, -1) editwindow.show_all()
def current_update(self, prevstatus_playlist, new_playlist_length): if self.connected(): if self.sonata_loaded(): playlistposition = self.current.get_visible_rect()[1] self.current.freeze_child_notify() if not self.current_update_skip: if not self.filterbox_visible: self.current.set_model(None) if prevstatus_playlist: changed_songs = mpdh.call(self.client, 'plchanges', prevstatus_playlist) else: changed_songs = mpdh.call(self.client, 'plchanges', 0) self.current_songs = [] newlen = int(new_playlist_length) currlen = len(self.currentdata) for track in changed_songs: pos = mpdh.get(track, 'pos', 0, True) items = [formatting.parse(part, track, True) for part in self.columnformat] if self.aimp_headers: items += [""] if pos < currlen: # Update attributes for item: i = self.currentdata.get_iter((pos, )) trackid = mpdh.get(track, 'id', 0, True) if trackid != self.currentdata.get_value(i, 0): self.currentdata.set_value(i, 0, trackid) for index in range(len(items)): if items[index] != self.currentdata.get_value(i, index + 1): self.currentdata.set_value(i, index + 1, items[index]) if pos < len(self.current_songs): self.current_songs[pos] = track elif pos == len(self.current_songs): self.current_songs.append(track) else: raise Exception else: # Add new item: self.currentdata.append([mpdh.get(track, 'id', 0, True)] + items) self.current_songs.append(track) if newlen == 0: self.currentdata.clear() self.current_songs = [] else: # Remove excess songs: for i in range(currlen-newlen): it = self.currentdata.get_iter((currlen-1-i,)) self.currentdata.remove(it) self.current_songs = self.current_songs[:newlen] if not self.filterbox_visible: self.current.set_model(self.currentdata) self.current_update_skip = False # Update AIMP headers if len(self.current_songs) > 0: self.currentdata.set_value(self.currentdata.get_iter(0), len(self.columnformat)+1, aimpheaders.by_filename(mpdh.get(self.current_songs[0], 'file'))) for i in range(1, len(self.current_songs)): this_header = aimpheaders.by_filename(mpdh.get(self.current_songs[i], 'file')) prev_header = aimpheaders.by_filename(mpdh.get(self.current_songs[i-1], 'file')) if this_header != prev_header: self.currentdata.set_value(self.currentdata.get_iter(i), len(self.columnformat)+1, this_header) else: self.currentdata.set_value(self.currentdata.get_iter(i), len(self.columnformat)+1, '') # Update statusbar time: self.total_time = 0 for track in self.current_songs: try: self.total_time = self.total_time + mpdh.get(track, 'time', 0, True) except: pass if 'pos' in self.songinfo(): currsong = mpdh.get(self.songinfo(), 'pos', 0, True) self.boldrow(currsong) self.prev_boldrow = currsong if self.filterbox_visible: # Refresh filtered results: self.prevtodo = "RETAIN_POS_AND_SEL" # Hacky, but this ensures we retain the self.current position/selection self.plpos = playlistposition self.searchfilter_feed_loop(self.filterpattern) elif self.sonata_loaded(): self.playlist_retain_view(self.current, playlistposition) self.current.thaw_child_notify() self.header_update_column_indicators() self.update_statusbar() ui.change_cursor(None)
def on_tags_edit(self, files, temp_mpdpaths, music_dir): """Display the editing dialog""" # Try loading module global tagpy if tagpy is None: try: import tagpy except ImportError: ui.show_msg(self.window, _("Taglib and/or tagpy not found, tag editing support disabled."), _("Edit Tags"), 'editTagsError', gtk.BUTTONS_CLOSE, response_cb=ui.dialog_destroy) ui.change_cursor(None) return # Set default tag encoding to utf8.. fixes some reported bugs. import tagpy.id3v2 as id3v2 id3v2.FrameFactory.instance().setDefaultTextEncoding(tagpy.StringType.UTF8) # Make sure tagpy is at least 0.91 if hasattr(tagpy.Tag.title, '__call__'): ui.show_msg(self.window, _("Tagpy version < 0.91. Please upgrade to a newer version, tag editing support disabled."), _("Edit Tags"), 'editTagsError', gtk.BUTTONS_CLOSE, response_cb=ui.dialog_destroy) ui.change_cursor(None) return if not os.path.isdir(misc.file_from_utf8(music_dir)): ui.show_msg(self.window, _("The path %s does not exist. Please specify a valid music directory in preferences.") % music_dir, _("Edit Tags"), 'editTagsError', gtk.BUTTONS_CLOSE, response_cb=ui.dialog_destroy) ui.change_cursor(None) return # XXX file list was created here if len(files) == 0: ui.change_cursor(None) return # Initialize: self.tagnum = -1 tags = [{'title':'', 'artist':'', 'album':'', 'year':'', 'track':'', 'genre':'', 'comment':'', 'title-changed':False, 'artist-changed':False, 'album-changed':False, 'year-changed':False, 'track-changed':False, 'genre-changed':False, 'comment-changed':False, 'fullpath':misc.file_from_utf8(filename), 'mpdpath':path} for filename, path in zip(files, temp_mpdpaths)] if not os.path.exists(tags[0]['fullpath']): ui.change_cursor(None) ui.show_msg(self.window, _("File '%s' not found. Please specify a valid music directory in preferences.") % tags[0]['fullpath'], _("Edit Tags"), 'editTagsError', gtk.BUTTONS_CLOSE, response_cb=ui.dialog_destroy) return if not self.tags_next_tag(tags): ui.change_cursor(None) ui.show_msg(self.window, _("No music files with editable tags found."), _("Edit Tags"), 'editTagsError', gtk.BUTTONS_CLOSE, response_cb=ui.dialog_destroy) return editwindow = ui.dialog(parent=self.window, flags=gtk.DIALOG_MODAL, role='editTags', resizable=False, separator=False) editwindow.set_size_request(375, -1) table = gtk.Table(9, 2, False) table.set_row_spacings(2) self.filelabel = ui.label(select=True, wrap=True) filehbox = gtk.HBox() sonataicon = ui.image(stock='sonata', stocksize=gtk.ICON_SIZE_DND, x=1) expandbutton = ui.button(" ") self.set_expandbutton_state(expandbutton) expandvbox = gtk.VBox() expandvbox.pack_start(ui.label(), True, True) expandvbox.pack_start(expandbutton, False, False) expandvbox.pack_start(ui.label(), True, True) expandbutton.connect('clicked', self.toggle_path) blanklabel = ui.label(w=5, h=12) filehbox.pack_start(sonataicon, False, False, 2) filehbox.pack_start(self.filelabel, True, True, 2) filehbox.pack_start(expandvbox, False, False, 2) filehbox.pack_start(blanklabel, False, False, 2) titlelabel, titleentry, titlebutton, titlehbox = self._create_label_entry_button_hbox(_("Title:")) artistlabel, artistentry, artistbutton, artisthbox = self._create_label_entry_button_hbox(_("Artist:")) albumlabel, albumentry, albumbutton, albumhbox = self._create_label_entry_button_hbox(_("Album:")) yearlabel, yearentry, yearbutton, yearhbox = self._create_label_entry_button_hbox(_("Year:")) yearentry.set_size_request(50,-1) tracklabel, trackentry, trackbutton, trackhbox = self._create_label_entry_button_hbox(" " + _("Track:"), True) trackentry.set_size_request(50,-1) yearandtrackhbox = gtk.HBox() yearandtrackhbox.pack_start(yearhbox, True, True, 0) yearandtrackhbox.pack_start(trackhbox, True, True, 0) yearentry.connect("insert_text", self.tags_win_entry_constraint, True) trackentry.connect("insert_text", self.tags_win_entry_constraint, False) genrelabel = ui.label(text=_("Genre:"), x=1) genrecombo = ui.comboentry(items=self.tags_win_genres(), wrap=2) genreentry = genrecombo.get_child() genrehbox = gtk.HBox() genrebutton = ui.button() genrebuttonvbox = self.tags_win_create_apply_all_button(genrebutton, genreentry) genrehbox.pack_start(genrelabel, False, False, 2) genrehbox.pack_start(genrecombo, True, True, 2) genrehbox.pack_start(genrebuttonvbox, False, False, 2) commentlabel, commententry, commentbutton, commenthbox = self._create_label_entry_button_hbox(_("Comment:")) ui.set_widths_equal([titlelabel, artistlabel, albumlabel, yearlabel, genrelabel, commentlabel, sonataicon]) genrecombo.set_size_request(-1, titleentry.size_request()[1]) tablewidgets = [ui.label(), filehbox, ui.label(), titlehbox, artisthbox, albumhbox, yearandtrackhbox, genrehbox, commenthbox, ui.label()] for i, widget in enumerate(tablewidgets): table.attach(widget, 1, 2, i+1, i+2, gtk.FILL|gtk.EXPAND, gtk.FILL|gtk.EXPAND, 2, 0) editwindow.vbox.pack_start(table) saveall_button = None if len(files) > 1: # Only show save all button if more than one song being edited. saveall_button = ui.button(text=_("Save _All")) editwindow.action_area.pack_start(saveall_button) editwindow.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT) editwindow.add_button(gtk.STOCK_SAVE, gtk.RESPONSE_ACCEPT) editwindow.connect('delete_event', self.tags_win_hide, tags) entries = [titleentry, artistentry, albumentry, yearentry, trackentry, genreentry, commententry] buttons = [titlebutton, artistbutton, albumbutton, yearbutton, trackbutton, genrebutton, commentbutton] entries_names = ["title", "artist", "album", "year", "track", "genre", "comment"] editwindow.connect('response', self.tags_win_response, tags, entries, entries_names) if saveall_button: saveall_button.connect('clicked', self.tags_win_save_all, editwindow, tags, entries, entries_names) for button, name, entry in zip(buttons, entries_names, entries): entry.connect('changed', self.tags_win_entry_changed) button.connect('clicked', self.tags_win_apply_all, name, tags, entry) self.tags_win_update(editwindow, tags, entries, entries_names) ui.change_cursor(None) self.filelabel.set_size_request(editwindow.size_request()[0] - titlelabel.size_request()[0] - 70, -1) editwindow.show_all()