redesign connection panel and use Avahi instead of profiles
This commit is contained in:
parent
ba47b38960
commit
3935f6ae5f
4 changed files with 143 additions and 237 deletions
|
|
@ -1,6 +1,26 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<schemalist>
|
<schemalist>
|
||||||
<schema path="/de/coderkun/mcg/" id="de.coderkun.mcg" gettext-domain="mcg">
|
<schema path="/de/coderkun/mcg/" id="de.coderkun.mcg" gettext-domain="mcg">
|
||||||
|
<key type="s" name="host">
|
||||||
|
<default>'localhost'</default>
|
||||||
|
<summary>MPD host</summary>
|
||||||
|
<description>MPD host to connect to</description>
|
||||||
|
</key>
|
||||||
|
<key type="i" name="port">
|
||||||
|
<default>6600</default>
|
||||||
|
<summary>MPD port</summary>
|
||||||
|
<description>MPD port to connect to</description>
|
||||||
|
</key>
|
||||||
|
<key type="s" name="image-dir">
|
||||||
|
<default>''</default>
|
||||||
|
<summary>Image dir</summary>
|
||||||
|
<description>Directory which a webserver is providing images on</description>
|
||||||
|
</key>
|
||||||
|
<key type="b" name="connected">
|
||||||
|
<default>false</default>
|
||||||
|
<summary>Connection state</summary>
|
||||||
|
<description>State of last connection</description>
|
||||||
|
</key>
|
||||||
<key type="ai" name="window-size">
|
<key type="ai" name="window-size">
|
||||||
<default>[800, 600]</default>
|
<default>[800, 600]</default>
|
||||||
<summary>Window size</summary>
|
<summary>Window size</summary>
|
||||||
|
|
@ -11,11 +31,6 @@
|
||||||
<summary>Window maximized</summary>
|
<summary>Window maximized</summary>
|
||||||
<description>Window maximized state.</description>
|
<description>Window maximized state.</description>
|
||||||
</key>
|
</key>
|
||||||
<key type="i" name="profile">
|
|
||||||
<default>0</default>
|
|
||||||
<summary>Last selected profile</summary>
|
|
||||||
<description>The index of the last selected profile used to connect to the MPD server.</description>
|
|
||||||
</key>
|
|
||||||
<key type="i" name="panel">
|
<key type="i" name="panel">
|
||||||
<range min="1" max="3"/>
|
<range min="1" max="3"/>
|
||||||
<default>1</default>
|
<default>1</default>
|
||||||
|
|
|
||||||
Binary file not shown.
240
gui/gtk.py
240
gui/gtk.py
|
|
@ -18,6 +18,7 @@ import threading
|
||||||
import urllib
|
import urllib
|
||||||
|
|
||||||
from gi.repository import Gio, Gtk, Gdk, GObject, GdkPixbuf, GLib
|
from gi.repository import Gio, Gtk, Gdk, GObject, GdkPixbuf, GLib
|
||||||
|
from gi.repository import Avahi
|
||||||
|
|
||||||
import mcg
|
import mcg
|
||||||
|
|
||||||
|
|
@ -27,9 +28,12 @@ import mcg
|
||||||
class Application(Gtk.Application):
|
class Application(Gtk.Application):
|
||||||
TITLE = "MPDCoverGrid (Gtk)"
|
TITLE = "MPDCoverGrid (Gtk)"
|
||||||
SETTINGS_BASE_KEY = 'de.coderkun.mcg'
|
SETTINGS_BASE_KEY = 'de.coderkun.mcg'
|
||||||
|
SETTING_HOST = 'host'
|
||||||
|
SETTING_PORT = 'port'
|
||||||
|
SETTING_CONNECTED = 'connected'
|
||||||
|
SETTING_IMAGE_DIR = 'image-dir'
|
||||||
SETTING_WINDOW_SIZE = 'window-size'
|
SETTING_WINDOW_SIZE = 'window-size'
|
||||||
SETTING_WINDOW_MAXIMIZED = 'window-maximized'
|
SETTING_WINDOW_MAXIMIZED = 'window-maximized'
|
||||||
SETTING_PROFILE = 'profile'
|
|
||||||
SETTING_PANEL = 'panel'
|
SETTING_PANEL = 'panel'
|
||||||
SETTING_ITEM_SIZE = 'item-size'
|
SETTING_ITEM_SIZE = 'item-size'
|
||||||
SETTING_SORT_ORDER = 'sort-order'
|
SETTING_SORT_ORDER = 'sort-order'
|
||||||
|
|
@ -156,6 +160,9 @@ class Window(Gtk.ApplicationWindow):
|
||||||
""")
|
""")
|
||||||
self.get_style_context().add_provider_for_screen(Gdk.Screen.get_default(), styleProvider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
|
self.get_style_context().add_provider_for_screen(Gdk.Screen.get_default(), styleProvider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
|
||||||
self.get_style_context().add_class(Window.STYLE_CLASS_BG_TEXTURE)
|
self.get_style_context().add_class(Window.STYLE_CLASS_BG_TEXTURE)
|
||||||
|
self._panels[Window._PANEL_INDEX_CONNECTION].set_host(self._settings.get_string(Application.SETTING_HOST))
|
||||||
|
self._panels[Window._PANEL_INDEX_CONNECTION].set_port(self._settings.get_int(Application.SETTING_PORT))
|
||||||
|
self._panels[Window._PANEL_INDEX_CONNECTION].set_image_dir(self._settings.get_string(Application.SETTING_IMAGE_DIR))
|
||||||
self._panels[Window._PANEL_INDEX_PLAYLIST].set_item_size(self._settings.get_int(Application.SETTING_ITEM_SIZE))
|
self._panels[Window._PANEL_INDEX_PLAYLIST].set_item_size(self._settings.get_int(Application.SETTING_ITEM_SIZE))
|
||||||
self._panels[Window._PANEL_INDEX_LIBRARY].set_item_size(self._settings.get_int(Application.SETTING_ITEM_SIZE))
|
self._panels[Window._PANEL_INDEX_LIBRARY].set_item_size(self._settings.get_int(Application.SETTING_ITEM_SIZE))
|
||||||
self._panels[Window._PANEL_INDEX_LIBRARY].set_sort_order(self._settings.get_string(Application.SETTING_SORT_ORDER))
|
self._panels[Window._PANEL_INDEX_LIBRARY].set_sort_order(self._settings.get_string(Application.SETTING_SORT_ORDER))
|
||||||
|
|
@ -169,7 +176,7 @@ class Window(Gtk.ApplicationWindow):
|
||||||
self._header_bar.connect_signal(HeaderBar.SIGNAL_CONNECT, self.on_header_bar_connect)
|
self._header_bar.connect_signal(HeaderBar.SIGNAL_CONNECT, self.on_header_bar_connect)
|
||||||
self._header_bar.connect_signal(HeaderBar.SIGNAL_PLAYPAUSE, self.on_header_bar_playpause)
|
self._header_bar.connect_signal(HeaderBar.SIGNAL_PLAYPAUSE, self.on_header_bar_playpause)
|
||||||
self._header_bar.connect_signal(HeaderBar.SIGNAL_SET_VOLUME, self.on_header_bar_set_volume)
|
self._header_bar.connect_signal(HeaderBar.SIGNAL_SET_VOLUME, self.on_header_bar_set_volume)
|
||||||
self._panels[Window._PANEL_INDEX_CONNECTION].connect_signal(ConnectionPanel.SIGNAL_PROFILE_CHANGED, self.on_connection_panel_profile_changed)
|
self._panels[Window._PANEL_INDEX_CONNECTION].connect_signal(ConnectionPanel.SIGNAL_CONNECTION_CHANGED, self.on_connection_panel_connection_changed)
|
||||||
self._panels[Window._PANEL_INDEX_PLAYLIST].connect_signal(PlaylistPanel.SIGNAL_CLEAR_PLAYLIST, self.on_playlist_panel_clear_playlist)
|
self._panels[Window._PANEL_INDEX_PLAYLIST].connect_signal(PlaylistPanel.SIGNAL_CLEAR_PLAYLIST, self.on_playlist_panel_clear_playlist)
|
||||||
self._panels[Window._PANEL_INDEX_COVER].connect_signal(CoverPanel.SIGNAL_TOGGLE_FULLSCREEN, self.on_cover_panel_toggle_fullscreen)
|
self._panels[Window._PANEL_INDEX_COVER].connect_signal(CoverPanel.SIGNAL_TOGGLE_FULLSCREEN, self.on_cover_panel_toggle_fullscreen)
|
||||||
self._panels[Window._PANEL_INDEX_COVER].connect_signal(CoverPanel.SIGNAL_SET_SONG, self.on_cover_panel_set_song)
|
self._panels[Window._PANEL_INDEX_COVER].connect_signal(CoverPanel.SIGNAL_SET_SONG, self.on_cover_panel_set_song)
|
||||||
|
|
@ -195,7 +202,8 @@ class Window(Gtk.ApplicationWindow):
|
||||||
self.show_all()
|
self.show_all()
|
||||||
self._infobar.hide()
|
self._infobar.hide()
|
||||||
self._stack.set_visible_child(self._panels[Window._PANEL_INDEX_CONNECTION])
|
self._stack.set_visible_child(self._panels[Window._PANEL_INDEX_CONNECTION])
|
||||||
self._panels[Window._PANEL_INDEX_CONNECTION].select_profile(self._settings.get_int(Application.SETTING_PROFILE))
|
if self._settings.get_boolean(Application.SETTING_CONNECTED):
|
||||||
|
self._connect()
|
||||||
|
|
||||||
|
|
||||||
def on_resize(self, widget, event):
|
def on_resize(self, widget, event):
|
||||||
|
|
@ -234,10 +242,10 @@ class Window(Gtk.ApplicationWindow):
|
||||||
|
|
||||||
# Panel callbacks
|
# Panel callbacks
|
||||||
|
|
||||||
def on_connection_panel_profile_changed(self, index, profile):
|
def on_connection_panel_connection_changed(self, host, port, password, image_dir):
|
||||||
self._settings.set_int(Application.SETTING_PROFILE, index)
|
self._settings.set_string(Application.SETTING_HOST, host)
|
||||||
if ConnectionPanel.TAG_AUTOCONNECT in profile.get_tags():
|
self._settings.set_int(Application.SETTING_PORT, port)
|
||||||
self._connect()
|
self._settings.set_string(Application.SETTING_IMAGE_DIR, image_dir)
|
||||||
|
|
||||||
|
|
||||||
def on_playlist_panel_clear_playlist(self):
|
def on_playlist_panel_clear_playlist(self):
|
||||||
|
|
@ -353,12 +361,14 @@ class Window(Gtk.ApplicationWindow):
|
||||||
self._header_bar.set_sensitive(False, True)
|
self._header_bar.set_sensitive(False, True)
|
||||||
if self._mcg.is_connected():
|
if self._mcg.is_connected():
|
||||||
self._mcg.disconnect()
|
self._mcg.disconnect()
|
||||||
|
self._settings.set_boolean(Application.SETTING_CONNECTED, False)
|
||||||
else:
|
else:
|
||||||
host = connection_panel.get_host()
|
host = connection_panel.get_host()
|
||||||
port = connection_panel.get_port()
|
port = connection_panel.get_port()
|
||||||
password = connection_panel.get_password()
|
password = connection_panel.get_password()
|
||||||
image_dir = connection_panel.get_image_dir()
|
image_dir = connection_panel.get_image_dir()
|
||||||
self._mcg.connect(host, port, password, image_dir)
|
self._mcg.connect(host, port, password, image_dir)
|
||||||
|
self._settings.set_boolean(Application.SETTING_CONNECTED, True)
|
||||||
|
|
||||||
|
|
||||||
def _connect_connected(self):
|
def _connect_connected(self):
|
||||||
|
|
@ -564,90 +574,83 @@ class Panel(mcg.Base):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ConnectionPanel(Panel, Gtk.HBox):
|
class ConnectionPanel(Panel, Gtk.VBox):
|
||||||
SIGNAL_PROFILE_CHANGED = 'profile-changed'
|
SIGNAL_CONNECTION_CHANGED = 'connection-changed'
|
||||||
TAG_AUTOCONNECT = 'autoconnect'
|
|
||||||
|
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
Panel.__init__(self)
|
Panel.__init__(self)
|
||||||
Gtk.HBox.__init__(self)
|
Gtk.VBox.__init__(self)
|
||||||
self._profile_config = mcg.MCGProfileConfig()
|
self._services = Gtk.ListStore(str, str, int)
|
||||||
self._profiles = Gtk.ListStore(str)
|
|
||||||
self._profile = None
|
self._profile = None
|
||||||
|
|
||||||
# Widgets
|
# Widgets
|
||||||
vbox = Gtk.VBox()
|
hbox = Gtk.HBox()
|
||||||
self.pack_start(vbox, True, False, 0)
|
self.pack_start(hbox, True, False, 0)
|
||||||
self._table = Gtk.Table(6, 2, False)
|
grid = Gtk.Grid()
|
||||||
vbox.pack_start(self._table, True, False, 0)
|
grid.set_column_spacing(5)
|
||||||
# Profile
|
grid.set_column_homogeneous(True)
|
||||||
profile_box = Gtk.HBox()
|
hbox.pack_start(grid, True, False, 0)
|
||||||
self._table.attach(profile_box, 0, 2, 0, 1)
|
# Zeroconf
|
||||||
# Profile Selection
|
zeroconf_box = Gtk.HBox()
|
||||||
self._profile_combo = Gtk.ComboBox.new_with_model(self._profiles)
|
grid.add(zeroconf_box)
|
||||||
self._profile_combo.set_entry_text_column(0)
|
# Zeroconf list
|
||||||
|
self._zeroconf_list = Gtk.TreeView(self._services)
|
||||||
|
self._zeroconf_list.get_selection().set_mode(Gtk.SelectionMode.SINGLE)
|
||||||
renderer = Gtk.CellRendererText()
|
renderer = Gtk.CellRendererText()
|
||||||
self._profile_combo.pack_start(renderer, True)
|
column = Gtk.TreeViewColumn("Zeroconf", renderer, text=0)
|
||||||
self._profile_combo.add_attribute(renderer, "text", 0)
|
self._zeroconf_list.append_column(column)
|
||||||
profile_box.pack_start(self._profile_combo, True, True, 0)
|
zeroconf_box.pack_start(self._zeroconf_list, True, True, 0)
|
||||||
# Profile Management
|
# Separator
|
||||||
profile_button_box = Gtk.HBox()
|
separator = Gtk.Separator.new(Gtk.Orientation.VERTICAL)
|
||||||
profile_box.pack_end(profile_button_box, False, True, 0)
|
zeroconf_box.pack_end(separator, False, False, 5)
|
||||||
# New Profile
|
# Connection grid
|
||||||
self._profile_new_button = Gtk.Button()
|
connection_grid = Gtk.Grid()
|
||||||
self._profile_new_button.set_image(Gtk.Image.new_from_stock(Gtk.STOCK_ADD, Gtk.IconSize.BUTTON))
|
grid.attach_next_to(connection_grid, zeroconf_box, Gtk.PositionType.RIGHT, 1, 1)
|
||||||
profile_button_box.add(self._profile_new_button)
|
|
||||||
# Delete Profile
|
|
||||||
self._profile_delete_button = Gtk.Button()
|
|
||||||
self._profile_delete_button.set_image(Gtk.Image.new_from_stock(Gtk.STOCK_DELETE, Gtk.IconSize.BUTTON))
|
|
||||||
profile_button_box.add(self._profile_delete_button)
|
|
||||||
# Host
|
# Host
|
||||||
host_label = Gtk.Label("Host:")
|
host_label = Gtk.Label("Host:")
|
||||||
host_label.set_alignment(0, 0.5)
|
host_label.set_alignment(0, 0.5)
|
||||||
self._table.attach(host_label, 0, 1, 1, 2)
|
connection_grid.add(host_label)
|
||||||
self._host_entry = Gtk.Entry()
|
self._host_entry = Gtk.Entry()
|
||||||
self._host_entry.set_text("localhost")
|
self._host_entry.set_text("localhost")
|
||||||
self._table.attach(self._host_entry, 1, 2, 1, 2)
|
connection_grid.attach_next_to(self._host_entry, host_label, Gtk.PositionType.BOTTOM, 1, 1)
|
||||||
# Port
|
# Port
|
||||||
port_label = Gtk.Label("Port:")
|
port_label = Gtk.Label("Port:")
|
||||||
port_label.set_alignment(0, 0.5)
|
port_label.set_alignment(0, 0.5)
|
||||||
self._table.attach(port_label, 0, 1, 2, 3)
|
connection_grid.attach_next_to(port_label, self._host_entry, Gtk.PositionType.BOTTOM, 1, 1)
|
||||||
adjustment = Gtk.Adjustment(6600, 1024, 9999, 1, 10, 10)
|
adjustment = Gtk.Adjustment(6600, 1024, 9999, 1, 10, 10)
|
||||||
self._port_spinner = Gtk.SpinButton()
|
self._port_spinner = Gtk.SpinButton()
|
||||||
self._port_spinner.set_adjustment(adjustment)
|
self._port_spinner.set_adjustment(adjustment)
|
||||||
self._table.attach(self._port_spinner, 1, 2, 2, 3)
|
connection_grid.attach_next_to(self._port_spinner, port_label, Gtk.PositionType.BOTTOM, 1, 1)
|
||||||
# Passwort
|
# Passwort
|
||||||
password_label = Gtk.Label("Password:")
|
password_label = Gtk.Label("Password:")
|
||||||
password_label.set_alignment(0, 0.5)
|
password_label.set_alignment(0, 0.5)
|
||||||
self._table.attach(password_label, 0, 1, 3, 4)
|
connection_grid.attach_next_to(password_label, self._port_spinner, Gtk.PositionType.BOTTOM, 1, 1)
|
||||||
self._password_entry = Gtk.Entry()
|
self._password_entry = Gtk.Entry()
|
||||||
self._table.attach(self._password_entry, 1, 2, 3, 4)
|
self._password_entry.set_input_purpose(Gtk.InputPurpose.PASSWORD)
|
||||||
|
self._password_entry.set_visibility(False)
|
||||||
|
connection_grid.attach_next_to(self._password_entry, password_label, Gtk.PositionType.BOTTOM, 1, 1)
|
||||||
# Image dir
|
# Image dir
|
||||||
image_dir_label = Gtk.Label("Image Dir:")
|
image_dir_label = Gtk.Label("Image Dir:")
|
||||||
image_dir_label.set_alignment(0, 0.5)
|
image_dir_label.set_alignment(0, 0.5)
|
||||||
self._table.attach(image_dir_label, 0, 1, 4, 5)
|
connection_grid.attach_next_to(image_dir_label, self._password_entry, Gtk.PositionType.BOTTOM, 1, 1)
|
||||||
self._image_dir_entry = Gtk.Entry()
|
self._image_dir_entry = Gtk.Entry()
|
||||||
self._table.attach(self._image_dir_entry, 1, 2, 4, 5)
|
connection_grid.attach_next_to(self._image_dir_entry, image_dir_label, Gtk.PositionType.BOTTOM, 1, 1)
|
||||||
# Autoconnect
|
|
||||||
self._autoconnect_button = Gtk.CheckButton("Autoconnect")
|
# Zeroconf provider
|
||||||
self._table.attach(self._autoconnect_button, 1, 2, 5, 6)
|
self._zeroconf_provider = ZeroconfProvider()
|
||||||
|
self._zeroconf_provider.connect_signal(ZeroconfProvider.SIGNAL_SERVICE_NEW, self.on_new_service)
|
||||||
|
|
||||||
# Signals
|
# Signals
|
||||||
self._profiles.connect('row-changed', self.on_profiles_changed)
|
self._zeroconf_list.get_selection().connect('changed', self.on_service_selected)
|
||||||
self._profiles.connect('row-inserted', self.on_profiles_changed)
|
self._zeroconf_list.connect('focus-out-event', self.on_zeroconf_list_outfocused)
|
||||||
self._profiles.connect('row-deleted', self.on_profiles_changed)
|
|
||||||
self._profile_combo.connect("changed", self.on_profile_combo_changed)
|
|
||||||
self._profile_new_button.connect('clicked', self.on_profile_new_clicked)
|
|
||||||
self._profile_delete_button.connect('clicked', self.on_profile_delete_clicked)
|
|
||||||
self._host_entry.connect('focus-out-event', self.on_host_entry_outfocused)
|
self._host_entry.connect('focus-out-event', self.on_host_entry_outfocused)
|
||||||
self._port_spinner.connect('value-changed', self.on_port_spinner_value_changed)
|
self._port_spinner.connect('value-changed', self.on_port_spinner_value_changed)
|
||||||
self._password_entry.connect('focus-out-event', self.on_password_entry_outfocused)
|
self._password_entry.connect('focus-out-event', self.on_password_entry_outfocused)
|
||||||
self._image_dir_entry.connect('focus-out-event', self.on_image_dir_entry_outfocused)
|
self._image_dir_entry.connect('focus-out-event', self.on_image_dir_entry_outfocused)
|
||||||
self._autoconnect_button.connect('toggled', self.on_autoconnect_button_toggled)
|
|
||||||
|
|
||||||
# Actions
|
# Actions
|
||||||
self._load_profiles()
|
#self._load_profiles()
|
||||||
|
|
||||||
|
|
||||||
def get_name(self):
|
def get_name(self):
|
||||||
|
|
@ -658,63 +661,37 @@ class ConnectionPanel(Panel, Gtk.HBox):
|
||||||
return "Server"
|
return "Server"
|
||||||
|
|
||||||
|
|
||||||
def on_profiles_changed(self, *data):
|
def on_new_service(self, service):
|
||||||
self._profile_config.save()
|
name, host, port = service
|
||||||
|
self._services.append([name, host, port])
|
||||||
|
|
||||||
|
|
||||||
def on_profile_combo_changed(self, combo):
|
def on_service_selected(self, selection):
|
||||||
(index, profile) = self._get_selected_profile()
|
model, treeiter = selection.get_selected()
|
||||||
if profile is not None:
|
if treeiter != None:
|
||||||
self._profile = profile
|
service = model[treeiter]
|
||||||
self.set_host(self._profile.get('host'))
|
self.set_host(service[1])
|
||||||
self.set_port(int(self._profile.get('port')))
|
self.set_port(service[2])
|
||||||
self.set_password(self._profile.get('password'))
|
|
||||||
self.set_image_dir(self._profile.get('image_dir'))
|
|
||||||
self._autoconnect_button.set_active(ConnectionPanel.TAG_AUTOCONNECT in self._profile.get_tags())
|
|
||||||
self._callback(ConnectionPanel.SIGNAL_PROFILE_CHANGED, index, profile)
|
|
||||||
|
|
||||||
|
|
||||||
def on_profile_new_clicked(self, widget):
|
def on_zeroconf_list_outfocused(self, widget, event):
|
||||||
profile = mcg.MCGProfile()
|
self._zeroconf_list.get_selection().unselect_all()
|
||||||
self._profile_config.add_profile(profile)
|
|
||||||
self._reload_profiles()
|
|
||||||
self._profile_combo.set_active(len(self._profiles)-1)
|
|
||||||
|
|
||||||
|
|
||||||
def on_profile_delete_clicked(self, widget):
|
|
||||||
(index, profile) = self._get_selected_profile()
|
|
||||||
if profile is not None:
|
|
||||||
self._profile_config.delete_profile(profile)
|
|
||||||
self._reload_profiles()
|
|
||||||
self._profile_combo.set_active(0)
|
|
||||||
|
|
||||||
|
|
||||||
def on_host_entry_outfocused(self, widget, event):
|
def on_host_entry_outfocused(self, widget, event):
|
||||||
self._profile.set('host', widget.get_text())
|
self._call_back()
|
||||||
self._profiles.set(self._profile_combo.get_active_iter(), 0, widget.get_text())
|
|
||||||
|
|
||||||
|
|
||||||
def on_port_spinner_value_changed(self, widget):
|
def on_port_spinner_value_changed(self, widget):
|
||||||
self._profile.set('port', self.get_port())
|
self._call_back()
|
||||||
|
|
||||||
|
|
||||||
def on_password_entry_outfocused(self, widget, event):
|
def on_password_entry_outfocused(self, widget, event):
|
||||||
self._profile.set('password', widget.get_text())
|
self._call_back()
|
||||||
|
|
||||||
|
|
||||||
def on_image_dir_entry_outfocused(self, widget, event):
|
def on_image_dir_entry_outfocused(self, widget, event):
|
||||||
self._profile.set('image_dir', widget.get_text())
|
self._call_back()
|
||||||
|
|
||||||
|
|
||||||
def on_autoconnect_button_toggled(self, widget):
|
|
||||||
tags = self._profile.get_tags()
|
|
||||||
if widget.get_active():
|
|
||||||
if ConnectionPanel.TAG_AUTOCONNECT not in tags:
|
|
||||||
tags.append(ConnectionPanel.TAG_AUTOCONNECT)
|
|
||||||
else:
|
|
||||||
if ConnectionPanel.TAG_AUTOCONNECT in tags:
|
|
||||||
tags.remove(ConnectionPanel.TAG_AUTOCONNECT)
|
|
||||||
self._profile.set_tags(tags)
|
|
||||||
|
|
||||||
|
|
||||||
def set_host(self, host):
|
def set_host(self, host):
|
||||||
|
|
@ -754,31 +731,8 @@ class ConnectionPanel(Panel, Gtk.HBox):
|
||||||
return self._image_dir_entry.get_text()
|
return self._image_dir_entry.get_text()
|
||||||
|
|
||||||
|
|
||||||
def select_profile(self, index):
|
def _call_back(self):
|
||||||
if len(self._profiles) <= index:
|
self._callback(ConnectionPanel.SIGNAL_CONNECTION_CHANGED, self.get_host(), self.get_port(), self.get_password(), self.get_image_dir())
|
||||||
index = 0
|
|
||||||
self._profile_combo.set_active(index)
|
|
||||||
|
|
||||||
|
|
||||||
def _load_profiles(self):
|
|
||||||
self._profile_config.load()
|
|
||||||
for profile in self._profile_config.get_profiles():
|
|
||||||
self._profiles.append([str(profile)])
|
|
||||||
|
|
||||||
|
|
||||||
def _reload_profiles(self):
|
|
||||||
self._profiles.clear()
|
|
||||||
for profile in self._profile_config.get_profiles():
|
|
||||||
self._profiles.append([str(profile)])
|
|
||||||
|
|
||||||
|
|
||||||
def _get_selected_profile(self):
|
|
||||||
index = self._profile_combo.get_active()
|
|
||||||
if index >= 0:
|
|
||||||
profiles = self._profile_config.get_profiles()
|
|
||||||
if index < len(profiles):
|
|
||||||
return (index, profiles[index])
|
|
||||||
return (-1, None)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1493,3 +1447,45 @@ class StackSwitcher(mcg.Base, Gtk.StackSwitcher):
|
||||||
else:
|
else:
|
||||||
self._temp_button = None
|
self._temp_button = None
|
||||||
self._callback(StackSwitcher.SIGNAL_STACK_SWITCHED, self)
|
self._callback(StackSwitcher.SIGNAL_STACK_SWITCHED, self)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class ZeroconfProvider(mcg.Base):
|
||||||
|
SIGNAL_SERVICE_NEW = 'service-new'
|
||||||
|
TYPE = '_mpd._tcp'
|
||||||
|
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
mcg.Base.__init__(self)
|
||||||
|
self._service_resolvers = []
|
||||||
|
self._services = {}
|
||||||
|
# Client
|
||||||
|
self._client = Avahi.Client(flags=0,)
|
||||||
|
self._client.start()
|
||||||
|
# Browser
|
||||||
|
self._service_browser = Avahi.ServiceBrowser(domain='local', flags=0, interface=-1, protocol=Avahi.Protocol.GA_PROTOCOL_UNSPEC, type=ZeroconfProvider.TYPE)
|
||||||
|
self._service_browser.connect('new_service', self.on_new_service)
|
||||||
|
self._service_browser.attach(self._client)
|
||||||
|
|
||||||
|
|
||||||
|
def on_new_service(self, browser, interface, protocol, name, type, domain, flags):
|
||||||
|
if not (flags & Avahi.LookupResultFlags.GA_LOOKUP_RESULT_LOCAL):
|
||||||
|
service_resolver = Avahi.ServiceResolver(interface=interface, protocol=protocol, name=name, type=type, domain=domain, aprotocol=Avahi.Protocol.GA_PROTOCOL_UNSPEC, flags=0,)
|
||||||
|
service_resolver.connect('found', self.on_found)
|
||||||
|
service_resolver.connect('failure', self.on_failure)
|
||||||
|
service_resolver.attach(self._client)
|
||||||
|
self._service_resolvers.append(service_resolver)
|
||||||
|
|
||||||
|
|
||||||
|
def on_found(self, resolver, interface, protocol, name, type, domain, host, date, port, *args):
|
||||||
|
if (host, port) not in self._services.keys():
|
||||||
|
service = (name,host,port)
|
||||||
|
self._services[(host,port)] = service
|
||||||
|
self._callback(ZeroconfProvider.SIGNAL_SERVICE_NEW, service)
|
||||||
|
|
||||||
|
|
||||||
|
def on_failure(self, resolver, date):
|
||||||
|
if resolver in self._service_resolvers:
|
||||||
|
self._service_resolvers.remove(resolver)
|
||||||
|
|
||||||
|
|
|
||||||
115
mcg.py
115
mcg.py
|
|
@ -202,6 +202,11 @@ class Client(Base):
|
||||||
self._add_action(self._set_volume, volume)
|
self._add_action(self._set_volume, volume)
|
||||||
|
|
||||||
|
|
||||||
|
def test(self):
|
||||||
|
self._logger.info("test")
|
||||||
|
self._add_action(self._test)
|
||||||
|
|
||||||
|
|
||||||
# Private methods
|
# Private methods
|
||||||
|
|
||||||
def _connect(self, host, port, password):
|
def _connect(self, host, port, password):
|
||||||
|
|
@ -836,116 +841,6 @@ class MCGConfig(configparser.ConfigParser):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class MCGProfileConfig(MCGConfig):
|
|
||||||
CONFIG_FILE = 'profiles.conf'
|
|
||||||
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
MCGConfig.__init__(self, MCGProfileConfig.CONFIG_FILE)
|
|
||||||
self._profiles = []
|
|
||||||
|
|
||||||
|
|
||||||
def add_profile(self, profile):
|
|
||||||
self._profiles.append(profile)
|
|
||||||
|
|
||||||
|
|
||||||
def delete_profile(self, profile):
|
|
||||||
if profile in self._profiles:
|
|
||||||
self._profiles.remove(profile)
|
|
||||||
self._force_default_profile()
|
|
||||||
|
|
||||||
|
|
||||||
def get_profiles(self):
|
|
||||||
return self._profiles
|
|
||||||
|
|
||||||
|
|
||||||
def load(self):
|
|
||||||
super().load()
|
|
||||||
count = 0
|
|
||||||
if self.has_section('profiles'):
|
|
||||||
if self.has_option('profiles', 'count'):
|
|
||||||
count = self.getint('profiles', 'count')
|
|
||||||
for index in range(count):
|
|
||||||
section = 'profile'+str(index+1)
|
|
||||||
if self.has_section(section):
|
|
||||||
profile = MCGProfile()
|
|
||||||
for attribute in profile.get_attributes():
|
|
||||||
if self.has_option(section, attribute):
|
|
||||||
profile.set(attribute, self.get(section, attribute))
|
|
||||||
self._profiles.append(profile)
|
|
||||||
self._force_default_profile()
|
|
||||||
|
|
||||||
|
|
||||||
def save(self):
|
|
||||||
if not self.has_section('profiles'):
|
|
||||||
self.add_section('profiles')
|
|
||||||
self.set('profiles', 'count', str(len(self._profiles)))
|
|
||||||
|
|
||||||
for index in range(len(self._profiles)):
|
|
||||||
profile = self._profiles[index]
|
|
||||||
section = 'profile'+str(index+1)
|
|
||||||
if not self.has_section(section):
|
|
||||||
self.add_section(section)
|
|
||||||
for attribute in profile.get_attributes():
|
|
||||||
self.set(section, attribute, str(profile.get(attribute)))
|
|
||||||
for section in self.sections()[len(self._profiles)+1:]:
|
|
||||||
self.remove_section(section)
|
|
||||||
super().save()
|
|
||||||
|
|
||||||
|
|
||||||
def _force_default_profile(self):
|
|
||||||
if len(self._profiles) == 0:
|
|
||||||
self._profiles.append(MCGProfile())
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class MCGConfigurable:
|
|
||||||
def __init__(self):
|
|
||||||
self._attributes = []
|
|
||||||
|
|
||||||
|
|
||||||
def get(self, attribute):
|
|
||||||
return getattr(self, attribute)
|
|
||||||
|
|
||||||
|
|
||||||
def set(self, attribute, value):
|
|
||||||
setattr(self, attribute, value)
|
|
||||||
if attribute not in self._attributes:
|
|
||||||
self._attributes.append(attribute)
|
|
||||||
|
|
||||||
|
|
||||||
def get_attributes(self):
|
|
||||||
return self._attributes
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class MCGProfile(MCGConfigurable):
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
MCGConfigurable.__init__(self)
|
|
||||||
self.set('host', "localhost")
|
|
||||||
self.set('port', 6600)
|
|
||||||
self.set('password', "")
|
|
||||||
self.set('image_dir', "")
|
|
||||||
self.set('tags', "")
|
|
||||||
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.get("host")
|
|
||||||
|
|
||||||
|
|
||||||
def get_tags(self):
|
|
||||||
return self.get('tags').split(',')
|
|
||||||
|
|
||||||
|
|
||||||
def set_tags(self, tags):
|
|
||||||
self.set('tags', ','.join(tags))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class MCGCache():
|
class MCGCache():
|
||||||
DIRNAME = '~/.cache/mcg/'
|
DIRNAME = '~/.cache/mcg/'
|
||||||
SIZE_FILENAME = 'size'
|
SIZE_FILENAME = 'size'
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue