def filter(self, orig_or_tag, value): fr = gdecode(self._from.get_text()) to = gdecode(self._to.get_text()) try: return re.sub(fr, to, value) except: return value
def __message(self, bus, message, librarian): if message.type == Gst.MessageType.EOS: print_d("Stream EOS") if not self._in_gapless_transition: self._source.next_ended() self._end(False) elif message.type == Gst.MessageType.TAG: self.__tag(message.parse_tag(), librarian) elif message.type == Gst.MessageType.ERROR: gerror, debug_info = message.parse_error() message = u"" if gerror: message = util.gdecode(gerror.message).rstrip(".") details = None if debug_info: # strip the first line, not user friendly debug_info = "\n".join(debug_info.splitlines()[1:]) # can contain paths, so not sure if utf-8 in all cases details = util.gdecode(debug_info) self._error(PlayerError(message, details)) elif message.type == Gst.MessageType.STATE_CHANGED: # pulsesink doesn't notify a volume change on startup # and the volume is only valid in > paused states. if message.src is self._ext_vol_element: self.notify("volume") if message.src is self._ext_mute_element: self.notify("mute") elif message.type == Gst.MessageType.STREAM_START: if self._in_gapless_transition: print_d("Stream changed") self._end(False) elif message.type == Gst.MessageType.ELEMENT: message_name = message.get_structure().get_name() if message_name == "missing-plugin": self.__handle_missing_plugin(message) elif message.type == Gst.MessageType.CLOCK_LOST: print_d("Clock lost") self.bin.set_state(Gst.State.PAUSED) self.bin.set_state(Gst.State.PLAYING) elif message.type == Gst.MessageType.LATENCY: print_d("Recalculate latency") self.bin.recalculate_latency() elif message.type == Gst.MessageType.REQUEST_STATE: state = message.parse_request_state() print_d("State requested: %s" % Gst.Element.state_get_name(state)) self.bin.set_state(state) elif message.type == Gst.MessageType.DURATION_CHANGED: if self.song.fill_length: ok, p = self.bin.query_duration(Gst.Format.TIME) if ok: p /= float(Gst.SECOND) self.song["~#length"] = p librarian.changed([self.song])
def __match_filter(self, completion, entrytext, iter, data): model = completion.get_model() entry = self.get_entry() entrytext = gdecode(entrytext) if entry is None: return False cursor = entry.get_position() if (cursor != len(entrytext) and not max( [entrytext[cursor:].startswith(s) for s in self.rightsep])): return False # find the border to the left left, f = max([(entrytext.rfind(c, 0, cursor), c) for c in self.leftsep]) if left < 0: left += 1 else: left += len(f) if left == cursor: return False key = entrytext[left:cursor] value = model.get_value(iter, self.get_property('text-column')) return bool(value and value.startswith(key))
def GStreamerSink(pipeline_desc): """Returns a list of unlinked gstreamer elements ending with an audio sink and a textual description of the pipeline. `pipeline_desc` can be gst-launch syntax for multiple elements with or without an audiosink. In case of an error, raises PlayerError """ pipe = None if pipeline_desc: try: pipe = [Gst.parse_launch(e) for e in pipeline_desc.split('!')] except GLib.GError as e: message = gdecode(e.message) raise PlayerError(_("Invalid GStreamer output pipeline"), message) if pipe: # In case the last element is linkable with a fakesink # it is not an audiosink, so we append the default one fake = Gst.ElementFactory.make('fakesink', None) if link_many([pipe[-1], fake]): unlink_many([pipe[-1], fake]) default_elm, default_desc = find_audio_sink() pipe += [default_elm] pipeline_desc += " ! " + default_desc else: elm, pipeline_desc = find_audio_sink() pipe = [elm] return pipe, pipeline_desc
def __edit_tag(self, renderer, path, new_value, model): new_value = gdecode(new_value) new_value = ', '.join(new_value.splitlines()) path = Gtk.TreePath.new_from_string(path) entry = model[path][0] error_dialog = None if not massagers.is_valid(entry.tag, new_value): error_dialog = qltk.WarningMessage( self, _("Invalid value"), _("Invalid value: <b>%(value)s</b>\n\n%(error)s") % { "value": new_value, "error": massagers.error_message(entry.tag, new_value)}) else: new_value = massagers.validate(entry.tag, new_value) comment = entry.value changed = comment.text != new_value if (changed and ((comment.shared and comment.complete) or new_value)) \ or (new_value and comment.shared and not comment.complete): # only give an error if we would have applied the value if error_dialog is not None: error_dialog.run() return entry.value = Comment(new_value) entry.edited = True entry.deleted = False model.path_changed(path)
def __row_edited(self, renderer, path, new, model, header): entry = model[path][0] new = gdecode(new) if entry.get_match(header) != new: entry.replace_match(header, new) self.preview.set_sensitive(True) self.save.set_sensitive(True)
def __match_filter(self, completion, entrytext, iter, data): model = completion.get_model() entry = self.get_entry() entrytext = gdecode(entrytext) if entry is None: return False cursor = entry.get_position() if (cursor != len(entrytext) and not max([entrytext[cursor:].startswith(s) for s in self.rightsep])): return False # find the border to the left left, f = max( [(entrytext.rfind(c, 0, cursor), c) for c in self.leftsep]) if left < 0: left += 1 else: left += len(f) if left == cursor: return False key = entrytext[left:cursor] value = model.get_value(iter, self.get_property('text-column')) return bool(value and value.startswith(key))
def __filter(self, model, iter_, data): """Filter a single row""" plugin = model.get_value(iter_) if not plugin: return False entry, state_combo, type_combo = data plugin_type = type_combo.get_active_type() if not issubclass(plugin.cls, plugin_type): return False tag_row = state_combo.get_active_row() if tag_row: plugin_tags = plugin.tags tag, flag = tag_row enabled = plugin_enabled(plugin) if (flag == EnabledType.NO and plugin_tags or flag == EnabledType.TAG and tag not in plugin_tags or flag == EnabledType.EN and not enabled or flag == EnabledType.DIS and enabled): return False filter_ = util.gdecode(entry.get_text()).lower() return (not filter_ or filter_ in plugin.name.lower() or filter_ in (plugin.description or "").lower())
def __edit_tag(self, renderer, path, new_value, model): new_value = gdecode(new_value) new_value = ', '.join(new_value.splitlines()) path = Gtk.TreePath.new_from_string(path) entry = model[path][0] error_dialog = None if not massagers.is_valid(entry.tag, new_value): error_dialog = qltk.WarningMessage( self, _("Invalid value"), _("Invalid value: <b>%(value)s</b>\n\n%(error)s") % { "value": new_value, "error": massagers.error_message(entry.tag, new_value) }) else: new_value = massagers.validate(entry.tag, new_value) comment = entry.value changed = comment.text != new_value if (changed and ((comment.shared and comment.complete) or new_value)) \ or (new_value and comment.shared and not comment.complete): # only give an error if we would have applied the value if error_dialog is not None: error_dialog.run() return entry.value = Comment(new_value) entry.edited = True entry.deleted = False model.path_changed(path)
def get_comment(self): """Returns the user provided error description Returns text_Type """ return util.gdecode(self._entry.get_text())
def __row_edited(self, renderer, path, new): path = Gtk.TreePath.new_from_string(path) model = self.view.get_model() entry = model[path][0] new = gdecode(new) if entry.new_name != new: entry.new_name = new self.preview.set_sensitive(True) self.save.set_sensitive(True) model.path_changed(path)
def __row_edited(self, render, path, new, model, preview, save): path = Gtk.TreePath.new_from_string(path) row = model[path] entry = row[0] new = gdecode(new) if entry.tracknumber != new: entry.tracknumber = new preview.set_sensitive(True) save.set_sensitive(True) model.path_changed(path)
def do_get_preferred_width(self): widths = Gtk.Label.do_get_preferred_width(self) # If for same number of characters, the needed width was larger, # use that instead of the current one num_chars = len(gdecode(self.get_text())) max_widths = self.__widths.get(num_chars, widths) widths = max(widths[0], max_widths[0]), max(widths[1], max_widths[1]) self.__widths[num_chars] = widths return widths
def __changed_entry(self, entry, label, frame): text = gdecode(entry.get_text()) if app.player.info is None: text = _("Not playing") else: text = Pattern(text) % app.player.info label.set_text(text) frame.set_tooltip_text(text) pconfig.set("tooltip", entry.get_text())
def get_backend_name(): """The GDK backend name""" display = Gdk.Display.get_default() if display is not None: name = gdecode(display.__gtype__.name) if name.startswith("Gdk"): name = name[3:] if name.endswith("Display"): name = name[:-7] return name return u"Unknown"
def __save(self, addreplace, library): pattern_text = gdecode(self.combo.get_child().get_text()) pattern = TagsFromPattern(pattern_text) model = self.view.get_model() add = bool(addreplace.get_active()) win = WritingWindow(self, len(model)) win.show() was_changed = set() all_done = False for entry in ((model and itervalues(model)) or []): song = entry.song changed = False if not song.valid(): win.hide() dialog = OverwriteWarning(self, song) resp = dialog.run() win.show() if resp != OverwriteWarning.RESPONSE_SAVE: break for i, h in enumerate(pattern.headers): text = entry.get_match(h) if text: can_multiple = song.can_multiple_values(h) if not add or h not in song or not can_multiple: 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 AudioFileError: util.print_exc() WriteFailedError(self, song).run() library.reload(song, changed=was_changed) break was_changed.add(song) if win.step(): break else: all_done = True win.destroy() library.changed(was_changed) self.save.set_sensitive(not all_done)
def __save(self, addreplace, library): pattern_text = gdecode(self.combo.get_child().get_text()) pattern = TagsFromPattern(pattern_text) model = self.view.get_model() add = bool(addreplace.get_active()) win = WritingWindow(self, len(model)) win.show() was_changed = set() all_done = False for entry in ((model and model.itervalues()) or []): song = entry.song changed = False if not song.valid(): win.hide() dialog = OverwriteWarning(self, song) resp = dialog.run() win.show() if resp != OverwriteWarning.RESPONSE_SAVE: break for i, h in enumerate(pattern.headers): text = entry.get_match(h) if text: can_multiple = song.can_multiple_values(h) if not add or h not in song or not can_multiple: 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 AudioFileError: util.print_exc() WriteFailedError(self, song).run() library.reload(song, changed=was_changed) break was_changed.add(song) if win.step(): break else: all_done = True win.destroy() library.changed(was_changed) self.save.set_sensitive(not all_done)
def _do_query(self, *args): """Search for album using the query text.""" query = util.gdecode(self.search_query.get_text()) if not query: self.result_label.set_markup("<b>%s</b>" % _("Please enter a query.")) self.search_button.set_sensitive(True) return self.result_label.set_markup("<i>%s</i>" % _(u"Searching…")) self._qthread.add(self._process_results, search_releases, query)
def __search_func(self, model, column, key, iter_, data): album = model.get_album(iter_) if album is None: return config.getboolean("browsers", "covergrid_all", False) key = util.gdecode(key).lower() title = album.title.lower() if key in title: return False if config.getboolean("browsers", "album_substrings"): people = (p.lower() for p in album.list("~people")) for person in people: if key in person: return False return True
def __handle_missing_plugin(self, message): get_installer_detail = \ GstPbutils.missing_plugin_message_get_installer_detail get_description = GstPbutils.missing_plugin_message_get_description details = get_installer_detail(message) if details is None: return self.stop() format_desc = get_description(message) title = _(u"No GStreamer element found to handle media format") error_details = _(u"Media format: %(format-description)s") % { "format-description": util.gdecode(format_desc) } def install_done_cb(plugins_return, *args): print_d("Gstreamer plugin install return: %r" % plugins_return) Gst.update_registry() context = GstPbutils.InstallPluginsContext.new() # new in 1.6 if hasattr(context, "set_desktop_id"): from gi.repository import Gtk context.set_desktop_id(app.id) # new in 1.6 if hasattr(context, "set_startup_notification_id"): current_time = Gtk.get_current_event_time() context.set_startup_notification_id("_TIME%d" % current_time) gdk_window = app.window.get_window() if gdk_window: try: xid = gdk_window.get_xid() except AttributeError: # non X11 pass else: context.set_xid(xid) res = GstPbutils.install_plugins_async([details], context, install_done_cb, None) print_d("Gstreamer plugin install result: %r" % res) if res in (GstPbutils.InstallPluginsReturn.HELPER_MISSING, GstPbutils.InstallPluginsReturn.INTERNAL_FAILURE): self._error(PlayerError(title, error_details))
def __handle_missing_plugin(self, message): get_installer_detail = \ GstPbutils.missing_plugin_message_get_installer_detail get_description = GstPbutils.missing_plugin_message_get_description details = get_installer_detail(message) if details is None: return self.stop() format_desc = get_description(message) title = _(u"No GStreamer element found to handle media format") error_details = _(u"Media format: %(format-description)s") % { "format-description": util.gdecode(format_desc)} def install_done_cb(plugins_return, *args): print_d("Gstreamer plugin install return: %r" % plugins_return) Gst.update_registry() context = GstPbutils.InstallPluginsContext.new() # new in 1.6 if hasattr(context, "set_desktop_id"): from gi.repository import Gtk context.set_desktop_id(app.id) # new in 1.6 if hasattr(context, "set_startup_notification_id"): current_time = Gtk.get_current_event_time() context.set_startup_notification_id("_TIME%d" % current_time) gdk_window = app.window.get_window() if gdk_window: try: xid = gdk_window.get_xid() except AttributeError: # non X11 pass else: context.set_xid(xid) res = GstPbutils.install_plugins_async( [details], context, install_done_cb, None) print_d("Gstreamer plugin install result: %r" % res) if res in (GstPbutils.InstallPluginsReturn.HELPER_MISSING, GstPbutils.InstallPluginsReturn.INTERNAL_FAILURE): self._error(PlayerError(title, error_details))
def __color(self, widget, validator): value = validator(gdecode(self.get_text())) if value is True: color = self.VALID elif value is False: color = self.INVALID elif value and isinstance(value, basestring): color = Gdk.RGBA() color.parse(value) else: color = None if color and self.get_property('sensitive'): self.override_color(Gtk.StateType.NORMAL, color) else: self.override_color(Gtk.StateType.NORMAL, None)
def __match_selected(self, completion, model, iter): value = model.get_value(iter, self.get_property('text-column')) entry = self.get_entry() cursor = entry.get_position() text = entry.get_text() text = gdecode(text) left, f = max([(text.rfind(c, 0, cursor), c) for c in self.leftsep]) if left == -1: left += 1 else: left += len(f) offset = cursor - left entry.insert_text(value[offset:], cursor) entry.set_position(left + len(value)) return True
def __match_selected(self, completion, model, iter): value = model.get_value(iter, self.get_property("text-column")) entry = self.get_entry() cursor = entry.get_position() text = entry.get_text() text = gdecode(text) left, f = max([(text.rfind(c, 0, cursor), c) for c in self.leftsep]) if left == -1: left += 1 else: left += len(f) offset = cursor - left entry.insert_text(value[offset:], cursor) entry.set_position(left + len(value)) return 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 _preview(self, songs): model = self.view.get_model() if songs is None: songs = [e.song for e in itervalues(model)] 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_text))).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 = [fsn2text(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 = 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 test_main(self): if PY2: self.assertTrue(isinstance(util.gdecode(b"foo"), text_type)) else: self.assertTrue(isinstance(util.gdecode(u"foo"), text_type))
def __save(self, save, song, buffer, delete): start, end = buffer.get_bounds() text = util.gdecode(buffer.get_text(start, end, True)) self._save_lyrics(song, text) delete.set_sensitive(True) save.set_sensitive(False)
def __all(self): text = gdecode(self.get_chars(0, -1)) pos = self.get_position() return [text, pos]
def on_changed(entry, *args): config.settext(section, option, gdecode(entry.get_text()))
def first_draw(*args): filename = unexpand(self.dump_path) offset = gdecode(label.get_text()).find(filename) label.select_region(offset, offset + len(filename)) self.disconnect(self.__draw_id)
def get_text(self): """Get the active text as unicode""" return gdecode(self.__entry.get_text())
def __search_func(self, model, column, key, iter_, data): entry = model.get_value(iter_) return not entry.contains_text(gdecode(key))
def __equal(self, value): entry_val = gdecode(self.entry.get_text()) self.failUnlessEqual(value, entry_val)
def on_textbuffer_changed(text_buffer, cfgname): start, end = text_buffer.get_bounds() text = gdecode(text_buffer.get_text(start, end, True)) pconfig.settext(cfgname, text)
def __preview(self, songs): if songs is None: songs = [row[0].song for row in (self.view.get_model() or [])] if songs: pattern_text = gdecode(self.combo.get_child().get_text()) else: pattern_text = "" try: pattern = TagsFromPattern(pattern_text) except re.error: qltk.ErrorMessage( self, _("Invalid pattern"), _("The pattern\n\t<b>%s</b>\nis invalid. " "Possibly it contains the same tag twice or " "it has unbalanced brackets (< / >).") % (util.escape(pattern_text))).run() return else: if pattern_text: self.combo.prepend_text(pattern_text) self.combo.write(TBP) invalid = [] for header in pattern.headers: if not min([song.can_change(header) for song in songs]): invalid.append(header) if len(invalid) and songs: if len(invalid) == 1: title = _("Invalid tag") msg = _("Invalid tag <b>%s</b>\n\nThe files currently" " selected do not support editing this tag.") else: title = _("Invalid tags") msg = _("Invalid tags <b>%s</b>\n\nThe files currently" " selected do not support editing these tags.") qltk.ErrorMessage(self, title, msg % ", ".join(invalid)).run() pattern = TagsFromPattern("") self.view.set_model(None) model = ObjectStore() for col in self.view.get_columns(): self.view.remove_column(col) render = Gtk.CellRendererText() col = TreeViewColumn(title=_('File')) col.pack_start(render, True) col.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) def cell_data_file(column, cell, model, iter_, data): entry = model.get_value(iter_) cell.set_property("text", entry.name) col.set_cell_data_func(render, cell_data_file) def cell_data_header(column, cell, model, iter_, header): entry = model.get_value(iter_) cell.set_property("text", entry.get_match(header)) self.view.append_column(col) for i, header in enumerate(pattern.headers): render = Gtk.CellRendererText() render.set_property('editable', True) render.connect('edited', self.__row_edited, model, header) escaped_title = header.replace("_", "__") col = Gtk.TreeViewColumn(escaped_title, render) col.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) col.set_cell_data_func(render, cell_data_header, header) self.view.append_column(col) for song in songs: entry = ListEntry(song) match = pattern.match(song) for h in pattern.headers: text = match.get(h, '') for f in self.filter_box.filters: if f.active: text = f.filter(h, text) if not song.can_multiple_values(h): text = u", ".join(text.split("\n")) entry.matches[h] = text model.append([entry]) # save for last to potentially save time if songs: self.view.set_model(model) self.preview.set_sensitive(False) self.save.set_sensitive(len(pattern.headers) > 0)
def get_value(self): return gdecode(self.__val.get_text())
def text(self): start, end = self.buffer.get_bounds() return gdecode(self.buffer.get_text(start, end, True))
def on_entry_changed(entry, cfgname): pconfig.settext(cfgname, gdecode(entry.get_text()))
def __preview(self, songs): if songs is None: songs = [row[0].song for row in (self.view.get_model() or [])] if songs: pattern_text = gdecode(self.combo.get_child().get_text()) else: pattern_text = "" try: pattern = TagsFromPattern(pattern_text) except re.error: qltk.ErrorMessage( self, _("Invalid pattern"), _("The pattern\n\t<b>%s</b>\nis invalid. " "Possibly it contains the same tag twice or " "it has unbalanced brackets (< / >).") % ( util.escape(pattern_text))).run() return else: if pattern_text: self.combo.prepend_text(pattern_text) self.combo.write(TBP) invalid = [] for header in pattern.headers: if not min([song.can_change(header) for song in songs]): invalid.append(header) if len(invalid) and songs: if len(invalid) == 1: title = _("Invalid tag") msg = _("Invalid tag <b>%s</b>\n\nThe files currently" " selected do not support editing this tag.") else: title = _("Invalid tags") msg = _("Invalid tags <b>%s</b>\n\nThe files currently" " selected do not support editing these tags.") qltk.ErrorMessage( self, title, msg % ", ".join(invalid)).run() pattern = TagsFromPattern("") self.view.set_model(None) model = ObjectStore() for col in self.view.get_columns(): self.view.remove_column(col) render = Gtk.CellRendererText() col = TreeViewColumn(title=_('File')) col.pack_start(render, True) col.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) def cell_data_file(column, cell, model, iter_, data): entry = model.get_value(iter_) cell.set_property("text", entry.name) col.set_cell_data_func(render, cell_data_file) def cell_data_header(column, cell, model, iter_, header): entry = model.get_value(iter_) cell.set_property("text", entry.get_match(header)) self.view.append_column(col) for i, header in enumerate(pattern.headers): render = Gtk.CellRendererText() render.set_property('editable', True) render.connect('edited', self.__row_edited, model, header) escaped_title = header.replace("_", "__") col = Gtk.TreeViewColumn(escaped_title, render) col.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) col.set_cell_data_func(render, cell_data_header, header) self.view.append_column(col) for song in songs: entry = ListEntry(song) match = pattern.match(song) for h in pattern.headers: text = match.get(h, '') for f in self.filter_box.filters: if f.active: text = f.filter(h, text) if not song.can_multiple_values(h): text = u", ".join(text.split("\n")) entry.matches[h] = text model.append([entry]) # save for last to potentially save time if songs: self.view.set_model(model) self.preview.set_sensitive(False) self.save.set_sensitive(len(pattern.headers) > 0)