def test_gtp(self):
     w = Gtk.Window()
     l = Gtk.Label()
     self.failUnlessEqual(qltk.get_top_parent(w), w)
     self.failUnlessEqual(qltk.get_top_parent(l), None)
     w.destroy()
     l.destroy()
 def test_gtp_packed(self):
     w = Gtk.Window()
     l = Gtk.Label()
     w.add(l)
     self.failUnlessEqual(qltk.get_top_parent(w), w)
     self.failUnlessEqual(qltk.get_top_parent(l), w)
     w.destroy()
     l.destroy()
示例#3
0
文件: main.py 项目: zsau/quodlibet
 def __drag_data_received(self, view, ctx, x, y, sel, tid, etime, library):
     # TreeModelSort doesn't support GtkTreeDragDestDrop.
     view.emit_stop_by_name('drag-data-received')
     model = view.get_model()
     if tid == DND_QL:
         filenames = qltk.selection_get_filenames(sel)
         songs = list(filter(None, [library.get(f) for f in filenames]))
         if not songs:
             Gtk.drag_finish(ctx, False, False, etime)
             return
         try:
             path, pos = view.get_dest_row_at_pos(x, y)
         except TypeError:
             playlist = FileBackedPlaylist.from_songs(PLAYLISTS, songs,
                                                      library)
             GLib.idle_add(self._select_playlist, playlist)
         else:
             playlist = model[path][0]
             playlist.extend(songs)
         self.changed(playlist)
         Gtk.drag_finish(ctx, True, False, etime)
         # Cause a refresh to the dragged-to playlist if it is selected
         # so that the dragged (duplicate) track(s) appears
         if playlist is self.__get_name_of_current_selected_playlist():
             model, plist_iter = self.__selected_playlists()
             songlist = qltk.get_top_parent(self).songlist
             self.activate(resort=not songlist.is_sorted())
     else:
         if tid == DND_URI_LIST:
             uri = sel.get_uris()[0]
             name = os.path.basename(uri)
         elif tid == DND_MOZ_URL:
             data = sel.get_data()
             uri, name = data.decode('utf16', 'replace').split('\n')
         else:
             Gtk.drag_finish(ctx, False, False, etime)
             return
         name = _name_for(name or os.path.basename(uri))
         try:
             sock = urlopen(uri)
             if uri.lower().endswith('.pls'):
                 playlist = parse_pls(sock, name, library=library)
             elif (uri.lower().endswith('.m3u') or
                     uri.lower().endswith('.m3u8')):
                 playlist = parse_m3u(sock, name, library=library)
             else:
                 raise IOError
             library.add(playlist.songs)
             self.changed(playlist)
             Gtk.drag_finish(ctx, True, False, etime)
         except IOError:
             Gtk.drag_finish(ctx, False, False, etime)
             qltk.ErrorMessage(
                 qltk.get_top_parent(self),
                 _("Unable to import playlist"),
                 _("Quod Libet can only import playlists in the M3U/M3U8 "
                   "and PLS formats.")).run()
示例#4
0
    def __init__(self, browser):
        if self.is_not_unique():
            return
        super(Preferences, self).__init__()
        self.set_border_width(12)
        self.set_title(_("Playlist Browser Preferences"))
        self.set_default_size(420, 240)
        self.set_transient_for(qltk.get_top_parent(browser))

        box = Gtk.VBox(spacing=6)
        edit_frame = self.edit_display_pane(browser, _("Playlist display"))
        box.pack_start(edit_frame, False, True, 12)

        main_box = Gtk.VBox(spacing=12)
        close = Button(_("_Close"), Icons.WINDOW_CLOSE)
        close.connect('clicked', lambda *x: self.destroy())
        b = Gtk.HButtonBox()
        b.set_layout(Gtk.ButtonBoxStyle.END)
        b.pack_start(close, True, True, 0)

        main_box.pack_start(box, True, True, 0)
        self.use_header_bar()

        if not self.has_close_button():
            main_box.pack_start(b, False, True, 0)
        self.add(main_box)

        close.grab_focus()
        self.show_all()
示例#5
0
文件: cover.py 项目: zsau/quodlibet
    def __init__(self, title, fileobj, parent):
        super(BigCenteredImage, self).__init__(type=Gtk.WindowType.POPUP)
        self.set_type_hint(Gdk.WindowTypeHint.TOOLTIP)

        assert parent
        parent = qltk.get_top_parent(parent)
        self.set_transient_for(parent)

        self.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)

        #If image fails to set, abort construction.
        if not self.set_image(fileobj, parent):
            self.destroy()
            return

        event_box = Gtk.EventBox()
        event_box.add(self.__image)

        frame = Gtk.Frame()
        frame.set_shadow_type(Gtk.ShadowType.OUT)
        frame.add(event_box)

        self.add(frame)

        event_box.connect('button-press-event', self.__destroy)
        event_box.connect('key-press-event', self.__destroy)

        self.get_child().show_all()
示例#6
0
    def __clicked(self, button):
        if self.__window.get_property('visible'):
            return

        if self._disable_slider:
            return

        if self.__grabbed:
            self.__popup_hide()

        window = self.__window
        frame = window.get_child()
        frame.show_all()

        window.set_transient_for(get_top_parent(self))
        # this type hint tells the wayland backend to create a popup
        window.set_type_hint(Gdk.WindowTypeHint.DROPDOWN_MENU)

        position_window_beside_widget(window, self)

        self.__grabbed = window_grab_and_map(
            window,
            Gdk.EventMask.BUTTON_PRESS_MASK |
            Gdk.EventMask.BUTTON_RELEASE_MASK |
            Gdk.EventMask.BUTTON_MOTION_MASK |
            Gdk.EventMask.POINTER_MOTION_MASK |
            Gdk.EventMask.SCROLL_MASK)
示例#7
0
    def pos_func(menu, data, widget=widget):
        screen = widget.get_screen()
        ref = get_top_parent(widget)
        menu.set_screen(screen)
        x, y = widget.translate_coordinates(ref, 0, 0)
        dx, dy = ref.get_window().get_origin()[1:]
        wa = widget.get_allocation()

        # fit menu to screen, aligned per text direction
        screen_width = screen.get_width()
        screen_height = screen.get_height()
        menu.realize()
        ma = menu.get_allocation()

        menu_y_under = y + dy + wa.height
        menu_y_above = y + dy - ma.height
        if under:
            menu_y = menu_y_under
            if menu_y + ma.height > screen_height and menu_y_above > 0:
                menu_y = menu_y_above
        else:
            menu_y = menu_y_above
            if menu_y < 0 and menu_y_under + ma.height < screen_height:
                menu_y = menu_y_under

        if Gtk.Widget.get_default_direction() == Gtk.TextDirection.LTR:
            menu_x = min(x + dx, screen_width - ma.width)
        else:
            menu_x = max(0, x + dx - ma.width + wa.width)

        return (menu_x, menu_y, True) # x, y, move_within_screen
示例#8
0
    def __show_cover(self, box, event):
        """Show the cover as a detached BigCenteredImage.
        If one is already showing, destroy it instead
        If there is no image, run the AlbumArt plugin
        """

        song = self.__song
        if not song:
            return

        if event.button != 1 or event.type != gtk.gdk.BUTTON_PRESS:
            return

        if not self.__file:
            from quodlibet.qltk.songsmenu import SongsMenu
            from quodlibet import app

            SongsMenu.plugins.handle("Download Album art", app.library,
                                     qltk.get_top_parent(self), [song])
            return

        if self.__current_bci is not None:
            # We're displaying it; destroy it.
            self.__current_bci.destroy()
            return

        try:
            self.__current_bci = BigCenteredImage(
                song.comma("album"), self.__file.name, parent=self)
        except gobject.GError: # reload in case the image file is gone
            self.refresh()
        else:
            self.__current_bci.connect('destroy', self.__reset_bci)
示例#9
0
 def __init__(self, cbes, title, validator=None):
     # Do this before calling parent constructor
     self.cbes = cbes
     super(CBESEditor, self).__init__(title, validator)
     self.set_transient_for(qltk.get_top_parent(cbes))
     connect_obj(self, 'destroy', self.__finish, cbes)
     self.value.set_text(cbes.get_child().get_text())
示例#10
0
    def __init__(self, parent):
        if self.is_not_unique(): return
        super(PreferencesWindow, self).__init__()
        self.set_title(_("Preferences") + " - Quod Libet")
        self.set_border_width(12)
        self.set_resizable(False)
        self.set_transient_for(qltk.get_top_parent(parent))

        self.__notebook = notebook = qltk.Notebook()
        for Page in [self.Connection, self.Player, self.SongList, self.Browsers,
            self.Library, self.Tagging]: notebook.append_page(Page())

        close = gtk.Button(stock=gtk.STOCK_CLOSE)
        close.connect_object('clicked', lambda x: x.destroy(), self)
        button_box = gtk.HButtonBox()
        button_box.set_layout(gtk.BUTTONBOX_END)
        button_box.pack_start(close)

        vbox = gtk.VBox(spacing=12)
        vbox.pack_start(notebook)
        vbox.pack_start(button_box, expand=False)
        self.add(vbox)

        self.connect_object('destroy', PreferencesWindow.__destroy, self)
        self.show_all()
示例#11
0
 def __init__(self, parent):
     super(AddFeedDialog, self).__init__(
         qltk.get_top_parent(parent),
         _("New Feed"),
         _("Enter the location of an audio feed:"),
         okbutton=Gtk.STOCK_ADD,
     )
示例#12
0
    def __init__(self, parent, default="", **kwargs):
        if self.is_not_unique():
            return
        super(TextEdit, self).__init__()
        self.set_title(_("Edit Display"))
        self.set_transient_for(qltk.get_top_parent(parent))
        self.set_border_width(12)
        self.set_default_size(420, 190)

        vbox = Gtk.VBox(spacing=12)
        close = Button(_("_Close"), Icons.WINDOW_CLOSE)
        close.connect('clicked', lambda *x: self.destroy())
        b = Gtk.HButtonBox()
        b.set_layout(Gtk.ButtonBoxStyle.END)
        b.pack_start(close, True, True, 0)

        self.box = box = self.Box(default, **kwargs)
        vbox.pack_start(box, True, True, 0)
        self.use_header_bar()
        if not self.has_close_button():
            vbox.pack_start(b, False, True, 0)

        self.add(vbox)
        self.apply = box.apply
        self.revert = box.revert

        close.grab_focus()
        self.get_child().show_all()
示例#13
0
文件: cover.py 项目: zsau/quodlibet
    def __show_cover(self, song):
        """Show the cover as a detached BigCenteredImage.
        If one is already showing, destroy it instead
        If there is no image, run the AlbumArt plugin
        """
        if not self.__file and song.is_file:
            from quodlibet.qltk.songsmenu import SongsMenu
            from quodlibet import app

            SongsMenu.plugins.handle(ALBUM_ART_PLUGIN_ID, app.library,
                                     qltk.get_top_parent(self), [song])

            return True

        if self.__current_bci is not None:
            # We're displaying it; destroy it.
            self.__current_bci.destroy()
            return True

        if not self.__file:
            return False

        try:
            self.__current_bci = BigCenteredImage(
                song.comma("album"), self.__file, parent=self)
        except GLib.GError: # reload in case the image file is gone
            self.refresh()
        else:
            self.__current_bci.show()
            self.__current_bci.connect('destroy', self.__reset_bci)

        return True
示例#14
0
文件: chooser.py 项目: zsau/quodlibet
def _run_chooser(parent, chooser):
    """Run the chooser ("blocking") and return a list of paths.

    Args:
        parent (Gtk.Widget)
        chooser (Gtk.FileChooser)
    Returns:
        List[fsnative]
    """

    chooser.set_current_folder(fsn2glib(get_current_dir()))
    chooser.set_transient_for(get_top_parent(parent))

    if _response is not None:
        response = _response
        while Gtk.events_pending():
            Gtk.main_iteration()
    else:
        response = chooser.run()

    if response == Gtk.ResponseType.ACCEPT:
        result = [glib2fsn(fn) for fn in chooser.get_filenames()]

        current_dir = chooser.get_current_folder()
        if current_dir:
            set_current_dir(glib2fsn(current_dir))
    else:
        result = []
    chooser.destroy()
    return result
示例#15
0
    def __drag_data_get(self, view, ctx, sel, tid, etime):
        model, paths = self.get_selection().get_selected_rows()
        if tid == DND_QL:
            songs = [model[path][0] for path in paths
                     if model[path][0].can_add]
            if len(songs) != len(paths):
                qltk.ErrorMessage(
                    qltk.get_top_parent(self), _("Unable to copy songs"),
                    _("The files selected cannot be copied to other "
                      "song lists or the queue.")).run()
                Gdk.drag_abort(ctx, etime)
                return

            qltk.selection_set_songs(sel, songs)

            # DEM 2018/05/25: The below check is a deliberate repitition of
            # code in the drag-motion signal handler.  In MacOS/Quartz, the
            # context action is not propogated between event handlers for
            # drag-motion and drag-data-get using "ctx.get_actions()".  It is
            # unclear if this is a bug or expected behavior.  Regardless, the
            # context widget information is the same so identical behavior can
            # be achieved by simply using the same widget check as in the move
            # action.
            if Gtk.drag_get_source_widget(ctx) == self and \
                    not self.__force_copy:
                self.__drag_iters = list(map(model.get_iter, paths))
            else:
                self.__drag_iters = []
        else:
            uris = [model[path][0]("~uri") for path in paths]
            sel.set_uris(uris)
            self.__drag_iters = []
示例#16
0
    def __clicked(self, button):
        if self.__window.get_property('visible'): return
        self.__window.child.show_all()
        self.__window.size_request()
        x, y = self.child.window.get_origin()
        w, h = self.child.window.get_size()        
        ww, wh = self.__window.child.parent.get_size()
        sx, sy = self._move_to(x, y, w, h, ww, wh, pad=3)
        self.__window.set_transient_for(get_top_parent(self))
        self.__window.move(sx, sy)
        self.__window.show()
        self.__window.grab_focus()
        self.__window.grab_add()
        pointer = gtk.gdk.pointer_grab(
            self.__window.window, True,
            gtk.gdk.BUTTON_PRESS_MASK |
            gtk.gdk.BUTTON_RELEASE_MASK |
            gtk.gdk.BUTTON_MOTION_MASK |
            gtk.gdk.POINTER_MOTION_MASK |
            gtk.gdk.SCROLL_MASK, None, None, gtk.get_current_event_time())
        keyboard = gtk.gdk.keyboard_grab(
            self.__window.window, True, gtk.get_current_event_time())

        if pointer != gtk.gdk.GRAB_SUCCESS or keyboard != gtk.gdk.GRAB_SUCCESS:
            self.__window.grab_remove()
            self.__window.hide()

            if pointer == gtk.gdk.GRAB_SUCCESS:
                gtk.gdk.pointer_ungrab(gtk.get_current_event_time())
            if keyboard == gtk.gdk.GRAB_SUCCESS:
                gtk.gdk.keyboard_ungrab(gtk.get_current_event_time())
示例#17
0
    def __init__(self, parent, default=""):
        if self.is_not_unique(): return
        super(TextEdit, self).__init__()
        self.set_title(_("Edit Display"))
        self.set_transient_for(qltk.get_top_parent(parent))
        self.set_border_width(12)
        self.set_default_size(420, 190)

        vbox = gtk.VBox(spacing=12)
        close = gtk.Button(stock=gtk.STOCK_CLOSE)
        close.connect('clicked', lambda *x: self.destroy())
        b = gtk.HButtonBox()
        b.set_layout(gtk.BUTTONBOX_END)
        b.pack_start(close)

        self.box = box = self.Box(default)
        vbox.pack_start(box)
        vbox.pack_start(b, expand=False)

        self.add(vbox)
        self.apply = box.apply
        self.revert = box.revert

        close.grab_focus()
        self.show_all()
示例#18
0
    def __init__(self, parent=None):
        super(LoggingWindow, self).__init__()
        self.set_default_size(400, 400)
        self.set_title(_("Output Log"))
        self.set_border_width(12)
        self.set_transient_for(qltk.get_top_parent(parent))
        notebook = qltk.Notebook()

        for logname in quodlibet.util.logging.names():
            text = "\n".join(quodlibet.util.logging.contents(logname))
            view = gtk.TextView()
            sw = gtk.ScrolledWindow()
            sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
            sw.set_shadow_type(gtk.SHADOW_IN)
            sw.add(view)
            buffer = view.get_buffer()
            buffer.set_text(text)
            notebook.append_page(sw, logname)

        close = gtk.Button(stock=gtk.STOCK_CLOSE)
        close.connect_object('clicked', lambda x: x.destroy(), self)
        button_box = gtk.HButtonBox()
        button_box.set_layout(gtk.BUTTONBOX_END)
        button_box.pack_start(close)

        vbox = gtk.VBox(spacing=12)
        vbox.pack_start(notebook)
        vbox.pack_start(button_box, expand=False)
        self.add(vbox)

        self.show_all()
示例#19
0
def show_uri(label, uri):
    """Shows a uri. The uri can be anything handled by GIO or a quodlibet
    specific one.

    Currently handled quodlibet uris:
        - quodlibet:///prefs/plugins/<plugin id>

    Args:
        label (str)
        uri (str) the uri to show
    Returns:
        True on success, False on error
    """

    parsed = urlparse(uri)
    if parsed.scheme == "quodlibet":
        if parsed.netloc != "":
            print_w("Unknown QuodLibet URL format (%s)" % uri)
            return False
        else:
            return __show_quodlibet_uri(parsed)
    else:
        # Gtk.show_uri_on_window exists since 3.22
        if hasattr(Gtk, "show_uri_on_window"):
            from quodlibet.qltk import get_top_parent
            return Gtk.show_uri_on_window(get_top_parent(label), uri, 0)
        else:
            return Gtk.show_uri(None, uri, 0)
示例#20
0
    def __init__(self, parent, title, description, traceback):
        super(MinExceptionDialog, self).__init__(
            get_top_parent(parent),
            title, description)

        assert isinstance(title, unicode)
        assert isinstance(description, unicode)
        assert isinstance(traceback, unicode)

        exp = Gtk.Expander(label=_("Error Details"))
        lab = Gtk.Label(label=traceback)
        lab.set_alignment(0.0, 0.0)
        lab.set_selectable(True)
        win = Gtk.ScrolledWindow()
        win.add_with_viewport(Align(lab, border=6))
        win.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        win.set_shadow_type(Gtk.ShadowType.ETCHED_OUT)
        win.set_size_request(500, 150)
        win.show_all()
        exp.add(win)
        exp.set_resize_toplevel(True)

        area = self.get_message_area()
        exp.show()
        area.pack_start(exp, False, True, 0)
示例#21
0
文件: media.py 项目: urielz/quodlibet
    def __init__(self, parent, device):
        super(DeviceProperties, self).__init__(
            title=_("Device Properties"),
            transient_for=qltk.get_top_parent(parent))

        self.add_icon_button(_("_Close"), Icons.WINDOW_CLOSE,
                             Gtk.ResponseType.CLOSE)
        self.set_default_size(400, -1)
        self.connect('response', self.__close)

        table = Gtk.Table()
        table.set_border_width(8)
        table.set_row_spacings(8)
        table.set_col_spacings(8)
        self.vbox.pack_start(table, False, True, 0)

        props = []

        props.append((_("Device:"), device.block_device, None))
        mountpoint = util.escape(
            device.mountpoint or ("<i>%s</i>" % _("Not mounted")))
        props.append((_("Mount point:"), mountpoint, None))

        props.append((None, None, None))

        entry = Gtk.Entry()
        entry.set_text(device['name'])
        props.append((_("_Name:"), entry, 'name'))

        y = 0
        for title, value, key in props + device.Properties():
            if title is None:
                table.attach(Gtk.HSeparator(), 0, 2, y, y + 1)
            else:
                if key and isinstance(value, Gtk.CheckButton):
                    value.set_label(title)
                    value.set_use_underline(True)
                    value.connect('toggled', self.__changed, key, device)
                    table.attach(value, 0, 2, y, y + 1,
                                 xoptions=Gtk.AttachOptions.FILL)
                else:
                    label = Gtk.Label()
                    label.set_markup("<b>%s</b>" % util.escape(title))
                    label.set_alignment(0.0, 0.5)
                    table.attach(label, 0, 1, y, y + 1,
                                 xoptions=Gtk.AttachOptions.FILL)
                    if key and isinstance(value, Gtk.Widget):
                        widget = value
                        label.set_mnemonic_widget(widget)
                        label.set_use_underline(True)
                        widget.connect('changed', self.__changed, key, device)
                    else:
                        widget = Gtk.Label(label=value)
                        widget.set_use_markup(True)
                        widget.set_selectable(True)
                        widget.set_alignment(0.0, 0.5)
                    table.attach(widget, 1, 2, y, y + 1)
            y += 1
        self.get_child().show_all()
示例#22
0
    def __event(self, event):
        if not self.__view:
            return True

        # hack: present the main window on key press
        if event.type == Gdk.EventType.BUTTON_PRESS:
            # hack: present is overridden to present all windows.
            # bypass to only select one
            if not is_wayland():  # present duplicates windows in weston
                Gtk.Window.present(get_top_parent(self.__view))

        def translate_enter_leave_event(event):
            # enter/leave events have different x/y values as motion events
            # so it makes sense to push them to the underlying view as
            # additional motion events.
            # Warning: this may result in motion events outside of the
            # view window.. ?
            new_event = Gdk.Event.new(Gdk.EventType.MOTION_NOTIFY)
            struct = new_event.motion
            for attr in ["x", "y", "x_root", "y_root", "time", "window",
                         "state", "send_event"]:
                setattr(struct, attr, getattr(event.crossing, attr))
            device = Gtk.get_current_event_device()
            if device is not None:
                struct.set_device(device)
            return new_event

        # FIXME: We should translate motion events on the tooltip
        # to crossing events for the underlying view.
        # (I think, no tested) Currently the hover scrollbar stays visible
        # if the mouse leaves the view through the tooltip without the
        # knowledge of the view.

        type_ = event.type
        real_event = None
        if type_ == Gdk.EventType.BUTTON_PRESS:
            real_event = event.button
        elif type_ == Gdk.EventType.BUTTON_RELEASE:
            real_event = event.button
        elif type_ == Gdk.EventType.MOTION_NOTIFY:
            real_event = event.motion
        elif type_ == Gdk.EventType.ENTER_NOTIFY:
            event = translate_enter_leave_event(event)
            real_event = event.motion
        elif type_ == Gdk.EventType.LEAVE_NOTIFY:
            event = translate_enter_leave_event(event)
            real_event = event.motion

        if real_event:
            real_event.x += self.__dx
            real_event.y += self.__dy

        # modifying event.window is a necessary evil, made okay because
        # nobody else should tie to any TreeViewHints events ever.
        event.any.window = self.__view.get_bin_window()

        Gtk.main_do_event(event)

        return True
示例#23
0
 def __init__(self, parent):
     super(AddFeedDialog, self).__init__(
         qltk.get_top_parent(parent),
         _("New Feed"),
         _("Enter the location of an audio feed:"),
         button_label=_("_Add"),
         button_icon=Icons.LIST_ADD,
     )
示例#24
0
    def __init__(self, parent, can_change, library):
        super(AddTagDialog, self).__init__(
            title=_("Add a Tag"), transient_for=qltk.get_top_parent(parent),
            use_header_bar=True)
        self.set_border_width(6)
        self.set_resizable(False)
        self.add_button(_("_Cancel"), Gtk.ResponseType.CANCEL)
        add = self.add_icon_button(_("_Add"), Icons.LIST_ADD,
                                   Gtk.ResponseType.OK)
        self.vbox.set_spacing(6)
        self.set_default_response(Gtk.ResponseType.OK)
        table = Gtk.Table(n_rows=2, n_columns=2)
        table.set_row_spacings(12)
        table.set_col_spacings(6)
        table.set_border_width(6)

        self.__tag = (TagsComboBoxEntry() if can_change is True
                      else TagsComboBox(can_change))

        label = Gtk.Label()
        label.set_alignment(0.0, 0.5)
        label.set_text(_("_Tag:"))
        label.set_use_underline(True)
        label.set_mnemonic_widget(self.__tag)
        table.attach(label, 0, 1, 0, 1)
        table.attach(self.__tag, 1, 2, 0, 1)

        self.__val = Gtk.Entry()
        self.__val.set_completion(LibraryValueCompletion("", library))
        label = Gtk.Label()
        label.set_text(_("_Value:"))
        label.set_alignment(0.0, 0.5)
        label.set_use_underline(True)
        label.set_mnemonic_widget(self.__val)
        valuebox = Gtk.EventBox()
        table.attach(label, 0, 1, 1, 2)
        table.attach(valuebox, 1, 2, 1, 2)
        hbox = Gtk.HBox()
        valuebox.add(hbox)
        hbox.pack_start(self.__val, True, True, 0)
        hbox.set_spacing(6)
        invalid = Gtk.Image.new_from_icon_name(
            Icons.DIALOG_WARNING, Gtk.IconSize.SMALL_TOOLBAR)
        hbox.pack_start(invalid, True, True, 0)

        self.vbox.pack_start(table, True, True, 0)
        self.get_child().show_all()
        invalid.hide()

        for entry in [self.__tag, self.__val]:
            entry.connect(
                'changed', self.__validate, add, invalid, valuebox)
        self.__tag.connect('changed', self.__set_value_completion, library)
        self.__set_value_completion(self.__tag, library)

        if can_change is True:
            connect_obj(self.__tag.get_child(),
                'activate', Gtk.Entry.grab_focus, self.__val)
示例#25
0
 def __init__(self, parent, title, initial_dir=None,
              action=gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER):
     super(FolderChooser, self).__init__(
         title=title, parent=get_top_parent(parent), action=action,
         buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
                  gtk.STOCK_OPEN, gtk.RESPONSE_OK))
     if initial_dir: self.set_current_folder(initial_dir)
     self.set_local_only(True)
     self.set_select_multiple(True)
示例#26
0
 def __init__(
     self, kind, parent, title, description, buttons=gtk.BUTTONS_OK):
     parent = get_top_parent(parent)
     text = ("<span weight='bold' size='larger'>%s</span>\n\n%s"
             % (title, description))
     super(Message, self).__init__(
         parent, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
         kind, buttons)
     self.set_markup(text)
示例#27
0
 def _on_new_playlist_activate(self, item, songs):
     parent = get_menu_item_top_parent(item)
     title = Playlist.suggested_name_for(songs)
     title = GetPlaylistName(qltk.get_top_parent(parent)).run(title)
     if title is None:
         return
     playlist = FileBackedPlaylist.new(PLAYLISTS, title)
     playlist.extend(songs)
     PlaylistsBrowser.changed(playlist)
示例#28
0
 def __init__(
     self, kind, parent, title, description, buttons=Gtk.ButtonsType.OK):
     parent = get_top_parent(parent)
     text = ("<span weight='bold' size='larger'>%s</span>\n\n%s"
             % (title, description))
     super(Message, self).__init__(
         transient_for=parent, modal=True, destroy_with_parent=True,
         message_type=kind, buttons=buttons)
     self.set_markup(text)
示例#29
0
 def __drag_data_received(self, view, ctx, x, y, sel, tid, etime, library):
     # TreeModelSort doesn't support GtkTreeDragDestDrop.
     view.emit_stop_by_name('drag-data-received')
     model = view.get_model()
     if tid == DND_QL:
         filenames = qltk.selection_get_filenames(sel)
         songs = filter(None, map(library.get, filenames))
         if not songs:
             Gtk.drag_finish(ctx, False, False, etime)
             return
         try:
             path, pos = view.get_dest_row_at_pos(x, y)
         except TypeError:
             playlist = FileBackedPlaylist.from_songs(PLAYLISTS, songs,
                                                      library)
             GLib.idle_add(self._select_playlist, playlist)
         else:
             playlist = model[path][0]
             playlist.extend(songs)
         self.changed(playlist)
         Gtk.drag_finish(ctx, True, False, etime)
     else:
         if tid == DND_URI_LIST:
             uri = sel.get_uris()[0]
             name = os.path.basename(uri)
         elif tid == DND_MOZ_URL:
             data = sel.get_data()
             uri, name = data.decode('utf16', 'replace').split('\n')
         else:
             Gtk.drag_finish(ctx, False, False, etime)
             return
         name = name or os.path.basename(uri) or _("New Playlist")
         uri = uri.encode('utf-8')
         try:
             sock = urlopen(uri)
             f = NamedTemporaryFile()
             f.write(sock.read())
             f.flush()
             if uri.lower().endswith('.pls'):
                 playlist = parse_pls(f.name, library=library)
             elif uri.lower().endswith('.m3u'):
                 playlist = parse_m3u(f.name, library=library)
             else:
                 raise IOError
             library.add_filename(playlist)
             if name:
                 playlist.rename(name)
             self.changed(playlist)
             Gtk.drag_finish(ctx, True, False, etime)
         except IOError:
             Gtk.drag_finish(ctx, False, False, etime)
             qltk.ErrorMessage(
                 qltk.get_top_parent(self),
                 _("Unable to import playlist"),
                 _("Quod Libet can only import playlists in the M3U "
                   "and PLS formats.")).run()
示例#30
0
        def __config_cols(self, button, buttons):
            def __closed(widget):
                cols = widget.get_strings()
                self.__update(buttons, self._toggle_data, cols)

            columns = self.__get_current_columns(buttons)
            m = TagListEditor(_("Edit Columns"), columns)
            m.set_transient_for(qltk.get_top_parent(self))
            m.connect('destroy', __closed)
            m.show()
示例#31
0
    def __init__(self, library, songs, parent=None):
        super(SongProperties, self).__init__(dialog=False)
        self.set_transient_for(qltk.get_top_parent(parent))

        default_width = 600
        config_suffix = ""
        if len(songs) <= 1:
            default_width -= 200
            config_suffix += "single"
        self.set_default_size(default_width, 400)

        self.enable_window_tracking("quodlibet_properties",
                                    size_suffix=config_suffix)

        self.auto_save_on_change = config.getboolean(
                'editing', 'auto_save_changes', False)

        paned = Gtk.HPaned()
        notebook = qltk.Notebook()
        notebook.props.scrollable = True
        pages = []
        pages.extend([Ctr(self, library) for Ctr in
                      [EditTags, TagsFromPath, RenameFiles]])
        if len(songs) > 1:
            pages.append(TrackNumbers(self, library))
        for page in pages:
            page.show()
            notebook.append_page(page)

        fbasemodel = Gtk.ListStore(object, str)
        fmodel = Gtk.TreeModelSort(model=fbasemodel)
        fview = HintedTreeView(model=fmodel)
        fview.connect('button-press-event', self.__pre_selection_changed)
        fview.set_rules_hint(True)
        selection = fview.get_selection()
        selection.set_mode(Gtk.SelectionMode.MULTIPLE)
        self.__save = None

        if len(songs) > 1:
            render = Gtk.CellRendererText()
            c1 = Gtk.TreeViewColumn(_('File'), render, text=1)
            render.set_property('ellipsize', Pango.EllipsizeMode.END)
            render.set_property('xpad', 3)
            c1.set_sort_column_id(1)
            fview.append_column(c1)
            sw = ScrolledWindow()
            sw.add(fview)
            sw.set_shadow_type(Gtk.ShadowType.IN)
            sw.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
            sw.show_all()
            paned.pack1(sw, shrink=False, resize=True)

        # Invisible selections behave a little strangely. So, when
        # handling this selection, there's a lot of if len(model) == 1
        # checks that "hardcode" the first row being selected.

        for song in songs:
            fbasemodel.append(row=[song, fsdecode(song("~basename"))])

        self.connect_object('changed', SongProperties.__set_title, self)

        selection.select_all()
        paned.pack2(notebook, shrink=False, resize=True)

        csig = selection.connect('changed', self.__selection_changed)
        s1 = library.connect(
            'changed', self.__refresh, fbasemodel, fview)
        s2 = library.connect(
            'removed', self.__remove, fbasemodel, selection, csig)
        self.connect_object('destroy', library.disconnect, s1)
        self.connect_object('destroy', library.disconnect, s2)
        self.connect_object('changed', self.set_pending, None)

        self.emit('changed', songs)
        self.add(paned)
        paned.set_position(175)
        notebook.show()
        paned.show()
示例#32
0
 def __drag_data_received(self, view, ctx, x, y, sel, tid, etime):
     # TreeModelSort doesn't support GtkTreeDragDestDrop.
     view.emit_stop_by_name('drag-data-received')
     model = view.get_model()
     if tid == DND_QL:
         filenames = qltk.selection_get_filenames(sel)
         songs = list(
             filter(None, [self.songs_lib.get(f) for f in filenames]))
         if not songs:
             Gtk.drag_finish(ctx, False, False, etime)
             return
         try:
             path, pos = view.get_dest_row_at_pos(x, y)
         except TypeError:
             playlist = self.pl_lib.create_from_songs(songs)
             GLib.idle_add(self._select_playlist, playlist)
         else:
             playlist = model[path][0]
             playlist.extend(songs)
         # self.changed(playlist)
         Gtk.drag_finish(ctx, True, False, etime)
         # Cause a refresh to the dragged-to playlist if it is selected
         # so that the dragged (duplicate) track(s) appears
         if playlist is self._selected_playlist():
             model, plist_iter = self.__selected_playlists()
             songlist = qltk.get_top_parent(self).songlist
             self.activate(resort=not songlist.is_sorted())
     else:
         if tid == DND_URI_LIST:
             uri = sel.get_uris()[0]
             name = os.path.basename(uri)
         elif tid == DND_MOZ_URL:
             data = sel.get_data()
             uri, name = data.decode('utf16', 'replace').split('\n')
         else:
             Gtk.drag_finish(ctx, False, False, etime)
             return
         name = _name_for(name or os.path.basename(uri))
         try:
             sock = urlopen(uri)
             uri = uri.lower()
             if uri.endswith('.pls'):
                 playlist = parse_pls(sock,
                                      name,
                                      songs_lib=self.songs_lib,
                                      pl_lib=self.pl_lib)
             elif uri.endswith('.m3u') or uri.endswith('.m3u8'):
                 playlist = parse_m3u(sock,
                                      name,
                                      songs_lib=self.songs_lib,
                                      pl_lib=self.pl_lib)
             else:
                 raise IOError
             self.songs_lib.add(playlist.songs)
             # TODO: change to use playlist library too?
             # self.changed(playlist)
             Gtk.drag_finish(ctx, True, False, etime)
         except IOError:
             Gtk.drag_finish(ctx, False, False, etime)
             qltk.ErrorMessage(
                 qltk.get_top_parent(self), _("Unable to import playlist"),
                 _("Quod Libet can only import playlists in the M3U/M3U8 "
                   "and PLS formats.")).run()
示例#33
0
文件: menu.py 项目: WammKD/quodlibet
 def _get_new_name(self, parent, title):
     """Ask the user for a name for the new playlist"""
     return GetPlaylistName(qltk.get_top_parent(parent)).run(title)
示例#34
0
 def __init__(self, parent):
     super(AddFeedDialog,
           self).__init__(qltk.get_top_parent(parent),
                          _("New Feed"),
                          _("Enter the location of an audio feed:"),
                          okbutton=Gtk.STOCK_ADD)
示例#35
0
 def __drag_data_browser_dropped(self, songs):
     window = qltk.get_top_parent(self)
     return window.browser.dropped(songs)
示例#36
0
 def test_none(self):
     self.failUnless(qltk.get_top_parent(None) is None)
示例#37
0
    def __init__(self, library, songs, parent=None):
        super().__init__(dialog=False)
        self.set_transient_for(qltk.get_top_parent(parent))

        default_width = 600
        config_suffix = ""
        if len(songs) <= 1:
            default_width -= 200
            config_suffix += "single"
        self.set_default_size(default_width, 400)

        self.enable_window_tracking("quodlibet_properties",
                                    size_suffix=config_suffix)

        self.auto_save_on_change = config.getboolean(
                'editing', 'auto_save_changes', False)

        paned = ConfigRPaned("memory", "quodlibet_properties_pos", 0.4)
        notebook = qltk.Notebook()
        notebook.props.scrollable = True
        pages = []
        pages.extend([Ctr(self, library) for Ctr in
                      [EditTags, TagsFromPath, RenameFiles]])
        if len(songs) > 1:
            pages.append(TrackNumbers(self, library))
        for page in pages:
            page.show()
            notebook.append_page(page)

        fbasemodel = ObjectStore()
        fmodel = ObjectModelSort(model=fbasemodel)
        fview = HintedTreeView(model=fmodel)
        fview.connect('button-press-event', self.__pre_selection_changed)
        fview.set_rules_hint(True)
        selection = fview.get_selection()
        selection.set_mode(Gtk.SelectionMode.MULTIPLE)
        self.__save = None

        render = Gtk.CellRendererText()
        c1 = Gtk.TreeViewColumn(_('File'), render)
        if fview.supports_hints():
            render.set_property('ellipsize', Pango.EllipsizeMode.END)
        render.set_property('xpad', 3)

        def cell_data(column, cell, model, iter_, data):
            entry = model.get_value(iter_)
            cell.set_property('text', entry.name)

        c1.set_cell_data_func(render, cell_data)

        def sort_func(model, a, b, data):
            a = model.get_value(a)
            b = model.get_value(b)
            return cmp(a.name, b.name)

        fmodel.set_sort_func(100, sort_func)
        c1.set_sort_column_id(100)
        fview.append_column(c1)

        sw = ScrolledWindow()
        sw.add(fview)
        sw.set_shadow_type(Gtk.ShadowType.IN)
        sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)

        # only show the list if there are is more than one song
        if len(songs) > 1:
            sw.show_all()

        paned.pack1(sw, shrink=False, resize=True)

        for song in songs:
            fbasemodel.append(row=[_ListEntry(song)])

        self.connect("changed", self.__on_changed)

        selection.select_all()
        paned.pack2(notebook, shrink=False, resize=True)

        csig = selection.connect('changed', self.__selection_changed)
        connect_destroy(library,
            'changed', self.__on_library_changed, fbasemodel, fview)
        connect_destroy(library,
            'removed', self.__on_library_removed, fbasemodel, selection, csig)

        self.emit('changed', songs)
        self.add(paned)
        paned.set_position(175)
        notebook.show()
        paned.show()
示例#38
0
    def __event(self, event):
        if not self.__view:
            return True

        # hack: present the main window on key press
        if event.type == Gdk.EventType.BUTTON_PRESS:
            # hack: present is overridden to present all windows.
            # bypass to only select one
            if not is_wayland():  # present duplicates windows in weston
                Gtk.Window.present(get_top_parent(self.__view))

        def translate_enter_leave_event(event):
            # enter/leave events have different x/y values as motion events
            # so it makes sense to push them to the underlying view as
            # additional motion events.
            # Warning: this may result in motion events outside of the
            # view window.. ?
            new_event = Gdk.Event.new(Gdk.EventType.MOTION_NOTIFY)
            struct = new_event.motion
            for attr in [
                    "x", "y", "x_root", "y_root", "time", "window", "state",
                    "send_event"
            ]:
                setattr(struct, attr, getattr(event.crossing, attr))
            device = Gtk.get_current_event_device()
            if device is not None:
                struct.set_device(device)
            return new_event

        # FIXME: We should translate motion events on the tooltip
        # to crossing events for the underlying view.
        # (I think, no tested) Currently the hover scrollbar stays visible
        # if the mouse leaves the view through the tooltip without the
        # knowledge of the view.

        type_ = event.type
        real_event = None
        if type_ == Gdk.EventType.BUTTON_PRESS:
            real_event = event.button
        elif type_ == Gdk.EventType.BUTTON_RELEASE:
            real_event = event.button
        elif type_ == Gdk.EventType.MOTION_NOTIFY:
            real_event = event.motion
        elif type_ == Gdk.EventType.ENTER_NOTIFY:
            event = translate_enter_leave_event(event)
            real_event = event.motion
        elif type_ == Gdk.EventType.LEAVE_NOTIFY:
            event = translate_enter_leave_event(event)
            real_event = event.motion

        if real_event:
            real_event.x += self.__dx
            real_event.y += self.__dy

        # modifying event.window is a necessary evil, made okay because
        # nobody else should tie to any TreeViewHints events ever.
        event.any.window = self.__view.get_bin_window()

        Gtk.main_do_event(event)

        return True
示例#39
0
 def __handle_songlist_delete(self, *args):
     songlist = qltk.get_top_parent(self).songlist
     model, iters = self.__get_selected_songs(songlist)
     self.__remove(iters, model)
示例#40
0
 def __get_selected_songs(self):
     songlist = qltk.get_top_parent(self).songlist
     model, rows = songlist.get_selection().get_selected_rows()
     iters = map(model.get_iter, rows)
     return model, iters
示例#41
0
 def __check_current(self, model, path, iter):
     model, citer = self.__view.get_selection().get_selected()
     if citer and model.get_path(citer) == path:
         songlist = qltk.get_top_parent(self).songlist
         self.activate(resort=not songlist.is_sorted())
示例#42
0
 def focus(widget, *args):
     qltk.get_top_parent(widget).songlist.grab_focus()
示例#43
0
    def __motion(self, view, event):
        label = self.__label
        clabel = self.__clabel

        # trigger over row area, not column headers
        if event.window is not view.get_bin_window():
            self.__undisplay()
            return False

        # hide if any modifier is active
        if event.get_state() & Gtk.accelerator_get_default_mod_mask():
            self.__undisplay()
            return False

        # get the cell at the mouse position
        x, y = map(int, [event.x, event.y])
        try:
            path, col, cellx, celly = view.get_path_at_pos(x, y)
        except TypeError:
            # no hints where no rows exist
            self.__undisplay()
            return False

        col_area = view.get_cell_area(path, col)
        # make sure we are on the same level
        if x < col_area.x:
            self.__undisplay()
            return False

        # hide for partial hidden rows at the bottom
        if y > view.get_visible_rect().height:
            self.__undisplay()
            return False

        # get the renderer at the mouse position and get the xpos/width
        renderers = col.get_cells()
        pos = sorted(zip(map(col.cell_get_position, renderers), renderers))
        pos = filter(lambda ((x, w), r): x < cellx, pos)
        if not pos:
            self.__undisplay()
            return False
        (render_offset, render_width), renderer = pos[-1]

        if self.__current_renderer == renderer and self.__current_path == path:
            return False

        # only ellipsized text renderers
        if not isinstance(renderer, Gtk.CellRendererText):
            self.__undisplay()
            return False

        ellipsize = renderer.get_property('ellipsize')
        if ellipsize == Pango.EllipsizeMode.END:
            expand_left = False
        elif ellipsize == Pango.EllipsizeMode.MIDDLE:
            # depending on where the cursor is
            expand_left = x > col_area.x + render_offset + render_width / 2
        elif ellipsize == Pango.EllipsizeMode.START:
            expand_left = True
        else:
            self.__undisplay()
            return False

        # don't display if the renderer is in editing mode
        if renderer.props.editing:
            self.__undisplay()
            return False

        # set the cell renderer attributes for the active cell
        model = view.get_model()
        col.cell_set_cell_data(model, model.get_iter(path), False, False)

        # the markup attribute is write only, so the markup text needs
        # to be saved on the python side, so we can copy it to the label
        markup = getattr(renderer, "markup", None)
        if markup is None:
            text = renderer.get_property('text')
            set_text = lambda l: l.set_text(text)
        else:
            # markup can also be column index
            if isinstance(markup, int):
                markup = model[path][markup]
            set_text = lambda l: l.set_markup(markup)

        # Use the renderer padding as label padding so the text offset matches
        render_xpad = renderer.get_property("xpad")
        label.set_padding(render_xpad, 0)
        set_text(clabel)
        clabel.set_padding(render_xpad, 0)
        label_width = clabel.get_layout().get_pixel_size()[0]
        label_width += clabel.get_layout_offsets()[0] or 0
        # layout offset includes the left padding, so add one more
        label_width += render_xpad

        # CellRenderer width is too large if it's the last one in a column.
        # Use cell_area width as a maximum and limit render_width.
        max_width = col_area.width
        if render_width + render_offset > max_width:
            render_width = max_width - render_offset

        # don't display if it doesn't need expansion
        if label_width < render_width:
            self.__undisplay()
            return False

        dummy, ox, oy = view.get_window().get_origin()

        # save for adjusting passthrough events
        self.__dx, self.__dy = col_area.x + render_offset, col_area.y
        if expand_left:
            # shift to the left
            # FIXME: ellipsize start produces a space at the end depending
            # on the text. I don't know how to compute it..
            self.__dx -= (label_width - render_width)

        # final window coordinates/size
        x = ox + self.__dx
        y = oy + self.__dy
        x, y = view.convert_bin_window_to_widget_coords(x, y)

        w = label_width
        h = col_area.height

        if not is_wayland():
            # clip if it's bigger than the screen
            screen_border = 5  # leave some space

            if not expand_left:
                space_right = Gdk.Screen.width() - x - w - screen_border

                if space_right < 0:
                    w += space_right
                    label.set_ellipsize(Pango.EllipsizeMode.END)
                else:
                    label.set_ellipsize(Pango.EllipsizeMode.NONE)
            else:
                space_left = x - screen_border
                if space_left < 0:
                    x -= space_left
                    self.__dx -= space_left
                    w += space_left
                    label.set_ellipsize(Pango.EllipsizeMode.START)
                else:
                    label.set_ellipsize(Pango.EllipsizeMode.NONE)
        else:
            label.set_ellipsize(Pango.EllipsizeMode.NONE)

        # Don't show if the resulting tooltip would be smaller
        # than the visible area (if not all is on the display)
        if w < render_width:
            self.__undisplay()
            return False

        self.__view = view
        self.__current_renderer = renderer
        self.__edit_id = renderer.connect('editing-started', self.__undisplay)
        self.__current_path = path
        self.__current_col = col

        if self.__hide_id:
            GLib.source_remove(self.__hide_id)
            self.__hide_id = None

        self.set_transient_for(get_top_parent(view))
        set_text(label)
        self.set_size_request(w, h)

        window = self.get_window()
        if self.get_visible() and window:
            window.move_resize(x, y, w, h)
        else:
            self.move(x, y)
            self.resize(w, h)
            self.show()

        return False
示例#44
0
    def __init__(self, browser):
        if self.is_not_unique():
            return
        super().__init__()
        self.set_border_width(12)
        self.set_title(_("Cover Grid Preferences"))
        self.set_default_size(420, 380)
        self.set_transient_for(qltk.get_top_parent(browser))
        # Do this config-driven setup at instance-time
        self._PREVIEW_ITEM["~rating"] = format_rating(0.75)
        self.mag_lock = False

        box = Gtk.VBox(spacing=6)
        vbox = Gtk.VBox(spacing=6)
        cb = ConfigCheckButton(_("Show album _text"), "browsers", "album_text")
        cb.set_active(config.getboolean("browsers", "album_text"))
        cb.connect('toggled', lambda s: browser.toggle_text())
        vbox.pack_start(cb, False, True, 0)

        cb2 = ConfigCheckButton(_("Show \"All Albums\" Item"), "browsers",
                                "covergrid_all")
        cb2.set_active(config.getboolean("browsers", "covergrid_all", True))

        def refilter(s):
            mod = browser.view.get_model()
            if mod:
                mod.refilter()

        cb2.connect('toggled', refilter)
        vbox.pack_start(cb2, False, True, 0)

        cb3 = ConfigCheckButton(_("Wide Mode"), "browsers", "covergrid_wide")
        cb3.set_active(config.getboolean("browsers", "covergrid_wide", False))
        cb3.connect('toggled', lambda s: browser.toggle_wide())
        vbox.pack_start(cb3, False, True, 0)

        # Redraws the covers only when the user releases the slider
        def mag_button_press(*_):
            self.mag_lock = True

        def mag_button_release(mag, _):
            self.mag_lock = False
            mag_changed(mag)

        def mag_changed(mag):
            if self.mag_lock:
                return
            newmag = mag.get_value()
            oldmag = config.getfloat("browsers", "covergrid_magnification", 3.)
            if newmag == oldmag:
                print_d("Covergrid magnification haven't changed: {0}".format(
                    newmag))
                return
            print_d('Covergrid magnification update from {0} to {1}'.format(
                oldmag, newmag))
            config.set("browsers", "covergrid_magnification", mag.get_value())
            browser.update_mag()

        mag_scale = Gtk.HScale(adjustment=Gtk.Adjustment.new(
            config.getfloat("browsers", "covergrid_magnification", 3), 0., 10.,
            .5, .5, 0))
        mag_scale.set_tooltip_text(_("Cover Magnification"))
        l = Gtk.Label(label=_("Cover Magnification"))
        mag_scale.set_value_pos(Gtk.PositionType.RIGHT)
        mag_scale.connect('button-press-event', mag_button_press)
        mag_scale.connect('button-release-event', mag_button_release)
        mag_scale.connect('value-changed', mag_changed)

        vbox.pack_start(l, False, True, 0)
        vbox.pack_start(mag_scale, False, True, 0)

        f = qltk.Frame(_("Options"), child=vbox)
        box.pack_start(f, False, True, 12)

        display_frame = self.edit_display_pane(browser, _("Album Display"))
        box.pack_start(display_frame, True, True, 0)

        main_box = Gtk.VBox(spacing=12)
        close = Button(_("_Close"), Icons.WINDOW_CLOSE)
        close.connect('clicked', lambda *x: self.destroy())
        b = Gtk.HButtonBox()
        b.set_layout(Gtk.ButtonBoxStyle.END)
        b.pack_start(close, True, True, 0)

        main_box.pack_start(box, True, True, 0)
        self.use_header_bar()

        if not self.has_close_button():
            main_box.pack_start(b, False, True, 0)
        self.add(main_box)

        close.grab_focus()
        self.show_all()
示例#45
0
    def __init__(self, parent, device):
        super(DeviceProperties,
              self).__init__(title=_("Device Properties"),
                             transient_for=qltk.get_top_parent(parent))

        self.add_icon_button(_("_Close"), Icons.WINDOW_CLOSE,
                             Gtk.ResponseType.CLOSE)
        self.set_default_size(400, -1)
        self.connect('response', self.__close)

        table = Gtk.Table()
        table.set_border_width(8)
        table.set_row_spacings(8)
        table.set_col_spacings(8)
        self.vbox.pack_start(table, False, True, 0)

        props = []

        props.append((_("Device:"), device.block_device, None))
        mountpoint = util.escape(device.mountpoint
                                 or ("<i>%s</i>" % _("Not mounted")))
        props.append((_("Mount point:"), mountpoint, None))

        props.append((None, None, None))

        entry = Gtk.Entry()
        entry.set_text(device['name'])
        props.append((_("_Name:"), entry, 'name'))

        y = 0
        for title, value, key in props + device.Properties():
            if title is None:
                table.attach(Gtk.HSeparator(), 0, 2, y, y + 1)
            else:
                if key and isinstance(value, Gtk.CheckButton):
                    value.set_label(title)
                    value.set_use_underline(True)
                    value.connect('toggled', self.__changed, key, device)
                    table.attach(value,
                                 0,
                                 2,
                                 y,
                                 y + 1,
                                 xoptions=Gtk.AttachOptions.FILL)
                else:
                    label = Gtk.Label()
                    label.set_markup("<b>%s</b>" % util.escape(title))
                    label.set_alignment(0.0, 0.5)
                    table.attach(label,
                                 0,
                                 1,
                                 y,
                                 y + 1,
                                 xoptions=Gtk.AttachOptions.FILL)
                    if key and isinstance(value, Gtk.Widget):
                        widget = value
                        label.set_mnemonic_widget(widget)
                        label.set_use_underline(True)
                        widget.connect('changed', self.__changed, key, device)
                    else:
                        widget = Gtk.Label(label=value)
                        widget.set_use_markup(True)
                        widget.set_selectable(True)
                        widget.set_alignment(0.0, 0.5)
                    table.attach(widget, 1, 2, y, y + 1)
            y += 1
        self.get_child().show_all()
示例#46
0
    def __init__(self, browser):
        if self.is_not_unique():
            return
        super(Preferences, self).__init__()
        self.set_border_width(12)
        self.set_title(_("Album List Preferences"))
        self.set_default_size(420, 380)
        self.set_transient_for(qltk.get_top_parent(browser))
        # Do this config-driven setup at instance-time
        self._EXAMPLE_ALBUM["~rating"] = format_rating(0.75)

        box = Gtk.VBox(spacing=6)
        vbox = Gtk.VBox(spacing=6)
        cb = ConfigCheckButton(_("Show album _covers"), "browsers",
                               "album_covers")
        cb.set_active(config.getboolean("browsers", "album_covers"))
        cb.connect('toggled', lambda s: browser.toggle_covers())
        vbox.pack_start(cb, False, True, 0)

        cb = ConfigCheckButton(_("Inline _search includes people"), "browsers",
                               "album_substrings")
        cb.set_active(config.getboolean("browsers", "album_substrings"))
        vbox.pack_start(cb, False, True, 0)
        f = qltk.Frame(_("Options"), child=vbox)
        box.pack_start(f, False, True, 12)

        vbox = Gtk.VBox(spacing=6)
        label = Gtk.Label()
        label.set_alignment(0.0, 0.5)
        label.set_padding(6, 6)
        eb = Gtk.EventBox()
        eb.get_style_context().add_class("entry")
        eb.add(label)

        edit = PatternEditBox(PATTERN)
        edit.text = browser._pattern_text
        edit.apply.connect('clicked', self.__set_pattern, edit, browser)
        connect_obj(edit.buffer, 'changed', self.__preview_pattern, edit,
                    label)

        vbox.pack_start(eb, False, True, 3)
        vbox.pack_start(edit, True, True, 0)
        self.__preview_pattern(edit, label)
        f = qltk.Frame(_("Album Display"), child=vbox)
        box.pack_start(f, True, True, 0)

        main_box = Gtk.VBox(spacing=12)
        close = Button(_("_Close"), Icons.WINDOW_CLOSE)
        close.connect('clicked', lambda *x: self.destroy())
        b = Gtk.HButtonBox()
        b.set_layout(Gtk.ButtonBoxStyle.END)
        b.pack_start(close, True, True, 0)

        main_box.pack_start(box, True, True, 0)
        self.use_header_bar()

        if not self.has_close_button():
            main_box.pack_start(b, False, True, 0)
        self.add(main_box)

        close.grab_focus()
        self.show_all()
 def __drag_data_browser_dropped(self, songs):
     window = qltk.get_top_parent(self)
     if callable(window.browser.dropped):
         return window.browser.dropped(self, songs)
     else:
         return False
示例#48
0
 def __add(self, button):
     parent = qltk.get_top_parent(self)
     uri = (AddNewStation(parent).run(clipboard=True) or "").strip()
     if uri != "":
         self.__add_station(uri)
示例#49
0
 def __song_added(self, librarian, songs):
     window = qltk.get_top_parent(self)
     filter_ = window.browser.active_filter
     if callable(filter_):
         self.add_songs(filter(filter_, songs))
示例#50
0
    def __motion(self, view, event):
        label = self.__label
        clabel = self.__clabel

        # trigger over row area, not column headers
        if event.window is not view.get_bin_window():
            self.__undisplay()
            return False

        x, y = map(int, [event.x, event.y])

        # For gtk3.16 overlay scrollbars: if our event x coordinate
        # is contained in the scrollbar, hide the tooltip. Unlike other
        # hiding events we don't want to send a leave event to the scrolled
        # window so the overlay scrollbar does't hide and can be interacted
        # with.
        parent = view.get_parent()
        # We only need to check if the tooltip is there since events
        # on the scrollbars don't get forwarded to us anyway.
        if self.__view and parent and isinstance(parent, Gtk.ScrolledWindow):
            vscrollbar = parent.get_vscrollbar()
            res = vscrollbar.translate_coordinates(view, 0, 0)
            if res is not None:
                x_offset = res[0]
                vbar_width = vscrollbar.get_allocation().width
                if x_offset <= x <= x_offset + vbar_width:
                    self.__undisplay(send_leave=False)
                    return False

        # hide if any modifier is active
        if event.get_state() & Gtk.accelerator_get_default_mod_mask():
            self.__undisplay()
            return False

        # get the cell at the mouse position
        try:
            path, col, cellx, celly = view.get_path_at_pos(x, y)
        except TypeError:
            # no hints where no rows exist
            self.__undisplay()
            return False

        col_area = view.get_cell_area(path, col)
        # make sure we are on the same level
        if x < col_area.x:
            self.__undisplay()
            return False

        # hide for partial hidden rows at the bottom
        if y > view.get_visible_rect().height:
            self.__undisplay()
            return False

        # get the renderer at the mouse position and get the xpos/width
        renderers = col.get_cells()
        pos = sorted(zip(map(col.cell_get_position, renderers), renderers))
        pos = filter(lambda p: p[0][0] < cellx, pos)
        if not pos:
            self.__undisplay()
            return False
        (render_offset, render_width), renderer = pos[-1]

        if self.__current_renderer == renderer and self.__current_path == path:
            return False

        # only ellipsized text renderers
        if not isinstance(renderer, Gtk.CellRendererText):
            self.__undisplay()
            return False

        ellipsize = renderer.get_property('ellipsize')
        if ellipsize == Pango.EllipsizeMode.END:
            expand_left = False
        elif ellipsize == Pango.EllipsizeMode.MIDDLE:
            # depending on where the cursor is
            expand_left = x > col_area.x + render_offset + render_width / 2
        elif ellipsize == Pango.EllipsizeMode.START:
            expand_left = True
        else:
            self.__undisplay()
            return False

        # don't display if the renderer is in editing mode
        if renderer.props.editing:
            self.__undisplay()
            return False

        # set the cell renderer attributes for the active cell
        model = view.get_model()
        col.cell_set_cell_data(model, model.get_iter(path), False, False)

        # the markup attribute is write only, so the markup text needs
        # to be saved on the python side, so we can copy it to the label
        markup = getattr(renderer, "markup", None)
        if markup is None:
            text = renderer.get_property('text')
            set_text = lambda l: l.set_text(text)
        else:
            # markup can also be column index
            if isinstance(markup, int):
                markup = model[path][markup]
            set_text = lambda l: l.set_markup(markup)

        # Use the renderer padding as label padding so the text offset matches
        render_xpad = renderer.get_property("xpad")

        # the renderer xpad is not enough for the tooltip, especially with
        # rounded corners the label gets nearly clipped.
        MIN_HINT_X_PAD = 4
        if render_xpad < MIN_HINT_X_PAD:
            extra_xpad = MIN_HINT_X_PAD - render_xpad
        else:
            extra_xpad = 0

        label.set_padding(render_xpad + extra_xpad, 0)
        set_text(clabel)
        clabel.set_padding(render_xpad, 0)
        label_width = clabel.get_layout().get_pixel_size()[0]
        label_width += clabel.get_layout_offsets()[0] or 0
        # layout offset includes the left padding, so add one more
        label_width += render_xpad

        # CellRenderer width is too large if it's the last one in a column.
        # Use cell_area width as a maximum and limit render_width.
        max_width = col_area.width
        if render_width + render_offset > max_width:
            render_width = max_width - render_offset

        # don't display if it doesn't need expansion
        if label_width < render_width:
            self.__undisplay()
            return False

        dummy, ox, oy = view.get_window().get_origin()
        bg_area = view.get_background_area(path, None)

        # save for adjusting passthrough events
        self.__dx, self.__dy = col_area.x + render_offset, bg_area.y
        self.__dx -= extra_xpad
        if expand_left:
            # shift to the left
            # FIXME: ellipsize start produces a space at the end depending
            # on the text. I don't know how to compute it..
            self.__dx -= (label_width - render_width)

        # final window coordinates/size
        x = ox + self.__dx
        y = oy + self.__dy
        x, y = view.convert_bin_window_to_widget_coords(x, y)

        w = label_width + extra_xpad * 2
        h = bg_area.height

        if not is_wayland():
            # clip if it's bigger than the monitor
            mon_border = 5  # leave some space
            screen = Gdk.Screen.get_default()
            if not expand_left:
                monitor_idx = screen.get_monitor_at_point(x, y)
                mon = screen.get_monitor_geometry(monitor_idx)
                space_right = mon.x + mon.width - x - w - mon_border

                if space_right < 0:
                    w += space_right
                    label.set_ellipsize(Pango.EllipsizeMode.END)
                else:
                    label.set_ellipsize(Pango.EllipsizeMode.NONE)
            else:
                monitor_idx = screen.get_monitor_at_point(x + w, y)
                mon = screen.get_monitor_geometry(monitor_idx)
                space_left = x - mon.x - mon_border

                if space_left < 0:
                    x -= space_left
                    self.__dx -= space_left
                    w += space_left
                    label.set_ellipsize(Pango.EllipsizeMode.START)
                else:
                    label.set_ellipsize(Pango.EllipsizeMode.NONE)
        else:
            label.set_ellipsize(Pango.EllipsizeMode.NONE)

        # Don't show if the resulting tooltip would be smaller
        # than the visible area (if not all is on the display)
        if w < render_width:
            self.__undisplay()
            return False

        self.__view = view
        self.__current_renderer = renderer
        self.__edit_id = renderer.connect('editing-started', self.__undisplay)
        self.__current_path = path
        self.__current_col = col

        if self.__hide_id:
            GLib.source_remove(self.__hide_id)
            self.__hide_id = None

        self.set_transient_for(get_top_parent(view))
        set_text(label)
        self.set_size_request(w, h)

        window = self.get_window()
        if self.get_visible() and window:
            window.move_resize(x, y, w, h)
        else:
            self.move(x, y)
            self.resize(w, h)
            self.show()

        return False
示例#51
0
 def __init__(self, parent):
     super(AddFeedDialog, self).__init__(
         qltk.get_top_parent(parent), _("New Feed"),
         _("Enter the location of an audio feed:"),
         button_label=_("_Add"), button_icon=Icons.LIST_ADD)