def __create_help_menu(): items = [] accelerators = [] def show_report_issue(*args): webbrowser.open('https://github.com/exaile/exaile/issues') def show_user_guide(*args): # TODO: Other languages webbrowser.open('http://exaile.readthedocs.org/en/latest/user/index.html') def show_about_dialog(widget, name, parent, context): dialog = dialogs.AboutDialog(parent.window) dialog.show() items.append(_smi('guide', [], _("User's Guide (website)"), 'help', show_user_guide)) items.append(_smi('report', [items[-1].name], _("Report an issue (GitHub)"), None, show_report_issue)) items.append(_sep('about-sep', [items[-1].name])) items.append(_smi('about', [items[-1].name], _("_About"), 'help-about', show_about_dialog)) for item in items: providers.register('menubar-help-menu', item) for accelerator in accelerators: providers.register('mainwindow-accelerators', accelerator)
def check_login(self): """ Tries to connect to the AudioScrobbler service with the existing login data """ username = settings.get_option('plugin/ascrobbler/user', '') password = settings.get_option('plugin/ascrobbler/password', '') url = settings.get_option( 'plugin/ascrobbler/url', 'http://post.audioscrobbler.com/' ) login_verified = False try: _scrobbler.login(username, password, post_url=url) except _scrobbler.AuthError: try: _scrobbler.login(username, password, hashpw=True, post_url=url) except _scrobbler.AuthError: pass else: login_verified = True else: login_verified = True if login_verified: GLib.idle_add(self.message.show_info, _('Verification successful'), '') else: GLib.idle_add( self.message.show_error, _('Verification failed'), _('Please make sure the entered data is correct.'), ) GLib.idle_add(self.widget.set_sensitive, True)
def __update(self, volume): """ Sets the volume level indicator """ icon_name = 'audio-volume-muted' tooltip = _('Muted') if volume > 0: i = clamp(int(round(volume * 2)), 0, len(self.icon_names) - 1) icon_name = 'audio-volume-%s' % self.icon_names[i] #TRANSLATORS: Volume percentage tooltip = _('%d%%') % (volume * 100) else: volume = 0 if volume == 1.0: tooltip = _('Full Volume') if volume > 0: self.button.set_active(False) self.button_image.set_from_icon_name(icon_name, Gtk.IconSize.BUTTON) self.button.set_tooltip_text(tooltip) self.slider.set_value(volume) self.slider.set_tooltip_text(tooltip)
def __init__(self, title): dialogs.ListDialog.__init__(self, title) col = self.list.get_column(0) col.set_title(_('Name')) col.set_expand(True) col.set_resizable(True) self.list.set_headers_visible(True) text = Gtk.CellRendererText() text.set_property('xalign', 1.0) col = Gtk.TreeViewColumn(_('Bitrate'), text) col.set_cell_data_func( text, lambda column, cell, model, iter: cell.set_property( 'text', model.get_value(iter, 0).bitrate ), ) self.list.append_column(col) text = Gtk.CellRendererText() text.set_property('xalign', 0.5) col = Gtk.TreeViewColumn(_('Format'), text) col.set_cell_data_func( text, lambda column, cell, model, iter: cell.set_property( 'text', model.get_value(iter, 0).format ), ) self.list.append_column(col)
def factory(self, menu, parent, context): """ Sets up the menu item """ item = Gtk.ImageMenuItem.new_with_mnemonic(_('_Love This Track')) item.set_image(Gtk.Image.new_from_icon_name('love', Gtk.IconSize.MENU)) if self.get_tracks_function is not None: tracks = self.get_tracks_function() empty = len(tracks) == 0 else: empty = context.get('selection-empty', True) if not empty: tracks = context.get('selected-tracks', []) if not empty and self.__lastfmlover.network is not None: # We only care about the first track track = tracks[0] lastfm_track = pylast.Track( track.get_tag_display('artist'), track.get_tag_display('title'), self.__lastfmlover.network, ) if lastfm_track in self.__lastfmlover.loved_tracks: item.set_label(_('Unlove This Track')) item.connect('activate', self.on_activate, track) else: item.set_sensitive(False) return item
def rename_playlist(self, playlist): """ Renames the playlist """ if playlist is None: return # Ask for new name dialog = dialogs.TextEntryDialog( _("Enter the new name you want for your playlist"), _("Rename Playlist"), playlist.name) result = dialog.run() name = dialog.get_value() dialog.destroy() if result != Gtk.ResponseType.OK or name == '': return if name in self.playlist_manager.playlists: # name is already in use dialogs.error(self.parent, _("The " "playlist name you entered is already in use.")) return selection = self.tree.get_selection() (model, iter) = selection.get_selected() model.set_value(iter, 1, name) # Update the manager aswell self.playlist_manager.rename_playlist(playlist, name)
def _load_playlists(self): """ Loads the currently saved playlists """ self.smart = self.model.append(None, [self.folder, _("Smart Playlists"), None]) self.custom = self.model.append(None, [self.folder, _("Custom Playlists"), None]) names = self.smart_manager.playlists[:] names.sort() for name in names: self.model.append(self.smart, [self.playlist_image, name, self.smart_manager.get_playlist(name)]) names = self.playlist_manager.playlists[:] names.sort() for name in names: playlist = self.playlist_manager.get_playlist(name) self.playlist_nodes[playlist] = self.model.append( self.custom, [self.playlist_image, name, playlist]) self._load_playlist_nodes(playlist) self.tree.expand_row(self.model.get_path(self.smart), False) self.tree.expand_row(self.model.get_path(self.custom), False)
def __create_marker_context_menu(): items = [] def on_jumpto_item_activate(widget, name, parent, context): # parent.seek(context['current-marker'].props.position) position = context['current-marker'].props.position player.PLAYER.set_progress(position) def on_remove_item_activate(widget, name, parent, context): providers.unregister('playback-markers', context['current-marker']) items.append( menu.simple_menu_item( 'jumpto-marker', [], _("_Jump to"), 'go-jump', on_jumpto_item_activate ) ) items.append(MoveMarkerMenuItem('move-marker', [items[-1].name])) items.append( menu.simple_menu_item( 'remove-marker', [items[-1].name], _("_Remove Marker"), 'list-remove', on_remove_item_activate, ) ) for item in items: providers.register('playback-marker-context-menu', item)
def format(self, track, parameters): """ Formats a raw tag value :param track: the track to get the tag from :type track: :class:`xl.trax.Track` :param parameters: optionally passed parameters :type parameters: dictionary :returns: the formatted value :rtype: string """ value = track.get_tag_raw(self.name) # TRANSLATORS: Indicates that a track has never been played before text = _('Never') try: last_played = date.fromtimestamp(value) except (TypeError, ValueError): text = _('Never') else: today = date.today() delta = today - last_played if delta.days == 0: text = _('Today') elif delta.days == 1: text = _('Yesterday') else: text = last_played.strftime('%x') return text
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 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 __init__(self, playlist, parent=None): """ :param playlist: the playlist to export :type playlist: :class:`xl.playlist.Playlist` :param parent: a parent window for modal operation or None :type parent: :class:`gtk.Window` """ FileOperationDialog.__init__(self, title=_('Export Current Playlist'), parent=parent, action=gtk.FILE_CHOOSER_ACTION_SAVE, buttons=( gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE, gtk.RESPONSE_OK ) ) self.set_local_only(False) self.relative_checkbox = gtk.CheckButton(_('Use relative paths to tracks')) self.relative_checkbox.set_active(True) self.extras_box.pack_start(self.relative_checkbox, False, False, 3) self.relative_checkbox.show() self.playlist = playlist extensions = {} for provider in providers.get('playlist-format-converter'): extensions[provider.name] = provider.title self.add_extensions(extensions) self.set_current_name('%s.m3u' % playlist.name) self.connect('response', self.on_response)
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 ask_for_playlist_name(playlist_manager, name=None): """ Returns a user-selected name that is not already used in the specified playlist manager :param name: A default name to show to the user Returns None if the user hits cancel """ while True: dialog = TextEntryDialog( _('Playlist name:'), _('Add new playlist...'), name, okbutton=gtk.STOCK_ADD) result = dialog.run() if result != gtk.RESPONSE_OK: return None name = dialog.get_value() if name == '': error(None, _("You did not enter a name for your playlist")) elif playlist_manager.has_playlist_name(name): # name is already in use error(None, _("The playlist name you entered is already in use.")) else: return name
def __init__(self, parent=None): """ :param parent: a parent window for modal operation or None :type parent: :class:`gtk.Window` """ gtk.FileChooserDialog.__init__(self, title=_('Import Playlist'), parent=parent, buttons=( gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK)) self.set_position(gtk.WIN_POS_CENTER_ON_PARENT) self.set_local_only(False) self.set_select_multiple(True) playlist_filter = gtk.FileFilter() playlist_filter.set_name(_('Playlist Files')) all_filter = gtk.FileFilter() all_filter.set_name(_('All Files')) all_filter.add_pattern('*') playlist_file_extensions = sum([p.file_extensions \ for p in providers.get('playlist-format-converter')], []) for extension in playlist_file_extensions: pattern = '*.%s' % extension playlist_filter.add_pattern(pattern) self.add_filter(playlist_filter) self.add_filter(all_filter) self.connect('response', self.on_response)
def do_init(self, captcha_id=None, captcha_solution=None): username = settings.get_option("plugin/douban_radio/username") password = settings.get_option("plugin/douban_radio/password") try: self.doubanfm = DoubanFM(username, password, captcha_id, captcha_solution) except DoubanLoginException as e: if e.data['captcha_id'] is None: self.exaile.gui.main.message.show_error( _('Douban FM Error'), _('Failed to login to douban.fm with your credential')) return else: captcha_id = e.data['captcha_id'] self.show_captcha_dialog(captcha_id) return self.channels = self.doubanfm.channels self.__create_menu_item__() self.check_to_enable_dbus() self.__register_events() self.doubanfm_cover = DoubanFMCover() providers.register('covers', self.doubanfm_cover) self.doubanfm_mode = DoubanFMMode(self.exaile, self)
def _parse_podcast(self, url, add_to_db=False): try: url = url.replace("itpc://", "http://") self._set_status(_("Loading %s...") % url) d = fp.parse(url) entries = d["entries"] title = d["feed"]["title"] if add_to_db: self._add_to_db(url, title) pl = playlist.Playlist(md5(url).hexdigest()) tracks = [] for e in entries: for link in e.get("enclosures", []): tr = trax.Track(link.href) date = e["updated_parsed"] tr.set_tag_raw("artist", title) tr.set_tag_raw("title", "%s: %s" % (e["title"], link.href.split("/")[-1])) tr.set_tag_raw("date", "%d-%02d-%02d" % (date.tm_year, date.tm_mon, date.tm_mday)) tracks.append(tr) pl.extend(tracks) self._set_status("") self._open_podcast(pl, title) self.podcast_playlists.save_playlist(pl, overwrite=True) except: logger.exception("Error loading podcast") self._set_status(_("Error loading podcast."), 2)
def __init__(self, preferences, widget): """ Initializes the preferences item expects the name of the widget in the designer file, the default for this setting, an optional function to be called when the value is changed, and an optional function to be called when this setting is applied """ self.widget = widget self.preferences = preferences if self.restart_required: self.message = dialogs.MessageBar( parent=preferences.builder.get_object('preferences_box'), type=gtk.MESSAGE_QUESTION, buttons=gtk.BUTTONS_CLOSE, text=_('Restart Exaile?')) self.message.set_secondary_text( _('A restart is required for this change to take effect.')) button = self.message.add_button(_('Restart'), gtk.RESPONSE_ACCEPT) button.set_image(gtk.image_new_from_stock( gtk.STOCK_REFRESH, gtk.ICON_SIZE_BUTTON)) self.message.connect('response', self.on_message_response) self._set_value() self._setup_change()
def get_document(self, url): """ Connects to the server and retrieves the document """ set_status(_('Contacting SomaFM server...')) hostinfo = urlparse.urlparse(url) try: c = httplib.HTTPConnection(hostinfo.netloc, timeout = 20) except TypeError: c = httplib.HTTPConnection(hostinfo.netloc) try: c.request('GET', hostinfo.path, headers={'User-Agent': self.user_agent}) response = c.getresponse() except (socket.timeout, socket.error): raise radio.RadioException(_('Error connecting to SomaFM server.')) if response.status != 200: raise radio.RadioException(_('Error connecting to SomaFM server.')) document = response.read() c.close() set_status('') return document
def factory(menu_, parent, context): item = None dt = (datetime.now() - close_time) if dt.seconds > 60: display_name = _('{playlist_name} ({track_count} tracks, closed {minutes} min ago)').format( playlist_name=playlist.name, track_count=len(playlist), minutes=dt.seconds // 60 ) else: display_name = _('{playlist_name} ({track_count} tracks, closed {seconds} sec ago)').format( playlist_name=playlist.name, track_count=len(playlist), seconds=dt.seconds ) item = gtk.ImageMenuItem(display_name) item.set_image(gtk.image_new_from_icon_name('music-library', gtk.ICON_SIZE_MENU)) # Add accelerator to top item if self.tab_history[0][1].name == item_name: key, mods = gtk.accelerator_parse(self.accelerator.keys) item.add_accelerator('activate', menu.FAKEACCELGROUP, key, mods, gtk.ACCEL_VISIBLE) item.connect('activate', lambda w: self.restore_closed_tab(item_name=item_name)) return item
def _parse_podcast(self, url, add_to_db=False): try: url = url.replace('itpc://', 'http://') self._set_status(_('Loading %s...') % url) d = fp.parse(url) entries = d['entries'] title = d['feed']['title'] if add_to_db: self._add_to_db(url, title) pl = playlist.Playlist(md5(url).hexdigest()) tracks = [] for e in entries: for link in e.get('enclosures', []): tr = trax.Track(link.href) date = e['updated_parsed'] tr.set_tag_raw('artist', title) tr.set_tag_raw('title', '%s: %s' % (e['title'], link.href.split('/')[-1])) tr.set_tag_raw('date', "%d-%02d-%02d" % (date.tm_year, date.tm_mon, date.tm_mday)) tracks.append(tr) pl.extend(tracks) self._set_status('') self._open_podcast(pl, title) self.podcast_playlists.save_playlist(pl, overwrite=True) except: traceback.print_exc() self._set_status(_('Error loading podcast.'), 2)
def __create_edit_menu(): items = [] accelerators = [] def collection_manager_cb(*args): from xlgui import get_controller get_controller().collection_manager() items.append(_smi('collection-manager', [], _("_Collection"), None, collection_manager_cb)) def queue_cb(*args): get_main().playlist_container.show_queue() items.append(_smi('queue', [items[-1].name], _("_Queue"), callback=queue_cb, accelerator='<Control>m')) accelerators.append(Accelerator('<Control>m', queue_cb)) def cover_manager_cb(*args): from xlgui.cover import CoverManager dialog = CoverManager(get_main().window, get_main().collection) items.append(_smi('cover-manager', [items[-1].name], _("C_overs"), None, cover_manager_cb)) def preferences_cb(*args): from xlgui.preferences import PreferencesDialog dialog = PreferencesDialog(get_main().window, get_main().controller) dialog.run() items.append(_smi('preferences', [items[-1].name], icon_name=gtk.STOCK_PREFERENCES, callback=preferences_cb)) for item in items: providers.register('menubar-edit-menu', item) for accelerator in accelerators: providers.register('mainwindow-accelerators', accelerator)
def __create_view_menu(): items = [] accelerators = [] def show_playing_track_cb(*args): get_main().playlist_container.show_current_track() items.append(menuitems.ShowCurrentTrackMenuItem('show-playing-track', [], show_playing_track_cb, accelerator='<Control>j')) accelerators.append(Accelerator('<Control>j', show_playing_track_cb)) items.append(_sep('show-playing-track-sep', [items[-1].name])) def playlist_utilities_cb(widget, name, parent, context): settings.set_option('gui/playlist_utilities_bar_visible', widget.get_active()) def playlist_utilities_is_checked(name, parent, context): return settings.get_option('gui/playlist_utilities_bar_visible', True) items.append(menu.check_menu_item('playlist-utilities', [items[-1].name], _("_Playlist Utilities Bar"), playlist_utilities_is_checked, playlist_utilities_cb)) items.append(_smi('columns', [items[-1].name], _('_Columns'), submenu=menu.ProviderMenu('playlist-columns-menu', get_main()))) def clear_playlist_cb(*args): page = get_main().get_selected_page() if page: page.playlist.clear() items.append(_smi('clear-playlist', [items[-1].name], _('C_lear playlist'), gtk.STOCK_CLEAR, clear_playlist_cb, accelerator='<Control>l')) accelerators.append(Accelerator('<Control>l', clear_playlist_cb)) for item in items: providers.register('menubar-view-menu', item) for accelerator in accelerators: providers.register('mainwindow-accelerators', accelerator)
def __init__(self, preferences, widget): """ Initializes the preferences item expects the name of the widget in the designer file, the default for this setting, an optional function to be called when the value is changed, and an optional function to be called when this setting is applied """ self.widget = widget self.preferences = preferences if self.restart_required: self.message = dialogs.MessageBar( parent=preferences.builder.get_object('preferences_box'), type=Gtk.MessageType.QUESTION, buttons=Gtk.ButtonsType.CLOSE, text=_('Restart Exaile?'), ) self.message.set_secondary_text( _('A restart is required for this change to take effect.') ) button = self.message.add_button(_('Restart'), Gtk.ResponseType.ACCEPT) button.set_image( Gtk.Image.new_from_icon_name('view-refresh', Gtk.IconSize.BUTTON) ) self.message.connect('response', self.on_message_response) self._set_value() self._setup_change()
def __create_menu_item__(self): exaile = self.exaile self.menuItem = gtk.MenuItem(_('Open Douban.fm')) menu = gtk.Menu() self.menuItem.set_submenu(menu) for channel_name in self.channels.keys(): menuItem = gtk.MenuItem(_(channel_name)) menuItem.connect('activate', self.active_douban_radio, channel_name) menu.prepend(menuItem) menuItem.show() # self.menu.connect('activate', self.active_douban_radio, self.exaile) exaile.gui.builder.get_object('file_menu').insert(self.menuItem, 5) self.menuItem.show() self.modeMenuItem = gtk.MenuItem(_('DoubanFM mode')) key, modifier = gtk.accelerator_parse('<Control><Alt>D') self.accels = gtk.AccelGroup() self.modeMenuItem.add_accelerator('activate', self.accels, key, modifier, gtk.ACCEL_VISIBLE) self.exaile.gui.main.window.add_accel_group(self.accels) self.modeMenuItem.connect('activate', self.show_mode) exaile.gui.builder.get_object('view_menu').append(self.modeMenuItem) self.modeMenuItem.show()
def _setup_tree(self): self.tree = FlatPlaylistDragTreeView(self, False, True) selection = self.tree.get_selection() selection.set_mode(gtk.SELECTION_MULTIPLE) self.tree.set_headers_visible(True) self.tree.set_model(self.model) self.scroll = gtk.ScrolledWindow() self.scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) self.scroll.add(self.tree) self.scroll.set_shadow_type(gtk.SHADOW_IN) self.box.pack_start(self.scroll, True, True) text = gtk.CellRendererText() col = gtk.TreeViewColumn(_('#')) col.pack_start(text, False) col.set_attributes(text, text=0) col.set_fixed_width(50) col.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) self.tree.append_column(col) text = gtk.CellRendererText() col = gtk.TreeViewColumn(_('Title')) col.pack_start(text, True) col.set_attributes(text, text=1) col.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE) col.set_cell_data_func(text, self._title_data_func) self.tree.append_column(col) self.box.show_all()
def on_timeout(self): """ Tries to shutdown the computer """ self.countdown = None if self.counter > 0: self.message.set_secondary_text(_("The computer will be shut down in %d seconds.") % self.counter) self.message.show() self.counter -= 1 return True self.do_shutdown = False bus = dbus.SystemBus() try: proxy = bus.get_object("org.freedesktop.login1", "/org/freedesktop/login1") proxy.PowerOff(False, dbus_interface="org.freedesktop.login1.Manager") except dbus.exceptions.DBusException: try: proxy = bus.get_object("org.freedesktop.ConsoleKit", "/org/freedesktop/ConsoleKit/Manager") proxy.Stop(dbus_interface="org.freedesktop.ConsoleKit.Manager") except dbus.exceptions.DBusException: try: proxy = bus.get_object("org.freedesktop.Hal", "/org/freedesktop/Hal/devices/computer") proxy.Shutdown(dbus_interface="org.freedesktop.Hal.Device.SystemPowerManagement") except dbus.exceptions.DBusException: self.message.show_warning(_("Shutdown failed"), _("Computer could not be shutdown using D-Bus."))
def _add_default_playlists(self): """ Adds some default smart playlists to the playlist manager """ from xl import playlist # entire playlist entire_lib = playlist.SmartPlaylist( _("Entire Library"), collection=self.collection ) self.smart_playlists.save_playlist(entire_lib, overwrite=True) # random playlists for count in (100, 300, 500): pl = playlist.SmartPlaylist( _("Random %d") % count, collection=self.collection ) pl.set_return_limit(count) pl.set_random_sort(True) self.smart_playlists.save_playlist(pl, overwrite=True) # rating based playlists for item in (3, 4): pl = playlist.SmartPlaylist( _("Rating > %d") % item, collection=self.collection ) pl.add_param('__rating', '>', item) self.smart_playlists.save_playlist(pl, overwrite=True)
def Query(self): """ Returns information about the currently playing track :returns: information about the current track :rtype: string """ status = self.__get_playback_status() if status.current is None or status.state == "stopped": return _('Not playing.') result = _('status: %(status)s, title: %(title)s, artist: %(artist)s,' ' album: %(album)s, length: %(length)s,' ' position: %(progress)s%% [%(position)s]') % { 'status': status.state, 'title': status.current["title"], 'artist': status.current["artist"], 'album': status.current["album"], 'length': status.current["__length"], 'progress': status.progress, 'position': status.position, } return result
def Query(self): """ Returns information about the currently playing track :returns: information about the current track :rtype: string """ status = self.__get_playback_status() if status.current is None or status.state == "stopped": return _("Not playing.") result = _( "status: %(status)s, title: %(title)s, artist: %(artist)s," " album: %(album)s, length: %(length)s," " position: %(progress)s%% [%(position)s]" ) % { "status": status.state, "title": status.current["title"], "artist": status.current["artist"], "album": status.current["album"], "length": status.current["__length"], "progress": status.progress, "position": status.position, } return result
def __init__(self, notebook, page, display_left=False): """ :param notebook: The notebook this tab will belong to :param page: The page this tab will be associated with """ gtk.EventBox.__init__(self) self.set_visible_window(False) self.closable = True self.notebook = notebook self.page = page self.menu = menu.ProviderMenu(self.menu_provider_name, self) self.connect('button-press-event', self.on_button_press) if display_left: box = gtk.VBox(False, 2) else: box = gtk.HBox(False, 2) self.add(box) self.icon = gtk.Image() self.icon.set_property("visible", False) self.label = gtk.Label(self.page.get_page_name()) self.label.set_max_width_chars(20) if display_left: self.label.set_angle(90) else: self.label.set_ellipsize(pango.ELLIPSIZE_END) self.label.set_tooltip_text(self.page.get_page_name()) if self.can_rename(): self.entry = gtk.Entry() self.entry.set_width_chars(self.label.get_max_width_chars()) self.entry.set_text(self.label.get_text()) self.entry.set_inner_border(gtk.Border(left=1, right=1)) self.entry.connect('activate', self.on_entry_activate) self.entry.connect('focus-out-event', self.on_entry_focus_out_event) self.entry.connect('key-press-event', self.on_entry_key_press_event) self.entry.set_no_show_all(True) self.button = button = gtk.Button() button.set_name("tabCloseButton") button.set_relief(gtk.RELIEF_NONE) button.set_focus_on_click(False) button.set_tooltip_text(_("Close Tab")) button.add( gtk.image_new_from_stock(gtk.STOCK_CLOSE, gtk.ICON_SIZE_MENU)) button.connect('clicked', self.close) button.connect('button-press-event', self.on_button_press) # pack the widgets in if display_left: box.pack_start(button, False, False) box.pack_end(self.icon, False, False) box.pack_end(self.label, False, False) if self.can_rename(): box.pack_end(self.entry, False, False) else: box.pack_start(self.icon, False, False) box.pack_start(self.label, False, False) if self.can_rename(): box.pack_start(self.entry, False, False) box.pack_end(button, False, False) page.set_tab(self) page.connect('name-changed', self.on_name_changed) self.show_all()
def __init__(self, notebook, page, vertical=False): """ :param notebook: The notebook this tab will belong to :type notebook: SmartNotebook :param page: The page this tab will be associated with :type page: NotebookPage :param vertical: Whether the tab contents are to be laid out vertically :type vertical: bool """ Gtk.EventBox.__init__(self) self.set_visible_window(False) self.closable = True self.notebook = notebook self.page = page self.page.tab_menu.attach_to_widget(self.page, None) self.connect('button-press-event', self.on_button_press) self.vertical = vertical if vertical: box = Gtk.Box(spacing=2, orientation=Gtk.Orientation.VERTICAL) else: box = Gtk.Box(spacing=2) self.add(box) apply_css(box) self.icon = Gtk.Image() self.icon.set_no_show_all(True) apply_css(self.icon) self.label = Gtk.Label(label=self.page.get_page_name()) self.label.set_tooltip_text(self.page.get_page_name()) apply_css(self.label) if vertical: self.label.set_angle(90) self.label.props.valign = Gtk.Align.CENTER # Don't ellipsize but give a sane maximum length. self.label.set_max_width_chars(20) else: self.label.props.halign = Gtk.Align.CENTER self.label.set_ellipsize(Pango.EllipsizeMode.END) self.adjust_label_width(Gtk.PositionType.TOP) if self.can_rename(): self.entry = entry = Gtk.Entry() entry.set_width_chars(self.label.get_max_width_chars()) entry.set_text(self.label.get_text()) border = Gtk.Border.new() border.left = 1 border.right = 1 entry.set_inner_border(border) entry.connect('activate', self.on_entry_activate) entry.connect('focus-out-event', self.on_entry_focus_out_event) entry.connect('key-press-event', self.on_entry_key_press_event) entry.set_no_show_all(True) apply_css(entry) self.button = button = Gtk.Button() button.set_relief(Gtk.ReliefStyle.NONE) button.set_halign(Gtk.Align.CENTER) button.set_valign(Gtk.Align.CENTER) button.set_focus_on_click(False) button.set_tooltip_text(_("Close Tab")) button.add( Gtk.Image.new_from_icon_name('window-close', Gtk.IconSize.MENU)) button.connect('clicked', self.close) button.connect('button-press-event', self.on_button_press) apply_css(button) # pack the widgets in if vertical: box.pack_start(button, False, False, 0) box.pack_end(self.icon, False, False, 0) box.pack_end(self.label, True, True, 0) if self.can_rename(): box.pack_end(self.entry, True, True, 0) else: box.pack_start(self.icon, False, False, 0) box.pack_start(self.label, True, True, 0) if self.can_rename(): box.pack_start(self.entry, True, True, 0) box.pack_end(button, False, False, 0) page.set_tab(self) page.connect('name-changed', self.on_name_changed) box.show_all()
def _error_cb(self, gerror, message_string): self.running = False xlgui.main.mainwindow().message.show_error( _("Error transcoding files from CD."), "%s" % gerror.message.encode())
def DeletePlaylistMenuItem(name, after, get_pl_func=generic_get_playlist_func): return menu.simple_menu_item( name, after, _('_Delete Playlist'), 'edit-delete', lambda w, n, o, c: o.remove_playlist(get_pl_func(o, c)))
def create_argument_parser(): """Create command-line argument parser for Exaile""" import argparse # argparse hard-codes "usage:" uncapitalized. We replace this with an # empty string and put "Usage:" in the actual usage string instead. class Formatter(argparse.HelpFormatter): def _format_usage(self, usage, actions, groups, prefix): return super(self.__class__, self)._format_usage(usage, actions, groups, "") p = argparse.ArgumentParser( usage=_("Usage: exaile [OPTION...] [LOCATION...]"), description=_("Launch Exaile, optionally adding tracks specified by" " LOCATION to the active playlist." " If Exaile is already running, this attempts to use the existing" " instance instead of creating a new one."), add_help=False, formatter_class=Formatter) p.add_argument('locs', nargs='*', help=argparse.SUPPRESS) group = p.add_argument_group(_('Playback Options')) group.add_argument("-n", "--next", dest="Next", action="store_true", default=False, help=_("Play the next track")) group.add_argument("-p", "--prev", dest="Prev", action="store_true", default=False, help=_("Play the previous track")) group.add_argument("-s", "--stop", dest="Stop", action="store_true", default=False, help=_("Stop playback")) group.add_argument("-a", "--play", dest="Play", action="store_true", default=False, help=_("Play")) group.add_argument("-u", "--pause", dest="Pause", action="store_true", default=False, help=_("Pause")) group.add_argument("-t", "--play-pause", dest="PlayPause", action="store_true", default=False, help=_("Pause or resume playback")) group.add_argument("--stop-after-current", dest="StopAfterCurrent", action="store_true", default=False, help=_("Stop playback after current track")) group = p.add_argument_group(_('Collection Options')) group.add_argument("--add", dest="Add", # TRANSLATORS: Meta variable for --add and --export-playlist metavar=_("LOCATION"), help=_("Add tracks from LOCATION to the collection")) group = p.add_argument_group(_('Playlist Options')) group.add_argument("--export-playlist", dest="ExportPlaylist", # TRANSLATORS: Meta variable for --add and --export-playlist metavar=_("LOCATION"), help=_('Export the current playlist to LOCATION')) group = p.add_argument_group(_('Track Options')) group.add_argument("-q", "--query", dest="Query", action="store_true", default=False, help=_("Query player")) group.add_argument("--format-query", dest="FormatQuery", # TRANSLATORS: Meta variable for --format-query metavar=_('FORMAT'), help=_('Retrieve the current playback state and track information as FORMAT')) group.add_argument("--format-query-tags", dest="FormatQueryTags", # TRANSLATORS: Meta variable for --format-query-tags metavar=_('TAGS'), help=_('Tags to retrieve from the current track; use with --format-query')) group.add_argument("--gui-query", dest="GuiQuery", action="store_true", default=False, help=_("Show a popup with data of the current track")) group.add_argument("--get-title", dest="GetTitle", action="store_true", default=False, help=_("Print the title of current track")) group.add_argument("--get-album", dest="GetAlbum", action="store_true", default=False, help=_("Print the album of current track")) group.add_argument("--get-artist", dest="GetArtist", action="store_true", default=False, help=_("Print the artist of current track")) group.add_argument("--get-length", dest="GetLength", action="store_true", default=False, help=_("Print the length of current track")) group.add_argument('--set-rating', dest="SetRating", type=int, # TRANSLATORS: Variable for command line options with arguments metavar=_('N'), help=_('Set rating for current track to N%').replace("%", "%%")) group.add_argument('--get-rating', dest='GetRating', action='store_true', default=False, help=_('Get rating for current track')) group.add_argument("--current-position", dest="CurrentPosition", action="store_true", default=False, help=_("Print the current playback position as time")) group.add_argument("--current-progress", dest="CurrentProgress", action="store_true", default=False, help=_("Print the current playback progress as percentage")) group = p.add_argument_group(_('Volume Options')) group.add_argument("-i", "--increase-vol", dest="IncreaseVolume", type=int, # TRANSLATORS: Meta variable for --increase-vol and--decrease-vol metavar=_("N"), help=_("Increase the volume by N%").replace("%", "%%")) group.add_argument("-l", "--decrease-vol", dest="DecreaseVolume", type=int, # TRANSLATORS: Meta variable for --increase-vol and--decrease-vol metavar=_("N"), help=_("Decrease the volume by N%").replace("%", "%%")) group.add_argument("-m", "--toggle-mute", dest="ToggleMute", action="store_true", default=False, help=_("Mute or unmute the volume")) group.add_argument("--get-volume", dest="GetVolume", action="store_true", default=False, help=_("Print the current volume percentage")) group = p.add_argument_group(_('Other Options')) group.add_argument("--new", dest="NewInstance", action="store_true", default=False, help=_("Start new instance")) group.add_argument("-h", "--help", action="help", help=_("Show this help message and exit")) group.add_argument("--version", dest="ShowVersion", action="store_true", help=_("Show program's version number and exit.")) group.add_argument("--start-minimized", dest="StartMinimized", action="store_true", default=False, help=_("Start minimized (to tray, if possible)")) group.add_argument("--toggle-visible", dest="GuiToggleVisible", action="store_true", default=False, help=_("Toggle visibility of the GUI (if possible)")) group.add_argument("--safemode", dest="SafeMode", action="store_true", default=False, help=_("Start in safe mode - sometimes" " useful when you're running into problems")) group.add_argument("--force-import", dest="ForceImport", action="store_true", default=False, help=_("Force import of old data" " from version 0.2.x (overwrites current data)")) group.add_argument("--no-import", dest="NoImport", action="store_true", default=False, help=_("Do not import old data" " from version 0.2.x")) group.add_argument("--start-anyway", dest="StartAnyway", action="store_true", default=False, help=_("Make control options like" " --play start Exaile if it is not running")) group = p.add_argument_group(_('Development/Debug Options')) group.add_argument("--datadir", dest="UseDataDir", metavar=_('DIRECTORY'), help=_("Set data directory")) group.add_argument("--all-data-dir", dest="UseAllDataDir", metavar=_('DIRECTORY'), help=_("Set data and config directory")) group.add_argument("--modulefilter", dest="ModuleFilter", metavar=_('MODULE'), help=_('Limit log output to MODULE')) group.add_argument("--levelfilter", dest="LevelFilter", metavar=_('LEVEL'), help=_('Limit log output to LEVEL'), choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL']) group.add_argument("--debug", dest="Debug", action="store_true", default=False, help=_("Show debugging output")) group.add_argument("--eventdebug", dest="DebugEvent", action="store_true", default=False, help=_("Enable debugging of" " xl.event. Generates lots of output")) group.add_argument("--eventdebug-full", dest="DebugEventFull", action="store_true", default=False, help=_("Enable full debugging of" " xl.event. Generates LOTS of output")) group.add_argument("--threaddebug", dest="DebugThreads", action="store_true", default=False, help=_("Add thread name to logging" " messages.")) group.add_argument("--eventfilter", dest="EventFilter", metavar=_('TYPE'), help=_("Limit xl.event debug to output of TYPE")) group.add_argument("--quiet", dest="Quiet", action="store_true", default=False, help=_("Reduce level of output")) group.add_argument('--startgui', dest='StartGui', action='store_true', default=False) group.add_argument('--no-dbus', dest='Dbus', action='store_false', default=True, help=_("Disable D-Bus support")) group.add_argument('--no-hal', dest='Hal', action='store_false', default=True, help=_("Disable HAL support.")) return p
def __create_tray_context_menu(): sep = menu.simple_separator items = [] # Play/Pause items.append( playback.PlayPauseMenuItem('playback-playpause', player.PLAYER, after=[]) ) # Next items.append( playback.NextMenuItem('playback-next', player.PLAYER, after=[items[-1].name]) ) # Prev items.append( playback.PrevMenuItem('playback-prev', player.PLAYER, after=[items[-1].name]) ) # Stop items.append( playback.StopMenuItem('playback-stop', player.PLAYER, after=[items[-1].name]) ) # ---- items.append(sep('playback-sep', [items[-1].name])) # Shuffle items.append( playlist.ShuffleModesMenuItem('playlist-mode-shuffle', after=[items[-1].name]) ) # Repeat items.append( playlist.RepeatModesMenuItem('playlist-mode-repeat', after=[items[-1].name]) ) # Dynamic items.append( playlist.DynamicModesMenuItem('playlist-mode-dynamic', after=[items[-1].name]) ) # ---- items.append(sep('playlist-mode-sep', [items[-1].name])) # Rating def rating_get_tracks_func(parent, context): current = player.PLAYER.current if current: return [current] else: return [] items.append( menuitems.RatingMenuItem('rating', [items[-1].name], rating_get_tracks_func) ) # Remove items.append(playlist.RemoveCurrentMenuItem([items[-1].name])) # ---- items.append(sep('misc-actions-sep', [items[-1].name])) # Quit def quit_cb(*args): from xl import main main.exaile().quit() items.append( menu.simple_menu_item( 'quit-application', [items[-1].name], _("_Quit Exaile"), 'application-exit', callback=quit_cb, ) ) for item in items: providers.register('tray-icon-context', item)
def add_new_playlist(self, tracks=[], name = None): """ Adds a new playlist to the list of playlists. If name is None or the name conflicts with an existing playlist, the user will be queried for a new name. Returns the name of the new playlist, or None if it was not added. """ do_add_playlist = False if name: if name in self.playlist_manager.playlists: name = dialogs.ask_for_playlist_name( self.get_panel().get_toplevel(), self.playlist_manager, name) else: if tracks: artists = [] composers = [] albums = [] for track in tracks: artist = track.get_tag_display('artist', artist_compilations=False) if artist is not None: artists += [artist] composer = track.get_tag_display('composer', artist_compilations=False) if composer is not None: composers += composer album = track.get_tag_display('album') if album is not None: albums += album artists = list(set(artists))[:3] composers = list(set(composers))[:3] albums = list(set(albums))[:3] if len(artists) > 0: name = artists[0] if len(artists) > 2: # TRANSLATORS: Playlist title suggestion with more # than two values name = _('%(first)s, %(second)s and others') % { 'first': artists[0], 'second': artists[1] } elif len(artists) > 1: # TRANSLATORS: Playlist title suggestion with two values name = _('%(first)s and %(second)s') % { 'first': artists[0], 'second': artists[1] } elif len(composers) > 0: name = composers[0] if len(composers) > 2: # TRANSLATORS: Playlist title suggestion with more # than two values name = _('%(first)s, %(second)s and others') % { 'first': composers[0], 'second': composers[1] } elif len(composers) > 1: # TRANSLATORS: Playlist title suggestion with two values name = _('%(first)s and %(second)s') % { 'first': composers[0], 'second': composers[1] } elif len(albums) > 0: name = albums[0] if len(albums) > 2: # TRANSLATORS: Playlist title suggestion with more # than two values name = _('%(first)s, %(second)s and others') % { 'first': albums[0], 'second': albums[1] } elif len(albums) > 1: # TRANSLATORS: Playlist title suggestion with two values name = _('%(first)s and %(second)s') % { 'first': albums[0], 'second': albums[1] } else: name = '' name = dialogs.ask_for_playlist_name( self.get_panel().get_toplevel(), self.playlist_manager, name) if name is not None: #Create the playlist from all of the tracks new_playlist = playlist.Playlist(name) new_playlist.extend(tracks) # We are adding a completely new playlist with tracks so we save it self.playlist_manager.save_playlist(new_playlist) return name
def get_page_name(self): return _('GroupTagger')
def ExportPlaylistFilesMenuItem(name, after, get_pl_func=generic_get_playlist_func): return menu.simple_menu_item( name, after, _('Export _Files'), 'document-save-as', lambda w, n, o, c: dialogs.export_playlist_files(get_pl_func(o, c)))
# # GroupTaggerView signal 'changed' enum # group_change = common.enum(added=object(), deleted=object(), edited=object()) # edited/toggled group category_change = common.enum( added=object(), deleted=object(), expanded=object(), # user expanded category display collapsed=object(), # user collapsed category display updated=object()) # added group, changed name # default group category uncategorized = _('Uncategorized') class GTShowTracksMenuItem(menu.MenuItem): def __init__(self, name, after): menu.MenuItem.__init__(self, name, None, after) def factory(self, menu, parent, context): groups = context['groups'] if len(groups) == 0: display_name = _('Show tracks with selected') elif len(groups) == 1: display_name = _('Show tracks tagged with "%s"') % groups[0] else:
from gi.repository import GLib from gi.repository import Gtk import os.path import _scrobbler from xl import ( common, settings, ) from xl.nls import gettext as _ from xlgui import icons from xlgui.preferences import widgets from xlgui.widgets import dialogs name = _('AudioScrobbler') basedir = os.path.dirname(os.path.realpath(__file__)) ui = os.path.join(basedir, "asprefs_pane.ui") icons.MANAGER.add_icon_name_from_directory('audioscrobbler', os.path.join(basedir, 'icons')) icon = 'audioscrobbler' class SubmitPreference(widgets.CheckPreference): default = True name = 'plugin/ascrobbler/submit' class MenuCheck(widgets.CheckPreference): default = False
def on_playback_error(self, type, player, message): """ Called when there has been a playback error """ self.message.show_error(_('Playback error encountered!'), message)
def __init__(self, exaile, model=None, editable=False): super(GroupTaggerView, self).__init__() self.exaile = exaile self.connect('notify::model', self.on_notify_model) self.set_model(model) self.set_enable_search(False) self.get_selection().set_mode(Gtk.SelectionMode.MULTIPLE) self._row_expanded_id = self.connect('row-expanded', self.on_row_expanded) self._row_collapsed_id = self.connect('row-collapsed', self.on_row_collapsed) if editable: self.set_reorderable(True) # Setup the first column, not shown by default cell = Gtk.CellRendererToggle() cell.set_property('mode', Gtk.CellRendererMode.ACTIVATABLE) cell.set_activatable(True) cell.connect('toggled', self.on_toggle) self.click_column = Gtk.TreeViewColumn(None, cell, active=0, visible=2) # Setup the second column cell = Gtk.CellRendererText() cell.set_property('editable', editable) if editable: cell.connect('edited', self.on_edit) self.text_column = cell self.append_column( Gtk.TreeViewColumn(_('Tag'), self.text_column, text=1, weight=3)) # # Menu setup # self.menu = GroupTaggerContextMenu(self) smi = menu.simple_menu_item sep = menu.simple_separator self.connect('popup-menu', self.on_popup_menu) self.connect('button-release-event', self.on_mouse_release) if editable: item = smi( 'addgrp', [], _('Add new tag'), \ callback=self.on_menu_add_group ) self.menu.add_item(item) item = smi( 'delgrp', ['addgrp'], _('Delete tag'), \ callback=self.on_menu_delete_group, \ condition_fn=lambda n,p,c: False if len(c['groups']) == 0 else True) self.menu.add_item(item) self.menu.add_item(sep('sep1', ['delgrp'])) item = smi( 'addcat', ['sep1'], _('Add new category'), \ callback=self.on_menu_add_category ) self.menu.add_item(item) item = smi( 'remcat', ['addcat'], _('Remove category'), \ callback=self.on_menu_del_category, condition_fn=lambda n,p,c: False if len(c['categories']) == 0 else True) self.menu.add_item(item) self.menu.add_item(sep('sep2', ['remcat'])) self.menu.add_item(GTShowTracksMenuItem('sel', ['sep2'])) item = smi( 'selcust', ['sel'], _('Show tracks with selected (custom)'), \ callback=lambda w,n,p,c: gt_common.create_custom_search_playlist( c['groups'], exaile ), condition_fn=lambda n,p,c: True if len(c['groups']) > 1 else False) self.menu.add_item(item)
def get_collection_count(self): """ Retrieves the collection count """ return _('%d in collection') % main.exaile().collection.get_count()
def on_buffering(self, type, player, percent): """ Called when a stream is buffering """ percent = min(percent, 100) self.statusbar.set_status(_("Buffering: %d%%...") % percent, 1)
# # # The developers of the Exaile media player hereby grant permission # for non-GPL compatible GStreamer and Exaile plugins to be used and # distributed together with GStreamer and Exaile. This permission is # above and beyond the permissions granted by the GPL license by which # Exaile is covered. If you modify this code, you may extend this # exception to your version of the code, but you are not obligated to # do so. If you do not wish to do so, delete this exception statement # from your version. from xl import covers, settings, xdg from xl.nls import gettext as _ from xlgui.preferences import widgets name = _('Covers') icon = 'image-x-generic' ui = xdg.get_data_path('ui', 'preferences', 'cover.ui') class TagCoverFetching(widgets.CheckPreference): default = True name = 'covers/use_tags' class LocalCoverFetching(widgets.CheckPreference): default = True name = 'covers/use_localfile' class LocalFilePreferredNamesPreference(widgets.Preference,
def __init__(self, manager_name, player, hotkey): SmartNotebook.__init__(self) self.tab_manager = PlaylistManager(manager_name) self.manager_name = manager_name self.player = player # For saving closed tab history self._moving_tab = False self.tab_history = [] self.history_counter = 90000 # to get unique (reverse-ordered) item names # Build static menu entries item = menu.simple_separator('clear-sep', []) item.register('playlist-closed-tab-menu', self) item = menu.simple_menu_item('clear-history', ['clear-sep'], _("_Clear Tab History"), 'edit-clear-all', self.clear_closed_tabs) item.register('playlist-closed-tab-menu', self) # Simple factory for 'Recently Closed Tabs' MenuItem submenu = menu.ProviderMenu('playlist-closed-tab-menu', self) def factory(menu_, parent, context): if self.page_num(parent) == -1: return None item = Gtk.MenuItem.new_with_mnemonic(_("Recently Closed _Tabs")) if len(self.tab_history) > 0: item.set_submenu(submenu) else: item.set_sensitive(False) return item # Add menu to tab context menu item = menu.MenuItem('%s-tab-history' % manager_name, factory, ['tab-close']) item.register('playlist-tab-context-menu') # Add menu to View menu #item = menu.MenuItem('tab-history', factory, ['clear-playlist']) #providers.register('menubar-view-menu', item) # setup notebook actions self.actions = NotebookActionService(self, 'playlist-notebook-actions') # Add hotkey self.accelerator = Accelerator(hotkey, _('Restore closed tab'), lambda *x: self.restore_closed_tab(0)) providers.register('mainwindow-accelerators', self.accelerator) # Load saved tabs self.load_saved_tabs() self.tab_placement_map = { 'left': Gtk.PositionType.LEFT, 'right': Gtk.PositionType.RIGHT, 'top': Gtk.PositionType.TOP, 'bottom': Gtk.PositionType.BOTTOM } self.connect('page-added', self.on_page_added) self.connect('page-removed', self.on_page_removed) self.on_option_set('gui_option_set', settings, 'gui/show_tabbar') self.on_option_set('gui_option_set', settings, 'gui/tab_placement') event.add_ui_callback(self.on_option_set, 'gui_option_set')
def __init__(self, notebook, page, display_left=False): """ :param notebook: The notebook this tab will belong to :type notebook: SmartNotebook :param page: The page this tab will be associated with :type page: NotebookPage """ Gtk.EventBox.__init__(self) self.set_visible_window(False) self.closable = True self.notebook = notebook self.page = page self.menu = menu.ProviderMenu(self.menu_provider_name, self) self.connect('button-press-event', self.on_button_press) if display_left: box = Gtk.Box(False, 2, orientation=Gtk.Orientation.VERTICAL) else: box = Gtk.Box(False, 2) self.add(box) self.icon = Gtk.Image() self.icon.set_no_show_all(True) self.label = Gtk.Label(label=self.page.get_page_name()) if display_left: self.label.set_angle(90) self.label.props.valign = Gtk.Align.CENTER # Don't ellipsize but give a sane maximum length. self.label.set_max_width_chars(20) else: self.label.props.halign = Gtk.Align.CENTER self.label.set_ellipsize(Pango.EllipsizeMode.END) self.label.set_width_chars(4) # Minimum, including ellipsis self.label.set_tooltip_text(self.page.get_page_name()) if self.can_rename(): self.entry = Gtk.Entry() self.entry.set_width_chars(self.label.get_max_width_chars()) self.entry.set_text(self.label.get_text()) border = Gtk.Border.new() border.left = 1 border.right = 1 self.entry.set_inner_border(border) self.entry.connect('activate', self.on_entry_activate) self.entry.connect('focus-out-event', self.on_entry_focus_out_event) self.entry.connect('key-press-event', self.on_entry_key_press_event) self.entry.set_no_show_all(True) self.button = button = Gtk.Button() button.set_relief(Gtk.ReliefStyle.NONE) button.set_halign(Gtk.Align.CENTER) button.set_valign(Gtk.Align.CENTER) button.set_focus_on_click(False) button.set_tooltip_text(_("Close Tab")) button.add(Gtk.Image.new_from_icon_name('window-close-symbolic', Gtk.IconSize.MENU)) button.connect('clicked', self.close) button.connect('button-press-event', self.on_button_press) # pack the widgets in if display_left: box.pack_start(button, False, False, 0) box.pack_end(self.icon, False, False, 0) box.pack_end(self.label, True, True, 0) if self.can_rename(): box.pack_end(self.entry, True, True, 0) else: box.pack_start(self.icon, False, False, 0) box.pack_start(self.label, True, True, 0) if self.can_rename(): box.pack_start(self.entry, True, True, 0) box.pack_end(button, False, False, 0) page.set_tab(self) page.connect('name-changed', self.on_name_changed) self.show_all()
def __create_file_menu(): items = [] accelerators = [] def new_playlist_cb(*args): get_main().playlist_container.create_new_playlist() accelerators.append( Accelerator('<Primary>t', _("_New Playlist"), new_playlist_cb)) items.append( _smi('new-playlist', [], icon_name='tab-new', callback=accelerators[-1])) items.append(_sep('new-sep', [items[-1].name])) def open_cb(*args): dialog = dialogs.MediaOpenDialog(get_main().window) dialog.connect('uris-selected', lambda d, uris: get_main().controller.open_uris(uris)) dialog.show() accelerators.append(Accelerator('<Primary>o', _("_Open"), open_cb)) items.append( _smi('open', [items[-1].name], icon_name='document-open', callback=accelerators[-1])) def open_uri_cb(*args): dialog = dialogs.URIOpenDialog(get_main().window) dialog.connect('uri-selected', lambda d, uri: get_main().controller.open_uri(uri)) dialog.show() accelerators.append( Accelerator('<Primary><Shift>o', _("Open _URL"), open_uri_cb)) items.append( _smi('open-uri', [items[-1].name], icon_name='emblem-web', callback=accelerators[-1])) def open_dirs_cb(*args): dialog = dialogs.DirectoryOpenDialog(get_main().window) dialog.props.create_folders = False dialog.connect('uris-selected', lambda d, uris: get_main().controller.open_uris(uris)) dialog.show() items.append( _smi('open-dirs', [items[-1].name], _("Open _Directories"), 'folder-open', open_dirs_cb)) items.append(_sep('open-sep', [items[-1].name])) items.append( _smi( 'import-playlist', [items[-1].name], _("_Import Playlist"), 'document-open', lambda *e: get_main().controller.get_panel( 'playlists').import_playlist())) def export_playlist_cb(*args): main = get_main() page = get_selected_playlist() if not page: return def on_message(dialog, message_type, message): """ Show messages in the main window message area """ if message_type == Gtk.MessageType.INFO: main.message.show_info(markup=message) elif message_type == Gtk.MessageType.ERROR: main.message.show_error(_('Playlist export failed!'), message) return True dialog = dialogs.PlaylistExportDialog(page.playlist, main.window) dialog.connect('message', on_message) dialog.show() items.append( _smi('export-playlist', [items[-1].name], _("E_xport Current Playlist"), 'document-save-as', export_playlist_cb)) items.append(_sep('export-sep', [items[-1].name])) def close_tab_cb(*args): get_main().get_selected_page().tab.close() accelerators.append( Accelerator('<Primary>w', _("Close _Tab"), close_tab_cb)) items.append( _smi('close-tab', [items[-1].name], icon_name='window-close', callback=accelerators[-1])) if get_main().controller.exaile.options.Debug: def restart_cb(*args): from xl import main main.exaile().quit(True) accelerators.append( Accelerator('<Primary>r', _("_Restart"), restart_cb)) items.append( _smi('restart-application', [items[-1].name], callback=accelerators[-1])) def quit_cb(*args): from xl import main main.exaile().quit() accelerators.append(Accelerator('<Primary>q', _("_Quit Exaile"), quit_cb)) items.append( _smi('quit-application', [items[-1].name], icon_name='application-exit', callback=accelerators[-1])) for item in items: providers.register('menubar-file-menu', item) for accelerator in accelerators: providers.register('mainwindow-accelerators', accelerator)