def __save_files(self, parent, model, library): win = WritingWindow(parent, len(model)) was_changed = set() for song, track in [(r[0], r[2]) for r in model]: if song.get("tracknumber") == track: win.step() continue if not song.valid() and not qltk.ConfirmAction( win, _("Tag may not be accurate"), _("<b>%s</b> changed while the program was running. " "Saving without refreshing your library may " "overwrite other changes to the song.\n\n" "Save this song anyway?") % util.escape(fsdecode(song("~basename")))).run(): break song["tracknumber"] = track try: song.write() except: util.print_exc() qltk.ErrorMessage( win, _("Unable to save song"), _("Saving <b>%s</b> failed. The file may be " "read-only, corrupted, or you do not have " "permission to edit it.") % util.escape(fsdecode(song('~basename')))).run() library.reload(song, changed=was_changed) break was_changed.add(song) if win.step(): break library.changed(was_changed) win.destroy()
def __save(self, addreplace, library): pattern_text = self.combo.get_child().get_text().decode('utf-8') pattern = TagsFromPattern(pattern_text) model = self.view.get_model() add = bool(addreplace.get_active()) win = WritingWindow(self, len(model)) win.show() was_changed = set() for row in (model or []): song = row[0] changed = False if not song.valid() and not qltk.ConfirmAction( self, _("Tag may not be accurate"), _("<b>%s</b> changed while the program was running. " "Saving without refreshing your library may " "overwrite other changes to the song.\n\n" "Save this song anyway?") % ( util.escape(fsdecode(song("~basename")))) ).run(): break for i, h in enumerate(pattern.headers): if row[i + 2]: text = row[i + 2].decode("utf-8") if not add or h not in song or not song.multiple_values: song[h] = text changed = True else: for val in text.split("\n"): if val not in song.list(h): song.add(h, val) changed = True if changed: try: song.write() except: qltk.ErrorMessage( self, _("Unable to edit song"), _("Saving <b>%s</b> failed. The file " "may be read-only, corrupted, or you " "do not have permission to edit it.") % ( util.escape(fsdecode(song('~basename')))) ).run() library.reload(song, changed=was_changed) break was_changed.add(song) if win.step(): break win.destroy() library.changed(was_changed) self.save.set_sensitive(False)
def __rename(self, library): model = self.view.get_model() win = WritingWindow(self, len(model)) win.show() was_changed = set() skip_all = False self.view.freeze_child_notify() # FIXME: encoding/decoding mess rows = [(row[0], row[1], row[2].decode('utf-8')) for row in model] for song, oldname, newname in rows: try: newname = util.fsnative(newname) library.rename(song, newname, changed=was_changed) except StandardError: util.print_exc() if skip_all: continue RESPONSE_SKIP_ALL = 1 buttons = (_("Ignore _All Errors"), RESPONSE_SKIP_ALL, Gtk.STOCK_STOP, Gtk.ResponseType.CANCEL, _("_Continue"), Gtk.ResponseType.OK) msg = qltk.Message( Gtk.MessageType.ERROR, win, _("Unable to rename file"), _("Renaming <b>%s</b> to <b>%s</b> failed. " "Possibly the target file already exists, " "or you do not have permission to make the " "new file or remove the old one.") % (util.escape( fsdecode(oldname)), util.escape(fsdecode(newname))), buttons=Gtk.ButtonsType.NONE) msg.add_buttons(*buttons) msg.set_default_response(Gtk.ResponseType.OK) resp = msg.run() skip_all |= (resp == RESPONSE_SKIP_ALL) # Preserve old behavior: shift-click is Ignore All mods = Gdk.Display.get_default().get_pointer()[3] skip_all |= mods & Gdk.ModifierType.SHIFT_MASK library.reload(song, changed=was_changed) if resp != Gtk.ResponseType.OK and resp != RESPONSE_SKIP_ALL: break if win.step(): break self.view.thaw_child_notify() win.destroy() library.changed(was_changed) self.save.set_sensitive(False)
def sort_key(song): """Sort by path so untagged albums have a good start order. Also take into account the directory in case it's split in different folders by medium. """ return util.human_sort_key(path.fsdecode(song("~filename")))
def test_main(self): self.assertEqual(decode_value("~#foo", 0.25), u"0.25") self.assertEqual(decode_value("~#foo", 4), u"4") self.assertEqual(decode_value("~#foo", "bar"), u"bar") self.assertTrue(isinstance(decode_value("~#foo", "bar"), unicode)) path = fsnative(u"/foobar") self.assertEqual(decode_value("~filename", path), fsdecode(path))
def _post(self, value, song): if value: fn = song.get("~filename", ".") ext = fn[fn.rfind("."):].lower() val_ext = value[-len(ext):].lower() if not ext == val_ext: value += ext.lower() if os.name == "nt": value = strip_win32_incompat_from_path(value) value = expanduser(value) # Limit each path section to 255 (bytes on linux, chars on win). # http://en.wikipedia.org/wiki/Comparison_of_file_systems#Limits path, ext = os.path.splitext(value) path = map(util.fsnative, path.split(os.sep)) limit = [255] * len(path) limit[-1] -= len(util.fsnative(ext)) elip = lambda (p, l): (len(p) > l and p[:l - 2] + "..") or p path = os.sep.join(map(elip, zip(path, limit))) value = fsdecode(path) + ext if os.sep in value and not os.path.isabs(value): raise ValueError("Pattern is not rooted") return value
def cdf(column, cell, model, iter, data): row = model[iter] filename = fsdecode(unexpand(row[0])) function = row[1] line = row[2] cell.set_property( "markup", "<b>%s</b> line %d\n\t%s" % ( util.escape(function), line, util.escape(filename)))
def __init__(self, parent, song): title = _("Unable to save song") fn_format = "<b>%s</b>" % util.escape(fsdecode(song("~basename"))) description = _("Saving %(file-name)s failed. The file may be " "read-only, corrupted, or you do not have " "permission to edit it.") % {"file-name": fn_format} super(WriteFailedError, self).__init__( parent, title, description)
def main(argv): import quodlibet from quodlibet.qltk import add_signal_watch, icons add_signal_watch(app.quit) opts = util.OptionParser("Ex Falso", const.VERSION, _("an audio tag editor"), "[%s]" % _("directory")) # FIXME: support unicode on Windows, sys.argv isn't good enough argv.append(os.path.abspath(fsnative(u"."))) opts, args = opts.parse(argv[1:]) args[0] = os.path.realpath(args[0]) config.init(os.path.join(quodlibet.get_user_dir(), "config")) app.name = "Ex Falso" app.id = "exfalso" quodlibet.init(icon=icons.EXFALSO, name=app.name, proc_title=app.id) import quodlibet.library import quodlibet.player app.library = quodlibet.library.init() app.player = quodlibet.player.init_player("nullbe", app.librarian) from quodlibet.qltk.songlist import PlaylistModel app.player.setup(PlaylistModel(), None, 0) pm = quodlibet.init_plugins() pm.rescan() from quodlibet.qltk.exfalsowindow import ExFalsoWindow dir_ = args[0] if os.name == "nt": dir_ = fsdecode(dir_) app.window = ExFalsoWindow(app.library, dir_) app.window.init_plugins() from quodlibet.util.cover import CoverManager app.cover_manager = CoverManager() app.cover_manager.init_plugins() from quodlibet.qltk import session session.init("exfalso") quodlibet.enable_periodic_save(save_library=False) quodlibet.main(app.window) quodlibet.finish_first_session(app.id) config.save() print_d("Finished shutdown.")
def scan(self, paths, exclude=[], cofuncid=None): added = [] exclude = [expanduser(path) for path in exclude if path] def need_yield(last_yield=[0]): current = time.time() if abs(current - last_yield[0]) > 0.015: last_yield[0] = current return True return False def need_added(last_added=[0]): current = time.time() if abs(current - last_added[0]) > 1.0: last_added[0] = current return True return False for fullpath in paths: print_d("Scanning %r." % fullpath, self) desc = _("Scanning %s") % (unexpand(fsdecode(fullpath))) with Task(_("Library"), desc) as task: if cofuncid: task.copool(cofuncid) fullpath = expanduser(fullpath) if filter(fullpath.startswith, exclude): continue for path, dnames, fnames in os.walk(fullpath): for filename in fnames: fullfilename = os.path.join(path, filename) if filter(fullfilename.startswith, exclude): continue if fullfilename not in self._contents: fullfilename = os.path.realpath(fullfilename) # skip unknown file extensions if not formats.filter(fullfilename): continue if filter(fullfilename.startswith, exclude): continue if fullfilename not in self._contents: item = self.add_filename(fullfilename, False) if item is not None: added.append(item) if len(added) > 100 or need_added(): self.add(added) added = [] task.pulse() yield if added and need_yield(): yield if added: self.add(added) added = [] task.pulse() yield True
def __init__(self, parent, song): title = _("Unable to save song") fn_format = "<b>%s</b>" % util.escape(fsdecode(song("~basename"))) description = _("Saving %(file-name)s failed. The file may be " "read-only, corrupted, or you do not have " "permission to edit it.") % { "file-name": fn_format } super(WriteFailedError, self).__init__(parent, title, description)
def comma(self, key): value = self.__song.comma(key) if isinstance(value, str): value = fsdecode(value) elif not isinstance(value, unicode): if isinstance(value, float): value = "%.2f" % value value = unicode(value) if self.__formatter: return self.__formatter(key, value) return value
def filename(self): """a local filename equivalent to the URI""" if self.scheme != "file": raise ValueError("only the file scheme supports filenames") elif self.netloc: raise ValueError("only local files have filenames") else: if os.name == "nt": return fsdecode(url2pathname(self.path)) else: return url2pathname(self.path)
def __dict(self, song): dict = {} for key, value in (song or {}).items(): if not isinstance(value, basestring): value = unicode(value) elif isinstance(value, str): value = fsdecode(value) dict[key] = dbusutils.dbus_unicode_validate(value) if song: dict["~uri"] = song("~uri") return dict
def __preview(self, pattern, songs): rows = [] for song in songs: match = pattern.match(song) row = [fsdecode(song("~basename"))] for header in pattern.headers: row.append(match.get(header, u"")) rows.append(row) headers = [_("File")] + pattern.headers nicks = ["file"] + pattern.headers print_table(rows, headers, nicks, nicks)
def __init__(self, parent, path): title = _("File exists") fn_format = "<b>%s</b>" % util.escape(fsdecode(path)) description = _("Replace %(file-name)s?") % {"file-name": fn_format} super(ConfirmFileReplace, self).__init__( parent, title, description, buttons=Gtk.ButtonsType.NONE) self.add_button(_("_Cancel"), Gtk.ResponseType.CANCEL) self.add_icon_button(_("_Replace File"), Icons.DOCUMENT_SAVE, self.RESPONSE_REPLACE) self.set_default_response(Gtk.ResponseType.CANCEL)
def __preview(self, songs): model = self.view.get_model() if songs is None: songs = [row[0] for row in model] pattern = self.combo.get_child().get_text().decode("utf-8") try: pattern = FileFromPattern(pattern) except ValueError: qltk.ErrorMessage( self, _("Path is not absolute"), _("The pattern\n\t<b>%s</b>\ncontains / but " "does not start from root. To avoid misnamed " "folders, root your pattern by starting " "it with / or ~/.") % (util.escape(pattern))).run() return else: if self.combo.get_child().get_text(): self.combo.prepend_text(self.combo.get_child().get_text()) self.combo.write(const.NBP) orignames = [song["~filename"] for song in songs] newnames = [pattern.format(song) for song in songs] for f in self.filters: if f.active: newnames = f.filter_list(orignames, newnames) model.clear() for song, newname in zip(songs, newnames): basename = fsdecode(song("~basename")) newname = fsdecode(newname) model.append(row=[song, basename, newname]) self.preview.set_sensitive(False) self.save.set_sensitive(bool(self.combo.get_child().get_text())) for song in songs: if not song.is_file: self.set_sensitive(False) break else: self.set_sensitive(True)
def __init__(self, parent, path): title = _("File exists") fn_format = "<b>%s</b>" % util.escape(fsdecode(path)) description = _("Replace %(file-name)s?") % {"file-name": fn_format} super(ConfirmFileReplace, self).__init__( parent, title, description, buttons=Gtk.ButtonsType.NONE) self.add_button(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL) save_button = Button(_("_Replace File"), "document-save") save_button.show() self.add_action_widget(save_button, self.RESPONSE_REPLACE) self.set_default_response(Gtk.ResponseType.CANCEL)
def parse_m3u(filename, library=None): plname = fsdecode(os.path.basename(os.path.splitext(filename)[0])) filenames = [] with open(filename, "rb") as h: for line in h: line = line.strip() if line.startswith("#"): continue else: filenames.append(line) return __parse_playlist(plname, filename, filenames, library)
def search(self, data): for name in self.__names: val = data.get(name) if val is None: # filename is the only real entry that's a path if name == "filename": val = fsdecode(data.get("~filename", "")) else: val = data.get("~" + name, "") if self.res.search(unicode(val)): return True for name in self.__intern: if self.res.search(unicode(data(name))): return True for name in self.__fs: if self.res.search(fsdecode(data(name))): return True return False
def main(): global quodlibet from quodlibet.qltk import add_signal_watch, icons add_signal_watch(app.quit) opts = util.OptionParser("Ex Falso", const.VERSION, _("an audio tag editor"), "[%s]" % _("directory")) # FIXME: support unicode on Windows, sys.argv isn't good enough sys.argv.append(os.path.abspath(".")) opts, args = opts.parse() args[0] = os.path.realpath(args[0]) config.init(const.CONFIG) app.name = "Ex Falso" app.id = "exfalso" quodlibet.init(icon=icons.EXFALSO, name=app.name, proc_title=app.id) import quodlibet.library import quodlibet.player app.library = quodlibet.library.init() app.player = quodlibet.player.init_player("nullbe", app.librarian) from quodlibet.qltk.songlist import PlaylistModel app.player.setup(PlaylistModel(), None, 0) pm = quodlibet.init_plugins() pm.rescan() from quodlibet.qltk.exfalsowindow import ExFalsoWindow dir_ = args[0] if os.name == "nt": dir_ = fsdecode(dir_) app.window = ExFalsoWindow(app.library, dir_) app.window.init_plugins() from quodlibet.util.cover import CoverManager app.cover_manager = CoverManager() app.cover_manager.init_plugins() from quodlibet.qltk import session session.init("exfalso") quodlibet.enable_periodic_save(save_library=False) quodlibet.main(app.window) quodlibet.finish_first_session(app.id) config.save(const.CONFIG) print_d("Finished shutdown.")
def __init__(self, parent, path): title = _("File exists") fn_format = "<b>%s</b>" % util.escape(fsdecode(path)) description = _("Replace %(file-name)s?") % {"file-name": fn_format} super(ConfirmFileReplace, self).__init__(parent, title, description, buttons=Gtk.ButtonsType.NONE) self.add_button(_("_Cancel"), Gtk.ResponseType.CANCEL) self.add_icon_button(_("_Replace File"), Icons.DOCUMENT_SAVE, self.RESPONSE_REPLACE) self.set_default_response(Gtk.ResponseType.CANCEL)
def decode_value(tag, value): """Returns a unicode representation of the passed value, based on the type and the tag it originated from. Not reversible. """ if isinstance(value, text_type): return value elif isinstance(value, float): return u"%.2f" % value elif tag in FILESYSTEM_TAGS: return fsdecode(value) return text_type(value)
def __init__(self, filename): with translate_errors(): with open(filename, "rb") as h: head = h.read(46) if len(head) != 46 or head[:27] != b"SNES-SPC700 Sound File Data": raise IOError("Not a valid SNES-SPC700 file") if getbyte(head, 35) == b"\x1a": data = h.read(210) if len(data) == 210: self.update(parse_id666(data)) self.setdefault("title", fsdecode(os.path.basename(filename)[:-4])) self.sanitize(filename)
def decode_value(tag, value): """Returns a unicode representation of the passed value, based on the type and the tag it originated from. Not reversible. """ if isinstance(value, unicode): return value elif isinstance(value, float): return u"%.2f" % value elif tag in FILESYSTEM_TAGS: return fsdecode(value) return unicode(value)
def parse_m3u(filename, library=None): plname = fsdecode(os.path.basename( os.path.splitext(filename)[0])).encode('utf-8') filenames = [] h = file(filename) for line in h: line = line.strip() if line.startswith("#"): continue else: filenames.append(line) h.close() return __parse_playlist(plname, filename, filenames, library)
def _song_to_text(self, song): # to text lines = [] for key in sorted(song.realkeys(), key=sortkey): for value in song.list(key): lines.append(u"%s=%s" % (key, value)) lines += [ u"", u"#" * 80, u"# Lines that are empty or start with '#' will be ignored", u"# File: %r" % fsdecode(song("~filename")), ] return u"\n".join(lines)
def __init__(self, paths): super(FileListExpander, self).__init__(label=_("Files:")) self.set_resize_toplevel(True) paths = [fsdecode(unexpand(p)) for p in paths] lab = Gtk.Label(label="\n".join(paths)) lab.set_alignment(0.0, 0.0) lab.set_selectable(True) win = Gtk.ScrolledWindow() win.add_with_viewport(Align(lab, border=6)) win.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) win.set_shadow_type(Gtk.ShadowType.ETCHED_OUT) win.set_size_request(-1, 100) self.add(win) win.show_all()
def __init__(self, parent, path): title = _("File exists") fn_format = "<b>%s</b>" % util.escape(fsdecode(path)) description = _("Replace %(file-name)s?") % {"file-name": fn_format} super(ConfirmFileReplace, self).__init__(parent, title, description, buttons=Gtk.ButtonsType.NONE) self.add_button(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL) save_button = Button(_("_Replace File"), "document-save") save_button.show() self.add_action_widget(save_button, self.RESPONSE_REPLACE) self.set_default_response(Gtk.ResponseType.CANCEL)
def __init__(self, paths): super(FileListExpander, self).__init__(label=_("Files:")) self.set_resize_toplevel(True) paths = [fsdecode(unexpand(p)) for p in paths] lab = Gtk.Label(label="\n".join(paths)) lab.set_alignment(0.0, 0.0) lab.set_selectable(True) win = Gtk.ScrolledWindow() win.add_with_viewport(Alignment(lab, border=6)) win.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) win.set_shadow_type(Gtk.ShadowType.ETCHED_OUT) win.set_size_request(-1, 100) self.add(win) win.show_all()
def sort_by_func(tag): """Returns a fast sort function for a specific tag (or pattern). Some keys are already in the sort cache, so we can use them.""" def artist_sort(song): return song.sort_key[1][2] if callable(tag): return lambda song: human(tag(song)) elif tag == "artistsort": return artist_sort elif tag in FILESYSTEM_TAGS: return lambda song: fsdecode(song(tag), note=False) elif tag.startswith("~#") and "~" not in tag[2:]: return lambda song: song(tag) return lambda song: human(song(tag))
def __init__(self, filename): with translate_errors(): with open(filename, "rb") as h: head = h.read(46) if len(head) != 46 or \ head[:27] != b'SNES-SPC700 Sound File Data': raise IOError("Not a valid SNES-SPC700 file") if getbyte(head, 35) == b'\x1a': data = h.read(210) if len(data) == 210: self.update(parse_id666(data)) self.setdefault("title", fsdecode(os.path.basename(filename)[:-4])) self.sanitize(filename)
def __init__(self, parent, song): title = _("Tag may not be accurate") fn_format = "<b>%s</b>" % util.escape(fsdecode(song("~basename"))) description = _("%(file-name)s changed while the program was running. " "Saving without refreshing your library may " "overwrite other changes to the song.") % {"file-name": fn_format} super(OverwriteWarning, self).__init__( parent, title, description, buttons=Gtk.ButtonsType.NONE) self.add_button(_("_Cancel"), Gtk.ResponseType.CANCEL) self.add_icon_button(_("_Save"), Icons.DOCUMENT_SAVE, self.RESPONSE_SAVE) self.set_default_response(Gtk.ResponseType.CANCEL)
def parse_pls(filename, name="", library=None): plname = fsdecode(os.path.basename(os.path.splitext(filename)[0])) filenames = [] with open(filename) as h: for line in h: line = line.strip() if not line.lower().startswith("file"): continue else: try: line = line[line.index("=") + 1:].strip() except ValueError: pass else: filenames.append(line) return __parse_playlist(plname, filename, filenames, library)
def match_path(self, path): assert is_fsnative(path) tail = os.path.splitdrive(path)[-1] # only match on the last n pieces of a filename, dictated by pattern # this means no pattern may effectively cross a /, despite .* doing so sep = os.path.sep matchon = sep + sep.join(tail.split(sep)[-self.slashes:]) # work on unicode matchon = fsdecode(matchon, note=False) match = self.pattern.search(matchon) # dicts for all! if match is None: return {} else: return match.groupdict()
def parse_pls(filename, name="", library=None): plname = fsdecode(os.path.basename(os.path.splitext(filename)[0])) filenames = [] h = file(filename) for line in h: line = line.strip() if not line.lower().startswith("file"): continue else: try: line = line[line.index("=") + 1 :].strip() except ValueError: pass else: filenames.append(line) h.close() return __parse_playlist(plname, filename, filenames, library)
def __preview(self, songs): model = self.view.get_model() if songs is None: songs = [e.song for e in model.itervalues()] pattern_text = gdecode(self.combo.get_child().get_text()) try: pattern = FileFromPattern(pattern_text) except ValueError: qltk.ErrorMessage( self, _("Path is not absolute"), _("The pattern\n\t<b>%s</b>\ncontains / but " "does not start from root. To avoid misnamed " "folders, root your pattern by starting " "it with / or ~/.") % ( util.escape(pattern))).run() return else: if pattern: self.combo.prepend_text(pattern_text) self.combo.write(NBP) # native paths orignames = [song["~filename"] for song in songs] newnames = [pattern.format(song) for song in songs] for f in self.filter_box.filters: if f.active: newnames = f.filter_list(orignames, newnames) model.clear() for song, newname in zip(songs, newnames): entry = Entry(song) entry.new_name = fsdecode(newname) model.append(row=[entry]) self.preview.set_sensitive(False) self.save.set_sensitive(bool(pattern_text)) for song in songs: if not song.is_file: self.set_sensitive(False) break else: self.set_sensitive(True)
def __preview(self, songs): model = self.view.get_model() if songs is None: songs = [e.song for e in model.itervalues()] pattern_text = gdecode(self.combo.get_child().get_text()) try: pattern = FileFromPattern(pattern_text) except ValueError: qltk.ErrorMessage( self, _("Path is not absolute"), _("The pattern\n\t<b>%s</b>\ncontains / but " "does not start from root. To avoid misnamed " "folders, root your pattern by starting " "it with / or ~/.") % (util.escape(pattern))).run() return else: if pattern: self.combo.prepend_text(pattern_text) self.combo.write(NBP) # native paths orignames = [song["~filename"] for song in songs] newnames = [pattern.format(song) for song in songs] for f in self.filter_box.filters: if f.active: newnames = f.filter_list(orignames, newnames) model.clear() for song, newname in zip(songs, newnames): entry = Entry(song) entry.new_name = fsdecode(newname) model.append(row=[entry]) self.preview.set_sensitive(False) self.save.set_sensitive(bool(pattern_text)) for song in songs: if not song.is_file: self.set_sensitive(False) break else: self.set_sensitive(True)
def comma(self, key): """Get all values of a tag, separated by commas. Synthetic tags are supported, but will be slower. All list items will be unicode. If the value is numeric, that is returned rather than a list. """ if "~" in key or key == "title": v = self(key, u"") if key in FILESYSTEM_TAGS: v = fsdecode(v) else: v = self.get(key, u"") if isinstance(v, number_types): return v else: return v.replace("\n", ", ")
def comma(self, key): """Get all values of a tag, separated by commas. Synthetic tags are supported, but will be slower. All list items will be unicode. If the value is numeric, that is returned rather than a list. """ if "~" in key or key == "title": v = self(key, u"") if key in FILESYSTEM_TAGS: v = fsdecode(v) else: v = self.get(key, u"") if isinstance(v, (int, long, float)): return v else: return v.replace("\n", ", ")
def __init__(self, parent, song): title = _("Tag may not be accurate") fn_format = "<b>%s</b>" % util.escape(fsdecode(song("~basename"))) description = _("%(file-name)s changed while the program was running. " "Saving without refreshing your library may " "overwrite other changes to the song.") % { "file-name": fn_format } super(OverwriteWarning, self).__init__(parent, title, description, buttons=Gtk.ButtonsType.NONE) self.add_button(_("_Cancel"), Gtk.ResponseType.CANCEL) self.add_icon_button(_("_Save"), Icons.DOCUMENT_SAVE, self.RESPONSE_SAVE) self.set_default_response(Gtk.ResponseType.CANCEL)
def _file(self, song, box): def ftime(t): if t == 0: return _("Unknown") else: timestr = time.strftime("%c", time.localtime(t)) encoding = util.get_locale_encoding() return timestr.decode(encoding) fn = fsdecode(unexpand(song["~filename"])) length = util.format_time_long(song.get("~#length", 0)) size = util.format_size( song.get("~#filesize") or filesize(song["~filename"])) mtime = ftime(util.path.mtime(song["~filename"])) format_ = song("~format") codec = song("~codec") encoding = song.comma("~encoding") bitrate = song("~bitrate") t = Gtk.Table(n_rows=4, n_columns=2) t.set_col_spacings(6) t.set_homogeneous(False) table = [(_("length"), length), (_("format"), format_), (_("codec"), codec), (_("encoding"), encoding), (_("bitrate"), bitrate), (_("file size"), size), (_("modified"), mtime)] fnlab = Label(fn) fnlab.set_ellipsize(Pango.EllipsizeMode.MIDDLE) t.attach(fnlab, 0, 2, 0, 1, xoptions=Gtk.AttachOptions.FILL) for i, (l, r) in enumerate(table): l = "<b>%s</b>" % util.capitalize(util.escape(l) + ":") lab = Label() lab.set_markup(l) t.attach(lab, 0, 1, i + 1, i + 2, xoptions=Gtk.AttachOptions.FILL) t.attach(Label(r), 1, 2, i + 1, i + 2) box.pack_start(Frame(_("File"), t), False, False, 0)
def _file(self, song, box): def ftime(t): if t == 0: return _("Unknown") else: timestr = time.strftime("%c", time.localtime(t)) return timestr.decode(const.ENCODING) fn = fsdecode(unexpand(song["~filename"])) length = util.format_time_long(song.get("~#length", 0)) size = util.format_size( song.get("~#filesize") or filesize(song["~filename"])) mtime = ftime(util.path.mtime(song["~filename"])) bitrate = song.get("~#bitrate", 0) if bitrate != 0: bitrate = _("%d kbps") % int(bitrate) else: bitrate = False t = Gtk.Table(n_rows=4, n_columns=2) t.set_col_spacings(6) t.set_homogeneous(False) table = [(_("length"), length), (_("file size"), size), (_("modified"), mtime)] if bitrate: table.insert(1, (_("bitrate"), bitrate)) fnlab = Label(fn) fnlab.set_ellipsize(Pango.EllipsizeMode.MIDDLE) t.attach(fnlab, 0, 2, 0, 1, xoptions=Gtk.AttachOptions.FILL) for i, (l, r) in enumerate(table): l = "<b>%s</b>" % util.capitalize(util.escape(l) + ":") lab = Label() lab.set_markup(l) t.attach(lab, 0, 1, i + 1, i + 2, xoptions=Gtk.AttachOptions.FILL) t.attach(Label(r), 1, 2, i + 1, i + 2) box.pack_start(Frame(_("File"), t), False, False, 0)
def _cdf(self, column, cell, model, iter_, user_data): values = model.get_value(iter_).list(self.header_name) value = values[0] if values else fsnative(u"") if not self._needs_update(value): return cell.set_property('text', fsdecode(unexpand(value)))
def cell_data(column, cell, model, iter_, userdata): value = model.get_value(iter_) cell.set_property('text', fsdecode(os.path.basename(value)))
def cell_data(column, cell, model, iter_, userdata): value = model.get_value(iter_) if value is not None: text = fsdecode(os.path.basename(value) or value) cell.set_property('text', text)
def sanitize(self, filename): super(WAVEFile, self).sanitize(filename) self["title"] = fsdecode(os.path.splitext( os.path.basename(self["~filename"]))[0])