Compare commits
11 Commits
30bcd30328
...
1397e6e9e3
Author | SHA1 | Date |
---|---|---|
Anna Schumaker | 1397e6e9e3 | |
Anna Schumaker | 717fdf39cd | |
Anna Schumaker | 9cf980d967 | |
Anna Schumaker | 87d8a2ae3a | |
Anna Schumaker | ddfd37130b | |
Anna Schumaker | 5011db344e | |
Anna Schumaker | 9f240bbc8b | |
Anna Schumaker | f6481f0182 | |
Anna Schumaker | 3d6350d7bd | |
Anna Schumaker | eb6b4d8ef4 | |
Anna Schumaker | f7349cd864 |
|
@ -21,7 +21,7 @@ from gi.repository import Adw
|
|||
|
||||
MAJOR_VERSION = 3
|
||||
MINOR_VERSION = 0
|
||||
MICRO_VERSION = 5
|
||||
MICRO_VERSION = 6
|
||||
|
||||
VERSION_NUMBER = f"{MAJOR_VERSION}.{MINOR_VERSION}.{MICRO_VERSION}"
|
||||
VERSION_STRING = f"Emmental {VERSION_NUMBER}{gsetup.DEBUG_STR}"
|
||||
|
@ -195,6 +195,8 @@ class Application(Adw.Application):
|
|||
self.db.settings.bind_setting(f"tracklist.{name}.visible",
|
||||
column, "visible")
|
||||
self.factory.bind_property("visible-playlist", track_list, "playlist")
|
||||
|
||||
self.__add_accelerators(track_list.accelerators)
|
||||
return track_list
|
||||
|
||||
def build_window(self) -> window.Window:
|
||||
|
|
|
@ -119,6 +119,13 @@ class ImageToggle(Button):
|
|||
inactive_tooltip_text=inactive_tooltip_text,
|
||||
tooltip_text=inactive_tooltip_text,
|
||||
active=active, **kwargs)
|
||||
self.connect("notify", self.__notify)
|
||||
|
||||
def __notify(self, toggle: Button, param: GObject.ParamSpec) -> None:
|
||||
match (param.name, self.active):
|
||||
case ("active-tooltip-text", True) | \
|
||||
("inactive-tooltip-text", False):
|
||||
self.set_tooltip_text(self.get_property(param.name))
|
||||
|
||||
def do_clicked(self) -> None:
|
||||
"""Handle a click event."""
|
||||
|
|
|
@ -21,29 +21,29 @@ box.emmental-splitbutton>menubutton>button {
|
|||
padding: 6px;
|
||||
}
|
||||
|
||||
listview > row:checked {
|
||||
row.emmental-active-row {
|
||||
font-weight: bold;
|
||||
background-color: alpha(@accent_color, 0.2);
|
||||
background-color: alpha(@accent_color, 0.15);
|
||||
}
|
||||
|
||||
listview > row:checked:hover {
|
||||
background-color: alpha(@accent_color, 0.27);
|
||||
row.emmental-active-row:hover {
|
||||
background-color: alpha(@accent_color, 0.22);
|
||||
}
|
||||
|
||||
listview > row:checked:active {
|
||||
background-color: alpha(@accent_color, 0.36);
|
||||
row.emmental-active-row:active {
|
||||
background-color: alpha(@accent_color, 0.31);
|
||||
}
|
||||
|
||||
listview > row:checked:selected {
|
||||
background-color: alpha(@accent_color, 0.3);
|
||||
row.emmental-active-row:selected {
|
||||
background-color: alpha(@accent_color, 0.25);
|
||||
}
|
||||
|
||||
listview > row:checked:selected:hover {
|
||||
background-color: alpha(@accent_color, 0.33);
|
||||
row.emmental-active-row:selected:hover {
|
||||
background-color: alpha(@accent_color, 0.28);
|
||||
}
|
||||
|
||||
listview > row:checked:selected:active {
|
||||
background-color: alpha(@accent_color, 0.39);
|
||||
row.emmental-active-row:selected:active {
|
||||
background-color: alpha(@accent_color, 0.34);
|
||||
}
|
||||
|
||||
image.emmental-sidebar-arrow {
|
||||
|
@ -70,6 +70,14 @@ button.emmental-stop>image {
|
|||
color: @red_3;
|
||||
}
|
||||
|
||||
columnview.emmental-track-list > header {
|
||||
background-color: @card_bg_color;
|
||||
}
|
||||
|
||||
columnview.emmental-track-list > listview {
|
||||
background-color: @card_bg_color;
|
||||
}
|
||||
|
||||
columnview.emmental-track-list > listview > row > cell {
|
||||
padding: 0px 2px;
|
||||
min-height: 40px;
|
||||
|
|
|
@ -61,17 +61,17 @@ class ListRow(GObject.GObject):
|
|||
@GObject.Property(type=bool, default=False)
|
||||
def active(self) -> bool:
|
||||
"""Get the active state of this Row."""
|
||||
if parent := self.listitem.get_child().get_parent():
|
||||
return parent.get_state_flags() & Gtk.StateFlags.CHECKED
|
||||
if self.listrow is not None:
|
||||
return self.listrow.has_css_class("emmental-active-row")
|
||||
return False
|
||||
|
||||
@active.setter
|
||||
def active(self, newval: bool) -> None:
|
||||
if parent := self.listitem.get_child().get_parent():
|
||||
if self.listrow is not None:
|
||||
if newval:
|
||||
parent.set_state_flags(Gtk.StateFlags.CHECKED, False)
|
||||
self.listrow.add_css_class("emmental-active-row")
|
||||
else:
|
||||
parent.unset_state_flags(Gtk.StateFlags.CHECKED)
|
||||
self.listrow.remove_css_class("emmental-active-row")
|
||||
|
||||
@GObject.Property(type=Gtk.Widget)
|
||||
def child(self) -> Gtk.Widget | None:
|
||||
|
@ -87,6 +87,11 @@ class ListRow(GObject.GObject):
|
|||
"""Get the list item for this Row."""
|
||||
return self.listitem.get_item()
|
||||
|
||||
@GObject.Property(type=Gtk.Widget)
|
||||
def listrow(self) -> Gtk.Widget:
|
||||
"""Get the listrow widget that our child widget is contained in."""
|
||||
return self.listitem.props.child.props.parent
|
||||
|
||||
|
||||
class InscriptionRow(ListRow):
|
||||
"""A ListRow for displaying Gtk.Inscription widgets."""
|
||||
|
|
|
@ -124,9 +124,9 @@ class Header(Gtk.HeaderBar):
|
|||
"""Get a list of accelerators for the Header."""
|
||||
res = [ActionEntry("open-file", self._open.activate, "<Control>o"),
|
||||
ActionEntry("decrease-volume", self._volume.decrement,
|
||||
"<Control>Down"),
|
||||
"<Shift><Control>Down"),
|
||||
ActionEntry("increase-volume", self._volume.increment,
|
||||
"<Control>Up"),
|
||||
"<Shift><Control>Up"),
|
||||
ActionEntry("toggle-bg-mode", self._background.activate,
|
||||
"<Shift><Control>b")]
|
||||
if __debug__:
|
||||
|
|
|
@ -4,12 +4,14 @@ from gi.repository import GObject
|
|||
from gi.repository import GLib
|
||||
from gi.repository import Gio
|
||||
from gi.repository import Gtk
|
||||
from ..action import ActionEntry
|
||||
from ..playlist.playlist import Playlist
|
||||
from ..playlist.previous import Previous
|
||||
from .. import db
|
||||
from .. import entry
|
||||
from . import buttons
|
||||
from . import footer
|
||||
from . import selection
|
||||
from . import trackview
|
||||
|
||||
|
||||
|
@ -21,23 +23,24 @@ class Card(Gtk.Box):
|
|||
def __init__(self, sql: db.Connection, **kwargs):
|
||||
"""Set up the Tracklist widget."""
|
||||
super().__init__(sql=sql, orientation=Gtk.Orientation.VERTICAL,
|
||||
spacing=6, **kwargs)
|
||||
**kwargs)
|
||||
self._top_left = Gtk.Box()
|
||||
self._top_right = Gtk.Box(sensitive=False)
|
||||
self._top_box = Gtk.CenterBox(margin_top=6, margin_start=6,
|
||||
margin_end=6)
|
||||
self._top_box = Gtk.CenterBox(margin_start=6, margin_end=6)
|
||||
self._filter = entry.Filter("tracks", hexpand=True,
|
||||
margin_start=100, margin_end=100)
|
||||
self._trackview = trackview.TrackView(sql, margin_start=6,
|
||||
margin_end=6)
|
||||
self._trackview = trackview.TrackView(sql)
|
||||
self._osd = selection.OSD(sql, self._trackview.selection_model,
|
||||
child=self._trackview)
|
||||
self._visible_cols = buttons.VisibleColumns(self._trackview.columns)
|
||||
self._unselect = Gtk.Button(icon_name="edit-select-none-symbolic",
|
||||
tooltip_text="unselect all tracks",
|
||||
has_frame=False, sensitive=False)
|
||||
self._loop = buttons.LoopButton()
|
||||
self._shuffle = buttons.ShuffleButton()
|
||||
self._sort = buttons.SortButton()
|
||||
self._footer = footer.Footer(margin_start=6, margin_end=6,
|
||||
margin_bottom=6)
|
||||
margin_top=6, margin_bottom=6)
|
||||
|
||||
self._top_left.append(self._visible_cols)
|
||||
self._top_left.append(self._unselect)
|
||||
|
@ -51,9 +54,14 @@ class Card(Gtk.Box):
|
|||
self._top_box.set_end_widget(self._top_right)
|
||||
|
||||
self.append(self._top_box)
|
||||
self.append(self._trackview)
|
||||
self.append(Gtk.Separator())
|
||||
self.append(self._osd)
|
||||
self.append(Gtk.Separator())
|
||||
self.append(self._footer)
|
||||
|
||||
self._osd.bind_property("have-selected", self._trackview,
|
||||
"have-selected")
|
||||
self._osd.bind_property("n-selected", self._trackview, "n-selected")
|
||||
self._trackview.bind_property("n-tracks", self._footer, "count")
|
||||
self._trackview.bind_property("n-selected", self._footer, "selected")
|
||||
self._trackview.bind_property("runtime", self._footer, "runtime")
|
||||
|
@ -62,16 +70,14 @@ class Card(Gtk.Box):
|
|||
"sensitive")
|
||||
|
||||
self._filter.connect("search-changed", self.__search_changed)
|
||||
self._unselect.connect("clicked", self.__clear_selection)
|
||||
self._unselect.connect("clicked", self._osd.clear_selection)
|
||||
self._loop.connect("notify::state", self.__update_loop_state)
|
||||
self._shuffle.connect("notify::active", self.__update_shuffle_state)
|
||||
self._sort.connect("notify::sort-order", self.__update_sort_order)
|
||||
|
||||
self._top_box.add_css_class("toolbar")
|
||||
self.add_css_class("card")
|
||||
|
||||
def __clear_selection(self, unselect: Gtk.Button) -> None:
|
||||
self._trackview.clear_selected_tracks()
|
||||
|
||||
def __playlist_notify(self, playlist: Playlist, param) -> None:
|
||||
match param.name:
|
||||
case "loop":
|
||||
|
@ -89,7 +95,7 @@ class Card(Gtk.Box):
|
|||
self._loop.state = self.playlist.loop
|
||||
self._shuffle.active = self.playlist.shuffle
|
||||
self._sort.set_sort_order(self.playlist.sort_order)
|
||||
self._trackview.reset_osd()
|
||||
self._osd.reset()
|
||||
|
||||
def __update_loop_state(self, loop: buttons.LoopButton, param) -> None:
|
||||
if self.playlist.loop != loop.state:
|
||||
|
@ -132,7 +138,24 @@ class Card(Gtk.Box):
|
|||
self._trackview.playlist.disconnect_by_func(self.__playlist_notify)
|
||||
|
||||
self._trackview.playlist = newval
|
||||
self._osd.playlist = newval
|
||||
|
||||
if newval is not None:
|
||||
self._top_right.set_sensitive(not isinstance(newval, Previous))
|
||||
self.__set_button_state()
|
||||
newval.connect("notify", self.__playlist_notify)
|
||||
|
||||
@property
|
||||
def accelerators(self) -> list[ActionEntry]:
|
||||
"""Get a list of accelerators for the Tracklist."""
|
||||
return [ActionEntry("focus-search-track", self._filter.grab_focus,
|
||||
"<Control>slash"),
|
||||
ActionEntry("clear-selected-tracks", self._unselect.activate,
|
||||
"Escape", enabled=(self._unselect, "sensitive")),
|
||||
ActionEntry("cycle-loop", self._loop.activate,
|
||||
"<Control>l", enabled=(self._top_right,
|
||||
"sensitive")),
|
||||
ActionEntry("toggle-shuffle", self._shuffle.activate,
|
||||
"<Control>s", enabled=(self._top_right,
|
||||
"sensitive"))] + \
|
||||
self._osd.accelerators
|
||||
|
|
|
@ -5,19 +5,28 @@ from gi.repository import Gio
|
|||
from gi.repository import Gtk
|
||||
from . import sorter
|
||||
from .. import buttons
|
||||
from .. import factory
|
||||
|
||||
|
||||
class VisibleSwitch(factory.ListRow):
|
||||
"""A list row containing a Gtk.Switch."""
|
||||
class VisibleRow(Gtk.ListBoxRow):
|
||||
"""A ListBoxRow containing a Gtk.Switch and a title Label."""
|
||||
|
||||
def __init__(self, listitem: Gtk.ListItem):
|
||||
"""Initialize a VisibleSwitch ListRow."""
|
||||
super().__init__(listitem=listitem, child=Gtk.Switch())
|
||||
active = GObject.Property(type=bool, default=True)
|
||||
title = GObject.Property(type=str)
|
||||
|
||||
def do_bind(self) -> None:
|
||||
"""Bind the visible property to the switch active property."""
|
||||
self.bind_and_set_property("visible", "active", bidirectional=True)
|
||||
def __init__(self, title: str, active: bool):
|
||||
"""Initialize a VisibleRow ListBoxRow."""
|
||||
super().__init__(title=title, active=active,
|
||||
child=Gtk.Box(margin_start=6, margin_end=6,
|
||||
margin_top=6, margin_bottom=6,
|
||||
spacing=6))
|
||||
self._switch = Gtk.Switch(active=active)
|
||||
self._label = Gtk.Label.new(title)
|
||||
|
||||
self.bind_property("active", self._switch, "active",
|
||||
GObject.BindingFlags.BIDIRECTIONAL)
|
||||
|
||||
self.props.child.append(self._switch)
|
||||
self.props.child.append(self._label)
|
||||
|
||||
|
||||
class VisibleColumns(buttons.PopoverButton):
|
||||
|
@ -28,21 +37,21 @@ class VisibleColumns(buttons.PopoverButton):
|
|||
def __init__(self, columns: Gio.ListModel, **kwargs):
|
||||
"""Initialize the VisibleColumns button."""
|
||||
super().__init__(columns=columns, icon_name="columns-symbolic",
|
||||
tooltip_text="configure visible columns",
|
||||
has_frame=False, **kwargs)
|
||||
self._selection = Gtk.NoSelection(model=self.columns)
|
||||
self.popover_child = Gtk.ColumnView(model=self._selection,
|
||||
show_row_separators=True)
|
||||
self.__append_column(factory.InscriptionFactory("title"),
|
||||
"Column", width=125)
|
||||
self.__append_column(factory.Factory(row_type=VisibleSwitch),
|
||||
"Visible")
|
||||
self.popover_child.add_css_class("data-table")
|
||||
self.popover_child = Gtk.ListBox(selection_mode=Gtk.SelectionMode.NONE)
|
||||
self.popover_child.bind_model(columns, self.__create_func)
|
||||
self.popover_child.connect("row-activated", self.__row_activated)
|
||||
self.popover_child.add_css_class("boxed-list")
|
||||
|
||||
def __append_column(self, factory: factory.Factory,
|
||||
title: str, *, width: int = -1) -> None:
|
||||
column = Gtk.ColumnViewColumn(factory=factory, title=title,
|
||||
fixed_width=width)
|
||||
self.popover_child.append_column(column)
|
||||
def __create_func(self, column: Gtk.ColumnViewColumn) -> VisibleRow:
|
||||
row = VisibleRow(column.get_title(), column.get_visible())
|
||||
row.bind_property("active", column, "visible",
|
||||
GObject.BindingFlags.BIDIRECTIONAL)
|
||||
return row
|
||||
|
||||
def __row_activated(self, box: Gtk.ListBox, row: Gtk.ListBoxRow) -> None:
|
||||
row.active = not row.active
|
||||
|
||||
|
||||
class LoopButton(buttons.ImageToggle):
|
||||
|
@ -53,7 +62,9 @@ class LoopButton(buttons.ImageToggle):
|
|||
def __init__(self, **kwargs):
|
||||
"""Initialize a Loop Button."""
|
||||
super().__init__(active_icon_name="media-playlist-repeat-song",
|
||||
active_tooltip_text="loop: track",
|
||||
inactive_icon_name="media-playlist-repeat",
|
||||
inactive_tooltip_text="loop: disabled",
|
||||
large_icon=False, state="None",
|
||||
has_frame=False, **kwargs)
|
||||
|
||||
|
@ -79,9 +90,11 @@ class LoopButton(buttons.ImageToggle):
|
|||
case ("None", True):
|
||||
self.active = False
|
||||
self.icon_opacity = 0.5
|
||||
self.inactive_tooltip_text = "loop: disabled"
|
||||
case ("Playlist", _):
|
||||
self.active = False
|
||||
self.icon_opacity = 1.0
|
||||
self.inactive_tooltip_text = "loop: playlist"
|
||||
case ("Track", _):
|
||||
self.active = True
|
||||
self.icon_opacity = 1.0
|
||||
|
@ -93,7 +106,9 @@ class ShuffleButton(buttons.ImageToggle):
|
|||
def __init__(self, **kwargs):
|
||||
"""Initialize a Shuffle Button."""
|
||||
super().__init__(active_icon_name="media-playlist-shuffle",
|
||||
active_tooltip_text="shuffle: enabled",
|
||||
inactive_icon_name="media-playlist-consecutive",
|
||||
inactive_tooltip_text="shuffle: disabled",
|
||||
large_icon=False, icon_opacity=0.5,
|
||||
has_frame=False, **kwargs)
|
||||
|
||||
|
@ -102,81 +117,57 @@ class ShuffleButton(buttons.ImageToggle):
|
|||
self.icon_opacity = 1.0 if self.active else 0.5
|
||||
|
||||
|
||||
class SortFieldWidget(Gtk.Box):
|
||||
"""A Widget to display in the Sort Order button popover."""
|
||||
class SortRow(Gtk.ListBoxRow):
|
||||
"""A ListBoxRow for managing Sort Order."""
|
||||
|
||||
active = GObject.Property(type=bool, default=False)
|
||||
sort_field = GObject.Property(type=sorter.SortField)
|
||||
|
||||
def __init__(self) -> None:
|
||||
"""Initialize a SortField Widget."""
|
||||
super().__init__(spacing=6)
|
||||
self._enabled = Gtk.Switch(valign=Gtk.Align.CENTER)
|
||||
self._name = Gtk.Label(hexpand=True, sensitive=False)
|
||||
def __init__(self, sort_field: sorter.SortField):
|
||||
"""Initialize a Sort Row."""
|
||||
super().__init__(sort_field=sort_field, active=sort_field.enabled,
|
||||
child=Gtk.Box(margin_start=6, margin_end=6,
|
||||
margin_top=6, margin_bottom=6,
|
||||
spacing=6))
|
||||
self._switch = Gtk.Switch(active=self.active, valign=Gtk.Align.CENTER)
|
||||
self._label = Gtk.Label(label=sort_field.name, hexpand=True,
|
||||
sensitive=self.active, xalign=0.0)
|
||||
self._reverse = buttons.ImageToggle("arrow1-up", "arrow1-down",
|
||||
large_icon=False, sensitive=False)
|
||||
self._box = Gtk.Box(sensitive=False)
|
||||
active=sort_field.reversed,
|
||||
sensitive=self.active,
|
||||
has_frame=False)
|
||||
self._move_box = Gtk.Box(sensitive=self.active)
|
||||
self._move_up = Gtk.Button(icon_name="go-up-symbolic")
|
||||
self._move_down = Gtk.Button(icon_name="go-down-symbolic")
|
||||
|
||||
self._enabled.bind_property("active", self._name, "sensitive")
|
||||
self._enabled.bind_property("active", self._reverse, "sensitive")
|
||||
self._enabled.bind_property("active", self._box, "sensitive")
|
||||
self._switch.connect("notify::active", self.__toggle_enabled)
|
||||
self._reverse.connect("toggled", self.__reverse)
|
||||
self._move_up.connect("clicked", self.__move_up)
|
||||
self._move_down.connect("clicked", self.__move_down)
|
||||
|
||||
self._enabled.connect("notify::active", self.__notify_enabled)
|
||||
self._reverse.connect("clicked", self.__reverse)
|
||||
self._move_up.connect("clicked", self.__move_item_up)
|
||||
self._move_down.connect("clicked", self.__move_item_down)
|
||||
self.props.child.append(self._switch)
|
||||
self.props.child.append(self._label)
|
||||
self.props.child.append(self._reverse)
|
||||
self.props.child.append(self._move_box)
|
||||
|
||||
self.append(self._enabled)
|
||||
self.append(self._name)
|
||||
self.append(self._reverse)
|
||||
self.append(self._box)
|
||||
self._move_box.append(self._move_up)
|
||||
self._move_box.append(self._move_down)
|
||||
self._move_box.add_css_class("linked")
|
||||
|
||||
self._box.append(self._move_up)
|
||||
self._box.append(self._move_down)
|
||||
self._box.add_css_class("linked")
|
||||
|
||||
def __move_item_down(self, button: Gtk.Button) -> None:
|
||||
if self.sort_field is not None:
|
||||
self.sort_field.move_down()
|
||||
|
||||
def __move_item_up(self, button: Gtk.Button) -> None:
|
||||
if self.sort_field is not None:
|
||||
self.sort_field.move_up()
|
||||
|
||||
def __notify_enabled(self, switch: Gtk.Switch, param) -> None:
|
||||
if self.sort_field is not None:
|
||||
if switch.get_active():
|
||||
self.sort_field.enable()
|
||||
else:
|
||||
self.sort_field.disable()
|
||||
def __toggle_enabled(self, switch: Gtk.Switch, param) -> None:
|
||||
if switch.props.active:
|
||||
self.sort_field.enable()
|
||||
else:
|
||||
self.sort_field.disable()
|
||||
|
||||
def __reverse(self, button: buttons.ImageToggle) -> None:
|
||||
if self.sort_field is not None:
|
||||
self.sort_field.reverse()
|
||||
self.sort_field.reverse()
|
||||
|
||||
def set_sort_field(self, field: sorter.SortField | None) -> None:
|
||||
"""Set the Sort Field displayed by this Widget."""
|
||||
self.sort_field = field
|
||||
self._name.set_text(field.name if field is not None else "")
|
||||
self._enabled.set_active(field is not None and field.enabled)
|
||||
self._reverse.active = field is not None and field.reversed
|
||||
def __move_up(self, button: Gtk.Button) -> None:
|
||||
self.sort_field.move_up()
|
||||
|
||||
|
||||
class SortRow(factory.ListRow):
|
||||
"""A row for managing Sort Order."""
|
||||
|
||||
def __init__(self, listitem: Gtk.ListItem):
|
||||
"""Initialize a Sort Row."""
|
||||
super().__init__(listitem=listitem, child=SortFieldWidget())
|
||||
|
||||
def do_bind(self) -> None:
|
||||
"""Bind Sort Field properties to the Widget."""
|
||||
self.child.set_sort_field(self.item)
|
||||
|
||||
def do_unbind(self) -> None:
|
||||
"""Unbind properties from the widget."""
|
||||
self.child.set_sort_field(None)
|
||||
def __move_down(self, button: Gtk.Button) -> None:
|
||||
self.sort_field.move_down()
|
||||
|
||||
|
||||
class SortButton(buttons.PopoverButton):
|
||||
|
@ -188,14 +179,24 @@ class SortButton(buttons.PopoverButton):
|
|||
def __init__(self, **kwargs):
|
||||
"""Initialize the Sort button."""
|
||||
super().__init__(has_frame=False, model=sorter.SortOrderModel(),
|
||||
tooltip_text="configure playlist sort order",
|
||||
icon_name="view-list-ordered-symbolic", **kwargs)
|
||||
self._selection = Gtk.NoSelection(model=self.model)
|
||||
self._factory = factory.Factory(row_type=SortRow)
|
||||
self.popover_child = Gtk.ListView(model=self._selection,
|
||||
factory=self._factory,
|
||||
show_separators=True)
|
||||
self.popover_child = Gtk.ListBox(selection_mode=Gtk.SelectionMode.NONE)
|
||||
self.popover_child.bind_model(self.model, self.__create_func)
|
||||
self.popover_child.connect("row-activated", self.__row_activated)
|
||||
self.popover_child.add_css_class("boxed-list")
|
||||
|
||||
self.model.bind_property("sort-order", self, "sort-order")
|
||||
|
||||
def __create_func(self, sort_field: sorter.SortField) -> SortRow:
|
||||
return SortRow(sort_field)
|
||||
|
||||
def __row_activated(self, box: Gtk.ListBox, row: SortRow) -> None:
|
||||
if row.active:
|
||||
row._reverse.active = not row.sort_field.reversed
|
||||
else:
|
||||
row.sort_field.enable()
|
||||
|
||||
def set_sort_order(self, newval: str) -> None:
|
||||
"""Directly set the sort order."""
|
||||
self.model.set_sort_order(newval)
|
||||
|
|
|
@ -63,23 +63,6 @@ class TrackRow(factory.ListRow):
|
|||
else:
|
||||
self.bind_album(child_prop)
|
||||
|
||||
@GObject.Property(type=bool, default=False)
|
||||
def active(self) -> bool:
|
||||
"""Get the active state of this Row."""
|
||||
if parent := self.listitem.get_child().get_parent():
|
||||
if parent := parent.get_parent():
|
||||
return parent.get_state_flags() & Gtk.StateFlags.CHECKED
|
||||
return False
|
||||
|
||||
@active.setter
|
||||
def active(self, newval: bool) -> None:
|
||||
if parent := self.listitem.get_child().get_parent():
|
||||
if parent := parent.get_parent():
|
||||
if newval:
|
||||
parent.set_state_flags(Gtk.StateFlags.CHECKED, False)
|
||||
else:
|
||||
parent.unset_state_flags(Gtk.StateFlags.CHECKED)
|
||||
|
||||
@GObject.Property(type=bool, default=True)
|
||||
def online(self) -> bool:
|
||||
"""Get the online state of this Row."""
|
||||
|
@ -90,6 +73,14 @@ class TrackRow(factory.ListRow):
|
|||
self.listitem.set_activatable(newval)
|
||||
self.child.set_sensitive(newval)
|
||||
|
||||
@GObject.Property(type=Gtk.Widget)
|
||||
def listrow(self) -> Gtk.Widget:
|
||||
"""Test property for active track styling."""
|
||||
if child := self.listitem.props.child:
|
||||
if cell := child.props.parent:
|
||||
return cell.props.parent
|
||||
return None
|
||||
|
||||
|
||||
class InscriptionRow(TrackRow):
|
||||
"""Base class for Track Rows displaying a Gtk.Inscription."""
|
||||
|
|
|
@ -4,40 +4,39 @@ from gi.repository import GObject
|
|||
from gi.repository import Gdk
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import Adw
|
||||
from ..action import ActionEntry
|
||||
from ..buttons import PopoverButton
|
||||
from .. import db
|
||||
from .. import factory
|
||||
from .. import playlist
|
||||
|
||||
|
||||
class PlaylistRowWidget(Gtk.Box):
|
||||
"""A row widget for Playlists."""
|
||||
class PlaylistRow(Gtk.ListBoxRow):
|
||||
"""A ListBoxRow widget for Playlists."""
|
||||
|
||||
name = GObject.Property(type=str)
|
||||
image = GObject.Property(type=GObject.TYPE_PYOBJECT)
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize a PlaylistRowWidget."""
|
||||
super().__init__()
|
||||
self._icon = Adw.Avatar(size=32)
|
||||
self._label = Gtk.Label(xalign=0.0)
|
||||
def __init__(self, name: str, image: GObject.TYPE_PYOBJECT):
|
||||
"""Initialize a PlaylistRow."""
|
||||
super().__init__(child=Gtk.Box(margin_start=6, margin_end=6,
|
||||
margin_top=6, margin_bottom=6,
|
||||
spacing=6), name=name)
|
||||
match name:
|
||||
case "Favorite Tracks": icon_name = "heart-filled-symbolic"
|
||||
case "Queued Tracks": icon_name = "music-queue-symbolic"
|
||||
case _: icon_name = "playlist2-symbolic"
|
||||
|
||||
self._icon = Adw.Avatar(size=32, text=name, icon_name=icon_name)
|
||||
self._label = Gtk.Label.new(name)
|
||||
|
||||
self.bind_property("name", self._label, "label")
|
||||
self.bind_property("name", self._icon, "text")
|
||||
self.connect("notify::name", self.__name_changed)
|
||||
self.connect("notify::image", self.__image_changed)
|
||||
self.image = image
|
||||
|
||||
self.append(self._icon)
|
||||
self.append(self._label)
|
||||
self.props.child.append(self._icon)
|
||||
self.props.child.append(self._label)
|
||||
|
||||
def __name_changed(self, row: Gtk.Box, param) -> None:
|
||||
match self.name:
|
||||
case "Favorite Tracks": icon = "heart-filled-symbolic"
|
||||
case "Queued Tracks": icon = "music-queue-symbolic"
|
||||
case _: icon = "playlist2-symbolic"
|
||||
self._icon.set_icon_name(icon)
|
||||
|
||||
def __image_changed(self, row: Gtk.Box, param) -> None:
|
||||
def __image_changed(self, row: Gtk.ListBoxRow,
|
||||
param: GObject.ParamSpec) -> None:
|
||||
if self.image is not None and self.image.is_file():
|
||||
texture = Gdk.Texture.new_from_filename(str(self.image))
|
||||
else:
|
||||
|
@ -45,20 +44,6 @@ class PlaylistRowWidget(Gtk.Box):
|
|||
self._icon.set_custom_image(texture)
|
||||
|
||||
|
||||
class PlaylistRow(factory.ListRow):
|
||||
"""A list row for displaying Playlists."""
|
||||
|
||||
def __init__(self, listitem: Gtk.ListItem):
|
||||
"""Initialize a PlaylistRow."""
|
||||
super().__init__(listitem)
|
||||
self.child = PlaylistRowWidget()
|
||||
|
||||
def do_bind(self):
|
||||
"""Bind a Playlist to this Row."""
|
||||
self.bind_and_set_property("name", "name")
|
||||
self.bind_and_set_property("image", "image")
|
||||
|
||||
|
||||
class UserTracksFilter(Gtk.Filter):
|
||||
"""Filters for tracks with user-tracks set to True."""
|
||||
|
||||
|
@ -77,28 +62,28 @@ class UserTracksFilter(Gtk.Filter):
|
|||
return playlist.user_tracks and playlist != self.playlist
|
||||
|
||||
|
||||
class PlaylistView(Gtk.ListView):
|
||||
class PlaylistView(Gtk.ListBox):
|
||||
"""A ListView for selecting Playlists."""
|
||||
|
||||
playlist = GObject.Property(type=db.playlist.Playlist)
|
||||
|
||||
def __init__(self, sql: db.Connection):
|
||||
"""Initialize the PlaylistView."""
|
||||
super().__init__(show_separators=True, single_click_activate=True)
|
||||
super().__init__(selection_mode=Gtk.SelectionMode.NONE)
|
||||
self._filtered = Gtk.FilterListModel(model=sql.playlists,
|
||||
filter=UserTracksFilter())
|
||||
self._selection = Gtk.NoSelection(model=self._filtered)
|
||||
self._factory = factory.Factory(PlaylistRow)
|
||||
|
||||
self.connect("activate", self.__playlist_activated)
|
||||
self.bind_property("playlist", self._filtered.get_filter(), "playlist")
|
||||
self.add_css_class("rich-list")
|
||||
self.bind_model(self._filtered, self.__create_func)
|
||||
self.connect("row-activated", self.__row_activated)
|
||||
self.add_css_class("boxed-list")
|
||||
|
||||
self.set_model(self._selection)
|
||||
self.set_factory(self._factory)
|
||||
def __row_activated(self, box: Gtk.ListBox, row: PlaylistRow) -> None:
|
||||
self.emit("playlist-selected", self._filtered[row.get_index()])
|
||||
|
||||
def __playlist_activated(self, view: Gtk.ListView, position: int) -> None:
|
||||
self.emit("playlist-selected", self._selection[position])
|
||||
def __create_func(self, playlist: db.playlist.Playlist) -> PlaylistRow:
|
||||
row = PlaylistRow(playlist.name, playlist.image)
|
||||
playlist.bind_property("image", row, "image")
|
||||
return row
|
||||
|
||||
@GObject.Signal(arg_types=(db.playlists.Playlist,))
|
||||
def playlist_selected(self, playlist: db.playlists.Playlist) -> None:
|
||||
|
@ -115,8 +100,10 @@ class MoveButtons(Gtk.Box):
|
|||
"""Initialize the Move Buttons."""
|
||||
super().__init__(**kwargs)
|
||||
self._down = Gtk.Button(icon_name="go-down-symbolic",
|
||||
tooltip_text="move selected track down",
|
||||
hexpand=True, sensitive=False)
|
||||
self._up = Gtk.Button(icon_name="go-up-symbolic",
|
||||
tooltip_text="move selected track up",
|
||||
hexpand=True, sensitive=False)
|
||||
|
||||
self.bind_property("can-move-down", self._down, "sensitive")
|
||||
|
@ -165,12 +152,15 @@ class OSD(Gtk.Overlay):
|
|||
super().__init__(sql=sql, selection=selection, **kwargs)
|
||||
self._add = PopoverButton(child=Adw.ButtonContent(label="Add",
|
||||
icon_name="list-add-symbolic"),
|
||||
tooltip_text="add selected tracks "
|
||||
"to a playlist",
|
||||
halign=Gtk.Align.START, valign=Gtk.Align.END,
|
||||
margin_start=16, margin_bottom=16,
|
||||
direction=Gtk.ArrowType.UP, visible=False,
|
||||
popover_child=PlaylistView(sql))
|
||||
self._remove = Gtk.Button(child=Adw.ButtonContent(label="Remove",
|
||||
icon_name="list-remove-symbolic"),
|
||||
tooltip_text="remove selected tracks",
|
||||
halign=Gtk.Align.END, valign=Gtk.Align.END,
|
||||
margin_end=16, margin_bottom=16,
|
||||
visible=False)
|
||||
|
@ -268,3 +258,15 @@ class OSD(Gtk.Overlay):
|
|||
self.__selection_changed(self.selection, 0, 0)
|
||||
if self.playlist is not None:
|
||||
self._add.popover_child.playlist = self.playlist.playlist
|
||||
|
||||
@property
|
||||
def accelerators(self) -> list[ActionEntry]:
|
||||
"""Get a list of accelerators for the OSD."""
|
||||
return [ActionEntry("remove-selected-tracks", self._remove.activate,
|
||||
"Delete", enabled=(self._remove, "visible")),
|
||||
ActionEntry("move-track-up", self._move._up.activate,
|
||||
"<Control>Up",
|
||||
enabled=(self._move, "can-move-up")),
|
||||
ActionEntry("move-track-down", self._move._down.activate,
|
||||
"<Control>Down",
|
||||
enabled=(self._move, "can-move-down"))]
|
||||
|
|
|
@ -7,10 +7,9 @@ from .. import db
|
|||
from .. import factory
|
||||
from .. import playlist
|
||||
from . import row
|
||||
from . import selection
|
||||
|
||||
|
||||
class TrackView(Gtk.Frame):
|
||||
class TrackView(Gtk.ScrolledWindow):
|
||||
"""A Gtk.ColumnView that has been configured to show Tracks."""
|
||||
|
||||
playlist = GObject.Property(type=playlist.playlist.Playlist)
|
||||
|
@ -30,8 +29,6 @@ class TrackView(Gtk.Frame):
|
|||
show_row_separators=True,
|
||||
enable_rubberband=True,
|
||||
model=self._selection)
|
||||
self._scrollwin = Gtk.ScrolledWindow(child=self._columnview)
|
||||
self._osd = selection.OSD(sql, self._selection, child=self._scrollwin)
|
||||
|
||||
self.__append_column("Art", "cover", row.AlbumCover, resizable=False)
|
||||
self.__append_column("Fav", "favorite", row.FavoriteButton,
|
||||
|
@ -57,16 +54,13 @@ class TrackView(Gtk.Frame):
|
|||
self.__append_column("Filepath", "path", row.PathString, visible=False)
|
||||
|
||||
self.bind_property("playlist", self._filtermodel, "model")
|
||||
self.bind_property("playlist", self._osd, "playlist")
|
||||
self._osd.bind_property("have-selected", self, "have-selected")
|
||||
self._osd.bind_property("n-selected", self, "n-selected")
|
||||
self._selection.bind_property("n-items", self, "n-tracks")
|
||||
|
||||
self._selection.connect("items-changed", self.__runtime_changed)
|
||||
self._columnview.connect("activate", self.__track_activated)
|
||||
self._columnview.add_css_class("emmental-track-list")
|
||||
|
||||
self.set_child(self._osd)
|
||||
self.set_child(self._columnview)
|
||||
|
||||
def __append_column(self, title: str, property: str, row_type: type,
|
||||
*, width: int = -1, visible: bool = True,
|
||||
|
@ -95,15 +89,12 @@ class TrackView(Gtk.Frame):
|
|||
pos = max(i - 3, 0) * adjustment.get_upper()
|
||||
adjustment.set_value(pos / self._selection.get_n_items())
|
||||
|
||||
def clear_selected_tracks(self) -> None:
|
||||
"""Clear the currently selected tracks."""
|
||||
self._osd.clear_selection()
|
||||
|
||||
def reset_osd(self) -> None:
|
||||
"""Reset the OSD."""
|
||||
self._osd.reset()
|
||||
|
||||
@GObject.Property(type=Gio.ListModel)
|
||||
def columns(self) -> Gio.ListModel:
|
||||
"""Get the ListModel for the columns."""
|
||||
return self._columnview.get_columns()
|
||||
|
||||
@GObject.Property(type=Gio.ListModel)
|
||||
def selection_model(self) -> Gio.ListModel:
|
||||
"""Get the SelectionModel for the ColumnView."""
|
||||
return self._columnview.get_model()
|
||||
|
|
|
@ -185,9 +185,9 @@ class TestHeader(tests.util.TestCase):
|
|||
"""Check that the accelerators list is set up properly."""
|
||||
entries = [("open-file", self.header._open.activate, "<Control>o"),
|
||||
("decrease-volume", self.header._volume.decrement,
|
||||
"<Control>Down"),
|
||||
"<Shift><Control>Down"),
|
||||
("increase-volume", self.header._volume.increment,
|
||||
"<Control>Up"),
|
||||
"<Shift><Control>Up"),
|
||||
("toggle-bg-mode", self.header._background.activate,
|
||||
"<Shift><Control>b"),
|
||||
("edit-settings", self.header._settings.activate,
|
||||
|
|
|
@ -211,6 +211,17 @@ class TestImageToggle(unittest.TestCase):
|
|||
button2.active = False
|
||||
self.assertEqual(button2.get_tooltip_text(), "inactive tooltip text")
|
||||
|
||||
def test_changing_tooltip_text(self):
|
||||
"""Test changing the tooltip text for the current state."""
|
||||
self.assertEqual(self.button.props.tooltip_text, None)
|
||||
self.button.inactive_tooltip_text = "inactive tooltip"
|
||||
self.assertEqual(self.button.props.tooltip_text, "inactive tooltip")
|
||||
|
||||
self.button.active = True
|
||||
self.assertEqual(self.button.props.tooltip_text, None)
|
||||
self.button.active_tooltip_text = "active tooltip"
|
||||
self.assertEqual(self.button.props.tooltip_text, "active tooltip")
|
||||
|
||||
def test_toggle(self):
|
||||
"""Test the toggle signal."""
|
||||
toggled = unittest.mock.Mock()
|
||||
|
|
|
@ -22,9 +22,9 @@ class TestEmmental(unittest.TestCase):
|
|||
"""Check that version constants have been set properly."""
|
||||
self.assertEqual(emmental.MAJOR_VERSION, 3)
|
||||
self.assertEqual(emmental.MINOR_VERSION, 0)
|
||||
self.assertEqual(emmental.MICRO_VERSION, 5)
|
||||
self.assertEqual(emmental.VERSION_NUMBER, "3.0.5")
|
||||
self.assertEqual(emmental.VERSION_STRING, "Emmental 3.0.5-debug")
|
||||
self.assertEqual(emmental.MICRO_VERSION, 6)
|
||||
self.assertEqual(emmental.VERSION_NUMBER, "3.0.6")
|
||||
self.assertEqual(emmental.VERSION_STRING, "Emmental 3.0.6-debug")
|
||||
|
||||
def test_application(self):
|
||||
"""Check that the application instance is initialized properly."""
|
||||
|
@ -63,7 +63,7 @@ class TestEmmental(unittest.TestCase):
|
|||
mock_startup.assert_called()
|
||||
mock_load.assert_called()
|
||||
mock_add_window.assert_called_with(self.application.win)
|
||||
mock_set_useragent.assert_called_with("emmental-debug", "3.0.5")
|
||||
mock_set_useragent.assert_called_with("emmental-debug", "3.0.6")
|
||||
|
||||
@unittest.mock.patch("sys.stdout")
|
||||
@unittest.mock.patch("gi.repository.Adw.Application.add_window")
|
||||
|
@ -128,8 +128,8 @@ class TestEmmental(unittest.TestCase):
|
|||
self.application.build_window()
|
||||
|
||||
for action, accel in [("app.open-file", "<Control>o"),
|
||||
("app.decrease-volume", "<Control>Down"),
|
||||
("app.increase-volume", "<Control>Up"),
|
||||
("app.decrease-volume", "<Shift><Control>Down"),
|
||||
("app.increase-volume", "<Shift><Control>Up"),
|
||||
("app.toggle-bg-mode", "<Shift><Control>b"),
|
||||
("app.edit-settings", "<Shift><Control>s")]:
|
||||
self.assertEqual(self.application.get_accels_for_action(action),
|
||||
|
@ -227,6 +227,16 @@ class TestEmmental(unittest.TestCase):
|
|||
self.application.player = emmental.audio.Player()
|
||||
win = self.application.build_window()
|
||||
|
||||
for action, accel in [("app.focus-search-track", "<Control>slash"),
|
||||
("app.clear-selected-tracks", "Escape"),
|
||||
("app.cycle-loop", "<Control>l"),
|
||||
("app.toggle-shuffle", "<Control>s"),
|
||||
("app.remove-selected-tracks", "Delete"),
|
||||
("app.move-track-up", "<Control>Up"),
|
||||
("app.move-track-down", "<Control>Down")]:
|
||||
self.assertEqual(self.application.get_accels_for_action(action),
|
||||
[accel])
|
||||
|
||||
self.assertEqual(win.tracklist.sql, self.application.db)
|
||||
|
||||
playlist = self.application.db.playlists.create("Test Playlist")
|
||||
|
|
|
@ -39,16 +39,21 @@ class TestListRow(unittest.TestCase):
|
|||
|
||||
def test_bind_active(self):
|
||||
"""Test binding a property to the Row's active property."""
|
||||
self.assertIsNone(self.row.listrow)
|
||||
self.row.active = True
|
||||
self.assertFalse(self.row.active)
|
||||
|
||||
parent = Gtk.Box()
|
||||
parent.append(self.row.child)
|
||||
self.assertEqual(self.row.listrow, parent)
|
||||
|
||||
self.row.bind_active("sensitive")
|
||||
self.assertEqual(len(self.row.bindings), 1)
|
||||
self.assertTrue(parent.get_state_flags() & Gtk.StateFlags.CHECKED)
|
||||
self.assertTrue(parent.has_css_class("emmental-active-row"))
|
||||
self.assertTrue(self.row.active)
|
||||
|
||||
self.item.set_sensitive(False)
|
||||
self.assertFalse(parent.get_state_flags() & Gtk.StateFlags.CHECKED)
|
||||
self.assertFalse(parent.has_css_class("emmental-active-row"))
|
||||
self.assertFalse(self.row.active)
|
||||
|
||||
def test_bind_and_set_property(self):
|
||||
|
|
|
@ -7,12 +7,62 @@ from gi.repository import Gio
|
|||
from gi.repository import Gtk
|
||||
|
||||
|
||||
class TestVisibleColumnRow(unittest.TestCase):
|
||||
"""Test the Visible Column ListBoxRow."""
|
||||
|
||||
def setUp(self):
|
||||
"""Set up common variables."""
|
||||
self.row = emmental.tracklist.buttons.VisibleRow("title", True)
|
||||
|
||||
def test_init(self):
|
||||
"""Test that the VisibleRow was set up properly."""
|
||||
self.assertIsInstance(self.row, Gtk.ListBoxRow)
|
||||
self.assertIsInstance(self.row.props.child, Gtk.Box)
|
||||
|
||||
self.assertEqual(self.row.title, "title")
|
||||
self.assertTrue(self.row.active)
|
||||
|
||||
self.assertEqual(self.row.props.child.props.margin_start, 6)
|
||||
self.assertEqual(self.row.props.child.props.margin_end, 6)
|
||||
self.assertEqual(self.row.props.child.props.margin_top, 6)
|
||||
self.assertEqual(self.row.props.child.props.margin_bottom, 6)
|
||||
self.assertEqual(self.row.props.child.props.spacing, 6)
|
||||
|
||||
row2 = emmental.tracklist.buttons.VisibleRow("title2", False)
|
||||
self.assertEqual(row2.title, "title2")
|
||||
self.assertFalse(row2.active)
|
||||
|
||||
def test_switch(self):
|
||||
"""Test the VisibleRow switch."""
|
||||
self.assertIsInstance(self.row._switch, Gtk.Switch)
|
||||
self.assertEqual(self.row._switch.props.parent, self.row.props.child)
|
||||
|
||||
self.assertTrue(self.row._switch.props.active)
|
||||
self.row.active = False
|
||||
self.assertFalse(self.row._switch.props.active)
|
||||
self.row._switch.props.active = True
|
||||
self.assertTrue(self.row.active)
|
||||
|
||||
row2 = emmental.tracklist.buttons.VisibleRow("title2", False)
|
||||
self.assertFalse(row2._switch.props.active)
|
||||
|
||||
def test_label(self):
|
||||
"""Test the VisibleRow title label."""
|
||||
self.assertIsInstance(self.row._label, Gtk.Label)
|
||||
self.assertEqual(self.row._label.props.label, "title")
|
||||
self.assertEqual(self.row._switch.get_next_sibling(),
|
||||
self.row._label)
|
||||
|
||||
|
||||
class TestVisibleColumns(unittest.TestCase):
|
||||
"""Test the Visible Columns button."""
|
||||
|
||||
def setUp(self):
|
||||
"""Set up common variables."""
|
||||
self.columns = Gio.ListStore()
|
||||
self.columns.append(Gtk.ColumnViewColumn(title="title", visible=True))
|
||||
self.columns.append(Gtk.ColumnViewColumn(title="title2",
|
||||
visible=False))
|
||||
self.button = emmental.tracklist.buttons.VisibleColumns(self.columns)
|
||||
|
||||
def test_init(self):
|
||||
|
@ -20,55 +70,43 @@ class TestVisibleColumns(unittest.TestCase):
|
|||
self.assertIsInstance(self.button, emmental.buttons.PopoverButton)
|
||||
self.assertFalse(self.button.get_has_frame())
|
||||
self.assertEqual(self.button.get_icon_name(), "columns-symbolic")
|
||||
self.assertEqual(self.button.get_tooltip_text(),
|
||||
"configure visible columns")
|
||||
self.assertEqual(self.button.columns, self.columns)
|
||||
|
||||
def test_popover_child(self):
|
||||
"""Test that the popover_child was set up properly."""
|
||||
self.assertIsInstance(self.button.popover_child, Gtk.ColumnView)
|
||||
self.assertIsInstance(self.button._selection, Gtk.NoSelection)
|
||||
self.assertTrue(self.button.popover_child.get_show_row_separators())
|
||||
self.assertTrue(self.button.popover_child.has_css_class("data-table"))
|
||||
self.assertIsInstance(self.button.popover_child, Gtk.ListBox)
|
||||
self.assertEqual(self.button.popover_child.props.selection_mode,
|
||||
Gtk.SelectionMode.NONE)
|
||||
self.assertTrue(self.button.popover_child.has_css_class("boxed-list"))
|
||||
|
||||
self.assertEqual(self.button.popover_child.get_model(),
|
||||
self.button._selection)
|
||||
self.assertEqual(self.button._selection.get_model(),
|
||||
self.button.columns)
|
||||
def test_create_func(self):
|
||||
"""Test that the Gtk.ListBox creates VisibleRows correctly."""
|
||||
row = self.button.popover_child.get_row_at_index(0)
|
||||
self.assertIsInstance(row, emmental.tracklist.buttons.VisibleRow)
|
||||
self.assertEqual(row.title, "title")
|
||||
self.assertTrue(row.active)
|
||||
|
||||
def test_columns(self):
|
||||
"""Test the popover_child columns."""
|
||||
columns = self.button.popover_child.get_columns()
|
||||
self.assertEqual(len(columns), 2)
|
||||
row.active = False
|
||||
self.assertFalse(self.columns[0].get_visible())
|
||||
row.active = True
|
||||
self.assertTrue(self.columns[0].get_visible())
|
||||
self.columns[0].set_visible(False)
|
||||
self.assertFalse(row.active)
|
||||
|
||||
self.assertIsInstance(columns[0].get_factory(),
|
||||
emmental.factory.InscriptionFactory)
|
||||
self.assertEqual(columns[0].get_title(), "Column")
|
||||
self.assertEqual(columns[0].get_fixed_width(), 125)
|
||||
row = self.button.popover_child.get_row_at_index(1)
|
||||
self.assertIsInstance(row, emmental.tracklist.buttons.VisibleRow)
|
||||
self.assertEqual(row.title, "title2")
|
||||
self.assertFalse(row.active)
|
||||
|
||||
self.assertIsInstance(columns[1].get_factory(),
|
||||
emmental.factory.Factory)
|
||||
self.assertEqual(columns[1].get_factory().row_type,
|
||||
emmental.tracklist.buttons.VisibleSwitch)
|
||||
self.assertEqual(columns[1].get_title(), "Visible")
|
||||
self.assertEqual(columns[1].get_fixed_width(), -1)
|
||||
|
||||
def test_visible_switch(self):
|
||||
"""Test the visible switch widget."""
|
||||
item = Gtk.Label()
|
||||
listitem = Gtk.ListItem()
|
||||
listitem.get_item = unittest.mock.Mock(return_value=item)
|
||||
switch = emmental.tracklist.buttons.VisibleSwitch(listitem)
|
||||
|
||||
self.assertIsInstance(switch, emmental.factory.ListRow)
|
||||
self.assertIsInstance(switch.child, Gtk.Switch)
|
||||
|
||||
switch.bind()
|
||||
self.assertEqual(len(switch.bindings), 1)
|
||||
self.assertTrue(switch.child.get_active())
|
||||
|
||||
item.set_visible(False)
|
||||
self.assertFalse(switch.child.get_active())
|
||||
switch.child.set_active(True)
|
||||
item.set_visible(True)
|
||||
def test_activate(self):
|
||||
"""Test activating a Gtk.ListBox row."""
|
||||
row = self.button.popover_child.get_row_at_index(0)
|
||||
self.button.popover_child.emit("row-activated", row)
|
||||
self.assertFalse(row.active)
|
||||
self.button.popover_child.emit("row-activated", row)
|
||||
self.assertTrue(row.active)
|
||||
|
||||
|
||||
class TestLoopButton(unittest.TestCase):
|
||||
|
@ -83,7 +121,9 @@ class TestLoopButton(unittest.TestCase):
|
|||
self.assertIsInstance(self.loop, emmental.buttons.ImageToggle)
|
||||
self.assertEqual(self.loop.active_icon_name,
|
||||
"media-playlist-repeat-song")
|
||||
self.assertEqual(self.loop.active_tooltip_text, "loop: track")
|
||||
self.assertEqual(self.loop.inactive_icon_name, "media-playlist-repeat")
|
||||
self.assertEqual(self.loop.inactive_tooltip_text, "loop: disabled")
|
||||
self.assertFalse(self.loop.large_icon)
|
||||
self.assertFalse(self.loop.get_has_frame())
|
||||
|
||||
|
@ -93,26 +133,31 @@ class TestLoopButton(unittest.TestCase):
|
|||
|
||||
self.assertEqual(self.loop.state, "None")
|
||||
self.assertAlmostEqual(self.loop.icon_opacity, 0.5, delta=0.005)
|
||||
self.assertEqual(self.loop.props.tooltip_text, "loop: disabled")
|
||||
self.assertFalse(self.loop.active)
|
||||
|
||||
self.loop.state = "Playlist"
|
||||
self.assertEqual(self.loop.state, "Playlist")
|
||||
self.assertEqual(self.loop.icon_opacity, 1.0)
|
||||
self.assertEqual(self.loop.props.tooltip_text, "loop: playlist")
|
||||
self.assertFalse(self.loop.active)
|
||||
|
||||
self.loop.state = "Track"
|
||||
self.assertEqual(self.loop.state, "Track")
|
||||
self.assertEqual(self.loop.icon_opacity, 1.0)
|
||||
self.assertEqual(self.loop.props.tooltip_text, "loop: track")
|
||||
self.assertTrue(self.loop.active)
|
||||
|
||||
self.loop.can_disable = False
|
||||
self.loop.state = "None"
|
||||
self.assertEqual(self.loop.state, "Track")
|
||||
self.assertEqual(self.loop.props.tooltip_text, "loop: track")
|
||||
self.assertTrue(self.loop.active)
|
||||
|
||||
self.loop.can_disable = True
|
||||
self.loop.state = "None"
|
||||
self.assertAlmostEqual(self.loop.icon_opacity, 0.5, delta=0.005)
|
||||
self.assertEqual(self.loop.inactive_tooltip_text, "loop: disabled")
|
||||
self.assertFalse(self.loop.active)
|
||||
|
||||
def test_click(self):
|
||||
|
@ -143,14 +188,20 @@ class TestShuffleButtons(unittest.TestCase):
|
|||
def test_init(self):
|
||||
"""Test that the shuffle button is configured correctly."""
|
||||
self.assertIsInstance(self.shuffle, emmental.buttons.ImageToggle)
|
||||
self.assertEqual(self.shuffle.active_icon_name,
|
||||
"media-playlist-shuffle")
|
||||
self.assertEqual(self.shuffle.inactive_icon_name,
|
||||
"media-playlist-consecutive")
|
||||
self.assertAlmostEqual(self.shuffle.icon_opacity, 0.5, delta=0.005)
|
||||
self.assertFalse(self.shuffle.large_icon)
|
||||
self.assertFalse(self.shuffle.get_has_frame())
|
||||
|
||||
self.assertEqual(self.shuffle.active_icon_name,
|
||||
"media-playlist-shuffle")
|
||||
self.assertEqual(self.shuffle.active_tooltip_text, "shuffle: enabled")
|
||||
|
||||
self.assertEqual(self.shuffle.inactive_icon_name,
|
||||
"media-playlist-consecutive")
|
||||
self.assertEqual(self.shuffle.inactive_tooltip_text,
|
||||
"shuffle: disabled")
|
||||
|
||||
self.assertAlmostEqual(self.shuffle.icon_opacity, 0.5, delta=0.005)
|
||||
|
||||
def test_opacity(self):
|
||||
"""Test adjusting the opacity based on active state."""
|
||||
self.shuffle.active = True
|
||||
|
@ -159,123 +210,123 @@ class TestShuffleButtons(unittest.TestCase):
|
|||
self.assertEqual(self.shuffle.icon_opacity, 0.5)
|
||||
|
||||
|
||||
class TestSortFieldWidget(unittest.TestCase):
|
||||
"""Test the Sort Field widget."""
|
||||
class TestSortRow(unittest.TestCase):
|
||||
"""Test the Sort Row ListBoxRow."""
|
||||
|
||||
def setUp(self):
|
||||
"""Set up common variables."""
|
||||
self.sort = emmental.tracklist.buttons.SortFieldWidget()
|
||||
self.model = emmental.tracklist.sorter.SortOrderModel()
|
||||
self.model[0].enable()
|
||||
self.model[0].reverse()
|
||||
self.model[1].reverse()
|
||||
self.row1 = emmental.tracklist.buttons.SortRow(self.model[0])
|
||||
self.row2 = emmental.tracklist.buttons.SortRow(self.model[1])
|
||||
|
||||
def test_init(self):
|
||||
"""Test that the Sort Field Widget is configured correctly."""
|
||||
self.assertIsInstance(self.sort, Gtk.Box)
|
||||
self.assertIsInstance(self.sort._box, Gtk.Box)
|
||||
self.assertIsInstance(self.sort._name, Gtk.Label)
|
||||
self.assertIsInstance(self.row1, Gtk.ListBoxRow)
|
||||
self.assertIsInstance(self.row1.props.child, Gtk.Box)
|
||||
|
||||
self.assertTrue(self.sort._name.get_hexpand())
|
||||
self.assertEqual(self.row1.props.child.props.margin_start, 6)
|
||||
self.assertEqual(self.row1.props.child.props.margin_end, 6)
|
||||
self.assertEqual(self.row1.props.child.props.margin_top, 6)
|
||||
self.assertEqual(self.row1.props.child.props.margin_bottom, 6)
|
||||
self.assertEqual(self.row1.props.child.props.spacing, 6)
|
||||
|
||||
self.assertEqual(self.sort.get_spacing(), 6)
|
||||
self.assertEqual(self.sort._enabled.get_next_sibling(),
|
||||
self.sort._name)
|
||||
self.assertEqual(self.sort._reverse.get_next_sibling(),
|
||||
self.sort._box)
|
||||
self.assertTrue(self.sort._box.has_css_class("linked"))
|
||||
self.assertEqual(self.row1.sort_field, self.model[0])
|
||||
self.assertTrue(self.row1.active)
|
||||
|
||||
def test_set_sort_field(self):
|
||||
"""Test setting a sort field to the Sort Field Widget."""
|
||||
self.assertIsNone(self.sort.sort_field)
|
||||
self.assertEqual(self.row2.sort_field, self.model[1])
|
||||
self.assertFalse(self.row2.active)
|
||||
|
||||
self.sort.set_sort_field(self.model[0])
|
||||
self.assertEqual(self.sort.sort_field, self.model[0])
|
||||
self.assertEqual(self.sort._name.get_text(), self.model[0].name)
|
||||
self.assertTrue(self.sort._enabled.get_active())
|
||||
self.assertTrue(self.sort._reverse.active)
|
||||
def test_switch(self):
|
||||
"""Test the SortRow switch."""
|
||||
self.assertIsInstance(self.row1._switch, Gtk.Switch)
|
||||
self.assertEqual(self.row1._switch.props.valign, Gtk.Align.CENTER)
|
||||
self.assertEqual(self.row1._switch.props.parent, self.row1.props.child)
|
||||
|
||||
self.sort.set_sort_field(None)
|
||||
self.assertIsNone(self.sort.sort_field)
|
||||
self.assertEqual(self.sort._name.get_text(), "")
|
||||
self.assertFalse(self.sort._enabled.get_active())
|
||||
self.assertFalse(self.sort._reverse.active)
|
||||
self.assertTrue(self.row1._switch.props.active)
|
||||
self.assertFalse(self.row2._switch.props.active)
|
||||
|
||||
def test_enabled(self):
|
||||
"""Test enabling and disabling a sort field."""
|
||||
self.assertIsInstance(self.sort._enabled, Gtk.Switch)
|
||||
self.assertEqual(self.sort._enabled.get_valign(), Gtk.Align.CENTER)
|
||||
self.assertEqual(self.sort.get_first_child(), self.sort._enabled)
|
||||
with unittest.mock.patch.object(self.model[0],
|
||||
"disable") as mock_disable:
|
||||
self.row1._switch.props.active = False
|
||||
mock_disable.assert_called()
|
||||
|
||||
self.sort._enabled.set_active(True)
|
||||
with unittest.mock.patch.object(self.model[0],
|
||||
"enable") as mock_enable:
|
||||
self.row1._switch.props.active = True
|
||||
mock_enable.assert_called()
|
||||
|
||||
self.sort.set_sort_field(self.model[1])
|
||||
self.assertFalse(self.sort._name.get_sensitive())
|
||||
self.assertFalse(self.sort._box.get_sensitive())
|
||||
self.assertFalse(self.sort._reverse.get_sensitive())
|
||||
def test_label(self):
|
||||
"""Test the SortRow title label."""
|
||||
self.assertIsInstance(self.row1._label, Gtk.Label)
|
||||
self.assertEqual(self.row1._switch.get_next_sibling(),
|
||||
self.row1._label)
|
||||
|
||||
self.sort._enabled.set_active(True)
|
||||
self.assertTrue(self.model[1].enabled)
|
||||
self.assertTrue(self.sort._name.get_sensitive())
|
||||
self.assertTrue(self.sort._box.get_sensitive())
|
||||
self.assertTrue(self.sort._reverse.get_sensitive())
|
||||
self.assertEqual(self.row1._label.props.label, self.model[0].name)
|
||||
self.assertEqual(self.row1._label.props.xalign, 0.0)
|
||||
self.assertTrue(self.row1._label.props.hexpand)
|
||||
|
||||
self.sort._enabled.set_active(False)
|
||||
self.assertFalse(self.model[1].enabled)
|
||||
self.assertFalse(self.sort._name.get_sensitive())
|
||||
self.assertFalse(self.sort._box.get_sensitive())
|
||||
self.assertFalse(self.sort._reverse.get_sensitive())
|
||||
|
||||
def test_move_down(self):
|
||||
"""Test the moving a sort field down."""
|
||||
self.assertIsInstance(self.sort._move_down, Gtk.Button)
|
||||
self.assertEqual(self.sort._move_down.get_icon_name(),
|
||||
"go-down-symbolic")
|
||||
self.assertEqual(self.sort._move_up.get_next_sibling(),
|
||||
self.sort._move_down)
|
||||
|
||||
self.sort._move_down.emit("clicked")
|
||||
|
||||
(field := self.model[0]).enable()
|
||||
self.model[1].enable()
|
||||
self.sort.set_sort_field(field)
|
||||
|
||||
self.sort._move_down.emit("clicked")
|
||||
self.assertEqual(self.model.index(field), 1)
|
||||
|
||||
def test_move_up(self):
|
||||
"""Test the moving a sort field."""
|
||||
self.assertIsInstance(self.sort._move_up, Gtk.Button)
|
||||
self.assertEqual(self.sort._move_up.get_icon_name(), "go-up-symbolic")
|
||||
|
||||
self.assertEqual(self.sort._box.get_first_child(),
|
||||
self.sort._move_up)
|
||||
|
||||
self.sort._move_up.emit("clicked")
|
||||
|
||||
self.model[0].enable()
|
||||
(field := self.model[1]).enable()
|
||||
self.sort.set_sort_field(field)
|
||||
|
||||
self.sort._move_up.emit("clicked")
|
||||
self.assertEqual(self.model.index(field), 0)
|
||||
self.assertTrue(self.row1._label.props.sensitive)
|
||||
self.assertFalse(self.row2._label.props.sensitive)
|
||||
|
||||
def test_reverse(self):
|
||||
"""Test reversing a sort field."""
|
||||
self.assertIsInstance(self.sort._reverse, emmental.buttons.ImageToggle)
|
||||
self.assertEqual(self.sort._name.get_next_sibling(),
|
||||
self.sort._reverse)
|
||||
"""Test the SortRow reverse button."""
|
||||
self.assertIsInstance(self.row1._reverse, emmental.buttons.ImageToggle)
|
||||
self.assertEqual(self.row1._label.get_next_sibling(),
|
||||
self.row1._reverse)
|
||||
|
||||
self.assertEqual(self.sort._reverse.active_icon_name, "arrow1-up")
|
||||
self.assertEqual(self.sort._reverse.inactive_icon_name, "arrow1-down")
|
||||
self.assertFalse(self.sort._reverse.large_icon)
|
||||
self.assertEqual(self.row1._reverse.active_icon_name, "arrow1-up")
|
||||
self.assertEqual(self.row1._reverse.inactive_icon_name, "arrow1-down")
|
||||
self.assertFalse(self.row1._reverse.props.has_frame)
|
||||
self.assertFalse(self.row1._reverse.large_icon)
|
||||
|
||||
self.sort._reverse.emit("clicked")
|
||||
self.assertFalse(self.row1._reverse.props.active)
|
||||
self.assertTrue(self.row1._reverse.props.sensitive)
|
||||
|
||||
self.sort.set_sort_field(self.model[0])
|
||||
self.sort._reverse.emit("clicked")
|
||||
self.assertFalse(self.model[0].reversed)
|
||||
self.sort._reverse.emit("clicked")
|
||||
self.assertTrue(self.model[0].reversed)
|
||||
self.assertTrue(self.row2._reverse.props.active)
|
||||
self.assertFalse(self.row2._reverse.props.sensitive)
|
||||
|
||||
with unittest.mock.patch.object(self.model[0],
|
||||
"reverse") as mock_reverse:
|
||||
self.row1._reverse.emit("toggled")
|
||||
mock_reverse.assert_called()
|
||||
|
||||
def test_move_box(self):
|
||||
"""Test the box containing the move up & down buttons."""
|
||||
self.assertIsInstance(self.row1._move_box, Gtk.Box)
|
||||
self.assertEqual(self.row1._reverse.get_next_sibling(),
|
||||
self.row1._move_box)
|
||||
self.assertTrue(self.row1._move_box.has_css_class("linked"))
|
||||
|
||||
self.assertTrue(self.row1._move_box.props.sensitive)
|
||||
self.assertFalse(self.row2._move_box.props.sensitive)
|
||||
|
||||
def test_move_up(self):
|
||||
"""Test the move up button."""
|
||||
self.assertIsInstance(self.row1._move_up, Gtk.Button)
|
||||
self.assertEqual(self.row1._move_up.get_icon_name(),
|
||||
"go-up-symbolic")
|
||||
self.assertEqual(self.row1._move_up.props.parent,
|
||||
self.row1._move_box)
|
||||
|
||||
with unittest.mock.patch.object(self.model[0],
|
||||
"move_up") as mock_move_up:
|
||||
self.row1._move_up.emit("clicked")
|
||||
mock_move_up.assert_called()
|
||||
|
||||
def test_move_down(self):
|
||||
"""Test the move down button."""
|
||||
self.assertIsInstance(self.row1._move_down, Gtk.Button)
|
||||
self.assertEqual(self.row1._move_down.get_icon_name(),
|
||||
"go-down-symbolic")
|
||||
self.assertEqual(self.row1._move_up.get_next_sibling(),
|
||||
self.row1._move_down)
|
||||
|
||||
with unittest.mock.patch.object(self.model[0],
|
||||
"move_down") as mock_move_down:
|
||||
self.row1._move_down.emit("clicked")
|
||||
mock_move_down.assert_called()
|
||||
|
||||
|
||||
class TestSortButton(unittest.TestCase):
|
||||
|
@ -288,45 +339,44 @@ class TestSortButton(unittest.TestCase):
|
|||
def test_init(self):
|
||||
"""Test that the Sort button is configured correctly."""
|
||||
self.assertIsInstance(self.sort, emmental.buttons.PopoverButton)
|
||||
|
||||
self.assertEqual(self.sort.get_icon_name(),
|
||||
"view-list-ordered-symbolic")
|
||||
self.assertEqual(self.sort.get_tooltip_text(),
|
||||
"configure playlist sort order")
|
||||
self.assertFalse(self.sort.get_has_frame())
|
||||
|
||||
def test_popover_child(self):
|
||||
"""Test that the popover_child is configured correctly."""
|
||||
self.assertIsInstance(self.sort.popover_child, Gtk.ListView)
|
||||
self.assertIsInstance(self.sort.model,
|
||||
emmental.tracklist.sorter.SortOrderModel)
|
||||
self.assertIsInstance(self.sort._selection, Gtk.NoSelection)
|
||||
self.assertIsInstance(self.sort._factory, emmental.factory.Factory)
|
||||
self.assertIsInstance(self.sort.popover_child, Gtk.ListBox)
|
||||
self.assertEqual(self.sort.popover_child.props.selection_mode,
|
||||
Gtk.SelectionMode.NONE)
|
||||
self.assertTrue(self.sort.popover_child.has_css_class("boxed-list"))
|
||||
|
||||
self.assertTrue(self.sort.popover_child.get_show_separators())
|
||||
def test_create_func(self):
|
||||
"""Test that the Gtk.ListBox creates SortRows correctly."""
|
||||
row = self.sort.popover_child.get_row_at_index(0)
|
||||
self.assertIsInstance(row, emmental.tracklist.buttons.SortRow)
|
||||
self.assertEqual(row.sort_field, self.sort.model[0])
|
||||
|
||||
self.assertEqual(self.sort.popover_child.get_model(),
|
||||
self.sort._selection)
|
||||
self.assertEqual(self.sort._selection.get_model(), self.sort.model)
|
||||
self.assertEqual(self.sort.popover_child.get_factory(),
|
||||
self.sort._factory)
|
||||
self.assertEqual(self.sort._factory.row_type,
|
||||
emmental.tracklist.buttons.SortRow)
|
||||
def test_activate(self):
|
||||
"""Test activating a Gtk.ListBox sort row."""
|
||||
row = self.sort.popover_child.get_row_at_index(0)
|
||||
field = row.sort_field
|
||||
self.assertFalse(field.enabled)
|
||||
self.assertFalse(field.reversed)
|
||||
|
||||
def test_sort_row(self):
|
||||
"""Test the Sort Row object."""
|
||||
(field := self.sort.model[0]).enable()
|
||||
listitem = Gtk.ListItem()
|
||||
listitem.get_item = lambda: field
|
||||
self.sort.model[1].enable()
|
||||
with unittest.mock.patch.object(field, "enable") as mock_enable:
|
||||
self.sort.popover_child.emit("row-activated", row)
|
||||
mock_enable.assert_called()
|
||||
|
||||
row = emmental.tracklist.buttons.SortRow(listitem)
|
||||
self.assertIsInstance(row, emmental.factory.ListRow)
|
||||
self.assertIsInstance(row.child,
|
||||
emmental.tracklist.buttons.SortFieldWidget)
|
||||
mock_enable.reset_mock()
|
||||
row.active = True
|
||||
|
||||
row.bind()
|
||||
self.assertEqual(row.child.sort_field, field)
|
||||
row.unbind()
|
||||
self.assertIsNone(row.child.sort_field)
|
||||
with unittest.mock.patch.object(field, "reverse") as mock_reverse:
|
||||
self.sort.popover_child.emit("row-activated", row)
|
||||
self.assertTrue(row._reverse.active)
|
||||
mock_enable.assert_not_called()
|
||||
mock_reverse.assert_called()
|
||||
|
||||
def test_sort_order(self):
|
||||
"""Test the sort-order property."""
|
||||
|
|
|
@ -41,11 +41,13 @@ class TestTrackRowWidgets(tests.util.TestCase):
|
|||
row = emmental.tracklist.row.TrackRow(self.listitem, "property")
|
||||
self.assertIsInstance(row, emmental.factory.ListRow)
|
||||
self.assertIsNone(row.album_binding)
|
||||
self.assertIsNone(row.listrow)
|
||||
self.assertEqual(row.property, "property")
|
||||
self.assertEqual(row.mediumid, 0)
|
||||
|
||||
row.child = Gtk.Label()
|
||||
self.columnrow.set_child(row.child)
|
||||
self.assertEqual(row.listrow, self.listrow)
|
||||
self.library.online = False
|
||||
self.track.active = True
|
||||
|
||||
|
@ -54,8 +56,7 @@ class TestTrackRowWidgets(tests.util.TestCase):
|
|||
self.assertFalse(self.listitem.get_activatable())
|
||||
self.assertFalse(row.child.get_sensitive())
|
||||
self.assertTrue(row.active)
|
||||
self.assertTrue(self.listrow.get_state_flags() &
|
||||
Gtk.StateFlags.CHECKED)
|
||||
self.assertTrue(self.listrow.has_css_class("emmental-active-row"))
|
||||
|
||||
self.library.online = True
|
||||
self.track.active = False
|
||||
|
@ -63,8 +64,7 @@ class TestTrackRowWidgets(tests.util.TestCase):
|
|||
self.assertTrue(self.listitem.get_activatable())
|
||||
self.assertTrue(row.child.get_sensitive())
|
||||
self.assertFalse(row.active)
|
||||
self.assertFalse(self.listrow.get_state_flags() &
|
||||
Gtk.StateFlags.CHECKED)
|
||||
self.assertFalse(self.listrow.has_css_class("emmental-active-row"))
|
||||
|
||||
def test_inscription_row(self):
|
||||
"""Test the base Inscription Row."""
|
||||
|
|
|
@ -10,83 +10,65 @@ from gi.repository import Gtk
|
|||
from gi.repository import Adw
|
||||
|
||||
|
||||
class TestPlaylistRowWidget(unittest.TestCase):
|
||||
"""Test the Playlist Row Widget."""
|
||||
class TestPlaylistRow(unittest.TestCase):
|
||||
"""Test the PlaylistRow Widget."""
|
||||
|
||||
def setUp(self):
|
||||
"""Set up common variables."""
|
||||
self.widget = emmental.tracklist.selection.PlaylistRowWidget()
|
||||
cover = tests.util.COVER_JPG
|
||||
self.row = emmental.tracklist.selection.PlaylistRow("name", cover)
|
||||
|
||||
def test_init(self):
|
||||
"""Test that the Playlist Row Widget is set up properly."""
|
||||
self.assertIsInstance(self.widget, Gtk.Box)
|
||||
"""Test that the PlaylistRow Widget is set up properly."""
|
||||
self.assertIsInstance(self.row, Gtk.ListBoxRow)
|
||||
self.assertIsInstance(self.row.props.child, Gtk.Box)
|
||||
|
||||
self.assertEqual(self.row.name, "name")
|
||||
self.assertEqual(self.row.image, tests.util.COVER_JPG)
|
||||
|
||||
self.assertEqual(self.row.props.child.props.margin_start, 6)
|
||||
self.assertEqual(self.row.props.child.props.margin_end, 6)
|
||||
self.assertEqual(self.row.props.child.props.margin_top, 6)
|
||||
self.assertEqual(self.row.props.child.props.margin_bottom, 6)
|
||||
self.assertEqual(self.row.props.child.props.spacing, 6)
|
||||
|
||||
def test_label(self):
|
||||
"""Test the Playlist Row Widget label."""
|
||||
self.widget.name = "Test Playlist Name"
|
||||
self.assertIsInstance(self.widget._label, Gtk.Label)
|
||||
self.assertEqual(self.widget._label.get_text(), "Test Playlist Name")
|
||||
self.assertEqual(self.widget._label.get_xalign(), 0.0)
|
||||
self.assertEqual(self.widget._icon.get_next_sibling(),
|
||||
self.widget._label)
|
||||
"""Test the PlaylistRow Widget label."""
|
||||
self.assertIsInstance(self.row._label, Gtk.Label)
|
||||
self.assertEqual(self.row._label.props.label, "name")
|
||||
self.assertEqual(self.row._icon.get_next_sibling(), self.row._label)
|
||||
|
||||
def test_icon(self):
|
||||
"""Test the Playlist Row Widget icon."""
|
||||
self.assertIsInstance(self.widget._icon, Adw.Avatar)
|
||||
self.assertEqual(self.widget.get_first_child(), self.widget._icon)
|
||||
self.assertEqual(self.widget._icon.get_size(), 32)
|
||||
|
||||
self.widget.name = "Favorite Tracks"
|
||||
self.assertEqual(self.widget._icon.get_icon_name(),
|
||||
"heart-filled-symbolic")
|
||||
self.assertEqual(self.widget._icon.get_text(), "Favorite Tracks")
|
||||
|
||||
self.widget.name = "Queued Tracks"
|
||||
self.assertEqual(self.widget._icon.get_icon_name(),
|
||||
"music-queue-symbolic")
|
||||
self.assertEqual(self.widget._icon.get_text(), "Queued Tracks")
|
||||
|
||||
self.widget.name = "Any Other Name"
|
||||
self.assertEqual(self.widget._icon.get_icon_name(),
|
||||
"""Test the PlaylistRow Widget icon."""
|
||||
self.assertIsInstance(self.row._icon, Adw.Avatar)
|
||||
self.assertEqual(self.row.props.child.get_first_child(),
|
||||
self.row._icon)
|
||||
self.assertEqual(self.row._icon.get_size(), 32)
|
||||
self.assertEqual(self.row._icon.get_text(), "name")
|
||||
self.assertEqual(self.row._icon.get_icon_name(),
|
||||
"playlist2-symbolic")
|
||||
self.assertEqual(self.widget._icon.get_text(), "Any Other Name")
|
||||
|
||||
fav = emmental.tracklist.selection.PlaylistRow("Favorite Tracks", None)
|
||||
self.assertEqual(fav._icon.props.icon_name, "heart-filled-symbolic")
|
||||
|
||||
queue = emmental.tracklist.selection.PlaylistRow("Queued Tracks", None)
|
||||
self.assertEqual(queue._icon.props.icon_name, "music-queue-symbolic")
|
||||
|
||||
def test_image(self):
|
||||
"""Test the Playlist Row Widget image."""
|
||||
self.assertIsNone(self.widget.image)
|
||||
self.widget.image = tests.util.COVER_JPG
|
||||
self.assertIsNotNone(self.widget._icon.get_custom_image())
|
||||
self.widget.image = None
|
||||
self.assertIsNone(self.widget._icon.get_custom_image())
|
||||
self.widget.image = pathlib.Path("/a/b/c.jpg")
|
||||
self.assertIsNone(self.widget._icon.get_custom_image())
|
||||
"""Test the PlaylistRow Widget image."""
|
||||
self.assertIsNotNone(self.row._icon.props.custom_image)
|
||||
|
||||
none = emmental.tracklist.selection.PlaylistRow("none", None)
|
||||
self.assertIsNone(none.image)
|
||||
self.assertIsNone(none._icon.props.custom_image)
|
||||
|
||||
class TestPlaylistRow(tests.util.TestCase):
|
||||
"""Test the PlaylistRow widget."""
|
||||
later = emmental.tracklist.selection.PlaylistRow("later", None)
|
||||
later.image = tests.util.COVER_JPG
|
||||
self.assertIsNotNone(later._icon.props.custom_image)
|
||||
|
||||
def setUp(self):
|
||||
"""Set up common variables."""
|
||||
super().setUp()
|
||||
self.playlist = self.sql.playlists.create("Test Playlist")
|
||||
self.listitem = Gtk.ListItem()
|
||||
self.listitem.get_item = unittest.mock.Mock(return_value=self.playlist)
|
||||
self.row = emmental.tracklist.selection.PlaylistRow(self.listitem)
|
||||
|
||||
def test_init(self):
|
||||
"""Test that the PlaylistRow is initialized properly."""
|
||||
self.assertIsInstance(self.row, emmental.factory.ListRow)
|
||||
self.assertIsInstance(self.row.child,
|
||||
emmental.tracklist.selection.PlaylistRowWidget)
|
||||
|
||||
def test_bind(self):
|
||||
"""Test binding the PlaylistRow."""
|
||||
self.row.bind()
|
||||
self.assertEqual(self.row.child.name, "Test Playlist")
|
||||
self.assertIsNone(self.row.child.image)
|
||||
|
||||
self.playlist.image = pathlib.Path("/a/b/c.jpg")
|
||||
self.assertEqual(self.row.child.image, pathlib.Path("/a/b/c.jpg"))
|
||||
path = pathlib.Path("/a/b/c.jpg")
|
||||
inval = emmental.tracklist.selection.PlaylistRow("inval", path)
|
||||
self.assertIsNone(inval._icon.props.custom_image)
|
||||
|
||||
|
||||
class TestUserTracksFilter(tests.util.TestCase):
|
||||
|
@ -134,35 +116,38 @@ class TestPlaylistView(tests.util.TestCase):
|
|||
|
||||
def test_init(self):
|
||||
"""Test that the Playlist View is set up properly."""
|
||||
self.assertIsInstance(self.view, Gtk.ListView)
|
||||
self.assertIsInstance(self.view, Gtk.ListBox)
|
||||
self.assertEqual(self.view.props.selection_mode,
|
||||
Gtk.SelectionMode.NONE)
|
||||
self.assertTrue(self.view.has_css_class("boxed-list"))
|
||||
|
||||
self.assertTrue(self.view.get_show_separators())
|
||||
self.assertTrue(self.view.get_single_click_activate())
|
||||
self.assertTrue(self.view.has_css_class("rich-list"))
|
||||
|
||||
def test_models(self):
|
||||
"""Test that the models have been connected correctly."""
|
||||
self.assertIsInstance(self.view._selection, Gtk.NoSelection)
|
||||
def test_filter_model(self):
|
||||
"""Test that the filter model has been connected correctly."""
|
||||
self.assertIsInstance(self.view._filtered, Gtk.FilterListModel)
|
||||
self.assertIsInstance(self.view._filtered.get_filter(),
|
||||
emmental.tracklist.selection.UserTracksFilter)
|
||||
|
||||
self.assertEqual(self.view.get_model(), self.view._selection)
|
||||
self.assertEqual(self.view._selection.get_model(), self.view._filtered)
|
||||
self.assertEqual(self.view._filtered.get_model(), self.sql.playlists)
|
||||
|
||||
def test_factory(self):
|
||||
"""Test that the factory has been configured correctly."""
|
||||
self.assertIsInstance(self.view._factory, emmental.factory.Factory)
|
||||
self.assertEqual(self.view.get_factory(), self.view._factory)
|
||||
self.assertEqual(self.view._factory.row_type,
|
||||
emmental.tracklist.selection.PlaylistRow)
|
||||
self.view.playlist = self.sql.playlists.collection
|
||||
self.assertEqual(self.view._filtered.get_filter().playlist,
|
||||
self.sql.playlists.collection)
|
||||
|
||||
def test_create_func(self):
|
||||
"""Test that the PlaylistView creates PlaylistRows correctly."""
|
||||
row = self.view.get_row_at_index(0)
|
||||
self.assertIsInstance(row, emmental.tracklist.selection.PlaylistRow)
|
||||
self.assertEqual(row.name, "Favorite Tracks")
|
||||
self.assertEqual(row.image, None)
|
||||
|
||||
self.sql.playlists.favorites.image = tests.util.COVER_JPG
|
||||
self.assertEqual(row.image, tests.util.COVER_JPG)
|
||||
|
||||
def test_activate(self):
|
||||
"""Test activating a Playlist Row for adding tracks."""
|
||||
selected = unittest.mock.Mock()
|
||||
self.view.connect("playlist-selected", selected)
|
||||
self.view.emit("activate", 0)
|
||||
|
||||
self.view.emit("row-activated", self.view.get_row_at_index(0))
|
||||
selected.assert_called_with(self.view, self.sql.playlists.favorites)
|
||||
|
||||
|
||||
|
@ -184,6 +169,8 @@ class TestMoveButtons(unittest.TestCase):
|
|||
"""Test the move down button."""
|
||||
self.assertIsInstance(self.move._down, Gtk.Button)
|
||||
self.assertEqual(self.move._down.get_icon_name(), "go-down-symbolic")
|
||||
self.assertEqual(self.move._down.get_tooltip_text(),
|
||||
"move selected track down")
|
||||
self.assertTrue(self.move._down.has_css_class("opaque"))
|
||||
self.assertTrue(self.move._down.has_css_class("pill"))
|
||||
self.assertTrue(self.move._down.get_hexpand())
|
||||
|
@ -209,6 +196,8 @@ class TestMoveButtons(unittest.TestCase):
|
|||
"""Test the move up button."""
|
||||
self.assertIsInstance(self.move._up, Gtk.Button)
|
||||
self.assertEqual(self.move._up.get_icon_name(), "go-up-symbolic")
|
||||
self.assertEqual(self.move._up.get_tooltip_text(),
|
||||
"move selected track up")
|
||||
self.assertTrue(self.move._up.has_css_class("opaque"))
|
||||
self.assertTrue(self.move._up.has_css_class("pill"))
|
||||
self.assertTrue(self.move._up.get_hexpand())
|
||||
|
@ -264,6 +253,8 @@ class TestOsd(tests.util.TestCase):
|
|||
self.assertEqual(self.osd._add.get_child().get_icon_name(),
|
||||
"list-add-symbolic")
|
||||
self.assertEqual(self.osd._add.get_child().get_label(), "Add")
|
||||
self.assertEqual(self.osd._add.get_tooltip_text(),
|
||||
"add selected tracks to a playlist")
|
||||
self.assertEqual(self.osd._add.get_halign(), Gtk.Align.START)
|
||||
self.assertEqual(self.osd._add.get_valign(), Gtk.Align.END)
|
||||
self.assertEqual(self.osd._add.get_margin_start(), 16)
|
||||
|
@ -313,6 +304,8 @@ class TestOsd(tests.util.TestCase):
|
|||
self.assertEqual(self.osd._remove.get_child().get_icon_name(),
|
||||
"list-remove-symbolic")
|
||||
self.assertEqual(self.osd._remove.get_child().get_label(), "Remove")
|
||||
self.assertEqual(self.osd._remove.get_tooltip_text(),
|
||||
"remove selected tracks")
|
||||
self.assertEqual(self.osd._remove.get_halign(), Gtk.Align.END)
|
||||
self.assertEqual(self.osd._remove.get_valign(), Gtk.Align.END)
|
||||
self.assertEqual(self.osd._remove.get_margin_end(), 16)
|
||||
|
@ -463,3 +456,28 @@ class TestOsd(tests.util.TestCase):
|
|||
self.osd.reset()
|
||||
mock_unselect.assert_called()
|
||||
self.assertFalse(self.osd.have_selected)
|
||||
|
||||
def test_accelerators(self):
|
||||
"""Test that the accelerators list is set up properly."""
|
||||
entries = [("remove-selected-tracks", self.osd._remove.activate,
|
||||
["Delete"], self.osd._remove, "visible"),
|
||||
("move-track-up", self.osd._move._up.activate,
|
||||
["<Control>Up"], self.osd._move, "can-move-up"),
|
||||
("move-track-down", self.osd._move._down.activate,
|
||||
["<Control>Down"], self.osd._move, "can-move-down")]
|
||||
|
||||
accels = self.osd.accelerators
|
||||
self.assertIsInstance(accels, list)
|
||||
|
||||
for i, (name, func, accel, gobject, prop) in enumerate(entries):
|
||||
with self.subTest(action=name):
|
||||
self.assertIsInstance(accels[i], emmental.action.ActionEntry)
|
||||
self.assertEqual(accels[i].name, name)
|
||||
self.assertEqual(accels[i].func, func)
|
||||
self.assertEqual(accels[i].accels, accel)
|
||||
|
||||
if gobject and prop:
|
||||
enabled = gobject.get_property(prop)
|
||||
self.assertEqual(accels[i].enabled, enabled)
|
||||
gobject.set_property(prop, not enabled)
|
||||
self.assertEqual(accels[i].enabled, not enabled)
|
||||
|
|
|
@ -27,11 +27,9 @@ class TestTracklist(tests.util.TestCase):
|
|||
self.assertIsInstance(self.tracklist._top_right, Gtk.Box)
|
||||
|
||||
self.assertEqual(self.tracklist.sql, self.sql)
|
||||
self.assertEqual(self.tracklist.get_spacing(), 6)
|
||||
self.assertEqual(self.tracklist.get_orientation(),
|
||||
Gtk.Orientation.VERTICAL)
|
||||
|
||||
self.assertEqual(self.tracklist._top_box.get_margin_top(), 6)
|
||||
self.assertEqual(self.tracklist._top_box.get_margin_start(), 6)
|
||||
self.assertEqual(self.tracklist._top_box.get_margin_end(), 6)
|
||||
self.assertEqual(self.tracklist._top_box.get_orientation(),
|
||||
|
@ -44,6 +42,7 @@ class TestTracklist(tests.util.TestCase):
|
|||
self.assertEqual(self.tracklist._top_box.get_end_widget(),
|
||||
self.tracklist._top_right)
|
||||
|
||||
self.assertTrue(self.tracklist._top_box.has_css_class("toolbar"))
|
||||
self.assertTrue(self.tracklist.has_css_class("card"))
|
||||
|
||||
def test_visible_columns(self):
|
||||
|
@ -61,14 +60,16 @@ class TestTracklist(tests.util.TestCase):
|
|||
self.assertIsInstance(self.tracklist._unselect, Gtk.Button)
|
||||
self.assertEqual(self.tracklist._unselect.get_icon_name(),
|
||||
"edit-select-none-symbolic")
|
||||
self.assertEqual(self.tracklist._unselect.get_tooltip_text(),
|
||||
"unselect all tracks")
|
||||
self.assertFalse(self.tracklist._unselect.get_has_frame())
|
||||
|
||||
self.assertFalse(self.tracklist._unselect.get_sensitive())
|
||||
self.tracklist._trackview.have_selected = True
|
||||
self.assertTrue(self.tracklist._unselect.get_sensitive())
|
||||
|
||||
with unittest.mock.patch.object(self.tracklist._trackview,
|
||||
"clear_selected_tracks") as mock_clear:
|
||||
with unittest.mock.patch.object(self.tracklist._osd.selection,
|
||||
"unselect_all") as mock_clear:
|
||||
self.tracklist._unselect.emit("clicked")
|
||||
mock_clear.assert_called()
|
||||
|
||||
|
@ -161,23 +162,45 @@ class TestTracklist(tests.util.TestCase):
|
|||
"""Test the Trackview widget."""
|
||||
self.assertIsInstance(self.tracklist._trackview,
|
||||
emmental.tracklist.trackview.TrackView)
|
||||
self.assertEqual(self.tracklist._top_box.get_next_sibling(),
|
||||
self.tracklist._trackview)
|
||||
|
||||
self.assertEqual(self.tracklist._trackview.get_margin_start(), 6)
|
||||
self.assertEqual(self.tracklist._trackview.get_margin_end(), 6)
|
||||
self.assertEqual(self.tracklist.columns,
|
||||
self.tracklist._trackview.columns)
|
||||
|
||||
sep = self.tracklist._top_box.get_next_sibling()
|
||||
self.assertIsInstance(sep, Gtk.Separator)
|
||||
self.assertEqual(sep.get_orientation(), Gtk.Orientation.HORIZONTAL)
|
||||
self.assertEqual(sep.get_next_sibling(), self.tracklist._osd)
|
||||
self.assertEqual(self.tracklist._osd.get_child(),
|
||||
self.tracklist._trackview)
|
||||
|
||||
def test_osd(self):
|
||||
"""Test the OSD widget."""
|
||||
self.assertIsInstance(self.tracklist._osd,
|
||||
emmental.tracklist.selection.OSD)
|
||||
self.assertEqual(self.tracklist._osd.sql, self.sql)
|
||||
self.assertEqual(self.tracklist._osd.selection,
|
||||
self.tracklist._trackview.selection_model)
|
||||
|
||||
self.assertFalse(self.tracklist._trackview.have_selected)
|
||||
self.tracklist._osd.have_selected = True
|
||||
self.assertTrue(self.tracklist._trackview.have_selected)
|
||||
|
||||
self.assertEqual(self.tracklist._trackview.n_selected, 0)
|
||||
self.tracklist._osd.n_selected = 4
|
||||
self.assertEqual(self.tracklist._trackview.n_selected, 4)
|
||||
|
||||
def test_footer(self):
|
||||
"""Test that the footer is wired up properly."""
|
||||
self.assertIsInstance(self.tracklist._footer,
|
||||
emmental.tracklist.footer.Footer)
|
||||
self.assertEqual(self.tracklist._footer.get_margin_start(), 6)
|
||||
self.assertEqual(self.tracklist._footer.get_margin_end(), 6)
|
||||
self.assertEqual(self.tracklist._footer.get_margin_top(), 6)
|
||||
self.assertEqual(self.tracklist._footer.get_margin_bottom(), 6)
|
||||
self.assertEqual(self.tracklist._trackview.get_next_sibling(),
|
||||
self.tracklist._footer)
|
||||
|
||||
sep = self.tracklist._osd.get_next_sibling()
|
||||
self.assertIsInstance(sep, Gtk.Separator)
|
||||
self.assertEqual(sep.get_orientation(), Gtk.Orientation.HORIZONTAL)
|
||||
self.assertEqual(sep.get_next_sibling(), self.tracklist._footer)
|
||||
|
||||
self.tracklist._trackview.n_tracks = 5
|
||||
self.tracklist._trackview.n_selected = 3
|
||||
|
@ -192,11 +215,12 @@ class TestTracklist(tests.util.TestCase):
|
|||
self.assertIsNone(self.tracklist.playlist)
|
||||
self.assertFalse(self.tracklist._top_right.get_sensitive())
|
||||
|
||||
with unittest.mock.patch.object(self.tracklist._trackview,
|
||||
"reset_osd") as mock_reset_osd:
|
||||
with unittest.mock.patch.object(self.tracklist._osd,
|
||||
"reset") as mock_reset_osd:
|
||||
self.tracklist.playlist = self.playlist
|
||||
self.assertEqual(self.tracklist.playlist, self.playlist)
|
||||
self.assertEqual(self.tracklist._trackview.playlist, self.playlist)
|
||||
self.assertEqual(self.tracklist._osd.playlist, self.playlist)
|
||||
self.assertTrue(self.tracklist._top_right.get_sensitive())
|
||||
mock_reset_osd.assert_called()
|
||||
|
||||
|
@ -226,3 +250,40 @@ class TestTracklist(tests.util.TestCase):
|
|||
self.assertEqual(self.tracklist._Card__scroll_idle(None),
|
||||
GLib.SOURCE_REMOVE)
|
||||
mock_scroll.assert_called_with(None)
|
||||
|
||||
def test_accelerators(self):
|
||||
"""Check that the accelerators list is set up properly."""
|
||||
entries = [("focus-search-track", self.tracklist._filter.grab_focus,
|
||||
["<Control>slash"], None, None),
|
||||
("clear-selected-tracks", self.tracklist._unselect.activate,
|
||||
["Escape"], self.tracklist._unselect, "sensitive"),
|
||||
("cycle-loop", self.tracklist._loop.activate,
|
||||
["<Control>l"], self.tracklist._top_right, "sensitive"),
|
||||
("toggle-shuffle", self.tracklist._shuffle.activate,
|
||||
["<Control>s"], self.tracklist._top_right, "sensitive")]
|
||||
|
||||
accels = self.tracklist.accelerators
|
||||
self.assertIsInstance(accels, list)
|
||||
|
||||
for i, (name, func, accel, gobject, prop) in enumerate(entries):
|
||||
with self.subTest(action=name):
|
||||
self.assertIsInstance(accels[i], emmental.action.ActionEntry)
|
||||
self.assertEqual(accels[i].name, name)
|
||||
self.assertEqual(accels[i].func, func)
|
||||
self.assertListEqual(accels[i].accels, accel)
|
||||
|
||||
if gobject and prop:
|
||||
enabled = gobject.get_property(prop)
|
||||
self.assertEqual(accels[i].enabled, enabled)
|
||||
gobject.set_property(prop, not enabled)
|
||||
self.assertEqual(accels[i].enabled, not enabled)
|
||||
|
||||
start = len(entries)
|
||||
osd_accels = self.tracklist._osd.accelerators
|
||||
for i, accel in enumerate(osd_accels):
|
||||
with self.subTest(name=accel.name):
|
||||
self.assertIsInstance(accels[start + i],
|
||||
emmental.action.ActionEntry)
|
||||
self.assertEqual(accels[start + i].name, accel.name)
|
||||
self.assertEqual(accels[start + i].func, accel.func)
|
||||
self.assertListEqual(accels[start + i].accels, accel.accels)
|
||||
|
|
|
@ -28,15 +28,8 @@ class TestTrackView(tests.util.TestCase):
|
|||
|
||||
def test_init(self):
|
||||
"""Test that the TrackView is initialized properly."""
|
||||
self.assertIsInstance(self.trackview, Gtk.Frame)
|
||||
self.assertIsInstance(self.trackview._scrollwin, Gtk.ScrolledWindow)
|
||||
self.assertIsInstance(self.trackview._osd,
|
||||
emmental.tracklist.selection.OSD)
|
||||
|
||||
self.assertEqual(self.trackview.get_child(), self.trackview._osd)
|
||||
self.assertEqual(self.trackview._osd.get_child(),
|
||||
self.trackview._scrollwin)
|
||||
self.assertEqual(self.trackview._scrollwin.get_child(),
|
||||
self.assertIsInstance(self.trackview, Gtk.ScrolledWindow)
|
||||
self.assertEqual(self.trackview.get_child(),
|
||||
self.trackview._columnview)
|
||||
|
||||
def test_list_models(self):
|
||||
|
@ -50,6 +43,8 @@ class TestTrackView(tests.util.TestCase):
|
|||
|
||||
self.assertEqual(self.trackview._selection.get_model(),
|
||||
self.trackview._filtermodel)
|
||||
self.assertEqual(self.trackview.selection_model,
|
||||
self.trackview._selection)
|
||||
|
||||
def test_columnview(self):
|
||||
"""Test the columnview."""
|
||||
|
@ -80,27 +75,12 @@ class TestTrackView(tests.util.TestCase):
|
|||
requested.assert_called_with(self.playlist, self.track)
|
||||
mock_unselect.assert_called()
|
||||
|
||||
def test_clear_selected_tracks(self):
|
||||
"""Test the clear_selected_tracks() function."""
|
||||
with unittest.mock.patch.object(self.trackview._osd,
|
||||
"clear_selection") as mock_clear:
|
||||
self.trackview.clear_selected_tracks()
|
||||
mock_clear.assert_called()
|
||||
|
||||
def test_reset_osd(self):
|
||||
"""Test the reset_osd() function."""
|
||||
with unittest.mock.patch.object(self.trackview._osd,
|
||||
"reset") as mock_reset:
|
||||
self.trackview.reset_osd()
|
||||
mock_reset.assert_called()
|
||||
|
||||
def test_playlist(self):
|
||||
"""Test the playlist property."""
|
||||
self.assertIsNone(self.trackview.playlist)
|
||||
self.trackview.playlist = self.playlist
|
||||
self.assertEqual(self.trackview._filtermodel.get_model(),
|
||||
self.playlist)
|
||||
self.assertEqual(self.trackview._osd.playlist, self.playlist)
|
||||
|
||||
def test_n_tracks(self):
|
||||
"""Test the n-tracks property."""
|
||||
|
@ -116,17 +96,6 @@ class TestTrackView(tests.util.TestCase):
|
|||
self.db_plist.add_track(self.track)
|
||||
self.assertEqual(self.trackview.runtime, 10.0)
|
||||
|
||||
def test_n_selected(self):
|
||||
"""Test the n-selected and have-selected properties."""
|
||||
self.assertEqual(self.trackview.n_selected, 0)
|
||||
self.assertFalse(self.trackview.have_selected)
|
||||
|
||||
self.trackview._osd.n_selected = 4
|
||||
self.trackview._osd.have_selected = True
|
||||
|
||||
self.assertEqual(self.trackview.n_selected, 4)
|
||||
self.assertTrue(self.trackview.have_selected)
|
||||
|
||||
|
||||
class TestTrackViewColumns(tests.util.TestCase):
|
||||
"""Test the TrackView Columns."""
|
||||
|
|
Loading…
Reference in New Issue