예제 #1
0
    def __button_press_event(self, event):
        if self.__browser_id == blaconst.BROWSER_FILESYSTEM:
            return False

        # Return on events that don't require any special treatment.
        if ((event.button == 1 and not (event.type == gtk.gdk._2BUTTON_PRESS or
            event.type == gtk.gdk._3BUTTON_PRESS)) or
            event.type == gtk.gdk._3BUTTON_PRESS or
            (event.button == 2 and event.type == gtk.gdk._2BUTTON_PRESS)):
            return False

        if event.button == 1:
            action = blacfg.getint("library", "doubleclick.action")
        elif event.button == 2:
            action = blacfg.getint("library", "middleclick.action")

        path = self.get_path_at_pos(*map(int, [event.x, event.y]))[0]
        # TODO: remove me
        if False and not self.__accept_button_event(column, path, event,
                                          check_expander=(event.button == 1)):
            self.__allow_selection(True)
            selection.unselect_all()

        # Handle LMB events
        if event.button == 1 and action == blaconst.ACTION_EXPAND_COLLAPSE:
            if self.row_expanded(path):
                self.collapse_row(path)
            else:
                self.expand_row(path, open_all=False)
            return False

        # On middle-clicks we must update the selection due to the way DND is
        # implemented.
        if event.button == 2:
            selection = self.get_selection()
            selection.unselect_all()
            selection.select_path(path)

        model = self.get_model()
        name = model[path][-1]
        tracks = self.get_tracks()

        if action == blaconst.ACTION_SEND_TO_CURRENT:
            playlist_manager.send_to_current_playlist(tracks)
        elif action == blaconst.ACTION_ADD_TO_CURRENT:
            playlist_manager.add_to_current_playlist(tracks)
        elif action == blaconst.ACTION_SEND_TO_NEW:
            playlist_manager.send_to_new_playlist(tracks, name)

        return False
예제 #2
0
    def __key_press_event(self, treeview, event):
        if self.__browser_id == blaconst.BROWSER_FILESYSTEM:
            return False

        if blagui.is_accel(event, "Q"):
            self.__send_to_queue()

        elif (blagui.is_accel(event, "Return") or
              blagui.is_accel(event, "KP_Enter")):
            action = blacfg.getint("library", "return.action")

            selections = self.get_selection().get_selected_rows()[-1]
            if not selections:
                return True
            name = self.get_model()[selections[0]][-1]
            tracks = self.get_tracks()

            if action == blaconst.ACTION_SEND_TO_CURRENT:
                playlist_manager.send_to_current_playlist(tracks)
            elif action == blaconst.ACTION_ADD_TO_CURRENT:
                playlist_manager.add_to_current_playlist(tracks)
            elif action == blaconst.ACTION_SEND_TO_NEW:
                playlist_manager.send_to_new_playlist(tracks, name)

        return False
예제 #3
0
파일: blaview.py 프로젝트: nkoep/blaplay
        def __new__(cls, name, bases, dct):
            # Make sure at least one baseclass inherits from gobject.GObject.
            if not any([issubclass(base, gobject.GObject) for base in bases]):
                raise TypeError("%s does not inherit from gobject.GObject" %
                                name)

            # Add the view_name property.
            if "view_name" in dct:
                raise ValueError("View class %s already defines an attribute "
                                 "'view_name'" % name)
            dct["view_name"] = property(lambda self: view_name)

            # Add the count_changed signal.
            signals = dct.get("__gsignals__", {})
            if "count_changed" in signals or "count-changed" in signals:
                raise ValueError("Class %s already defines a 'count_changed' "
                                 "signal" % name)
            signals["count_changed"] = blautil.signal(2)
            dct["__gsignals__"] = signals

            # Add the init-function stub.
            if "init" not in dct:
                dct["init"] = lambda self: None

            # Add default behavior for `update_statusbar()'.
            if "update_statusbar" not in dct:
                dct["update_statusbar"] = lambda s: BlaStatusbar.set_view_info(
                    blacfg.getint("general", "view"), "")

            return super(_BlaViewMeta, cls).__new__(cls, name, bases, dct)
예제 #4
0
파일: blaview.py 프로젝트: nkoep/blaplay
    def set_view(self, view):
        view_prev = blacfg.getint("general", "view")
        blacfg.set("general", "view", view)

        if player.video:
            # If the previous view was the video view coerce the cover art
            # display into acting as new video canvas.
            self.__side_pane.cover_display.use_as_video_canvas(
                view != blaconst.VIEW_VIDEO)

        child = self.__container.get_child()
        if view == view_prev and child is not None:
            return
        if child is not None:
            self.__container.remove(child)
        child = self.__views[view]
        if child.get_parent() is not None:
            child.unparent()
        self.__container.add(child)
        child.update_statusbar()

        # Not all menu items are available for all views so update them
        # accordingly.
        ui_manager.update_menu(view)
        self.__side_pane.set_active_view(view)
예제 #5
0
 def set_view_info(cls, view, string):
     # TODO: get rid of the view argument
     if view == blacfg.getint("general", "view"):
         try:
             cls.__instance.__view_info.set_text(string)
         except AttributeError:
             pass
     return False
예제 #6
0
파일: blampris.py 프로젝트: nkoep/blaplay
 def __shuffle(self, value=None):
     # Read value
     if value is None:
         return (blacfg.getint("general", "play.order") ==
                 blaconst.ORDER_SHUFFLE)
     else:
         # TODO: see __loop_status
         pass
예제 #7
0
 def populated(model):
     self.__expanded_rows = []
     self.__treeview.set_model(model)
     organize_by = blacfg.getint("library", "organize.by")
     if (organize_by == blaconst.ORGANIZE_BY_DIRECTORY and
         model.get_iter_first()):
         self.__treeview.expand_row((0,), open_all=False)
     try:
         self.window.set_cursor(None)
     except AttributeError:
         pass
예제 #8
0
파일: blaview.py 프로젝트: nkoep/blaplay
 def sync_handler():
     view = blacfg.getint("general", "view")
     if view == blaconst.VIEW_VIDEO:
         element = self.__views[blaconst.VIEW_VIDEO]
     else:
         element = self.__side_pane.cover_display
         # Coerce the cover display into a video canvas.
         element.use_as_video_canvas(True)
     canvas = element.get_video_canvas()
     if canvas.get_realized():
         return canvas.window.xid
     print_w("Drawing area for video playback not yet realized")
     return 0
예제 #9
0
파일: blaradio.py 프로젝트: nkoep/blaplay
    def __get_station(self, choice):
        def get_random(old=None):
            idx_max = len(model)-1
            path = randint(0, idx_max)
            if old is not None and idx_max > 0:
                while path == old[0]:
                    path = randint(0, idx_max)
            return (path,)

        model = self.__treeview.get_model()
        for row in model:
            row[0] = None
        path = (0,)

        # FIXME:
        # The `choice' variable can either be a direction constant as defined
        # in blaconst if the method is invoked as player callback or a
        # treemodel path if it's invoked as row_activated callback on the
        # treeview.
        if not isinstance(choice, tuple):
            if len(model) == 0:
                return player.play_station(None)

            if self.__current:
                for row in model:
                    if row[1] == self.__current:
                        path = row.path
                        break

            order = blacfg.getint("general", "play.order")
            if choice == blaconst.TRACK_RANDOM:
                path = get_random()
            elif order == blaconst.ORDER_SHUFFLE:
                path = get_random(path)
            else:
                if choice == blaconst.TRACK_NEXT:
                    iterator = model.iter_next(model.get_iter(path))
                    if not iterator:
                        return player.play_station(None)
                    path = model.get_path(iterator)
                elif choice == blaconst.TRACK_PREVIOUS:
                    if path[0] < 1:
                        return player.play_station(None)
                    path = (path[0]-1,)
        else:
            path = choice

        self.__treeview.set_cursor(path)
        self.__current = model[path][1]
        player.play_station(self.__current)
예제 #10
0
파일: blampris.py 프로젝트: nkoep/blaplay
 def __loop_status(self, value=None):
     # Read value
     if value is None:
         order = blacfg.getint("general", "play.order")
         if order == blaconst.ORDER_REPEAT:
             return "Track"
         elif order == blaconst.ORDER_SHUFFLE:
             return "Playlist"
         return "None"
     else:
         # TODO: export a method somewhere which changes the play order.
         #       better yet, let widgets listen for changes of the config
         #       and check if play.order changed.
         pass
예제 #11
0
    def __query(self, uri):
        track = library[uri]
        strings = [track[identifier] for identifier in (ARTIST, TITLE, ALBUM)]

        if (blacfg.getint("library", "organize.by") ==
            blaconst.ORGANIZE_BY_DIRECTORY):
            strings.append(track.basename)

        for r in self.__res:
            search = r.search
            for string in strings:
                if search(string):
                    break
            else:
                return False
        return True
예제 #12
0
    def __init__(self):
        super(BlaBrowsers, self).__init__()

        type(self).__library_browser = BlaLibraryBrowser(self)
        self.__file_browser = BlaFileBrowser(self)
        self.append_page(self.__library_browser, gtk.Label("Library"))
        self.append_page(self.__file_browser, gtk.Label("Filesystem"))

        self.show_all()

        page_num = blacfg.getint("general", "browser.view")
        if page_num not in (0, 1):
            page_num = 0
        self.set_current_page(page_num)
        self.connect("switch_page",
                     lambda *x: blacfg.set("general", "browser.view", x[-1]))
예제 #13
0
파일: blaplayer.py 프로젝트: nkoep/blaplay
    def play(self):
        if not self.__uri:
            if blacfg.getint("general", "view") == blaconst.VIEW_RADIO:
                args = ("get_station", blaconst.TRACK_PLAY)
            else:
                args = ("get_track", blaconst.TRACK_PLAY, True)
            return self.emit(*args)

        # Check if the resource is available. If it's not it's best to stop
        # trying and inform the user about the situation. If we'd just ask
        # for another track we'd potentially end up hitting the interpreter's
        # recursion limit in case lots of tracks turn out to be invalid.
        if not os.path.exists(self.__uri) or not os.path.isfile(self.__uri):
            from blaplay.blagui import blaguiutils
            uri = self.__uri
            self.stop()
            blaguiutils.error_dialog("Playback error",
                                     "Resource \"%s\" unavailable." % uri)
            return

        # If `update_track' returns None it means the track needed updating,
        # but failed to be parsed properly so request another song.
        if library.update_track(self.__uri) is None:
            self.emit("get_track", blaconst.TRACK_PLAY, True)

        if (self.__state == blaconst.STATE_STOPPED and
            not self.__init_pipeline()):
            return
        self.__bin.set_state(gst.STATE_NULL)
        self.__bin.set_property("uri", "file://%s" % self.__uri)
        self.__bin.set_state(gst.STATE_PLAYING)
        self.__station = None

        self.__state = blaconst.STATE_PLAYING
        self.emit("track_changed")
        self.emit("state_changed")
예제 #14
0
 def queue_model_update(*args):
     self.__queue_model_update(blacfg.getint("library", "organize.by"))
예제 #15
0
    def __init__(self, parent):
        super(BlaLibraryBrowser, self).__init__()

        self.__treeview = BlaTreeView(parent=parent, multicol=False,
                                      browser_id=blaconst.BROWSER_LIBRARY)
        self.__treeview.set_headers_visible(False)
        column = gtk.TreeViewColumn()
        column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
        self.__treeview.append_column(column)
        self.__treeview.connect("row_collapsed", self.__row_collapsed)
        self.__treeview.connect("row_expanded", self.__row_expanded)

        self.__treeview.enable_model_drag_source(
            gtk.gdk.BUTTON1_MASK,
            [blagui.DND_TARGETS[blagui.DND_LIBRARY]],
            gtk.gdk.ACTION_COPY)
        self.__treeview.connect_object(
            "drag_data_get", BlaLibraryBrowser.__drag_data_get, self)

        sw = BlaScrolledWindow()
        sw.add(self.__treeview)

        hbox = gtk.HBox()

        cb = gtk.combo_box_new_text()
        for label in ["directory", "artist", "artist - album", "album",
                      "genre", "year"]:
            cb.append_text(label)
        cb.set_active(blacfg.getint("library", "organize.by"))
        cb.connect("changed", self.__organize_by_changed)

        alignment = gtk.Alignment()
        alignment.add(gtk.Label("Organize by:"))
        table = gtk.Table(rows=2, columns=1, homogeneous=False)
        table.attach(alignment, 0, 1, 0, 1, xpadding=2, ypadding=2)
        table.attach(cb, 0, 1, 1, 2)
        hbox.pack_start(table, expand=False)

        def queue_model_update(*args):
            self.__queue_model_update(blacfg.getint("library", "organize.by"))

        self.__entry = gtk.Entry()
        self.__entry.set_icon_from_stock(gtk.ENTRY_ICON_SECONDARY,
                                         gtk.STOCK_CLEAR)
        self.__entry.connect(
            "icon_release", lambda *x: x[0].delete_text(0, -1))
        self.__entry.connect("changed", self.__filter_parameters_changed)
        self.__entry.connect("activate", queue_model_update)

        button = gtk.Button()
        button.add(
            gtk.image_new_from_stock(gtk.STOCK_FIND,
                                     gtk.ICON_SIZE_SMALL_TOOLBAR))
        button.connect("clicked", queue_model_update)

        alignment = gtk.Alignment()
        alignment.add(gtk.Label("Filter:"))
        table = gtk.Table(rows=2, columns=1, homogeneous=False)
        table.attach(alignment, 0, 1, 0, 1, xpadding=2, ypadding=2)
        hbox2 = gtk.HBox()
        hbox2.pack_start(self.__entry, expand=True)
        hbox2.pack_start(button, expand=False)
        table.attach(hbox2, 0, 1, 1, 2)
        hbox.pack_start(table)

        self.pack_start(sw, expand=True)
        self.pack_start(hbox, expand=False)

        self.update_treeview_style()
        self.update_tree_lines()
        def config_changed(cfg, section, key):
            if section == "library":
                if key == "custom.browser":
                    self.update_treeview_style()
                elif key == "draw.tree.lines":
                    self.update_tree_lines()
        blacfg.connect("changed", config_changed)

        library.connect("library_updated", queue_model_update)
        queue_model_update()
예제 #16
0
파일: blaview.py 프로젝트: nkoep/blaplay
    def __init__(self, views):
        super(BlaSidePane, self).__init__(spacing=blaconst.WIDGET_SPACING)

        notebook = gtk.Notebook()
        notebook.set_scrollable(True)

        # Set up the lyrics textview.
        self.__tv = gtk.TextView()
        self.__tv.set_size_request(self.__MIN_WIDTH, -1)
        self.__tv.set_editable(False)
        self.__tv.set_cursor_visible(False)
        self.__tv.set_wrap_mode(gtk.WRAP_WORD)
        self.__tv.set_justification(gtk.JUSTIFY_CENTER)

        sw = BlaScrolledWindow()
        sw.set_shadow_type(gtk.SHADOW_NONE)
        sw.add(self.__tv)
        sw.show_all()

        self.__style = self.__tv.get_modifier_style().copy()
        self.__tb = self.__tv.get_buffer()
        self.__tb.create_tag("bold", weight=pango.WEIGHT_BOLD)
        self.__tb.create_tag("large", scale=pango.SCALE_LARGE)
        self.__tb.create_tag("italic", style=pango.STYLE_ITALIC)
        self.__tag = self.__tb.create_tag("color")

        # Set up the view selector.
        viewport = gtk.Viewport()
        viewport.set_shadow_type(gtk.SHADOW_IN)
        self.__treeview = blaguiutils.BlaTreeViewBase(
            allow_empty_selection=False)
        self.__treeview.get_selection().set_mode(gtk.SELECTION_SINGLE)
        self.__treeview.set_headers_visible(False)
        self.__treeview.set_property("rules_hint", True)
        r = gtk.CellRendererText()
        r.set_property("ellipsize", pango.ELLIPSIZE_END)
        c = gtk.TreeViewColumn()
        c.pack_start(r, expand=True)
        c.add_attribute(r, "text", 0)
        r = gtk.CellRendererText()
        r.set_alignment(1.0, 0.5)
        c.pack_start(r, expand=False)
        def cell_data_func(column, renderer, model, iterator):
            count = model[iterator][1]
            renderer.set_property(
                "markup", "<i>(%d)</i>" % count if count > 0 else "")
        c.set_cell_data_func(r, cell_data_func)
        self.__treeview.append_column(c)
        viewport.add(self.__treeview)
        model = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_INT)
        self.__treeview.set_model(model)
        [model.append([view.view_name, 0]) for view in views]
        selection = self.__treeview.get_selection()
        selection.select_path(blacfg.getint("general", "view"))
        self.__treeview.get_selection().connect(
            "changed", self.__selection_changed)

        self.cover_display = BlaSidePane.BlaCoverDisplay()

        hbox = gtk.HBox(spacing=blaconst.WIDGET_SPACING)
        hbox.pack_start(viewport, expand=True)
        hbox.pack_start(self.cover_display, expand=False, fill=True)

        notebook.append_page(BlaTagEditor(views[blaconst.VIEW_PLAYLISTS]),
                             gtk.Label("Tags"))
        notebook.append_page(BlaProperties(views[blaconst.VIEW_PLAYLISTS]),
                             gtk.Label("Properties"))
        notebook.append_page(sw, gtk.Label("Lyrics"))

        def switch_page(notebook, page, page_num):
            action_widget = notebook.get_action_widget(gtk.PACK_END)
            if action_widget.child is not None:
                action_widget.remove(action_widget.child)

            page = notebook.get_nth_page(page_num)
            blacfg.set("general", "metadata.view", page_num)

            if page_num == blaconst.METADATA_TAGS:
                widget = page.get_control_widget()
            elif page_num == blaconst.METADATA_LYRICS:
                button = gtk.Button()
                button.set_tooltip_text("Edit lyrics")
                button.set_relief(gtk.RELIEF_NONE)
                button.set_focus_on_click(False)
                button.add(
                    gtk.image_new_from_stock(gtk.STOCK_EDIT,
                                             gtk.ICON_SIZE_MENU))
                style = gtk.RcStyle()
                style.xthickness = style.ythickness = 0
                button.modify_style(style)
                # TODO: Implement a widget to edit metadata.
                button.connect("clicked", lambda *x: False)
                button.show_all()
                widget = button

                action_widget.set_visible(False)
                return
            else:
                action_widget.set_visible(False)
                return

            action_widget.add(widget)
            action_widget.set_visible(True)
            action_widget.show_all()

        viewport = gtk.Viewport()
        viewport.set_shadow_type(gtk.SHADOW_NONE)
        notebook.set_action_widget(viewport, gtk.PACK_END)
        notebook.connect("switch_page", switch_page)
        page_num = blacfg.getint("general", "metadata.view")
        notebook.set_current_page(page_num)
        # Make sure the notebook's action widget gets initialized.
        switch_page(notebook, None, page_num)

        self.pack_start(notebook, expand=True)
        self.pack_start(hbox, expand=False)

        # Hook up the metadata callbacks.
        BlaSidePane.fetcher = blametadata.BlaFetcher()
        self.fetcher.connect_object(
            "lyrics", BlaSidePane.__update_lyrics, self)
        self.fetcher.connect_object(
            "cover", type(self.cover_display).update, self.cover_display)

        notebook.show()
        hbox.show_all()
        self.show()
예제 #17
0
파일: blaview.py 프로젝트: nkoep/blaplay
    def __init__(self):
        super(BlaView, self).__init__()

        actions = [
            ("Clear", None, "_Clear", None, "", self.__clear),
            ("SelectAll", None, "All", None, "",
             lambda *x: self.__select(blaconst.SELECT_ALL)),
            ("SelectComplement", None, "Complement", None, "",
             lambda *x: self.__select(blaconst.SELECT_COMPLEMENT)),
            ("SelectByArtist", None, "By artist", None, "",
             lambda *x: self.__select(blaconst.SELECT_BY_ARTISTS)),
            ("SelectByAlbum", None, "By album", None, "",
             lambda *x: self.__select(blaconst.SELECT_BY_ALBUMS)),
            ("SelectByAlbumArtist", None, "By album artist", None, "",
             lambda *x: self.__select(blaconst.SELECT_BY_ALBUM_ARTISTS)),
            ("SelectByGenre", None, "By genre", None, "",
             lambda *x: self.__select(blaconst.SELECT_BY_GENRES)),
            ("Cut", None, "Cut", None, "", self.__cut),
            ("Copy", None, "Copy", None, "", self.__copy),
            ("Remove", None, "Remove", None, "", self.__remove),
            ("Paste", None, "Paste", None, "", self.__paste),
            ("RemoveDuplicates", None, "Remove _duplicates", None, "",
             self.__remove_duplicates),
            ("RemoveInvalidTracks", None, "Remove _invalid tracks", None, "",
             self.__remove_invalid_tracks)
        ]
        ui_manager.add_actions(actions)

        radio_actions = [
            ("Playlists", None, "_Playlists", None, "",
             blaconst.VIEW_PLAYLISTS),
            ("Queue", None, "_Queue", None, "", blaconst.VIEW_QUEUE),
            ("Radio", None, "R_adio", None, "", blaconst.VIEW_RADIO),
            ("Video", None, "_Video", None, "", blaconst.VIEW_VIDEO),
            ("RecommendedEvents", None, "_Recommended events", None, "",
             blaconst.VIEW_EVENTS),
            ("NewReleases", None, "_New releases", None, "",
             blaconst.VIEW_RELEASES),
        ]
        ui_manager.add_radio_actions(
            radio_actions, value=blacfg.getint("general", "view"),
            on_change=lambda *x: self.set_view(
            x[-1].get_current_value()))

        from blaplaylist import playlist_manager
        from blaqueue import queue
        from blavideo import BlaVideo
        from blaradio import BlaRadio
        from blaeventbrowser import BlaEventBrowser
        from blareleasebrowser import BlaReleaseBrowser
        self.__views = [playlist_manager, queue, BlaRadio(), BlaVideo(),
                        BlaEventBrowser(), BlaReleaseBrowser()]

        self.__container = gtk.Viewport()
        self.__container.set_shadow_type(gtk.SHADOW_NONE)
        self.__side_pane = BlaSidePane(self.__views)

        player.connect(
            "state_changed", lambda *x: self.__side_pane.update_track())
        # The sync handler gets called every time gstreamer needs an xwindow
        # for rendering video.
        def sync_handler():
            view = blacfg.getint("general", "view")
            if view == blaconst.VIEW_VIDEO:
                element = self.__views[blaconst.VIEW_VIDEO]
            else:
                element = self.__side_pane.cover_display
                # Coerce the cover display into a video canvas.
                element.use_as_video_canvas(True)
            canvas = element.get_video_canvas()
            if canvas.get_realized():
                return canvas.window.xid
            print_w("Drawing area for video playback not yet realized")
            return 0
        player.set_sync_handler(sync_handler)

        for view in self.__views:
            view.connect("count_changed", self.__side_pane.update_count)
        # We have to defer initialization until all count_changed signal
        # handlers have been hooked up.
        for view in self.__views:
            view.init()

        self.show()
        self.__container.show_all()
        self.__side_pane.show()

        self.pack1(self.__container, resize=True, shrink=False)
        self.pack2(self.__side_pane, resize=False, shrink=False)

        def startup_complete(*args):
            self.set_view(blacfg.getint("general", "view"))
        blaplay.bla.connect("startup_complete", startup_complete)
예제 #18
0
파일: blaview.py 프로젝트: nkoep/blaplay
        def __button_press_event(self, event):
            def open_cover(*args):
                blautil.open_with_filehandler(
                    self.__cover, "Failed to open image '%s'" % self.__cover)

            def fetch_cover(*args):
                BlaSidePane.fetcher.fetch_cover(
                    BlaSidePane.track, self.__update_timestamp(),
                    force_download=True)

            def set_cover(*args):
                diag = gtk.FileChooserDialog(
                    "Select cover",
                    buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
                             gtk.STOCK_OPEN, gtk.RESPONSE_OK))
                diag.set_local_only(True)
                response = diag.run()
                path = diag.get_filename()
                diag.destroy()

                if response == gtk.RESPONSE_OK and path:
                    BlaSidePane.fetcher.set_cover(
                        self.__update_timestamp(), path)

            def delete_cover(*args):
                BlaSidePane.fetcher.set_cover(self.__update_timestamp())

            # If the cover art display is used to display video delegate the
            # button event to the default handler.
            if (blacfg.getint("general", "view") != blaconst.VIEW_VIDEO and
                player.video):
                return False

            if (event.button == 1 and event.type == gtk.gdk._2BUTTON_PRESS and
                self.__cover != blaconst.COVER):
                open_cover()
            elif (event.button == 3 and
                  event.type not in [gtk.gdk._2BUTTON_PRESS,
                                     gtk.gdk._3BUTTON_PRESS]):
                menu = gtk.Menu()
                sensitive = self.__cover != blaconst.COVER
                items = [
                    ("Open in image viewer", open_cover, sensitive),
                    ("Open directory", lambda *x: blautil.open_directory(
                     os.path.dirname(self.__cover)), sensitive),
                    None,
                    ("Fetch cover", fetch_cover, True),
                    ("Set cover...",
                     lambda *x: set_cover(self.__update_timestamp()), True),
                    ("Delete cover", delete_cover, sensitive)
                ]
                track = BlaSidePane.track
                if (player.get_state() == blaconst.STATE_STOPPED or
                    not track[ARTIST] or not track[ALBUM]):
                    state = False
                else:
                    state = True

                for item in items:
                    if not item:
                        m = gtk.SeparatorMenuItem()
                    else:
                        label, callback, sensitive = item
                        m = gtk.MenuItem(label)
                        m.connect("activate", callback)
                        m.set_sensitive(sensitive)
                    menu.append(m)

                menu.show_all()
                menu.popup(None, None, None, event.button, event.time)

            return True
예제 #19
0
    def __update_models(self):
        def set_sensitive(state):
            self.__hbox.set_sensitive(state)
            self.__treeview.set_sensitive(state)
            return False
        gobject.idle_add(set_sensitive, False)

        with self.__lock:
            images = set()
            releases = (blafm.get_new_releases(),
                        blafm.get_new_releases(recommended=True))
            active = blacfg.getint("general", "releases.filter")
            if releases[0]:
                self.__count_library = len(releases[0])
            if releases[1]:
                self.__count_recommended = len(releases[1])
            items = [
                (blaconst.NEW_RELEASES_FROM_LIBRARY, releases[0] or []),
                (blaconst.NEW_RELEASES_RECOMMENDED, releases[1] or [])
            ]
            current_week = datetime.date.today().isocalendar()[:2]
            for filt, releases in items:
                model = gtk.ListStore(gobject.TYPE_PYOBJECT)
                previous_week = None
                for release in releases:
                    release = BlaRelease(release)
                    week = release.calender_week
                    if previous_week != week:
                        previous_week = week
                        date = self.__cw_to_start_end_day(*week)
                        date = "%s - %s" % (date[0].strftime("%a %d %b"),
                                            date[1].strftime("%a %d %b"))
                        datestring = "\n<span size=\"larger\"><b>%s\n"
                        if week == current_week:
                            datestring %= "This week</b></span> (%s)" % date
                        else:
                            datestring %= "Week of %s</b></span>" % date
                        model.append([datestring])
                    model.append([release])
                    path = release.get_cover()
                    if path:
                        images.add(path)
                self.__models[filt] = model

            # Get rid of covers for releases that don't show up anymore.
            for image in set(blautil.discover(blaconst.RELEASES)).difference(
                images):
                try:
                    os.unlink(image)
                except OSError:
                    pass

            gobject.idle_add(set_sensitive, True)
            gobject.idle_add(self.__treeview.set_model, self.__models[active])

            if active == blaconst.NEW_RELEASES_FROM_LIBRARY:
                count = self.__count_library
            else:
                count = self.__count_recommended
            gobject.idle_add(
                self.emit, "count_changed", blaconst.VIEW_RELEASES, count)
            return True
예제 #20
0
    def __init__(self):
        super(BlaReleaseBrowser, self).__init__()
        self.set_shadow_type(gtk.SHADOW_NONE)

        vbox = gtk.VBox()
        vbox.set_border_width(10)

        # Heading
        hbox = gtk.HBox()
        items = [
            ("<b><span size=\"xx-large\">New releases</span></b>",
             0.0, 0.5, 0),
            ("<b><span size=\"x-small\">powered by</span></b>",
             1.0, 1.0, 5)
        ]
        for markup, xalign, yalign, padding in items:
            label = gtk.Label()
            label.set_markup(markup)
            alignment = gtk.Alignment(xalign, yalign)
            alignment.add(label)
            hbox.pack_start(alignment, expand=True, fill=True, padding=padding)

        image = gtk.image_new_from_file(blaconst.LASTFM_LOGO)
        alignment = gtk.Alignment(1.0, 0.5)
        alignment.add(image)
        hbox.pack_start(alignment, expand=False)
        vbox.pack_start(hbox, expand=False)

        # Type selector
        self.__hbox = gtk.HBox(spacing=5)
        self.__hbox.set_border_width(10)
        items = [
            ("From artists in your library",
             blaconst.NEW_RELEASES_FROM_LIBRARY),
            ("Recommended by Last.fm", blaconst.NEW_RELEASES_RECOMMENDED)
        ]
        active = blacfg.getint("general", "releases.filter")
        radiobutton = None
        for label, filt in items:
            radiobutton = gtk.RadioButton(radiobutton, label)
            if filt == active:
                radiobutton.set_active(True)
            radiobutton.connect("toggled", self.__filter_changed, filt)
            self.__hbox.pack_start(radiobutton, expand=False)
        button = gtk.Button("Refresh")
        button.set_focus_on_click(False)
        button.connect_object(
            "clicked", BlaReleaseBrowser.__update_models, self)
        self.__hbox.pack_start(button, expand=False, padding=5)
        vbox.pack_start(self.__hbox, expand=False)

        # Releases list
        def cell_data_func_pixbuf(column, renderer, model, iterator):
            release = model[iterator][0]
            try:
                renderer.set_property("content", release.cover)
            except AttributeError:
                renderer.set_property("content", release)

        def cell_data_func_text(column, renderer, model, iterator):
            release = model[iterator][0]
            try:
                markup = "<b>%s</b>\n%s\nReleased: %s" % (
                    release.release_name, release.artist_name,
                    release.release_date)
            except AttributeError:
                markup = ""
            renderer.set_property("markup", markup.replace("&", "&amp;"))

        self.__treeview = blaguiutils.BlaTreeViewBase(
            set_button_event_handlers=False)
        self.__treeview.set_rules_hint(True)
        self.__treeview.get_selection().set_mode(gtk.SELECTION_SINGLE)
        self.__treeview.set_headers_visible(False)
        r = BlaCellRendererPixbuf()
        column = gtk.TreeViewColumn()
        column.pack_start(r, expand=False)
        column.set_cell_data_func(r, cell_data_func_pixbuf)
        r = gtk.CellRendererText()
        r.set_alignment(0.0, 0.0)
        r.set_property("ellipsize", pango.ELLIPSIZE_END)
        column.pack_start(r)
        column.set_cell_data_func(r, cell_data_func_text)
        self.__treeview.append_column(column)
        self.__treeview.connect("row_activated", self.__row_activated)
        self.__treeview.connect_object(
            "key_press_event", BlaReleaseBrowser.__key_press_event, self)
        self.__treeview.connect_object(
            "button_press_event", BlaReleaseBrowser.__button_press_event, self)
        self.__models = map(gtk.ListStore, [gobject.TYPE_PYOBJECT] * 2)
        self.__treeview.set_model(self.__models[active])
        vbox.pack_start(self.__treeview, expand=True, padding=10)

        # FIXME: The treeview in the vbox, wrapped in a gtk.ScrolledWindow,
        #        does not cause the viewport to scroll according to the
        #        selection in the treeview.
        self.add_with_viewport(vbox)
        self.show_all()

        blaplay.bla.register_for_cleanup(self)
예제 #21
0
    def __update_models(self):
        def set_sensitive(state):
            self.__hbox.set_sensitive(state)
            self.__treeview.set_sensitive(state)
            return False
        gobject.idle_add(set_sensitive, False)

        with self.__lock:
            images = set()

            active = blacfg.getint("general", "events.filter")
            limit = blacfg.getint("general", "events.limit")
            country = blacfg.getstring("general", "events.country")
            city = blacfg.getstring("general", "events.city")

            events = (blafm.get_events(limit=limit, recommended=True),
                      blafm.get_events(limit=limit, recommended=False,
                                       country=country, city=city))
            if events[0]:
                self.__count_recommended = len(events[0])
            if events[1]:
                self.__count_all = len(events[1])
            items = [
                (blaconst.EVENTS_RECOMMENDED, events[0] or []),
                (blaconst.EVENTS_ALL, events[1] or [])
            ]
            for filt, events in items:
                model = gtk.ListStore(gobject.TYPE_PYOBJECT)
                previous_date = None
                for event in events:
                    event = BlaEvent(event)
                    date = event.date
                    if previous_date != date:
                        previous_date = date
                        model.append(
                            ["\n<span size=\"larger\"><b>%s</b></span>\n" %
                             date])
                    model.append([event])
                    path = event.get_image()
                    if path:
                        images.add(path)
                self.__models[filt] = model

            # Get rid of images for events that don't show up anymore.
            for image in set(blautil.discover(blaconst.EVENTS)).difference(
                images):
                try:
                    os.unlink(image)
                except OSError:
                    pass

            gobject.idle_add(set_sensitive, True)
            # TODO: Only set the model when we verified that we successfully
            #       retrieved event information. This avoids that we delete a
            #       restored model.
            gobject.idle_add(self.__treeview.set_model, self.__models[active])

            if active == blaconst.EVENTS_RECOMMENDED:
                count = self.__count_recommended
            else:
                count = self.__count_all
            gobject.idle_add(
                self.emit, "count_changed", blaconst.VIEW_EVENTS, count)
            return True
예제 #22
0
    def __init__(self):
        super(BlaEventBrowser, self).__init__()
        self.set_shadow_type(gtk.SHADOW_NONE)

        vbox = gtk.VBox()
        vbox.set_border_width(10)

        # Heading
        hbox = gtk.HBox()
        items = [
            ("<b><span size=\"xx-large\">Events</span></b>",
             0.0, 0.5, 0),
            ("<b><span size=\"x-small\">powered by</span></b>",
             1.0, 1.0, 5)
        ]
        for markup, xalign, yalign, padding in items:
            label = gtk.Label()
            label.set_markup(markup)
            alignment = gtk.Alignment(xalign, yalign)
            alignment.add(label)
            hbox.pack_start(alignment, expand=True, fill=True, padding=padding)

        image = gtk.image_new_from_file(blaconst.LASTFM_LOGO)
        alignment = gtk.Alignment(1.0, 0.5)
        alignment.add(image)
        hbox.pack_start(alignment, expand=False)
        vbox.pack_start(hbox, expand=False)

        # Location
        hbox_location = gtk.HBox(spacing=5)

        label = gtk.Label()
        label.set_markup("<b>Location:</b>")
        location = gtk.Label()
        country = blacfg.getstring("general", "events.country")
        city = blacfg.getstring("general", "events.city")
        if not city:
            location.set_markup("<i>Unspecified</i>")
        else:
            location.set_text(
                ", ".join([city, country] if country else [city]))

        button = gtk.Button("Change location")
        button.set_focus_on_click(False)
        button.connect(
            "clicked", self.__change_location, location)

        for widget, padding in [(label, 0), (location, 0), (button, 5)]:
            alignment = gtk.Alignment(0.0, 0.5)
            alignment.add(widget)
            hbox_location.pack_start(alignment, expand=False, padding=padding)
        vbox.pack_start(hbox_location, expand=False)

        # Type selector
        self.__hbox = gtk.HBox(spacing=5)
        self.__hbox.set_border_width(10)
        items = [
            ("Recommended events", blaconst.EVENTS_RECOMMENDED),
            ("All events", blaconst.EVENTS_ALL)
        ]
        active = blacfg.getint("general", "events.filter")
        radiobutton = None
        for label, filt in items:
            radiobutton = gtk.RadioButton(radiobutton, label)
            if filt == active:
                radiobutton.set_active(True)
            radiobutton.connect(
                "toggled", self.__filter_changed, filt, hbox_location)
            self.__hbox.pack_start(radiobutton, expand=False)

        button = gtk.Button("Refresh")
        button.set_focus_on_click(False)
        button.connect_object("clicked", BlaEventBrowser.__update_models, self)
        self.__hbox.pack_start(button, expand=False)
        vbox.pack_start(self.__hbox, expand=False)

        hbox = gtk.HBox(spacing=5)
        hbox.pack_start(gtk.Label("Maximum number of results:"), expand=False)
        limit = blacfg.getint("general", "events.limit")
        adjustment = gtk.Adjustment(limit, 1.0, 100.0, 1.0, 5.0, 0.0)
        spinbutton = gtk.SpinButton(adjustment)
        spinbutton.set_numeric(True)
        spinbutton.connect(
            "value_changed",
            lambda sb: blacfg.set("general", "events.limit", sb.get_value()))
        hbox.pack_start(spinbutton, expand=False)
        vbox.pack_start(hbox, expand=False)

        # Events list
        def cell_data_func_pixbuf(column, renderer, model, iterator):
            event = model[iterator][0]
            try:
                renderer.set_property("content", event.image)
            except AttributeError:
                renderer.set_property("content", event)

        def cell_data_func_text(column, renderer, model, iterator):
            event = model[iterator][0]
            # FIXME: Too much code in the try-block.
            try:
                limit = 8
                markup = "<b>%s</b>\n%%s" % event.event_name
                artists = ", ".join(event.artists[:limit])
                if len(event.artists) > limit:
                    artists += ", and more"
                markup %= artists
            except AttributeError:
                markup = ""
            renderer.set_property("markup", markup.replace("&", "&amp;"))

        def cell_data_func_text2(column, renderer, model, iterator):
            event = model[iterator][0]
            try:
                markup = "<b>%s</b>\n%s\n%s" % (
                    event.venue, event.city, event.country)
            except AttributeError:
                markup = ""
            renderer.set_property("markup", markup.replace("&", "&amp;"))

        def cell_data_func_text3(column, renderer, model, iterator):
            event = model[iterator][0]
            markup = ""
            try:
                if event.cancelled:
                    markup = "<span size=\"x-large\"><b>Cancelled</b></span>"
            except AttributeError:
                pass
            renderer.set_property("markup", markup.replace("&", "&amp;"))

        self.__treeview = blaguiutils.BlaTreeViewBase(
            set_button_event_handlers=False)
        self.__treeview.set_rules_hint(True)
        self.__treeview.get_selection().set_mode(gtk.SELECTION_SINGLE)
        self.__treeview.set_headers_visible(False)

        # Image
        r = BlaCellRendererPixbuf()
        column = gtk.TreeViewColumn()
        column.pack_start(r, expand=False)
        column.set_cell_data_func(r, cell_data_func_pixbuf)

        # Title and artists
        r = gtk.CellRendererText()
        r.set_alignment(0.0, 0.0)
        r.set_property("wrap_mode", pango.WRAP_WORD)
        r.set_property("wrap_width", 350)
        column.pack_start(r, expand=False)
        column.set_cell_data_func(r, cell_data_func_text)

        # Location
        r = gtk.CellRendererText()
        r.set_alignment(0.0, 0.0)
        r.set_property("ellipsize", pango.ELLIPSIZE_END)
        column.pack_start(r)
        column.set_cell_data_func(r, cell_data_func_text2)

        # Event cancelled status
        r = gtk.CellRendererText()
        r.set_property("ellipsize", pango.ELLIPSIZE_END)
        column.pack_start(r)
        column.set_cell_data_func(r, cell_data_func_text3)

        self.__treeview.append_column(column)
        self.__treeview.connect("row_activated", self.__row_activated)
        self.__treeview.connect_object(
            "key_press_event", BlaEventBrowser.__key_press_event, self)
        self.__treeview.connect_object(
            "button_press_event", BlaEventBrowser.__button_press_event, self)
        self.__models = map(gtk.ListStore, [gobject.TYPE_PYOBJECT] * 2)
        self.__treeview.set_model(self.__models[active])
        vbox.pack_start(self.__treeview, expand=True, padding=10)

        self.add_with_viewport(vbox)
        self.show_all()
        if active == blaconst.EVENTS_RECOMMENDED:
            hbox_location.set_visible(False)

        blaplay.bla.register_for_cleanup(self)
예제 #23
0
파일: blaview.py 프로젝트: nkoep/blaplay
 def startup_complete(*args):
     self.set_view(blacfg.getint("general", "view"))
예제 #24
0
    def __init__(self):
        super(BlaMainWindow, self).__init__(gtk.WINDOW_TOPLEVEL)
        self.set_resizable(True)
        self.connect("delete_event", self.__delete_event)
        self.enable_tracking(is_main_window=True)

        # Set up the fullscreen window.
        self.__fullscreen_window = gtk.Window()
        def map_(window):
            pass
        self.__fullscreen_window.connect("map", map_)
        self.__fullscreen_window.set_modal(True)
        self.__fullscreen_window.set_transient_for(self)
        self.__fullscreen_window.connect_object(
            "window_state_event", BlaMainWindow.__window_state_event, self)
        def key_press_event(window, event):
            if blagui.is_accel(event, "Escape"):
                window.child.emit("toggle_fullscreen")
            elif blagui.is_accel(event, "space"):
                player.play_pause()
            elif blagui.is_accel(event, "<Ctrl>Q"):
                blaplay.shutdown()
        self.__fullscreen_window.connect_object(
            "key_press_event", key_press_event, self.__fullscreen_window)
        # Realize the fullscreen window. If we don't do this here and reparent
        # the drawingarea to it later that in turn will get unrealized again,
        # causing bad X window errors.
        self.__fullscreen_window.realize()

        # Install a global mouse hook. If connected callbacks don't consume the
        # event by returning True this hook gets called for every widget in the
        # hierarchy that re-emits the event. We therefore cache the event's
        # timestamp to detect and ignore signal re-emissions.
        def button_press_hook(receiver, event):
            event_time = event.get_time()
            if event_time != self.__previous_event_time:
                self.__previous_event_time = event_time
                if event.button == 8:
                    player.previous()
                elif event.button == 9:
                    player.next()
            # This behaves like gobject.{timeout|idle}_add: if the callback
            # doesn't return True it's only called once. It does NOT prevent
            # signal callbacks from executing.
            return True
        self.__previous_event_time = -1
        gobject.add_emission_hook(self, "button_press_event",
                                  button_press_hook)

        # Main menu
        ui_manager = blaplay.bla.ui_manager
        self.add_accel_group(ui_manager.get_accel_group())

        actions = [
            # Menus and submenus
            ("File", None, "_File"),
            ("Edit", None, "_Edit"),
            ("Select", None, "S_elect"),
            ("Selection", None, "Se_lection"),
            ("NewPlaylistFrom", None, "_New playlist from"),
            ("PlayOrder", None, "_Order"),
            ("View", None, "_View"),
            ("Help", None, "_Help"),

            # Menu items
            ("OpenPlaylist", None, "Open playlist...", None, "",
             self.__open_playlist),
            ("AddFiles", None, "Add _files...", None, "",
             lambda *x: self.__add_tracks()),
            ("AddDirectories", None, "_Add directories...", None, "",
             lambda *x: self.__add_tracks(files=False)),
            ("SavePlaylist", None, "_Save playlist...", None, "",
             self.__save_playlist),
            ("Quit", gtk.STOCK_QUIT, "_Quit", "<Ctrl>Q", "",
             lambda *x: blaplay.shutdown()),
            ("Preferences", None, "Pre_ferences...", None, "", BlaPreferences),
            ("About", None, "_About...", None, "", BlaAbout)
        ]
        ui_manager.add_actions(actions)

        toggle_actions = [
            ("Statusbar", None, "St_atusbar", None, "",
             self.__toggle_statusbar, blacfg.getboolean("general",
                                                        "statusbar")),
            ("Visualization", None, "Visualization", None, "",
             self.__toggle_visualization,
             blacfg.getboolean("general", "show.visualization"))
        ]
        ui_manager.add_toggle_actions(toggle_actions)

        radio_actions = [
            ("OrderNormal", None, "_Normal", None, "", blaconst.ORDER_NORMAL),
            ("OrderRepeat", None, "_Repeat", None, "", blaconst.ORDER_REPEAT),
            ("OrderShuffle", None, "_Shuffle", None, "",
             blaconst.ORDER_SHUFFLE)
        ]
        # TODO: Emit "order_changed" signal in the on_change handler instead
        #       and let interested widgets handle this instead.
        ui_manager.add_radio_actions(
            radio_actions, value=blacfg.getint("general", "play.order"),
            on_change=BlaStatusbar.set_order)

        # This is the topmost box that holds all the other components.
        self.add(gtk.VBox())

        # Create instances of the main parts of the GUI.
        self.__toolbar = BlaToolbar()
        self.__browsers = BlaBrowsers()
        self.__visualization = BlaVisualization()
        self.__view = BlaView()
        self.__statusbar = BlaStatusbar()

        # Group browsers and visualization widget.
        self.__vbox_left = gtk.VBox(spacing=blaconst.WIDGET_SPACING)
        self.__vbox_left.pack_start(self.__browsers, expand=True)
        self.__vbox_left.pack_start(self.__visualization, expand=False)
        self.__vbox_left.show()

        # Pack the browser + view-widget into a gtk.HPane instance.
        hpane = gtk.HPaned()
        hpane.pack1(self.__vbox_left, resize=False, shrink=False)
        hpane.pack2(self.__view, resize=True, shrink=True)
        hpane.show()

        # Restore pane positions.
        def notify(pane, propspec, key):
            blacfg.set("general", key, str(pane.get_position()))
        for pane, side in [(hpane, "left"), (self.__view, "right")]:
            key = "pane.pos.%s" % side
            try:
                pane.set_position(blacfg.getint("general", key))
            except TypeError:
                pass
            pane.connect("notify", notify, key)

        # Create a vbox hpane and the statusbar. This allows for setting a
        # border around those items which excludes the menubar and the toolbar.
        vbox = gtk.VBox(spacing=blaconst.BORDER_PADDING)
        vbox.set_border_width(blaconst.BORDER_PADDING)
        vbox.pack_start(hpane)
        vbox.pack_start(self.__statusbar, expand=False)
        vbox.show()

        self.child.pack_start(ui_manager.get_widget("/Menu"), expand=False)
        self.child.pack_start(self.__toolbar, expand=False)
        self.child.pack_start(vbox)
        self.child.show()

        self.__tray = BlaTray()

        def update_title(*args):
            self.__update_title()
        player.connect("state_changed", update_title)
        library.connect("library_updated", update_title)
        self.__update_title()
예제 #25
0
    def __init__(self):
        super(BlaStatusbar, self).__init__(rows=1, columns=3, homogeneous=True)
        type(self).__instance = self

        self.__pb = gtk.ProgressBar()
        self.__pb_label = gtk.Label("Scanning library:")

        self.__track_info = gtk.Label(self.__state_string)

        hbox = gtk.HBox(spacing=10)
        hbox.pack_start(self.__pb_label, expand=False)
        hbox.pack_start(self.__pb, expand=False, fill=True)
        hbox.pack_start(self.__track_info, expand=True)

        self.__view_info = gtk.Label("")

        # Playback order
        self.__order = gtk.combo_box_new_text()
        map(self.__order.append_text, blaconst.ORDER_LITERALS)
        self.__order.set_active(blacfg.getint("general", "play.order"))
        def order_changed(cb):
            order = cb.get_active()
            states = [False] * len(blaconst.ORDER_LITERALS)
            states[order] = True
            ui_manager = blaplay.bla.ui_manager
            for idx, order in enumerate(blaconst.MENU_ORDER):
                action = ui_manager.get_widget(order)
                action.set_active(states[idx])
        self.__order.connect("changed", order_changed)

        table = gtk.Table(rows=1, columns=3)

        table.attach(gtk.Label("Order:"), 0, 1, 0, 1, xpadding=10)
        table.attach(self.__order, 1, 2, 0, 1)
        button = gtk.Button()
        button.set_tooltip_text("Clear queue")
        from blaqueue import queue
        button.connect("clicked", lambda *x: queue.clear())
        queue.connect("count_changed",
                      lambda *x: button.set_sensitive(x[-1] > 0))
        button.add(gtk.image_new_from_stock(gtk.STOCK_CLEAR,
                                            gtk.ICON_SIZE_SMALL_TOOLBAR))
        button.set_relief(gtk.RELIEF_NONE)
        button.set_sensitive(False)
        table.attach(button, 2, 3, 0, 1),

        count = 0
        for widget, xalign in [(hbox, 0.0), (self.__view_info, 0.5),
                               (table, 1.0)]:
            alignment = gtk.Alignment(xalign, 0.5, 0.0, 0.5)
            alignment.add(widget)
            self.attach(alignment, count, count+1, 0, 1)
            count += 1

        player.connect("state_changed", self.__changed)
        library.connect("progress", self.update_progress)

        self.show_all()
        # TODO: group these two
        self.__pb.set_visible(False)
        self.__pb_label.set_visible(False)
        self.set_visible(blacfg.getboolean("general", "statusbar"))
예제 #26
0
        def __init__(self):
            super(BlaPreferences.LibraryBrowsersSettings, self).__init__(
                "Library/Browsers")

            restrict_string = blacfg.getstring("library", "restrict.to")
            exclude_string = blacfg.getstring("library", "exclude")
            def destroy(*args):
                if (restrict_string !=
                    blacfg.getstring("library", "restrict.to") or
                    exclude_string != blacfg.getstring("library", "exclude")):
                    library.sync()
            self.connect("destroy", destroy)

            hbox = gtk.HBox(spacing=10)

            model = gtk.ListStore(gobject.TYPE_STRING)
            treeview = gtk.TreeView(model)
            treeview.set_property("rules_hint", True)
            r = gtk.CellRendererText()
            treeview.insert_column_with_attributes(
                -1, "Directories", r, text=0)

            sw = BlaScrolledWindow()
            sw.set_shadow_type(gtk.SHADOW_IN)
            sw.set_size_request(-1, 140)
            sw.add(treeview)

            directories = blacfg.getdotliststr("library", "directories")
            for f in directories:
                model.append([f])

            table = gtk.Table(rows=2, columns=1)
            items = [
                ("Add...", self.__add_directory),
                ("Remove", self.__remove_directory),
                ("Rescan all", self.__rescan_all)
            ]
            for idx, (label, callback) in enumerate(items):
                button = gtk.Button(label)
                button.connect("clicked", callback, treeview)
                table.attach(button, 0, 1, idx, idx+1, yoptions=not gtk.EXPAND)

            hbox.pack_start(sw, expand=True)
            hbox.pack_start(table, expand=False, fill=False)

            # Update library checkbutton
            update_library = gtk.CheckButton("Update library on startup")
            update_library.set_active(
                blacfg.getboolean("library", "update.on.startup"))
            update_library.connect(
                "toggled",
                lambda cb: blacfg.setboolean("library", "update.on.startup",
                                             cb.get_active()))

            # The file types
            restrict_to_entry = gtk.Entry()
            restrict_to_entry.set_tooltip_text(
                "Comma-separated list, works on filenames")
            restrict_to_entry.set_text(
                blacfg.getstring("library", "restrict.to"))
            restrict_to_entry.connect(
                "changed",
                lambda entry: blacfg.set("library", "restrict.to",
                                         entry.get_text()))

            exclude_entry = gtk.Entry()
            exclude_entry.set_tooltip_text(
                "Comma-separated list, works on filenames")
            exclude_entry.set_text(
                blacfg.getstring("library", "exclude"))
            exclude_entry.connect(
                "changed",
                lambda entry: blacfg.set("library", "exclude",
                                         entry.get_text()))

            pairs = [
                (blaconst.ACTION_SEND_TO_CURRENT, "send to current playlist"),
                (blaconst.ACTION_ADD_TO_CURRENT, "add to current playlist"),
                (blaconst.ACTION_SEND_TO_NEW, "send to new playlist"),
                (blaconst.ACTION_EXPAND_COLLAPSE, "expand/collapse")
            ]
            # FIXME: Ugly!!
            actions = [""] * 4
            for idx, label in pairs:
                actions[idx] = label
            comboboxes = []

            def cb_changed(combobox, key):
                blacfg.set("library", "%s.action" % key, combobox.get_active())

            for key in ["doubleclick", "middleclick", "return"]:
                cb = gtk.combo_box_new_text()
                map(cb.append_text, actions)
                if key == "return":
                    cb.remove_text(3)
                cb.set_active(blacfg.getint("library", "%s.action" % key))
                cb.connect("changed", cb_changed, key)
                comboboxes.append(cb)

            widgets = [restrict_to_entry, exclude_entry] + comboboxes
            labels = ["Restrict to", "Exclude", "Double-click", "Middle-click",
                      "Return"]

            action_table = gtk.Table(rows=len(labels), columns=2,
                                     homogeneous=False)

            count = 0
            for label, widget in zip(labels, widgets):
                label = gtk.Label("%s:" % label)
                label.set_alignment(xalign=0.0, yalign=0.5)
                action_table.attach(label, 0, 1, count, count+1,
                                    xoptions=gtk.FILL, xpadding=5)
                action_table.attach(widget, 1, 2, count, count+1)
                count += 1

            hbox2 = gtk.HBox(spacing=10)

            draw_tree_lines = gtk.CheckButton("Draw tree lines in browsers")
            draw_tree_lines.set_active(
                blacfg.getboolean("library", "draw.tree.lines"))
            draw_tree_lines.connect("toggled", self.__tree_lines_changed)

            custom_library_browser = gtk.CheckButton(
                "Use custom treeview as library browser")
            custom_library_browser.set_active(
                blacfg.getboolean("library", "custom.browser"))
            custom_library_browser.connect(
                "toggled", self.__custom_library_browser_changed)

            hbox2.pack_start(draw_tree_lines)
            hbox2.pack_start(custom_library_browser)

            self.pack_start(hbox, expand=False)
            self.pack_start(update_library, expand=False)
            self.pack_start(action_table, expand=False)
            self.pack_start(hbox2, expand=False)
예제 #27
0
파일: blaview.py 프로젝트: nkoep/blaplay
 def __mediator(self, method_name, *args):
     view = blacfg.getint("general", "view")
     if view in (blaconst.VIEW_PLAYLISTS, blaconst.VIEW_QUEUE):
         getattr(self.__views[view], method_name)(*args)